From aa9004449786be6ea9f761f0cab0664cf79d0e36 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 08:54:04 -0400 Subject: [PATCH 001/558] Roll Skia from 3a6550ab8965 to f21a717e1347 (3 revisions) (#35043) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 615876c8930d0..7c3ce16c5843a 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': '3a6550ab89657cbe4c977589cc8c03fe7aad65cc', + 'skia_revision': 'f21a717e1347b022ec72f26dbb8bae66b4c6f7a2', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f30bdf768ad22..0c1842345c5fb 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 55ba1fcdf9cf335e810af15c73b9254e +Signature: d1acca273e5026e188310f7c464a250c UNUSED LICENSES: From fb222ad68a0725db0a02bf6d01409d87ef36eedf Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 09:11:04 -0400 Subject: [PATCH 002/558] Roll Dart SDK from 03c6091964b5 to c9dc429fb986 (1 revision) (#35045) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 7c3ce16c5843a..eedfe318da537 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '03c6091964b59b587e0cfa5ee822a1aa5947b8b8', + 'dart_revision': 'c9dc429fb986010b6d57133c16bc58ccffacd00e', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 884899f3dc60544695b1b79a5adc5e00395b9667 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 10:48:05 -0400 Subject: [PATCH 003/558] Roll Skia from f21a717e1347 to 1dabe55b7969 (1 revision) (#35047) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index eedfe318da537..67515f84c14b6 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': 'f21a717e1347b022ec72f26dbb8bae66b4c6f7a2', + 'skia_revision': '1dabe55b79696e6a0f8ddaa925b810f6a947ed37', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 0c1842345c5fb..db8c3256449b6 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d1acca273e5026e188310f7c464a250c +Signature: 358b1ca2a81d0e7a1a89f3e044a184b8 UNUSED LICENSES: From 924d3cd25dc85cfbd076e1ef30aacfa276e12bce Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 12:15:04 -0400 Subject: [PATCH 004/558] Roll Skia from 1dabe55b7969 to c65c95a453b2 (2 revisions) (#35048) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 67515f84c14b6..a98cf5f2bcb78 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': '1dabe55b79696e6a0f8ddaa925b810f6a947ed37', + 'skia_revision': 'c65c95a453b2d73facd3366e5d412df13941ddb2', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index db8c3256449b6..e1ea339c35eb6 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 358b1ca2a81d0e7a1a89f3e044a184b8 +Signature: 351bb84e2c2506e8cc1228128381e4d0 UNUSED LICENSES: From 03910785a2d8dd11d2ab47088ab098b27fb4cd4d Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Mon, 1 Aug 2022 09:25:04 -0700 Subject: [PATCH 005/558] Enable avoid_returning_null & native_function_body_in_non_sdk_code (#35015) --- analysis_options.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 64f8d393da8dd..867bfa30a999b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -16,7 +16,6 @@ analyzer: missing_required_param: warning # treat missing returns as a warning (not a hint) missing_return: warning - native_function_body_in_non_sdk_code: ignore # DIFFERENT FROM FLUTTER/FLUTTER # allow having TODO comments in the code todo: ignore # allow dart:ui to import dart:_internal @@ -65,7 +64,7 @@ linter: - avoid_relative_lib_imports - avoid_renaming_method_parameters - avoid_return_types_on_setters - # - avoid_returning_null # still violated by some pre-nnbd code that we haven't yet migrated + - avoid_returning_null - avoid_returning_null_for_future - avoid_returning_null_for_void # - avoid_returning_this # there are enough valid reasons to return `this` that this lint ends up with too many false positives From 6d2fd23404b85c238cf8d9d5a95538f65a7f7b97 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Mon, 1 Aug 2022 09:27:03 -0700 Subject: [PATCH 006/558] Enable conditional_uri_does_not_exist (#35021) --- analysis_options.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 867bfa30a999b..90b4b99515146 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -88,7 +88,7 @@ linter: # - close_sinks # not reliable enough - combinators_ordering # - comment_references # blocked on https://github.com/dart-lang/linter/issues/1142 - # - conditional_uri_does_not_exist # not yet tested + - conditional_uri_does_not_exist # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 - control_flow_in_finally - curly_braces_in_flow_control_structures From 26c2efc499449cff83540d4da346fa62b844a6cd Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 13:23:04 -0400 Subject: [PATCH 007/558] Roll Skia from c65c95a453b2 to 07b833fd6c79 (7 revisions) (#35050) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index a98cf5f2bcb78..42fda65b6cca3 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': 'c65c95a453b2d73facd3366e5d412df13941ddb2', + 'skia_revision': '07b833fd6c79d89593a9735154bf61c5c9d5ad46', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index e1ea339c35eb6..0949c5e14b3b6 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 351bb84e2c2506e8cc1228128381e4d0 +Signature: e3bd2f2fed908d3abff03d8b74fe28a8 UNUSED LICENSES: From 3b3286d0a8d3457b7336665105d4a095fc7d713c Mon Sep 17 00:00:00 2001 From: joshualitt Date: Mon, 1 Aug 2022 10:26:26 -0700 Subject: [PATCH 008/558] [web] Changes to support `dart:wasm`. (#34991) --- sky/packages/sky_engine/BUILD.gn | 10 ++++++++++ sky/packages/sky_engine/lib/_embedder.yaml | 1 + web_sdk/libraries.json | 16 ++++++++++++++++ web_sdk/libraries.yaml | 11 +++++++++++ web_sdk/sdk_rewriter.dart | 1 - web_sdk/test/sdk_rewriter_test.dart | 1 - 6 files changed, 38 insertions(+), 2 deletions(-) diff --git a/sky/packages/sky_engine/BUILD.gn b/sky/packages/sky_engine/BUILD.gn index 89ff158dbcd47..88e059a8dae08 100644 --- a/sky/packages/sky_engine/BUILD.gn +++ b/sky/packages/sky_engine/BUILD.gn @@ -22,6 +22,7 @@ import("//third_party/dart/sdk/lib/js/js_sources.gni") import("//third_party/dart/sdk/lib/js_util/js_util_sources.gni") import("//third_party/dart/sdk/lib/math/math_sources.gni") import("//third_party/dart/sdk/lib/typed_data/typed_data_sources.gni") +import("//third_party/dart/sdk/lib/wasm/wasm_sources.gni") if (!is_fuchsia) { copy("copy_sky_engine_authors") { @@ -145,6 +146,13 @@ copy("typed_data") { ] } +copy("wasm") { + lib_path = rebase_path("wasm", "", dart_sdk_lib_path) + sources = rebase_path(wasm_sdk_sources, "", lib_path) + outputs = + [ "$root_gen_dir/dart-pkg/sky_engine/lib/wasm/{{source_file_part}}" ] +} + copy("copy_dart_ui") { sources = dart_ui_files @@ -178,6 +186,7 @@ group("copy_dart_sdk") { ":js_util", ":math", ":typed_data", + ":wasm", ] } @@ -202,6 +211,7 @@ generated_file("_embedder_yaml") { " \"dart:math\": \"math/math.dart\"", " \"dart:typed_data\": \"typed_data/typed_data.dart\"", " \"dart:ui\": \"ui/ui.dart\"", + " \"dart:wasm\": \"wasm/wasm_types.dart\"", "", " \"dart:_http\": \"_http/http.dart\"", " \"dart:_interceptors\": \"_interceptors/interceptors.dart\"", diff --git a/sky/packages/sky_engine/lib/_embedder.yaml b/sky/packages/sky_engine/lib/_embedder.yaml index c59d3623cd678..d14230709a8a7 100644 --- a/sky/packages/sky_engine/lib/_embedder.yaml +++ b/sky/packages/sky_engine/lib/_embedder.yaml @@ -16,6 +16,7 @@ embedded_libs: "dart:math": "../../../../../third_party/dart/sdk/lib/math/math.dart" "dart:typed_data": "../../../../../third_party/dart/sdk/lib/typed_data/typed_data.dart" "dart:ui": "../../../../lib/ui/ui.dart" + "dart:wasm": "../../../../../third_party/dart/sdk/lib/wasm/wasm_types.dart" "dart:_http": "../../../../../third_party/dart/sdk/lib/_http/http.dart" "dart:_interceptors": "../../../../../third_party/dart/sdk/lib/_interceptors/interceptors.dart" diff --git a/web_sdk/libraries.json b/web_sdk/libraries.json index c0ddf48ca527f..01a9fece85a0e 100644 --- a/web_sdk/libraries.json +++ b/web_sdk/libraries.json @@ -32,5 +32,21 @@ "uri": "lib/_engine/engine.dart" } } + }, + "wasm": { + "include": [ + { + "path": "../dart-sdk/lib/libraries.json", + "target": "wasm" + } + ], + "libraries": { + "ui": { + "uri": "lib/ui/ui.dart" + }, + "_engine": { + "uri": "lib/_engine/engine.dart" + } + } } } \ No newline at end of file diff --git a/web_sdk/libraries.yaml b/web_sdk/libraries.yaml index 73cfbe3bf8258..46bb23f079dec 100644 --- a/web_sdk/libraries.yaml +++ b/web_sdk/libraries.yaml @@ -34,3 +34,14 @@ dart2js: _engine: uri: "lib/_engine/engine.dart" + +wasm: + include: + - {path: "../dart-sdk/lib/libraries.json", target: wasm} + + libraries: + ui: + uri: "lib/ui/ui.dart" + + _engine: + uri: "lib/_engine/engine.dart" diff --git a/web_sdk/sdk_rewriter.dart b/web_sdk/sdk_rewriter.dart index 39da4b6dfe7a6..c71e0d5f8a054 100644 --- a/web_sdk/sdk_rewriter.dart +++ b/web_sdk/sdk_rewriter.dart @@ -45,7 +45,6 @@ import 'dart:developer' as developer; import 'dart:js_util' as js_util; import 'dart:_js_annotations'; import 'dart:math' as math; -import 'dart:svg' as svg; import 'dart:typed_data'; import 'dart:ui' as ui; '''), diff --git a/web_sdk/test/sdk_rewriter_test.dart b/web_sdk/test/sdk_rewriter_test.dart index 4d3cccc8a9b07..36de7f6939798 100644 --- a/web_sdk/test/sdk_rewriter_test.dart +++ b/web_sdk/test/sdk_rewriter_test.dart @@ -33,7 +33,6 @@ import 'dart:developer' as developer; import 'dart:js_util' as js_util; import 'dart:_js_annotations'; import 'dart:math' as math; -import 'dart:svg' as svg; import 'dart:typed_data'; import 'dart:ui' as ui; From 7d25cbadbef40538c85ac0bbeaf1e7d6953721d1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 13:37:04 -0400 Subject: [PATCH 009/558] Roll Fuchsia Linux SDK from 13FsbGdE9... to v8t2ulUK5... (#35049) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 42fda65b6cca3..1c757829230ae 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': '13FsbGdE97bnZF8KOg3CT33qNvj481lj3Ke4vN4kRMEC' + 'version': 'v8t2ulUK5j2G1pxiLp5MQM-TynZ-q6FpeATFYCBRZ_4C' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 037552e059f96..c8e596c0df640 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: f84c656031e13f699bfe7293ac52fd9e +Signature: b69dd228524fa047db35855b5227ca35 UNUSED LICENSES: From f182794500dcb17f6db452608015499fc038b961 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Mon, 1 Aug 2022 10:43:03 -0700 Subject: [PATCH 010/558] Minor adjustment to analysis_options.yaml (#35051) --- analysis_options.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 90b4b99515146..dcbaa56a57069 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -5,9 +5,6 @@ # "DIFFERENT FROM FLUTTER/FLUTTER" below. analyzer: - exclude: - # Fixture depends on dart:ui and raises false positives. - - flutter_frontend_server/test/fixtures/lib/main.dart language: strict-casts: true strict-raw-types: true @@ -27,6 +24,9 @@ analyzer: unnecessary_null_comparison: ignore # TODO(goderbauer): remove when https://github.com/dart-lang/sdk/issues/49563 is fixed. ffi_native_unexpected_number_of_parameters: ignore # DIFFERENT FROM FLUTTER/FLUTTER + exclude: # DIFFERENT FROM FLUTTER/FLUTTER + # Fixture depends on dart:ui and raises false positives. + - flutter_frontend_server/test/fixtures/lib/main.dart linter: rules: From 25e8021c91e4c4f3805f6fa635868d4dca1e29f0 Mon Sep 17 00:00:00 2001 From: Jaeheon Yi Date: Mon, 1 Aug 2022 12:06:23 -0700 Subject: [PATCH 011/558] [fuchsia] Convert Gfx PlatformView to use modern TouchSource API (#35018) Original PR: #32877 Revert of #32877: commit 1965c92ea417e1d4114b5bfea03b93e3532cb1f2 (#33471) *This* patch: Revert of #33471 fxbug.dev/85125 --- shell/platform/fuchsia/flutter/engine.cc | 4 +- .../platform/fuchsia/flutter/platform_view.cc | 48 +++++++++---------- .../fuchsia/flutter/platform_view_unittest.cc | 3 +- .../fuchsia/flutter/pointer_delegate.cc | 4 +- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/shell/platform/fuchsia/flutter/engine.cc b/shell/platform/fuchsia/flutter/engine.cc index ab94955d6776a..1d491d393302c 100644 --- a/shell/platform/fuchsia/flutter/engine.cc +++ b/shell/platform/fuchsia/flutter/engine.cc @@ -166,8 +166,8 @@ void Engine::Initialize( } else { gfx_protocols.set_view_focuser(focuser.NewRequest()); gfx_protocols.set_view_ref_focused(view_ref_focused.NewRequest()); - // TODO(fxbug.dev/85125): Enable TouchSource for GFX. - // gfx_protocols.set_touch_source(touch_source.NewRequest()); + gfx_protocols.set_touch_source(touch_source.NewRequest()); + // GFX used only on products without a mouse. } scenic->CreateSessionT(std::move(gfx_protocols), [] {}); diff --git a/shell/platform/fuchsia/flutter/platform_view.cc b/shell/platform/fuchsia/flutter/platform_view.cc index 6ae402b4ef163..85d671c1e773f 100644 --- a/shell/platform/fuchsia/flutter/platform_view.cc +++ b/shell/platform/fuchsia/flutter/platform_view.cc @@ -109,33 +109,31 @@ PlatformView::PlatformView( }); // Begin watching for pointer events. - if (is_flatland) { // TODO(fxbug.dev/85125): make unconditional - pointer_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()]( - std::vector events) { - if (!weak) { - FML_LOG(WARNING) << "PlatformView use-after-free attempted. Ignoring."; - return; - } + pointer_delegate_->WatchLoop([weak = weak_factory_.GetWeakPtr()]( + std::vector events) { + if (!weak) { + FML_LOG(WARNING) << "PlatformView use-after-free attempted. Ignoring."; + return; + } - if (events.size() == 0) { - return; // No work, bounce out. - } + if (events.empty()) { + return; // No work, bounce out. + } - // If pixel ratio hasn't been set, use a default value of 1. - const float pixel_ratio = weak->view_pixel_ratio_.value_or(1.f); - auto packet = std::make_unique(events.size()); - for (size_t i = 0; i < events.size(); ++i) { - auto& event = events[i]; - // Translate logical to physical coordinates, as per - // flutter::PointerData contract. Done here because pixel ratio comes - // from the graphics API. - event.physical_x = event.physical_x * pixel_ratio; - event.physical_y = event.physical_y * pixel_ratio; - packet->SetPointerData(i, event); - } - weak->DispatchPointerDataPacket(std::move(packet)); - }); - } + // If pixel ratio hasn't been set, use a default value of 1. + const float pixel_ratio = weak->view_pixel_ratio_.value_or(1.f); + auto packet = std::make_unique(events.size()); + for (size_t i = 0; i < events.size(); ++i) { + auto& event = events[i]; + // Translate logical to physical coordinates, as per + // flutter::PointerData contract. Done here because pixel ratio comes + // from the graphics API. + event.physical_x = event.physical_x * pixel_ratio; + event.physical_y = event.physical_y * pixel_ratio; + packet->SetPointerData(i, event); + } + weak->DispatchPointerDataPacket(std::move(packet)); + }); // Configure the pointer injector delegate. pointer_injector_delegate_ = std::make_unique( diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index b39fdb60edde6..3afa8526877f3 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -1394,8 +1394,7 @@ TEST_F(PlatformViewTests, OnShaderWarmup) { EXPECT_EQ(expected_result_string, response->result_string); } -// TODO(fxbug.dev/85125): Enable when GFX converts to TouchSource. -TEST_F(PlatformViewTests, DISABLED_TouchSourceLogicalToPhysicalConversion) { +TEST_F(PlatformViewTests, TouchSourceLogicalToPhysicalConversion) { constexpr std::array, 2> kRect = {{{0, 0}, {20, 20}}}; constexpr std::array kIdentity = {1, 0, 0, 0, 1, 0, 0, 0, 1}; constexpr fuchsia::ui::pointer::TouchInteractionId kIxnOne = { diff --git a/shell/platform/fuchsia/flutter/pointer_delegate.cc b/shell/platform/fuchsia/flutter/pointer_delegate.cc index 71cdb63d73eb1..1977521468a77 100644 --- a/shell/platform/fuchsia/flutter/pointer_delegate.cc +++ b/shell/platform/fuchsia/flutter/pointer_delegate.cc @@ -447,7 +447,9 @@ void PointerDelegate::WatchLoop( // Start watching both channels. touch_source_->Watch(std::move(touch_responses_), /*copy*/ touch_responder_); touch_responses_.clear(); - mouse_source_->Watch(/*copy*/ mouse_responder_); + if (mouse_source_) { + mouse_source_->Watch(/*copy*/ mouse_responder_); + } } } // namespace flutter_runner From f9eb93de5eb14853ec41cdf44b841eecab99e82c Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Mon, 1 Aug 2022 20:09:01 +0100 Subject: [PATCH 012/558] [Windows] Merge TaskRunnerWin32 into TaskRunner (#35029) With the removal of the UWP embedder, we can merge Win32-specific implementation classes with their abstract superclasses where those superclasses existed only to support both UWP and Win32. No new tests since this is purely a restructuring of existing code within the Win32 embedder, with no expected change in behaviour. Issue: https://github.com/flutter/flutter/issues/108386 --- ci/licenses_golden/licenses_flutter | 6 +-- shell/platform/windows/BUILD.gn | 6 +-- .../windows/flutter_windows_engine.cc | 2 +- shell/platform/windows/task_runner.cc | 18 ++++++- shell/platform/windows/task_runner.h | 54 +++++++++---------- shell/platform/windows/task_runner_win32.cc | 40 -------------- shell/platform/windows/task_runner_win32.h | 46 ---------------- ..._win32_window.cc => task_runner_window.cc} | 41 +++++++------- ...er_win32_window.h => task_runner_window.h} | 12 +++-- 9 files changed, 76 insertions(+), 149 deletions(-) delete mode 100644 shell/platform/windows/task_runner_win32.cc delete mode 100644 shell/platform/windows/task_runner_win32.h rename shell/platform/windows/{task_runner_win32_window.cc => task_runner_window.cc} (72%) rename shell/platform/windows/{task_runner_win32_window.h => task_runner_window.h} (78%) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 1c8291fb821a9..6b43cac4a16a6 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2428,10 +2428,8 @@ FILE: ../../../flutter/shell/platform/windows/system_utils_unittests.cc FILE: ../../../flutter/shell/platform/windows/task_runner.cc FILE: ../../../flutter/shell/platform/windows/task_runner.h FILE: ../../../flutter/shell/platform/windows/task_runner_unittests.cc -FILE: ../../../flutter/shell/platform/windows/task_runner_win32.cc -FILE: ../../../flutter/shell/platform/windows/task_runner_win32.h -FILE: ../../../flutter/shell/platform/windows/task_runner_win32_window.cc -FILE: ../../../flutter/shell/platform/windows/task_runner_win32_window.h +FILE: ../../../flutter/shell/platform/windows/task_runner_window.cc +FILE: ../../../flutter/shell/platform/windows/task_runner_window.h FILE: ../../../flutter/shell/platform/windows/text_input_manager.cc FILE: ../../../flutter/shell/platform/windows/text_input_manager.h FILE: ../../../flutter/shell/platform/windows/text_input_plugin.cc diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 3aa94757e4cff..d8b39d099be59 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -92,10 +92,8 @@ source_set("flutter_windows_source") { "system_utils.h", "task_runner.cc", "task_runner.h", - "task_runner_win32.cc", - "task_runner_win32.h", - "task_runner_win32_window.cc", - "task_runner_win32_window.h", + "task_runner_window.cc", + "task_runner_window.h", "text_input_manager.cc", "text_input_manager.h", "text_input_plugin.cc", diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 20d7318aaceab..3ed63ae3a3556 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -156,7 +156,7 @@ FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project) embedder_api_.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&embedder_api_); - task_runner_ = TaskRunner::Create( + task_runner_ = std::make_unique( embedder_api_.GetCurrentTime, [this](const auto* task) { if (!engine_) { std::cerr << "Cannot post an engine task when engine is not running." diff --git a/shell/platform/windows/task_runner.cc b/shell/platform/windows/task_runner.cc index 464afbc43827e..10a699403d919 100644 --- a/shell/platform/windows/task_runner.cc +++ b/shell/platform/windows/task_runner.cc @@ -12,7 +12,15 @@ namespace flutter { TaskRunner::TaskRunner(CurrentTimeProc get_current_time, const TaskExpiredCallback& on_task_expired) : get_current_time_(get_current_time), - on_task_expired_(std::move(on_task_expired)) {} + on_task_expired_(std::move(on_task_expired)) { + main_thread_id_ = GetCurrentThreadId(); + task_runner_window_ = TaskRunnerWindow::GetSharedInstance(); + task_runner_window_->AddDelegate(this); +} + +TaskRunner::~TaskRunner() { + task_runner_window_->RemoveDelegate(this); +} std::chrono::nanoseconds TaskRunner::ProcessTasks() { const TaskTimePoint now = GetCurrentTimeForTask(); @@ -101,4 +109,12 @@ void TaskRunner::EnqueueTask(Task task) { WakeUp(); } +bool TaskRunner::RunsTasksOnCurrentThread() const { + return GetCurrentThreadId() == main_thread_id_; +} + +void TaskRunner::WakeUp() { + task_runner_window_->WakeUp(); +} + } // namespace flutter diff --git a/shell/platform/windows/task_runner.h b/shell/platform/windows/task_runner.h index 685ed77e93f08..b211dbedcd427 100644 --- a/shell/platform/windows/task_runner.h +++ b/shell/platform/windows/task_runner.h @@ -14,21 +14,30 @@ #include #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/windows/task_runner_window.h" namespace flutter { typedef uint64_t (*CurrentTimeProc)(); -class TaskRunner { +// A custom task runner that integrates with user32 GetMessage semantics so +// that host app can own its own message loop and flutter still gets to process +// tasks on a timely basis. +class TaskRunner : public TaskRunnerWindow::Delegate { public: using TaskTimePoint = std::chrono::steady_clock::time_point; using TaskExpiredCallback = std::function; using TaskClosure = std::function; - virtual ~TaskRunner() = default; + // Creates a new task runner with the current thread, current time + // provider, and callback for tasks that are ready to be run. + TaskRunner(CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); + + virtual ~TaskRunner(); // Returns `true` if the current thread is this runner's thread. - virtual bool RunsTasksOnCurrentThread() const = 0; + virtual bool RunsTasksOnCurrentThread() const; // Post a Flutter engine task to the event loop for delayed execution. void PostFlutterTask(FlutterTask flutter_task, @@ -47,33 +56,9 @@ class TaskRunner { } } - // Creates a new task runner with the current thread, current time - // provider, and callback for tasks that are ready to be run. - static std::unique_ptr Create( - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); - - protected: - TaskRunner(CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); - - // Schedules timers to call `ProcessTasks()` at the runner's thread. - virtual void WakeUp() = 0; - - // Executes expired task, and returns the duration until the next task - // deadline if exists, otherwise returns `std::chrono::nanoseconds::max()`. - // - // Each platform implementations must call this to schedule the tasks. + // |TaskRunnerWindow::Delegate| std::chrono::nanoseconds ProcessTasks(); - // Returns the current TaskTimePoint that can be used to determine whether a - // task is expired. - // - // Tests can override this to mock up the time. - virtual TaskTimePoint GetCurrentTimeForTask() const { - return TaskTimePoint::clock::now(); - } - private: typedef std::variant TaskVariant; @@ -95,6 +80,17 @@ class TaskRunner { // Enqueues the given task. void EnqueueTask(Task task); + // Schedules timers to call `ProcessTasks()` at the runner's thread. + virtual void WakeUp(); + + // Returns the current TaskTimePoint that can be used to determine whether a + // task is expired. + // + // Tests can override this to mock up the time. + virtual TaskTimePoint GetCurrentTimeForTask() const { + return TaskTimePoint::clock::now(); + } + // Returns a TaskTimePoint computed from the given target time from Flutter. TaskTimePoint TimePointFromFlutterTime( uint64_t flutter_target_time_nanos) const; @@ -103,6 +99,8 @@ class TaskRunner { TaskExpiredCallback on_task_expired_; std::mutex task_queue_mutex_; std::priority_queue, Task::Comparer> task_queue_; + DWORD main_thread_id_; + std::shared_ptr task_runner_window_; TaskRunner(const TaskRunner&) = delete; TaskRunner& operator=(const TaskRunner&) = delete; diff --git a/shell/platform/windows/task_runner_win32.cc b/shell/platform/windows/task_runner_win32.cc deleted file mode 100644 index 01c7179c792f5..0000000000000 --- a/shell/platform/windows/task_runner_win32.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/windows/task_runner_win32.h" - -namespace flutter { - -// static -std::unique_ptr TaskRunner::Create( - CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) { - return std::make_unique(get_current_time, on_task_expired); -} - -TaskRunnerWin32::TaskRunnerWin32(CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired) - : TaskRunner(get_current_time, on_task_expired) { - main_thread_id_ = GetCurrentThreadId(); - task_runner_window_ = TaskRunnerWin32Window::GetSharedInstance(); - task_runner_window_->AddDelegate(this); -} - -TaskRunnerWin32::~TaskRunnerWin32() { - task_runner_window_->RemoveDelegate(this); -} - -bool TaskRunnerWin32::RunsTasksOnCurrentThread() const { - return GetCurrentThreadId() == main_thread_id_; -} - -std::chrono::nanoseconds TaskRunnerWin32::ProcessTasks() { - return TaskRunner::ProcessTasks(); -} - -void TaskRunnerWin32::WakeUp() { - task_runner_window_->WakeUp(); -} - -} // namespace flutter diff --git a/shell/platform/windows/task_runner_win32.h b/shell/platform/windows/task_runner_win32.h deleted file mode 100644 index 6e3ceb8476f63..0000000000000 --- a/shell/platform/windows/task_runner_win32.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_H_ -#define FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_H_ - -#include - -#include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/windows/task_runner.h" -#include "flutter/shell/platform/windows/task_runner_win32_window.h" - -namespace flutter { - -// A custom task runner that integrates with user32 GetMessage semantics so that -// host app can own its own message loop and flutter still gets to process -// tasks on a timely basis. -class TaskRunnerWin32 : public TaskRunner, - public TaskRunnerWin32Window::Delegate { - public: - TaskRunnerWin32(CurrentTimeProc get_current_time, - const TaskExpiredCallback& on_task_expired); - virtual ~TaskRunnerWin32(); - - // |TaskRunner| - bool RunsTasksOnCurrentThread() const override; - - // |TaskRunnerWin32Window::Delegate| - std::chrono::nanoseconds ProcessTasks() override; - - protected: - // |TaskRunner| - void WakeUp() override; - - private: - DWORD main_thread_id_; - std::shared_ptr task_runner_window_; - - TaskRunnerWin32(const TaskRunnerWin32&) = delete; - TaskRunnerWin32& operator=(const TaskRunnerWin32&) = delete; -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_H_ diff --git a/shell/platform/windows/task_runner_win32_window.cc b/shell/platform/windows/task_runner_window.cc similarity index 72% rename from shell/platform/windows/task_runner_win32_window.cc rename to shell/platform/windows/task_runner_window.cc index a08f88cd33621..ccdf4b570ac13 100644 --- a/shell/platform/windows/task_runner_win32_window.cc +++ b/shell/platform/windows/task_runner_window.cc @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/platform/windows/task_runner_win32_window.h" +#include "flutter/shell/platform/windows/task_runner_window.h" #include #include namespace flutter { -TaskRunnerWin32Window::TaskRunnerWin32Window() { +TaskRunnerWindow::TaskRunnerWindow() { WNDCLASS window_class = RegisterWindowClass(); window_handle_ = CreateWindowEx(0, window_class.lpszClassName, L"", 0, 0, 0, 0, 0, @@ -31,7 +31,7 @@ TaskRunnerWin32Window::TaskRunnerWin32Window() { } } -TaskRunnerWin32Window::~TaskRunnerWin32Window() { +TaskRunnerWindow::~TaskRunnerWindow() { if (window_handle_) { DestroyWindow(window_handle_); window_handle_ = nullptr; @@ -39,37 +39,36 @@ TaskRunnerWin32Window::~TaskRunnerWin32Window() { UnregisterClass(window_class_name_.c_str(), nullptr); } -std::shared_ptr -TaskRunnerWin32Window::GetSharedInstance() { - static std::weak_ptr instance; +std::shared_ptr TaskRunnerWindow::GetSharedInstance() { + static std::weak_ptr instance; auto res = instance.lock(); if (!res) { // can't use make_shared with private contructor - res.reset(new TaskRunnerWin32Window()); + res.reset(new TaskRunnerWindow()); instance = res; } return res; } -void TaskRunnerWin32Window::WakeUp() { +void TaskRunnerWindow::WakeUp() { if (!PostMessage(window_handle_, WM_NULL, 0, 0)) { std::cerr << "Failed to post message to main thread." << std::endl; } } -void TaskRunnerWin32Window::AddDelegate(Delegate* delegate) { +void TaskRunnerWindow::AddDelegate(Delegate* delegate) { delegates_.push_back(delegate); SetTimer(std::chrono::nanoseconds::zero()); } -void TaskRunnerWin32Window::RemoveDelegate(Delegate* delegate) { +void TaskRunnerWindow::RemoveDelegate(Delegate* delegate) { auto i = std::find(delegates_.begin(), delegates_.end(), delegate); if (i != delegates_.end()) { delegates_.erase(i); } } -void TaskRunnerWin32Window::ProcessTasks() { +void TaskRunnerWindow::ProcessTasks() { auto next = std::chrono::nanoseconds::max(); auto delegates_copy(delegates_); for (auto delegate : delegates_copy) { @@ -82,7 +81,7 @@ void TaskRunnerWin32Window::ProcessTasks() { SetTimer(next); } -void TaskRunnerWin32Window::SetTimer(std::chrono::nanoseconds when) { +void TaskRunnerWindow::SetTimer(std::chrono::nanoseconds when) { if (when == std::chrono::nanoseconds::max()) { KillTimer(window_handle_, 0); } else { @@ -91,7 +90,7 @@ void TaskRunnerWin32Window::SetTimer(std::chrono::nanoseconds when) { } } -WNDCLASS TaskRunnerWin32Window::RegisterWindowClass() { +WNDCLASS TaskRunnerWindow::RegisterWindowClass() { window_class_name_ = L"FlutterTaskRunnerWindow"; WNDCLASS window_class{}; @@ -110,9 +109,9 @@ WNDCLASS TaskRunnerWin32Window::RegisterWindowClass() { } LRESULT -TaskRunnerWin32Window::HandleMessage(UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { +TaskRunnerWindow::HandleMessage(UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { switch (message) { case WM_TIMER: case WM_NULL: @@ -122,11 +121,11 @@ TaskRunnerWin32Window::HandleMessage(UINT const message, return DefWindowProcW(window_handle_, message, wparam, lparam); } -LRESULT TaskRunnerWin32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (auto* that = reinterpret_cast( +LRESULT TaskRunnerWindow::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (auto* that = reinterpret_cast( GetWindowLongPtr(window, GWLP_USERDATA))) { return that->HandleMessage(message, wparam, lparam); } else { diff --git a/shell/platform/windows/task_runner_win32_window.h b/shell/platform/windows/task_runner_window.h similarity index 78% rename from shell/platform/windows/task_runner_win32_window.h rename to shell/platform/windows/task_runner_window.h index a11d8ef0dd628..ae874f82af71f 100644 --- a/shell/platform/windows/task_runner_win32_window.h +++ b/shell/platform/windows/task_runner_window.h @@ -15,14 +15,18 @@ namespace flutter { // Hidden HWND responsible for processing flutter tasks on main thread -class TaskRunnerWin32Window { +class TaskRunnerWindow { public: class Delegate { public: + // Executes expired task, and returns the duration until the next task + // deadline if exists, otherwise returns `std::chrono::nanoseconds::max()`. + // + // Each platform implementation must call this to schedule the tasks. virtual std::chrono::nanoseconds ProcessTasks() = 0; }; - static std::shared_ptr GetSharedInstance(); + static std::shared_ptr GetSharedInstance(); // Triggers processing delegate tasks on main thread void WakeUp(); @@ -30,10 +34,10 @@ class TaskRunnerWin32Window { void AddDelegate(Delegate* delegate); void RemoveDelegate(Delegate* delegate); - ~TaskRunnerWin32Window(); + ~TaskRunnerWindow(); private: - TaskRunnerWin32Window(); + TaskRunnerWindow(); void ProcessTasks(); From e771729efdde3cdbdf0404973c3e72dc15933ad0 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Mon, 1 Aug 2022 15:24:03 -0400 Subject: [PATCH 013/558] [impeller] Set binding base for fragment shaders (#35052) Fixes: https://github.com/flutter/flutter/issues/108739 --- impeller/compiler/compiler.cc | 15 +++++++++++++++ impeller/compiler/compiler.h | 2 ++ impeller/compiler/compiler_test.cc | 12 ++++++++++++ impeller/compiler/compiler_test.h | 3 +++ impeller/compiler/compiler_unittests.cc | 23 +++++++++++++++++++++++ impeller/fixtures/BUILD.gn | 1 + impeller/fixtures/sample.frag | 14 ++++++++++++++ 7 files changed, 70 insertions(+) create mode 100644 impeller/fixtures/sample.frag diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index e5b2018fd267f..e38aa14714555 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -13,10 +13,15 @@ #include "impeller/compiler/compiler_backend.h" #include "impeller/compiler/includer.h" #include "impeller/compiler/logger.h" +#include "impeller/compiler/types.h" namespace impeller { namespace compiler { +const uint32_t kFragBindingBase = 128; +const size_t kNumUniformKinds = + int(shaderc_uniform_kind::shaderc_uniform_kind_buffer) + 1; + static CompilerBackend CreateMSLCompiler(const spirv_cross::ParsedIR& ir, const SourceOptions& source_options) { auto sl_compiler = std::make_shared(ir); @@ -104,6 +109,15 @@ static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir, return compiler; } +void Compiler::SetBindingBase(shaderc::CompileOptions& compiler_opts) const { + for (size_t uniform_kind = 0; uniform_kind < kNumUniformKinds; + uniform_kind++) { + compiler_opts.SetBindingBaseForStage( + ToShaderCShaderKind(SourceType::kFragmentShader), + static_cast(uniform_kind), kFragBindingBase); + } +} + Compiler::Compiler(const fml::Mapping& source_mapping, SourceOptions source_options, Reflector::Options reflector_options) @@ -212,6 +226,7 @@ Compiler::Compiler(const fml::Mapping& source_mapping, } spirv_options.SetAutoBindUniforms(true); + SetBindingBase(spirv_options); spirv_options.SetAutoMapLocations(true); std::vector included_file_names; diff --git a/impeller/compiler/compiler.h b/impeller/compiler/compiler.h index 9dd3d901c3dde..379f610fd2286 100644 --- a/impeller/compiler/compiler.h +++ b/impeller/compiler/compiler.h @@ -57,6 +57,8 @@ class Compiler { std::string GetDependencyNames(std::string separator) const; + void SetBindingBase(shaderc::CompileOptions& compiler_opts) const; + FML_DISALLOW_COPY_AND_ASSIGN(Compiler); }; diff --git a/impeller/compiler/compiler_test.cc b/impeller/compiler/compiler_test.cc index 85b3abaa5f9c5..402d05fe7346f 100644 --- a/impeller/compiler/compiler_test.cc +++ b/impeller/compiler/compiler_test.cc @@ -6,6 +6,11 @@ #include +#include "flutter/fml/file.h" +#include "flutter/fml/logging.h" +#include "flutter/fml/mapping.h" +#include "flutter/fml/unique_fd.h" + namespace impeller { namespace compiler { namespace testing { @@ -58,6 +63,13 @@ static std::string SLFileName(const char* fixture_name, return stream.str(); } +std::unique_ptr CompilerTest::GetReflectionJson( + const char* fixture_name) const { + auto filename = ReflectionJSONName(fixture_name); + auto fd = fml::OpenFileReadOnly(intermediates_directory_, filename.c_str()); + return fml::FileMapping::CreateReadOnly(fd); +} + bool CompilerTest::CanCompileAndReflect(const char* fixture_name, SourceType source_type) const { auto fixture = flutter::testing::OpenFixtureAsMapping(fixture_name); diff --git a/impeller/compiler/compiler_test.h b/impeller/compiler/compiler_test.h index a7be1c688b198..0e4fd94fd3929 100644 --- a/impeller/compiler/compiler_test.h +++ b/impeller/compiler/compiler_test.h @@ -25,6 +25,9 @@ class CompilerTest : public ::testing::TestWithParam { const char* fixture_name, SourceType source_type = SourceType::kUnknown) const; + std::unique_ptr GetReflectionJson( + const char* fixture_name) const; + private: fml::UniqueFD intermediates_directory_; diff --git a/impeller/compiler/compiler_unittests.cc b/impeller/compiler/compiler_unittests.cc index d19d9f00c98c0..f46b745c81703 100644 --- a/impeller/compiler/compiler_unittests.cc +++ b/impeller/compiler/compiler_unittests.cc @@ -9,6 +9,8 @@ #include "impeller/compiler/source_options.h" #include "impeller/compiler/types.h" +#include "nlohmann/json.hpp" + namespace impeller { namespace compiler { namespace testing { @@ -50,6 +52,27 @@ TEST_P(CompilerTest, CanCompileComputeShader) { ASSERT_TRUE(CanCompileAndReflect("sample.comp", SourceType::kComputeShader)); } +TEST_P(CompilerTest, BindingBaseForFragShader) { + if (GetParam() == TargetPlatform::kFlutterSPIRV) { + // This is a failure of reflection which this target doesn't perform. + GTEST_SKIP(); + } + + ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader)); + ASSERT_TRUE(CanCompileAndReflect("sample.frag", SourceType::kFragmentShader)); + + auto get_binding = [&](const char* fixture) -> uint32_t { + auto json_fd = GetReflectionJson(fixture); + nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping()); + return shader_json["buffers"][0]["binding"].get(); + }; + + auto vert_uniform_binding = get_binding("sample.vert"); + auto frag_uniform_binding = get_binding("sample.frag"); + + ASSERT_GT(frag_uniform_binding, vert_uniform_binding); +} + TEST_P(CompilerTest, MustFailDueToMultipleLocationPerStructMember) { if (GetParam() == TargetPlatform::kFlutterSPIRV) { // This is a failure of reflection which this target doesn't perform. diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index d955a90bfa9df..635125cc1ecc9 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -43,6 +43,7 @@ test_fixtures("file_fixtures") { "embarcadero.jpg", "kalimba.jpg", "sample.comp", + "sample.frag", "sample.tesc", "sample.tese", "sample.vert", diff --git a/impeller/fixtures/sample.frag b/impeller/fixtures/sample.frag new file mode 100644 index 0000000000000..5d9c83604dd68 --- /dev/null +++ b/impeller/fixtures/sample.frag @@ -0,0 +1,14 @@ +// 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. + +uniform FragInfo { + vec4 color; +} +frag_info; + +out vec4 frag_color; + +void main() { + frag_color = frag_info.color; +} From eea28879dcf87d3b36ae006d07f8df9a1100c5dd Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Mon, 1 Aug 2022 21:12:36 +0100 Subject: [PATCH 014/558] [Windows] Merge PlatformHandlerWin32 to superclass (#35056) With the removal of the UWP embedder, we can merge Win32-specific implementation classes with their abstract superclasses where those superclasses existed only to support both UWP and Win32. No new tests since this is purely a restructuring of existing code within the Win32 embedder, with no expected change in behaviour. Covered by existing tests in task_runner_unittests.cc. Issue: https://github.com/flutter/flutter/issues/108386 --- ci/licenses_golden/licenses_flutter | 3 - shell/platform/windows/BUILD.gn | 3 - .../platform/windows/flutter_windows_view.cc | 3 +- shell/platform/windows/platform_handler.cc | 292 ++++++++++++++++- shell/platform/windows/platform_handler.h | 62 +++- .../windows/platform_handler_unittests.cc | 309 +++++++++++++++++- .../windows/platform_handler_win32.cc | 309 ------------------ .../platform/windows/platform_handler_win32.h | 87 ----- .../platform_handler_win32_unittests.cc | 296 ----------------- 9 files changed, 642 insertions(+), 722 deletions(-) delete mode 100644 shell/platform/windows/platform_handler_win32.cc delete mode 100644 shell/platform/windows/platform_handler_win32.h delete mode 100644 shell/platform/windows/platform_handler_win32_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 6b43cac4a16a6..cf00c43c74d5f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2412,9 +2412,6 @@ FILE: ../../../flutter/shell/platform/windows/keyboard_utils_unittests.cc FILE: ../../../flutter/shell/platform/windows/platform_handler.cc FILE: ../../../flutter/shell/platform/windows/platform_handler.h FILE: ../../../flutter/shell/platform/windows/platform_handler_unittests.cc -FILE: ../../../flutter/shell/platform/windows/platform_handler_win32.cc -FILE: ../../../flutter/shell/platform/windows/platform_handler_win32.h -FILE: ../../../flutter/shell/platform/windows/platform_handler_win32_unittests.cc FILE: ../../../flutter/shell/platform/windows/public/flutter_windows.h FILE: ../../../flutter/shell/platform/windows/sequential_id_generator.cc FILE: ../../../flutter/shell/platform/windows/sequential_id_generator.h diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index d8b39d099be59..5531f8a41310d 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -82,8 +82,6 @@ source_set("flutter_windows_source") { "keyboard_utils.h", "platform_handler.cc", "platform_handler.h", - "platform_handler_win32.cc", - "platform_handler_win32.h", "sequential_id_generator.cc", "sequential_id_generator.h", "settings_plugin.cc", @@ -182,7 +180,6 @@ executable("flutter_windows_unittests") { "keyboard_unittests.cc", "keyboard_utils_unittests.cc", "platform_handler_unittests.cc", - "platform_handler_win32_unittests.cc", "sequential_id_generator_unittests.cc", "settings_plugin_unittests.cc", "system_utils_unittests.cc", diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 23d3ed17e94c8..d9f901219b664 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -63,7 +63,8 @@ void FlutterWindowsView::SetEngine( // Set up the system channel handlers. auto internal_plugin_messenger = internal_plugin_registrar_->messenger(); InitializeKeyboard(); - platform_handler_ = PlatformHandler::Create(internal_plugin_messenger, this); + platform_handler_ = + std::make_unique(internal_plugin_messenger, this); cursor_handler_ = std::make_unique(internal_plugin_messenger, binding_handler_.get()); diff --git a/shell/platform/windows/platform_handler.cc b/shell/platform/windows/platform_handler.cc index c3791f152376f..d1ab70090ed5b 100644 --- a/shell/platform/windows/platform_handler.cc +++ b/shell/platform/windows/platform_handler.cc @@ -4,7 +4,15 @@ #include "flutter/shell/platform/windows/platform_handler.h" +#include + +#include +#include +#include + +#include "flutter/fml/platform/win/wstring_conversion.h" #include "flutter/shell/platform/common/json_method_codec.h" +#include "flutter/shell/platform/windows/flutter_windows_view.h" static constexpr char kChannelName[] = "flutter/platform"; @@ -15,26 +23,304 @@ static constexpr char kPlaySoundMethod[] = "SystemSound.play"; static constexpr char kTextPlainFormat[] = "text/plain"; static constexpr char kTextKey[] = "text"; - static constexpr char kUnknownClipboardFormatMessage[] = "Unknown clipboard format"; +static constexpr char kValueKey[] = "value"; +static constexpr int kAccessDeniedErrorCode = 5; +static constexpr int kErrorSuccess = 0; + namespace flutter { -PlatformHandler::PlatformHandler(BinaryMessenger* messenger) +namespace { + +// A scoped wrapper for GlobalAlloc/GlobalFree. +class ScopedGlobalMemory { + public: + // Allocates |bytes| bytes of global memory with the given flags. + ScopedGlobalMemory(unsigned int flags, size_t bytes) { + memory_ = ::GlobalAlloc(flags, bytes); + if (!memory_) { + std::cerr << "Unable to allocate global memory: " << ::GetLastError(); + } + } + + ~ScopedGlobalMemory() { + if (memory_) { + if (::GlobalFree(memory_) != nullptr) { + std::cerr << "Failed to free global allocation: " << ::GetLastError(); + } + } + } + + // Prevent copying. + ScopedGlobalMemory(ScopedGlobalMemory const&) = delete; + ScopedGlobalMemory& operator=(ScopedGlobalMemory const&) = delete; + + // Returns the memory pointer, which will be nullptr if allocation failed. + void* get() { return memory_; } + + void* release() { + void* memory = memory_; + memory_ = nullptr; + return memory; + } + + private: + HGLOBAL memory_; +}; + +// A scoped wrapper for GlobalLock/GlobalUnlock. +class ScopedGlobalLock { + public: + // Attempts to acquire a global lock on |memory| for the life of this object. + ScopedGlobalLock(HGLOBAL memory) { + source_ = memory; + if (memory) { + locked_memory_ = ::GlobalLock(memory); + if (!locked_memory_) { + std::cerr << "Unable to acquire global lock: " << ::GetLastError(); + } + } + } + + ~ScopedGlobalLock() { + if (locked_memory_) { + if (!::GlobalUnlock(source_)) { + DWORD error = ::GetLastError(); + if (error != NO_ERROR) { + std::cerr << "Unable to release global lock: " << ::GetLastError(); + } + } + } + } + + // Prevent copying. + ScopedGlobalLock(ScopedGlobalLock const&) = delete; + ScopedGlobalLock& operator=(ScopedGlobalLock const&) = delete; + + // Returns the locked memory pointer, which will be nullptr if acquiring the + // lock failed. + void* get() { return locked_memory_; } + + private: + HGLOBAL source_; + void* locked_memory_; +}; + +// A Clipboard wrapper that automatically closes the clipboard when it goes out +// of scope. +class ScopedClipboard : public ScopedClipboardInterface { + public: + ScopedClipboard(); + virtual ~ScopedClipboard(); + + // Prevent copying. + ScopedClipboard(ScopedClipboard const&) = delete; + ScopedClipboard& operator=(ScopedClipboard const&) = delete; + + int Open(HWND window) override; + + bool HasString() override; + + std::variant GetString() override; + + int SetString(const std::wstring string) override; + + private: + bool opened_ = false; +}; + +ScopedClipboard::ScopedClipboard() {} + +ScopedClipboard::~ScopedClipboard() { + if (opened_) { + ::CloseClipboard(); + } +} + +int ScopedClipboard::Open(HWND window) { + opened_ = ::OpenClipboard(window); + + if (!opened_) { + return ::GetLastError(); + } + + return kErrorSuccess; +} + +bool ScopedClipboard::HasString() { + // Allow either plain text format, since getting data will auto-interpolate. + return ::IsClipboardFormatAvailable(CF_UNICODETEXT) || + ::IsClipboardFormatAvailable(CF_TEXT); +} + +std::variant ScopedClipboard::GetString() { + assert(opened_); + + HANDLE data = ::GetClipboardData(CF_UNICODETEXT); + if (data == nullptr) { + return ::GetLastError(); + } + ScopedGlobalLock locked_data(data); + + if (!locked_data.get()) { + return ::GetLastError(); + } + return static_cast(locked_data.get()); +} + +int ScopedClipboard::SetString(const std::wstring string) { + assert(opened_); + if (!::EmptyClipboard()) { + return ::GetLastError(); + } + size_t null_terminated_byte_count = + sizeof(decltype(string)::traits_type::char_type) * (string.size() + 1); + ScopedGlobalMemory destination_memory(GMEM_MOVEABLE, + null_terminated_byte_count); + ScopedGlobalLock locked_memory(destination_memory.get()); + if (!locked_memory.get()) { + return ::GetLastError(); + } + memcpy(locked_memory.get(), string.c_str(), null_terminated_byte_count); + if (!::SetClipboardData(CF_UNICODETEXT, locked_memory.get())) { + return ::GetLastError(); + } + // The clipboard now owns the global memory. + destination_memory.release(); + return kErrorSuccess; +} + +} // namespace + +PlatformHandler::PlatformHandler( + BinaryMessenger* messenger, + FlutterWindowsView* view, + std::optional()>> + scoped_clipboard_provider) : channel_(std::make_unique>( messenger, kChannelName, - &JsonMethodCodec::GetInstance())) { + &JsonMethodCodec::GetInstance())), + view_(view) { channel_->SetMethodCallHandler( [this](const MethodCall& call, std::unique_ptr> result) { HandleMethodCall(call, std::move(result)); }); + if (scoped_clipboard_provider.has_value()) { + scoped_clipboard_provider_ = scoped_clipboard_provider.value(); + } else { + scoped_clipboard_provider_ = []() { + return std::make_unique(); + }; + } } PlatformHandler::~PlatformHandler() = default; +void PlatformHandler::GetPlainText( + std::unique_ptr> result, + std::string_view key) { + std::unique_ptr clipboard = + scoped_clipboard_provider_(); + + int open_result = clipboard->Open(std::get(*view_->GetRenderTarget())); + if (open_result != kErrorSuccess) { + rapidjson::Document error_code; + error_code.SetInt(open_result); + result->Error(kClipboardError, "Unable to open clipboard", error_code); + return; + } + if (!clipboard->HasString()) { + result->Success(rapidjson::Document()); + return; + } + std::variant get_string_result = clipboard->GetString(); + if (std::holds_alternative(get_string_result)) { + rapidjson::Document error_code; + error_code.SetInt(std::get(get_string_result)); + result->Error(kClipboardError, "Unable to get clipboard data", error_code); + return; + } + + rapidjson::Document document; + document.SetObject(); + rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); + document.AddMember( + rapidjson::Value(key.data(), allocator), + rapidjson::Value( + fml::WideStringToUtf8(std::get(get_string_result)), + allocator), + allocator); + result->Success(document); +} + +void PlatformHandler::GetHasStrings( + std::unique_ptr> result) { + std::unique_ptr clipboard = + scoped_clipboard_provider_(); + + bool hasStrings; + int open_result = clipboard->Open(std::get(*view_->GetRenderTarget())); + if (open_result != kErrorSuccess) { + // Swallow errors of type ERROR_ACCESS_DENIED. These happen when the app is + // not in the foreground and GetHasStrings is irrelevant. + // See https://github.com/flutter/flutter/issues/95817. + if (open_result != kAccessDeniedErrorCode) { + rapidjson::Document error_code; + error_code.SetInt(open_result); + result->Error(kClipboardError, "Unable to open clipboard", error_code); + return; + } + hasStrings = false; + } else { + hasStrings = clipboard->HasString(); + } + + rapidjson::Document document; + document.SetObject(); + rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); + document.AddMember(rapidjson::Value(kValueKey, allocator), + rapidjson::Value(hasStrings), allocator); + result->Success(document); +} + +void PlatformHandler::SetPlainText( + const std::string& text, + std::unique_ptr> result) { + std::unique_ptr clipboard = + scoped_clipboard_provider_(); + + int open_result = clipboard->Open(std::get(*view_->GetRenderTarget())); + if (open_result != kErrorSuccess) { + rapidjson::Document error_code; + error_code.SetInt(open_result); + result->Error(kClipboardError, "Unable to open clipboard", error_code); + return; + } + int set_result = clipboard->SetString(fml::Utf8ToWideString(text)); + if (set_result != kErrorSuccess) { + rapidjson::Document error_code; + error_code.SetInt(set_result); + result->Error(kClipboardError, "Unable to set clipboard data", error_code); + return; + } + result->Success(); +} + +void PlatformHandler::SystemSoundPlay( + const std::string& sound_type, + std::unique_ptr> result) { + if (sound_type.compare(kSoundTypeAlert) == 0) { + MessageBeep(MB_OK); + result->Success(); + } else { + result->NotImplemented(); + } +} + void PlatformHandler::HandleMethodCall( const MethodCall& method_call, std::unique_ptr> result) { diff --git a/shell/platform/windows/platform_handler.h b/shell/platform/windows/platform_handler.h index 3483273e961a4..4da0ab2180527 100644 --- a/shell/platform/windows/platform_handler.h +++ b/shell/platform/windows/platform_handler.h @@ -5,6 +5,13 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_H_ +#include + +#include +#include +#include +#include + #include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/method_channel.h" #include "rapidjson/document.h" @@ -12,39 +19,40 @@ namespace flutter { class FlutterWindowsView; +class ScopedClipboardInterface; // Handler for internal system channels. class PlatformHandler { public: - explicit PlatformHandler(BinaryMessenger* messenger); + explicit PlatformHandler( + BinaryMessenger* messenger, + FlutterWindowsView* view, + std::optional()>> + scoped_clipboard_provider = std::nullopt); virtual ~PlatformHandler(); - // Creates a new platform handler using the given messenger and view. - static std::unique_ptr Create(BinaryMessenger* messenger, - FlutterWindowsView* view); - protected: // Gets plain text from the clipboard and provides it to |result| as the // value in a dictionary with the given |key|. virtual void GetPlainText( std::unique_ptr> result, - std::string_view key) = 0; + std::string_view key); // Provides a boolean to |result| as the value in a dictionary at key // "value" representing whether or not the clipboard has a non-empty string. virtual void GetHasStrings( - std::unique_ptr> result) = 0; + std::unique_ptr> result); // Sets the clipboard's plain text to |text|, and reports the result (either // an error, or null for success) to |result|. virtual void SetPlainText( const std::string& text, - std::unique_ptr> result) = 0; + std::unique_ptr> result); virtual void SystemSoundPlay( const std::string& sound_type, - std::unique_ptr> result) = 0; + std::unique_ptr> result); // A error type to use for error responses. static constexpr char kClipboardError[] = "Clipboard error"; @@ -59,6 +67,42 @@ class PlatformHandler { // The MethodChannel used for communication with the Flutter engine. std::unique_ptr> channel_; + + // A reference to the Flutter view. + FlutterWindowsView* view_; + + // A scoped clipboard provider that can be passed in for mocking in tests. + // Use this to acquire clipboard in each operation to avoid blocking clipboard + // unnecessarily. See flutter/flutter#103205. + std::function()> + scoped_clipboard_provider_; +}; + +// A public interface for ScopedClipboard, so that it can be injected into +// PlatformHandler. +class ScopedClipboardInterface { + public: + virtual ~ScopedClipboardInterface(){}; + + // Attempts to open the clipboard for the given window, returning the error + // code in the case of failure and 0 otherwise. + virtual int Open(HWND window) = 0; + + // Returns true if there is string data available to get. + virtual bool HasString() = 0; + + // Returns string data from the clipboard. + // + // If getting a string fails, returns the error code. + // + // Open(...) must have succeeded to call this method. + virtual std::variant GetString() = 0; + + // Sets the string content of the clipboard, returning the error code on + // failure and 0 otherwise. + // + // Open(...) must have succeeded to call this method. + virtual int SetString(const std::wstring string) = 0; }; } // namespace flutter diff --git a/shell/platform/windows/platform_handler_unittests.cc b/shell/platform/windows/platform_handler_unittests.cc index bcbeb070e80e8..02a98281f4295 100644 --- a/shell/platform/windows/platform_handler_unittests.cc +++ b/shell/platform/windows/platform_handler_unittests.cc @@ -7,6 +7,8 @@ #include #include "flutter/shell/platform/common/json_method_codec.h" +#include "flutter/shell/platform/windows/flutter_windows_view.h" +#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h" #include "flutter/shell/platform/windows/testing/test_binary_messenger.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -30,16 +32,24 @@ 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 { public: - explicit TestPlatformHandler(BinaryMessenger* messenger) - : PlatformHandler(messenger) {} + explicit TestPlatformHandler( + BinaryMessenger* messenger, + FlutterWindowsView* view, + std::optional()>> + scoped_clipboard_provider = std::nullopt) + : PlatformHandler(messenger, view, scoped_clipboard_provider) {} - virtual ~TestPlatformHandler() {} + virtual ~TestPlatformHandler() = default; - // |PlatformHandler| MOCK_METHOD2(GetPlainText, void(std::unique_ptr>, std::string_view key)); @@ -64,11 +74,86 @@ class MockMethodResult : public MethodResult { MOCK_METHOD0(NotImplementedInternal, void()); }; +// A test version of system clipboard. +class MockSystemClipboard { + public: + void OpenClipboard() { opened = true; } + void CloseClipboard() { opened = false; } + bool opened = false; +}; + +// A test version of the private ScopedClipboard. +class TestScopedClipboard : public ScopedClipboardInterface { + public: + TestScopedClipboard(int open_error, + bool has_strings, + std::shared_ptr clipboard); + ~TestScopedClipboard(); + + // Prevent copying. + TestScopedClipboard(TestScopedClipboard const&) = delete; + TestScopedClipboard& operator=(TestScopedClipboard const&) = delete; + + int Open(HWND window) override; + + bool HasString() override; + + std::variant GetString() override; + + int SetString(const std::wstring string) override; + + private: + bool opened_ = false; + bool has_strings_; + int open_error_; + std::shared_ptr clipboard_; +}; + +TestScopedClipboard::TestScopedClipboard( + int open_error, + bool has_strings, + std::shared_ptr clipboard = nullptr) { + open_error_ = open_error; + has_strings_ = has_strings; + clipboard_ = clipboard; +} + +TestScopedClipboard::~TestScopedClipboard() { + if ((!open_error_) && clipboard_ != nullptr) { + clipboard_->CloseClipboard(); + } +} + +int TestScopedClipboard::Open(HWND window) { + if ((!open_error_) && clipboard_ != nullptr) { + clipboard_->OpenClipboard(); + } + return open_error_; +} + +bool TestScopedClipboard::HasString() { + return has_strings_; +} + +std::variant TestScopedClipboard::GetString() { + return -1; +} + +int TestScopedClipboard::SetString(const std::wstring string) { + return -1; +} + } // namespace TEST(PlatformHandler, GettingTextCallsThrough) { TestBinaryMessenger messenger; - TestPlatformHandler platform_handler(&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); + }); auto args = std::make_unique(rapidjson::kStringType); auto& allocator = args->GetAllocator(); @@ -92,7 +177,13 @@ TEST(PlatformHandler, GettingTextCallsThrough) { TEST(PlatformHandler, RejectsGettingUnknownTypes) { TestBinaryMessenger messenger; - TestPlatformHandler platform_handler(&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); + }); auto args = std::make_unique(rapidjson::kStringType); auto& allocator = args->GetAllocator(); @@ -114,7 +205,13 @@ TEST(PlatformHandler, RejectsGettingUnknownTypes) { TEST(PlatformHandler, GetHasStringsCallsThrough) { TestBinaryMessenger messenger; - TestPlatformHandler platform_handler(&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); + }); auto args = std::make_unique(rapidjson::kStringType); auto& allocator = args->GetAllocator(); @@ -139,7 +236,13 @@ TEST(PlatformHandler, GetHasStringsCallsThrough) { TEST(PlatformHandler, RejectsGetHasStringsOnUnknownTypes) { TestBinaryMessenger messenger; - TestPlatformHandler platform_handler(&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); + }); auto args = std::make_unique(rapidjson::kStringType); auto& allocator = args->GetAllocator(); @@ -161,7 +264,13 @@ TEST(PlatformHandler, RejectsGetHasStringsOnUnknownTypes) { TEST(PlatformHandler, SettingTextCallsThrough) { TestBinaryMessenger messenger; - TestPlatformHandler platform_handler(&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); + }); auto args = std::make_unique(rapidjson::kObjectType); auto& allocator = args->GetAllocator(); @@ -187,7 +296,13 @@ TEST(PlatformHandler, SettingTextCallsThrough) { TEST(PlatformHandler, RejectsSettingUnknownTypes) { TestBinaryMessenger messenger; - TestPlatformHandler platform_handler(&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); + }); auto args = std::make_unique(rapidjson::kObjectType); auto& allocator = args->GetAllocator(); @@ -209,7 +324,13 @@ TEST(PlatformHandler, RejectsSettingUnknownTypes) { TEST(PlatformHandler, PlayingSystemSoundCallsThrough) { TestBinaryMessenger messenger; - TestPlatformHandler platform_handler(&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); + }); auto args = std::make_unique(rapidjson::kStringType); auto& allocator = args->GetAllocator(); @@ -233,5 +354,171 @@ TEST(PlatformHandler, PlayingSystemSoundCallsThrough) { [](const uint8_t* reply, size_t reply_size) {})); } +// Regression test for https://github.com/flutter/flutter/issues/95817. +TEST(PlatformHandler, HasStringsAccessDeniedReturnsFalseWithoutError) { + TestBinaryMessenger messenger; + FlutterWindowsView view( + std::make_unique<::testing::NiceMock>()); + // HasStrings will receive access denied on the clipboard, but will return + // false without error. + PlatformHandler platform_handler(&messenger, &view, []() { + return std::make_unique(kAccessDeniedErrorCode, true); + }); + + 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); + })); +} + +TEST(PlatformHandler, HasStringsSuccessWithStrings) { + 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); + }); + + 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); + })); +} + +TEST(PlatformHandler, HasStringsSuccessWithoutStrings) { + TestBinaryMessenger messenger; + FlutterWindowsView view( + std::make_unique<::testing::NiceMock>()); + // HasStrings will succeed and return false. + PlatformHandler platform_handler(&messenger, &view, []() { + return std::make_unique(kErrorSuccess, false); + }); + + 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); + })); +} + +TEST(PlatformHandler, HasStringsError) { + TestBinaryMessenger messenger; + FlutterWindowsView view( + std::make_unique<::testing::NiceMock>()); + // HasStrings will fail. + PlatformHandler platform_handler(&messenger, &view, []() { + return std::make_unique(kArbitraryErrorCode, true); + }); + + 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); + })); +} + +// Regression test for https://github.com/flutter/flutter/issues/103205. +TEST(PlatformHandler, ReleaseClipboard) { + auto system_clipboard = std::make_shared(); + + TestBinaryMessenger messenger; + FlutterWindowsView view( + std::make_unique<::testing::NiceMock>()); + TestPlatformHandler platform_handler(&messenger, &view, [system_clipboard]() { + return std::make_unique(kErrorSuccess, false, + system_clipboard); + }); + + platform_handler.GetPlainText(std::make_unique(), "text"); + ASSERT_FALSE(system_clipboard->opened); + + platform_handler.GetHasStrings(std::make_unique()); + ASSERT_FALSE(system_clipboard->opened); + + platform_handler.SetPlainText("", std::make_unique()); + ASSERT_FALSE(system_clipboard->opened); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/platform_handler_win32.cc b/shell/platform/windows/platform_handler_win32.cc deleted file mode 100644 index 6932e8e0dd7fd..0000000000000 --- a/shell/platform/windows/platform_handler_win32.cc +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/windows/platform_handler_win32.h" - -#include - -#include -#include -#include - -#include "flutter/fml/platform/win/wstring_conversion.h" -#include "flutter/shell/platform/windows/flutter_windows_view.h" - -static constexpr char kValueKey[] = "value"; -static constexpr int kAccessDeniedErrorCode = 5; -static constexpr int kErrorSuccess = 0; - -namespace flutter { - -namespace { - -// A scoped wrapper for GlobalAlloc/GlobalFree. -class ScopedGlobalMemory { - public: - // Allocates |bytes| bytes of global memory with the given flags. - ScopedGlobalMemory(unsigned int flags, size_t bytes) { - memory_ = ::GlobalAlloc(flags, bytes); - if (!memory_) { - std::cerr << "Unable to allocate global memory: " << ::GetLastError(); - } - } - - ~ScopedGlobalMemory() { - if (memory_) { - if (::GlobalFree(memory_) != nullptr) { - std::cerr << "Failed to free global allocation: " << ::GetLastError(); - } - } - } - - // Prevent copying. - ScopedGlobalMemory(ScopedGlobalMemory const&) = delete; - ScopedGlobalMemory& operator=(ScopedGlobalMemory const&) = delete; - - // Returns the memory pointer, which will be nullptr if allocation failed. - void* get() { return memory_; } - - void* release() { - void* memory = memory_; - memory_ = nullptr; - return memory; - } - - private: - HGLOBAL memory_; -}; - -// A scoped wrapper for GlobalLock/GlobalUnlock. -class ScopedGlobalLock { - public: - // Attempts to acquire a global lock on |memory| for the life of this object. - ScopedGlobalLock(HGLOBAL memory) { - source_ = memory; - if (memory) { - locked_memory_ = ::GlobalLock(memory); - if (!locked_memory_) { - std::cerr << "Unable to acquire global lock: " << ::GetLastError(); - } - } - } - - ~ScopedGlobalLock() { - if (locked_memory_) { - if (!::GlobalUnlock(source_)) { - DWORD error = ::GetLastError(); - if (error != NO_ERROR) { - std::cerr << "Unable to release global lock: " << ::GetLastError(); - } - } - } - } - - // Prevent copying. - ScopedGlobalLock(ScopedGlobalLock const&) = delete; - ScopedGlobalLock& operator=(ScopedGlobalLock const&) = delete; - - // Returns the locked memory pointer, which will be nullptr if acquiring the - // lock failed. - void* get() { return locked_memory_; } - - private: - HGLOBAL source_; - void* locked_memory_; -}; - -// A Clipboard wrapper that automatically closes the clipboard when it goes out -// of scope. -class ScopedClipboard : public ScopedClipboardInterface { - public: - ScopedClipboard(); - virtual ~ScopedClipboard(); - - // Prevent copying. - ScopedClipboard(ScopedClipboard const&) = delete; - ScopedClipboard& operator=(ScopedClipboard const&) = delete; - - int Open(HWND window) override; - - bool HasString() override; - - std::variant GetString() override; - - int SetString(const std::wstring string) override; - - private: - bool opened_ = false; -}; - -ScopedClipboard::ScopedClipboard() {} - -ScopedClipboard::~ScopedClipboard() { - if (opened_) { - ::CloseClipboard(); - } -} - -int ScopedClipboard::Open(HWND window) { - opened_ = ::OpenClipboard(window); - - if (!opened_) { - return ::GetLastError(); - } - - return kErrorSuccess; -} - -bool ScopedClipboard::HasString() { - // Allow either plain text format, since getting data will auto-interpolate. - return ::IsClipboardFormatAvailable(CF_UNICODETEXT) || - ::IsClipboardFormatAvailable(CF_TEXT); -} - -std::variant ScopedClipboard::GetString() { - assert(opened_); - - HANDLE data = ::GetClipboardData(CF_UNICODETEXT); - if (data == nullptr) { - return ::GetLastError(); - } - ScopedGlobalLock locked_data(data); - - if (!locked_data.get()) { - return ::GetLastError(); - } - return static_cast(locked_data.get()); -} - -int ScopedClipboard::SetString(const std::wstring string) { - assert(opened_); - if (!::EmptyClipboard()) { - return ::GetLastError(); - } - size_t null_terminated_byte_count = - sizeof(decltype(string)::traits_type::char_type) * (string.size() + 1); - ScopedGlobalMemory destination_memory(GMEM_MOVEABLE, - null_terminated_byte_count); - ScopedGlobalLock locked_memory(destination_memory.get()); - if (!locked_memory.get()) { - return ::GetLastError(); - } - memcpy(locked_memory.get(), string.c_str(), null_terminated_byte_count); - if (!::SetClipboardData(CF_UNICODETEXT, locked_memory.get())) { - return ::GetLastError(); - } - // The clipboard now owns the global memory. - destination_memory.release(); - return kErrorSuccess; -} - -} // namespace - -// static -std::unique_ptr PlatformHandler::Create( - BinaryMessenger* messenger, - FlutterWindowsView* view) { - return std::make_unique(messenger, view); -} - -PlatformHandlerWin32::PlatformHandlerWin32( - BinaryMessenger* messenger, - FlutterWindowsView* view, - std::optional()>> - scoped_clipboard_provider) - : PlatformHandler(messenger), view_(view) { - if (scoped_clipboard_provider.has_value()) { - scoped_clipboard_provider_ = scoped_clipboard_provider.value(); - } else { - scoped_clipboard_provider_ = []() { - return std::make_unique(); - }; - } -} - -PlatformHandlerWin32::~PlatformHandlerWin32() = default; - -void PlatformHandlerWin32::GetPlainText( - std::unique_ptr> result, - std::string_view key) { - std::unique_ptr clipboard = - scoped_clipboard_provider_(); - - int open_result = clipboard->Open(std::get(*view_->GetRenderTarget())); - if (open_result != kErrorSuccess) { - rapidjson::Document error_code; - error_code.SetInt(open_result); - result->Error(kClipboardError, "Unable to open clipboard", error_code); - return; - } - if (!clipboard->HasString()) { - result->Success(rapidjson::Document()); - return; - } - std::variant get_string_result = clipboard->GetString(); - if (std::holds_alternative(get_string_result)) { - rapidjson::Document error_code; - error_code.SetInt(std::get(get_string_result)); - result->Error(kClipboardError, "Unable to get clipboard data", error_code); - return; - } - - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); - document.AddMember( - rapidjson::Value(key.data(), allocator), - rapidjson::Value( - fml::WideStringToUtf8(std::get(get_string_result)), - allocator), - allocator); - result->Success(document); -} - -void PlatformHandlerWin32::GetHasStrings( - std::unique_ptr> result) { - std::unique_ptr clipboard = - scoped_clipboard_provider_(); - - bool hasStrings; - int open_result = clipboard->Open(std::get(*view_->GetRenderTarget())); - if (open_result != kErrorSuccess) { - // Swallow errors of type ERROR_ACCESS_DENIED. These happen when the app is - // not in the foreground and GetHasStrings is irrelevant. - // See https://github.com/flutter/flutter/issues/95817. - if (open_result != kAccessDeniedErrorCode) { - rapidjson::Document error_code; - error_code.SetInt(open_result); - result->Error(kClipboardError, "Unable to open clipboard", error_code); - return; - } - hasStrings = false; - } else { - hasStrings = clipboard->HasString(); - } - - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); - document.AddMember(rapidjson::Value(kValueKey, allocator), - rapidjson::Value(hasStrings), allocator); - result->Success(document); -} - -void PlatformHandlerWin32::SetPlainText( - const std::string& text, - std::unique_ptr> result) { - std::unique_ptr clipboard = - scoped_clipboard_provider_(); - - int open_result = clipboard->Open(std::get(*view_->GetRenderTarget())); - if (open_result != kErrorSuccess) { - rapidjson::Document error_code; - error_code.SetInt(open_result); - result->Error(kClipboardError, "Unable to open clipboard", error_code); - return; - } - int set_result = clipboard->SetString(fml::Utf8ToWideString(text)); - if (set_result != kErrorSuccess) { - rapidjson::Document error_code; - error_code.SetInt(set_result); - result->Error(kClipboardError, "Unable to set clipboard data", error_code); - return; - } - result->Success(); -} - -void PlatformHandlerWin32::SystemSoundPlay( - const std::string& sound_type, - std::unique_ptr> result) { - if (sound_type.compare(kSoundTypeAlert) == 0) { - MessageBeep(MB_OK); - result->Success(); - } else { - result->NotImplemented(); - } -} - -} // namespace flutter diff --git a/shell/platform/windows/platform_handler_win32.h b/shell/platform/windows/platform_handler_win32.h deleted file mode 100644 index 86cf2a3adfe1f..0000000000000 --- a/shell/platform/windows/platform_handler_win32.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_WIN32_H_ -#define FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_WIN32_H_ - -#include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h" -#include "flutter/shell/platform/common/client_wrapper/include/flutter/method_channel.h" -#include "flutter/shell/platform/windows/flutter_windows_view.h" -#include "flutter/shell/platform/windows/platform_handler.h" -#include "rapidjson/document.h" - -namespace flutter { - -class FlutterWindowsView; - -// A public interface for ScopedClipboard, so that it can be injected into -// PlatformHandlerWin32. -class ScopedClipboardInterface { - public: - virtual ~ScopedClipboardInterface(){}; - - // Attempts to open the clipboard for the given window, returning the error - // code in the case of failure and 0 otherwise. - virtual int Open(HWND window) = 0; - - // Returns true if there is string data available to get. - virtual bool HasString() = 0; - - // Returns string data from the clipboard. - // - // If getting a string fails, returns the error code. - // - // Open(...) must have succeeded to call this method. - virtual std::variant GetString() = 0; - - // Sets the string content of the clipboard, returning the error code on - // failure and 0 otherwise. - // - // Open(...) must have succeeded to call this method. - virtual int SetString(const std::wstring string) = 0; -}; - -// Win32 implementation of PlatformHandler. -class PlatformHandlerWin32 : public PlatformHandler { - public: - explicit PlatformHandlerWin32( - BinaryMessenger* messenger, - FlutterWindowsView* view, - std::optional()>> - scoped_clipboard_provider = std::nullopt); - - virtual ~PlatformHandlerWin32(); - - protected: - // |PlatformHandler| - void GetPlainText(std::unique_ptr> result, - std::string_view key) override; - - // |PlatformHandler| - void GetHasStrings( - std::unique_ptr> result) override; - - // |PlatformHandler| - void SetPlainText( - const std::string& text, - std::unique_ptr> result) override; - - // |PlatformHandler| - void SystemSoundPlay( - const std::string& sound_type, - std::unique_ptr> result) override; - - private: - // A reference to the Flutter view. - FlutterWindowsView* view_; - // A scoped clipboard provider that can be passed in for mocking in tests. - // Use this to acquire clipboard in each operation to avoid blocking clipboard - // unnecessarily. See flutter/flutter#103205. - std::function()> - scoped_clipboard_provider_; -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_WIN32_H_ diff --git a/shell/platform/windows/platform_handler_win32_unittests.cc b/shell/platform/windows/platform_handler_win32_unittests.cc deleted file mode 100644 index 6b1afabae8a75..0000000000000 --- a/shell/platform/windows/platform_handler_win32_unittests.cc +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/windows/platform_handler_win32.h" - -#include - -#include "flutter/shell/platform/common/json_method_codec.h" -#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h" -#include "flutter/shell/platform/windows/testing/test_binary_messenger.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "rapidjson/document.h" - -namespace flutter { -namespace testing { - -namespace { -using ::testing::_; - -static constexpr char kChannelName[] = "flutter/platform"; - -static constexpr char kHasStringsClipboardMethod[] = "Clipboard.hasStrings"; - -static constexpr char kTextPlainFormat[] = "text/plain"; - -static constexpr char kValueKey[] = "value"; -static constexpr int kAccessDeniedErrorCode = 5; -static constexpr int kErrorSuccess = 0; -static constexpr int kArbitraryErrorCode = 1; - -} // namespace - -// A test version of system clipboard. -class MockSystemClipboard { - public: - void OpenClipboard() { opened = true; } - void CloseClipboard() { opened = false; } - bool opened = false; -}; - -class TestPlatformHandlerWin32 : public PlatformHandlerWin32 { - public: - explicit TestPlatformHandlerWin32( - BinaryMessenger* messenger, - FlutterWindowsView* view, - std::optional()>> - scoped_clipboard_provider = std::nullopt) - : PlatformHandlerWin32(messenger, view, scoped_clipboard_provider) {} - - virtual ~TestPlatformHandlerWin32() = default; - - FRIEND_TEST(PlatformHandlerWin32, ReleaseClipboard); -}; - -// A test version of the private ScopedClipboard. -class TestScopedClipboard : public ScopedClipboardInterface { - public: - TestScopedClipboard(int open_error, - bool has_strings, - std::shared_ptr clipboard); - ~TestScopedClipboard(); - - // Prevent copying. - TestScopedClipboard(TestScopedClipboard const&) = delete; - TestScopedClipboard& operator=(TestScopedClipboard const&) = delete; - - int Open(HWND window) override; - - bool HasString() override; - - std::variant GetString() override; - - int SetString(const std::wstring string) override; - - private: - bool opened_ = false; - bool has_strings_; - int open_error_; - std::shared_ptr clipboard_; -}; - -TestScopedClipboard::TestScopedClipboard( - int open_error, - bool has_strings, - std::shared_ptr clipboard = nullptr) { - open_error_ = open_error; - has_strings_ = has_strings; - clipboard_ = clipboard; -} - -TestScopedClipboard::~TestScopedClipboard() { - if ((!open_error_) && clipboard_ != nullptr) { - clipboard_->CloseClipboard(); - } -} - -int TestScopedClipboard::Open(HWND window) { - if ((!open_error_) && clipboard_ != nullptr) { - clipboard_->OpenClipboard(); - } - return open_error_; -} - -bool TestScopedClipboard::HasString() { - return has_strings_; -} - -std::variant TestScopedClipboard::GetString() { - return -1; -} - -int TestScopedClipboard::SetString(const std::wstring string) { - return -1; -} - -class MockMethodResult : public MethodResult { - 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()); -}; - -// Regression test for https://github.com/flutter/flutter/issues/95817. -TEST(PlatformHandlerWin32, HasStringsAccessDeniedReturnsFalseWithoutError) { - TestBinaryMessenger messenger; - FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - // HasStrings will receive access denied on the clipboard, but will return - // false without error. - PlatformHandlerWin32 platform_handler(&messenger, &view, []() { - return std::make_unique(kAccessDeniedErrorCode, true); - }); - - 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); - })); -} - -TEST(PlatformHandlerWin32, HasStringsSuccessWithStrings) { - TestBinaryMessenger messenger; - FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - // HasStrings will succeed and return true. - PlatformHandlerWin32 platform_handler(&messenger, &view, []() { - return std::make_unique(kErrorSuccess, true); - }); - - 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); - })); -} - -TEST(PlatformHandlerWin32, HasStringsSuccessWithoutStrings) { - TestBinaryMessenger messenger; - FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - // HasStrings will succeed and return false. - PlatformHandlerWin32 platform_handler(&messenger, &view, []() { - return std::make_unique(kErrorSuccess, false); - }); - - 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); - })); -} - -TEST(PlatformHandlerWin32, HasStringsError) { - TestBinaryMessenger messenger; - FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - // HasStrings will fail. - PlatformHandlerWin32 platform_handler(&messenger, &view, []() { - return std::make_unique(kArbitraryErrorCode, true); - }); - - 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); - })); -} - -// Regression test for https://github.com/flutter/flutter/issues/103205. -TEST(PlatformHandlerWin32, ReleaseClipboard) { - auto system_clipboard = std::make_shared(); - - TestBinaryMessenger messenger; - FlutterWindowsView view( - std::make_unique<::testing::NiceMock>()); - TestPlatformHandlerWin32 platform_handler( - &messenger, &view, [system_clipboard]() { - return std::make_unique(kErrorSuccess, false, - system_clipboard); - }); - - platform_handler.GetPlainText(std::make_unique(), "text"); - ASSERT_FALSE(system_clipboard->opened); - - platform_handler.GetHasStrings(std::make_unique()); - ASSERT_FALSE(system_clipboard->opened); - - platform_handler.SetPlainText("", std::make_unique()); - ASSERT_FALSE(system_clipboard->opened); -} - -} // namespace testing -} // namespace flutter From 7d0f6d2f11df7213eca423976e9d2d70ec1fc51a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 16:27:05 -0400 Subject: [PATCH 015/558] Roll Dart SDK from c9dc429fb986 to ae4da4b1300c (1 revision) (#35059) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 1c757829230ae..52fdd0d061fcf 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'c9dc429fb986010b6d57133c16bc58ccffacd00e', + 'dart_revision': 'ae4da4b1300c8b779d53cccc6ef3ba7435a5b6fd', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 404b3f1e837078dc087558397e87e67e065ad944 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 1 Aug 2022 13:58:29 -0700 Subject: [PATCH 016/558] [macOS, Keyboard] Fix Khmer layout crashing (#35044) Fix test Impl --- .../Source/FlutterKeyboardManager.mm | 12 +-- .../Source/FlutterKeyboardManagerUnittests.mm | 88 ++++++------------- 2 files changed, 35 insertions(+), 65 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm index 6f6706305223f..116c94537d9be 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm @@ -269,9 +269,9 @@ - (void)buildLayout { } // Derive key mapping for each key code based on their layout clues. - // Max key code is 127 for ADB keyboards. - // https://developer.apple.com/documentation/coreservices/1390584-uckeytranslate?language=objc#parameters - const uint16_t kMaxKeyCode = 127; + // Key code 0x00 - 0x32 are typewriter keys (letters, digits, and symbols.) + // See keyCodeToPhysicalKey. + const uint16_t kMaxKeyCode = 0x32; #ifdef DEBUG_PRINT_LAYOUT NSString* debugLayoutData = @""; #endif @@ -303,8 +303,10 @@ - (void)buildLayout { } bool hasAnyEascii = isEascii(thisKeyClues[0]) || isEascii(thisKeyClues[1]); // See if any produced char meets the requirement as a logical key. - if (_layoutMap[@(keyCode)] == nil && !hasAnyEascii) { - _layoutMap[@(keyCode)] = @(usLayoutGoalsByKeyCode[keyCode].keyChar); + auto foundUsLayoutGoal = usLayoutGoalsByKeyCode.find(keyCode); + if (foundUsLayoutGoal != usLayoutGoalsByKeyCode.end() && _layoutMap[@(keyCode)] == nil && + !hasAnyEascii) { + _layoutMap[@(keyCode)] = @(foundUsLayoutGoal->second.keyChar); } } #ifdef DEBUG_PRINT_LAYOUT diff --git a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm index e257e94a9a031..b5fe0e65626f6 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm @@ -17,6 +17,7 @@ using flutter::testing::keycodes::kLogicalBracketLeft; using flutter::testing::keycodes::kLogicalDigit1; +using flutter::testing::keycodes::kLogicalDigit2; using flutter::testing::keycodes::kLogicalKeyA; using flutter::testing::keycodes::kLogicalKeyM; using flutter::testing::keycodes::kLogicalKeyQ; @@ -67,26 +68,7 @@ typedef void (^AsyncEmbedderCallbackHandler)(const FlutterKeyEvent* event, /* 0x24 */ 0x00000, 0x00000, 0x0006c, 0x0004c, 0x0006a, 0x0004a, 0x00027, 0x00022, /* 0x28 */ 0x0006b, 0x0004b, 0x0003b, 0x0003a, 0x0005c, 0x0007c, 0x0002c, 0x0003c, /* 0x2c */ 0x0002f, 0x0003f, 0x0006e, 0x0004e, 0x0006d, 0x0004d, 0x0002e, 0x0003e, - /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x00060, 0x0007e, 0x00000, 0x00000, - /* 0x34 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x38 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x3c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x40 */ 0x00000, 0x00000, 0x0002e, 0x0002e, 0x00000, 0x0002a, 0x0002a, 0x0002a, - /* 0x44 */ 0x00000, 0x00000, 0x0002b, 0x0002b, 0x00000, 0x0002b, 0x00000, 0x00000, - /* 0x48 */ 0x00000, 0x0003d, 0x00000, 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002f, - /* 0x4c */ 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002d, 0x0002d, 0x00000, 0x00000, - /* 0x50 */ 0x00000, 0x00000, 0x0003d, 0x0003d, 0x00030, 0x00030, 0x00031, 0x00031, - /* 0x54 */ 0x00032, 0x00032, 0x00033, 0x00033, 0x00034, 0x00034, 0x00035, 0x00035, - /* 0x58 */ 0x00036, 0x00036, 0x00037, 0x00037, 0x00000, 0x00000, 0x00038, 0x00038, - /* 0x5c */ 0x00039, 0x00039, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x60 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x64 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x68 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x6c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x70 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x74 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x78 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x7c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x00060, 0x0007e, }; MockLayoutData kFrenchLayout = { @@ -103,26 +85,7 @@ typedef void (^AsyncEmbedderCallbackHandler)(const FlutterKeyEvent* event, /* 0x24 */ 0x00000, 0x00000, 0x0006c, 0x0004c, 0x0006a, 0x0004a, 0x000f9, 0x00025, /* 0x28 */ 0x0006b, 0x0004b, 0x0006d, 0x0004d, 0x10060, 0x000a3, 0x0003b, 0x0002e, /* 0x2c */ 0x0003d, 0x0002b, 0x0006e, 0x0004e, 0x0002c, 0x0003f, 0x0003a, 0x0002f, - /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x0003c, 0x0003e, 0x00000, 0x00000, - /* 0x34 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x38 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x3c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x40 */ 0x00000, 0x00000, 0x0002c, 0x0002e, 0x00000, 0x0002a, 0x0002a, 0x0002a, - /* 0x44 */ 0x00000, 0x00000, 0x0002b, 0x0002b, 0x00000, 0x0002b, 0x00000, 0x00000, - /* 0x48 */ 0x00000, 0x0003d, 0x00000, 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002f, - /* 0x4c */ 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002d, 0x0002d, 0x00000, 0x00000, - /* 0x50 */ 0x00000, 0x00000, 0x0003d, 0x0003d, 0x00030, 0x00030, 0x00031, 0x00031, - /* 0x54 */ 0x00032, 0x00032, 0x00033, 0x00033, 0x00034, 0x00034, 0x00035, 0x00035, - /* 0x58 */ 0x00036, 0x00036, 0x00037, 0x00037, 0x00000, 0x00000, 0x00038, 0x00038, - /* 0x5c */ 0x00039, 0x00039, 0x00040, 0x00023, 0x0003c, 0x0003e, 0x00000, 0x00000, - /* 0x60 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x64 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x68 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x6c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x70 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x74 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x78 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x7c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x0003c, 0x0003e, }; MockLayoutData kRussianLayout = { @@ -139,26 +102,24 @@ typedef void (^AsyncEmbedderCallbackHandler)(const FlutterKeyEvent* event, /* 0x24 */ 0x00000, 0x00000, 0x00434, 0x00414, 0x0043e, 0x0041e, 0x0044d, 0x0042d, /* 0x28 */ 0x0043b, 0x0041b, 0x00436, 0x00416, 0x00451, 0x00401, 0x00431, 0x00411, /* 0x2c */ 0x0002f, 0x0003f, 0x00442, 0x00422, 0x0044c, 0x0042c, 0x0044e, 0x0042e, - /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x0005d, 0x0005b, 0x00000, 0x00000, - /* 0x34 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x38 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x3c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x40 */ 0x00000, 0x00000, 0x0002c, 0x0002e, 0x00000, 0x0002a, 0x0002a, 0x0002a, - /* 0x44 */ 0x00000, 0x00000, 0x0002b, 0x0002b, 0x00000, 0x0002b, 0x00000, 0x00000, - /* 0x48 */ 0x00000, 0x0003d, 0x00000, 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002f, - /* 0x4c */ 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002d, 0x0002d, 0x00000, 0x00000, - /* 0x50 */ 0x00000, 0x00000, 0x0003d, 0x0003d, 0x00030, 0x00030, 0x00031, 0x00031, - /* 0x54 */ 0x00032, 0x00032, 0x00033, 0x00033, 0x00034, 0x00034, 0x00035, 0x00035, - /* 0x58 */ 0x00036, 0x00036, 0x00037, 0x00037, 0x00000, 0x00000, 0x00038, 0x00038, - /* 0x5c */ 0x00039, 0x00039, 0x0003e, 0x0003c, 0x0005d, 0x0005b, 0x00000, 0x00000, - /* 0x60 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x64 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x68 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x6c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x70 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x74 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x78 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x7c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x0005d, 0x0005b, +}; + +MockLayoutData kKhmerLayout = { + // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift + /* 0x00 */ 0x017b6, 0x017ab, 0x0179f, 0x017c3, 0x0178a, 0x0178c, 0x01790, 0x01792, + /* 0x04 */ 0x017a0, 0x017c7, 0x01784, 0x017a2, 0x0178b, 0x0178d, 0x01781, 0x01783, + /* 0x08 */ 0x01785, 0x01787, 0x0179c, 0x017c8, 0x00000, 0x00000, 0x01794, 0x01796, + /* 0x0c */ 0x01786, 0x01788, 0x017b9, 0x017ba, 0x017c1, 0x017c2, 0x0179a, 0x017ac, + /* 0x10 */ 0x01799, 0x017bd, 0x0178f, 0x01791, 0x017e1, 0x00021, 0x017e2, 0x017d7, + /* 0x14 */ 0x017e3, 0x00022, 0x017e4, 0x017db, 0x017e6, 0x017cd, 0x017e5, 0x00025, + /* 0x18 */ 0x017b2, 0x017ce, 0x017e9, 0x017b0, 0x017e7, 0x017d0, 0x017a5, 0x017cc, + /* 0x1c */ 0x017e8, 0x017cf, 0x017e0, 0x017b3, 0x017aa, 0x017a7, 0x017c4, 0x017c5, + /* 0x20 */ 0x017bb, 0x017bc, 0x017c0, 0x017bf, 0x017b7, 0x017b8, 0x01795, 0x01797, + /* 0x24 */ 0x00000, 0x00000, 0x0179b, 0x017a1, 0x017d2, 0x01789, 0x017cb, 0x017c9, + /* 0x28 */ 0x01780, 0x01782, 0x017be, 0x017d6, 0x017ad, 0x017ae, 0x017a6, 0x017b1, + /* 0x2c */ 0x017ca, 0x017af, 0x01793, 0x0178e, 0x01798, 0x017c6, 0x017d4, 0x017d5, + /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x0200b, 0x000ab, 0x000bb, }; NSEvent* keyDownEvent(unsigned short keyCode, NSString* chars = @"", NSString* charsUnmod = @"") { @@ -757,6 +718,13 @@ - (bool)correctLogicalKeyForLayouts { sendTap(kVK_ANSI_LeftBracket, @"х", @"х"); VERIFY_DOWN(kLogicalBracketLeft, "х"); + /* Khmer keyboard layout */ + // Regression test for https://github.com/flutter/flutter/issues/108729 + [tester setLayout:kKhmerLayout]; + + sendTap(kVK_ANSI_2, @"២", @"២"); // Digit2 + VERIFY_DOWN(kLogicalDigit2, "២"); + return TRUE; } From a8c04a1bc6f52c743437968d04992e3cd11a8eb8 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 16:59:04 -0400 Subject: [PATCH 017/558] Roll Skia from 07b833fd6c79 to 79c3cf00a31b (5 revisions) (#35061) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 52fdd0d061fcf..966f73e11e249 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': '07b833fd6c79d89593a9735154bf61c5c9d5ad46', + 'skia_revision': '79c3cf00a31b2d4835d666fa3f75ee0e0813e2a7', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 0949c5e14b3b6..6149e989cbeb0 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e3bd2f2fed908d3abff03d8b74fe28a8 +Signature: 9687aa666ab6c3af6d59a35a74087a03 UNUSED LICENSES: From b257966d8daa3515391c6b3b64731c954fbd97d4 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 1 Aug 2022 14:41:03 -0700 Subject: [PATCH 018/558] [Window, Keyboard] Fix repeat events of modifier keys (#35046) --- .../windows/keyboard_key_embedder_handler.cc | 25 +++++++++++++++---- .../windows/keyboard_key_embedder_handler.h | 6 +++-- shell/platform/windows/keyboard_unittests.cc | 12 +++++++++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/shell/platform/windows/keyboard_key_embedder_handler.cc b/shell/platform/windows/keyboard_key_embedder_handler.cc index 5d596091a4053..0a072e80551f7 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler.cc +++ b/shell/platform/windows/keyboard_key_embedder_handler.cc @@ -186,6 +186,7 @@ void KeyboardKeyEmbedderHandler::KeyboardHookImpl( const bool is_event_down = action == WM_KEYDOWN || action == WM_SYSKEYDOWN; + bool event_key_can_be_repeat = true; UpdateLastSeenCritialKey(key, physical_key, sequence_logical_key); // Synchronize the toggled states of critical keys (such as whether CapsLocks // is enabled). Toggled states can only be changed upon a down event, so if @@ -197,14 +198,15 @@ void KeyboardKeyEmbedderHandler::KeyboardHookImpl( // updated to the true state, while the critical keys whose toggled state have // been changed will be pressed regardless of their true pressed state. // Updating the pressed state will be done by SynchronizeCritialPressedStates. - SynchronizeCritialToggledStates(key, is_event_down); + SynchronizeCritialToggledStates(key, is_event_down, &event_key_can_be_repeat); // Synchronize the pressed states of critical keys (such as whether CapsLocks // is pressed). // // After this function, all critical keys except for the target key will have // their toggled state and pressed state matched with their true states. The // target key's pressed state will be updated immediately after this. - SynchronizeCritialPressedStates(key, physical_key, is_event_down); + SynchronizeCritialPressedStates(key, physical_key, is_event_down, + event_key_can_be_repeat); // The resulting event's `type`. FlutterKeyEventType type; @@ -340,7 +342,8 @@ void KeyboardKeyEmbedderHandler::UpdateLastSeenCritialKey( void KeyboardKeyEmbedderHandler::SynchronizeCritialToggledStates( int event_virtual_key, - bool is_event_down) { + bool is_event_down, + bool* event_key_can_be_repeat) { // NowState ----------------> PreEventState --------------> TrueState // Synchronization Event for (auto& kv : critical_keys_) { @@ -385,6 +388,7 @@ void KeyboardKeyEmbedderHandler::SynchronizeCritialToggledStates( key_info.physical_key, key_info.logical_key, empty_character), nullptr, nullptr); + *event_key_can_be_repeat = false; } key_info.toggled_on = true_toggled; } @@ -394,7 +398,8 @@ void KeyboardKeyEmbedderHandler::SynchronizeCritialToggledStates( void KeyboardKeyEmbedderHandler::SynchronizeCritialPressedStates( int event_virtual_key, int event_physical_key, - bool is_event_down) { + bool is_event_down, + bool event_key_can_be_repeat) { // During an incoming event, there might be a synthesized Flutter event for // each key of each pressing goal, followed by an eventual main Flutter // event. @@ -424,8 +429,18 @@ void KeyboardKeyEmbedderHandler::SynchronizeCritialPressedStates( if (is_event_down) { // For down events, this key is the event key if they have the same // virtual key, because virtual key represents "functionality." + // + // In that case, normally Flutter should synthesize nothing since the + // resulting event can adapt to the current state by dispatching either + // a down or a repeat event. However, in certain cases (when Flutter has + // just synchronized the key's toggling state) the event must not be a + // repeat event. if (virtual_key == event_virtual_key) { - pre_event_pressed = false; + if (event_key_can_be_repeat) { + continue; + } else { + pre_event_pressed = false; + } } } else { // For up events, this key is the event key if they have the same diff --git a/shell/platform/windows/keyboard_key_embedder_handler.h b/shell/platform/windows/keyboard_key_embedder_handler.h index 426a38d42deab..67ff6490e5fc4 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler.h +++ b/shell/platform/windows/keyboard_key_embedder_handler.h @@ -115,12 +115,14 @@ class KeyboardKeyEmbedderHandler // Check each key's state from |get_key_state_| and synthesize events // if their toggling states have been desynchronized. void SynchronizeCritialToggledStates(int event_virtual_key, - bool is_event_down); + bool is_event_down, + bool* event_key_can_be_repeat); // Check each key's state from |get_key_state_| and synthesize events // if their pressing states have been desynchronized. void SynchronizeCritialPressedStates(int event_virtual_key, int event_physical_key, - bool is_event_down); + bool is_event_down, + bool event_key_can_be_repeat); // Wraps perform_send_event_ with state tracking. Use this instead of // |perform_send_event_| to send events to the framework. diff --git a/shell/platform/windows/keyboard_unittests.cc b/shell/platform/windows/keyboard_unittests.cc index 0bea6b97167d8..f532c1a92af85 100644 --- a/shell/platform/windows/keyboard_unittests.cc +++ b/shell/platform/windows/keyboard_unittests.cc @@ -696,6 +696,18 @@ TEST(KeyboardTest, ShiftLeftUnhandled) { clear_key_calls(); EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); + // Hold ShiftLeft + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasDown}.Build( + kWmResultZero)}); + + EXPECT_EQ(key_calls.size(), 1); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeRepeat, + kPhysicalShiftLeft, kLogicalShiftLeft, "", + kNotSynthesized); + clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); + // Release ShiftLeft tester.InjectKeyboardChanges(std::vector{ KeyStateChange{VK_LSHIFT, false, true}, From 45673327ae4d1e79f2e62377ba36a1f1afd9a710 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 1 Aug 2022 14:54:03 -0700 Subject: [PATCH 019/558] [Impeller] Remove redundant GN flags. (#35062) --- impeller/BUILD.gn | 4 ---- impeller/tools/impeller.gni | 16 ++-------------- shell/platform/android/platform_view_android.cc | 10 ---------- 3 files changed, 2 insertions(+), 28 deletions(-) diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn index 49c9ace17c74a..5b583c9283f14 100644 --- a/impeller/BUILD.gn +++ b/impeller/BUILD.gn @@ -9,10 +9,6 @@ config("impeller_public_config") { defines = [] - if (impeller_supports_platform) { - defines += [ "IMPELLER_SUPPORTS_PLATFORM=1" ] - } - if (impeller_supports_rendering) { defines += [ "IMPELLER_SUPPORTS_RENDERING=1" ] } diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index 89b37a427bbd4..ba7ee027eae4d 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -10,9 +10,6 @@ declare_args() { # Whether playgrounds are enabled for unit tests. impeller_enable_playground = false - # Whether Impeller is supported on the platform. - impeller_supports_platform = true - # Whether the Metal backend is enabled. impeller_enable_metal = is_mac || is_ios @@ -36,11 +33,6 @@ declare_args() { } declare_args() { - # Whether Impeller shaders are supported on the platform. - impeller_shaders_supports_platform = - impeller_enable_metal || impeller_enable_opengles || - impeller_enable_vulkan - # Whether Impeller supports rendering on the platform. impeller_supports_rendering = impeller_enable_metal || impeller_enable_opengles || @@ -61,7 +53,7 @@ template("impeller_component") { group(target_name) { not_needed(invoker, "*") } - } else if (impeller_supports_platform) { + } else { target_type = "source_set" if (defined(invoker.target_type)) { target_type = invoker.target_type @@ -96,10 +88,6 @@ template("impeller_component") { cflags_objcc += flutter_cflags_objcc_arc } } - } else { - group(target_name) { - not_needed(invoker, "*") - } } } @@ -586,7 +574,7 @@ template("impeller_shaders") { } } - if (!impeller_shaders_supports_platform) { + if (!impeller_supports_rendering) { not_needed(invoker, "*") } diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index 305948de8a093..5e0ab4be7f2e7 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -10,14 +10,10 @@ #include "flutter/fml/synchronization/waitable_event.h" #include "flutter/shell/common/shell_io_manager.h" #include "flutter/shell/gpu/gpu_surface_gl_delegate.h" -#if IMPELLER_SUPPORTS_PLATFORM #include "flutter/shell/platform/android/android_context_gl_impeller.h" -#endif #include "flutter/shell/platform/android/android_context_gl_skia.h" #include "flutter/shell/platform/android/android_external_texture_gl.h" -#if IMPELLER_SUPPORTS_PLATFORM #include "flutter/shell/platform/android/android_surface_gl_impeller.h" -#endif #include "flutter/shell/platform/android/android_surface_gl_skia.h" #include "flutter/shell/platform/android/android_surface_software.h" #include "flutter/shell/platform/android/context/android_context.h" @@ -46,17 +42,13 @@ std::unique_ptr AndroidSurfaceFactoryImpl::CreateSurface() { return std::make_unique(android_context_, jni_facade_); case AndroidRenderingAPI::kOpenGLES: -#if IMPELLER_SUPPORTS_PLATFORM if (enable_impeller_) { return std::make_unique(android_context_, jni_facade_); } else { -#endif return std::make_unique(android_context_, jni_facade_); -#if IMPELLER_SUPPORTS_PLATFORM } -#endif default: FML_DCHECK(false); return nullptr; @@ -71,11 +63,9 @@ static std::shared_ptr CreateAndroidContext( if (use_software_rendering) { return std::make_shared(AndroidRenderingAPI::kSoftware); } -#if IMPELLER_SUPPORTS_PLATFORM if (enable_impeller) { return std::make_unique(); } -#endif return std::make_unique( AndroidRenderingAPI::kOpenGLES, // fml::MakeRefCounted(), // From 8fd7435ee1f5c343c73a75d850568bcfdf363104 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 1 Aug 2022 15:00:04 -0700 Subject: [PATCH 020/558] [Impeller] Use portable geometry constants. (#35064) --- impeller/BUILD.gn | 2 -- impeller/geometry/constants.h | 2 ++ impeller/geometry/geometry_unittests.cc | 37 +++++++++++++------------ 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn index 5b583c9283f14..2fbc00d125343 100644 --- a/impeller/BUILD.gn +++ b/impeller/BUILD.gn @@ -35,8 +35,6 @@ config("impeller_public_config") { if (is_win) { defines += [ - "_USE_MATH_DEFINES", - # TODO(dnfield): https://github.com/flutter/flutter/issues/50053 "_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING", ] diff --git a/impeller/geometry/constants.h b/impeller/geometry/constants.h index 95f56a546f2a0..5e775b5385194 100644 --- a/impeller/geometry/constants.h +++ b/impeller/geometry/constants.h @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#pragma once + namespace impeller { // e diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 276b6751ccb06..31e876d9b81c4 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -7,6 +7,7 @@ #include #include "flutter/testing/testing.h" +#include "impeller/geometry/constants.h" #include "impeller/geometry/path.h" #include "impeller/geometry/path_builder.h" #include "impeller/geometry/path_component.h" @@ -28,7 +29,7 @@ TEST(GeometryTest, ScalarNearlyEqual) { } TEST(GeometryTest, RotationMatrix) { - auto rotation = Matrix::MakeRotationZ(Radians{M_PI_4}); + auto rotation = Matrix::MakeRotationZ(Radians{kPiOver4}); auto expect = Matrix{0.707, 0.707, 0, 0, // -0.707, 0.707, 0, 0, // 0, 0, 1, 0, // @@ -38,7 +39,7 @@ TEST(GeometryTest, RotationMatrix) { TEST(GeometryTest, InvertMultMatrix) { { - auto rotation = Matrix::MakeRotationZ(Radians{M_PI_4}); + auto rotation = Matrix::MakeRotationZ(Radians{kPiOver4}); auto invert = rotation.Invert(); auto expect = Matrix{0.707, -0.707, 0, 0, // 0.707, 0.707, 0, 0, // @@ -71,7 +72,7 @@ TEST(GeometryTest, MatrixBasis) { } TEST(GeometryTest, MutliplicationMatrix) { - auto rotation = Matrix::MakeRotationZ(Radians{M_PI_4}); + auto rotation = Matrix::MakeRotationZ(Radians{kPiOver4}); auto invert = rotation.Invert(); ASSERT_MATRIX_NEAR(rotation * invert, Matrix{}); } @@ -98,7 +99,7 @@ TEST(GeometryTest, InvertMatrix) { } TEST(GeometryTest, TestDecomposition) { - auto rotated = Matrix::MakeRotationZ(Radians{M_PI_4}); + auto rotated = Matrix::MakeRotationZ(Radians{kPiOver4}); auto result = rotated.Decompose(); @@ -106,12 +107,12 @@ TEST(GeometryTest, TestDecomposition) { MatrixDecomposition res = result.value(); - auto quaternion = Quaternion{{0.0, 0.0, 1.0}, M_PI_4}; + auto quaternion = Quaternion{{0.0, 0.0, 1.0}, kPiOver4}; ASSERT_QUATERNION_NEAR(res.rotation, quaternion); } TEST(GeometryTest, TestDecomposition2) { - auto rotated = Matrix::MakeRotationZ(Radians{M_PI_4}); + auto rotated = Matrix::MakeRotationZ(Radians{kPiOver4}); auto scaled = Matrix::MakeScale({2.0, 3.0, 1.0}); auto translated = Matrix::MakeTranslation({-200, 750, 20}); @@ -121,7 +122,7 @@ TEST(GeometryTest, TestDecomposition2) { MatrixDecomposition res = result.value(); - auto quaternion = Quaternion{{0.0, 0.0, 1.0}, M_PI_4}; + auto quaternion = Quaternion{{0.0, 0.0, 1.0}, kPiOver4}; ASSERT_QUATERNION_NEAR(res.rotation, quaternion); @@ -138,7 +139,7 @@ TEST(GeometryTest, TestRecomposition) { /* * Decomposition. */ - auto rotated = Matrix::MakeRotationZ(Radians{M_PI_4}); + auto rotated = Matrix::MakeRotationZ(Radians{kPiOver4}); auto result = rotated.Decompose(); @@ -146,7 +147,7 @@ TEST(GeometryTest, TestRecomposition) { MatrixDecomposition res = result.value(); - auto quaternion = Quaternion{{0.0, 0.0, 1.0}, M_PI_4}; + auto quaternion = Quaternion{{0.0, 0.0, 1.0}, kPiOver4}; ASSERT_QUATERNION_NEAR(res.rotation, quaternion); @@ -158,7 +159,7 @@ TEST(GeometryTest, TestRecomposition) { TEST(GeometryTest, TestRecomposition2) { auto matrix = Matrix::MakeTranslation({100, 100, 100}) * - Matrix::MakeRotationZ(Radians{M_PI_4}) * + Matrix::MakeRotationZ(Radians{kPiOver4}) * Matrix::MakeScale({2.0, 2.0, 2.0}); auto result = matrix.Decompose(); @@ -171,7 +172,7 @@ TEST(GeometryTest, TestRecomposition2) { TEST(GeometryTest, MatrixVectorMultiplication) { { auto matrix = Matrix::MakeTranslation({100, 100, 100}) * - Matrix::MakeRotationZ(Radians{M_PI_2}) * + Matrix::MakeRotationZ(Radians{kPiOver2}) * Matrix::MakeScale({2.0, 2.0, 2.0}); auto vector = Vector4(10, 20, 30, 2); @@ -182,7 +183,7 @@ TEST(GeometryTest, MatrixVectorMultiplication) { { auto matrix = Matrix::MakeTranslation({100, 100, 100}) * - Matrix::MakeRotationZ(Radians{M_PI_2}) * + Matrix::MakeRotationZ(Radians{kPiOver2}) * Matrix::MakeScale({2.0, 2.0, 2.0}); auto vector = Vector3(10, 20, 30); @@ -193,7 +194,7 @@ TEST(GeometryTest, MatrixVectorMultiplication) { { auto matrix = Matrix::MakeTranslation({100, 100, 100}) * - Matrix::MakeRotationZ(Radians{M_PI_2}) * + Matrix::MakeRotationZ(Radians{kPiOver2}) * Matrix::MakeScale({2.0, 2.0, 2.0}); auto vector = Point(10, 20); @@ -206,7 +207,7 @@ TEST(GeometryTest, MatrixVectorMultiplication) { TEST(GeometryTest, MatrixTransformDirection) { { auto matrix = Matrix::MakeTranslation({100, 100, 100}) * - Matrix::MakeRotationZ(Radians{M_PI_2}) * + Matrix::MakeRotationZ(Radians{kPiOver2}) * Matrix::MakeScale({2.0, 2.0, 2.0}); auto vector = Vector4(10, 20, 30, 2); @@ -217,7 +218,7 @@ TEST(GeometryTest, MatrixTransformDirection) { { auto matrix = Matrix::MakeTranslation({100, 100, 100}) * - Matrix::MakeRotationZ(Radians{M_PI_2}) * + Matrix::MakeRotationZ(Radians{kPiOver2}) * Matrix::MakeScale({2.0, 2.0, 2.0}); auto vector = Vector3(10, 20, 30); @@ -228,7 +229,7 @@ TEST(GeometryTest, MatrixTransformDirection) { { auto matrix = Matrix::MakeTranslation({100, 100, 100}) * - Matrix::MakeRotationZ(Radians{M_PI_2}) * + Matrix::MakeRotationZ(Radians{kPiOver2}) * Matrix::MakeScale({2.0, 2.0, 2.0}); auto vector = Point(10, 20); @@ -303,11 +304,11 @@ TEST(GeometryTest, MatrixMakePerspective) { TEST(GeometryTest, QuaternionLerp) { auto q1 = Quaternion{{0.0, 0.0, 1.0}, 0.0}; - auto q2 = Quaternion{{0.0, 0.0, 1.0}, M_PI_4}; + auto q2 = Quaternion{{0.0, 0.0, 1.0}, kPiOver4}; auto q3 = q1.Slerp(q2, 0.5); - auto expected = Quaternion{{0.0, 0.0, 1.0}, M_PI_4 / 2.0}; + auto expected = Quaternion{{0.0, 0.0, 1.0}, kPiOver4 / 2.0}; ASSERT_QUATERNION_NEAR(q3, expected); } From 60e5eb6f3c2c45e3c98135155c3abf15ceb328de Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 1 Aug 2022 15:09:04 -0700 Subject: [PATCH 021/558] Don't insist on modules when attempting to include the Flutter umbrella header. (#35060) --- shell/platform/darwin/ios/BUILD.gn | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 1ee7c5cadbd11..74aa338ab2971 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -381,11 +381,7 @@ copy("copy_license") { shared_library("copy_and_verify_framework_module") { framework_search_path = rebase_path("$root_out_dir") visibility = [ ":*" ] - cflags_objc = [ - "-F$framework_search_path", - "-fmodules", - "-Wnon-modular-include-in-framework-module", - ] + cflags_objc = [ "-F$framework_search_path" ] sources = [ "framework/Source/FlutterUmbrellaImport.m" ] deps = [ From af880588b4c55b95f5194f45fbe73e63bf504bdc Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 18:11:04 -0400 Subject: [PATCH 022/558] Roll Skia from 79c3cf00a31b to 06ff6f6c64ab (3 revisions) (#35065) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 966f73e11e249..90c22cd86c74c 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': '79c3cf00a31b2d4835d666fa3f75ee0e0813e2a7', + 'skia_revision': '06ff6f6c64ab7562f379b257c6294a84a6aa4804', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 6149e989cbeb0..3eb7940f6a9dc 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 9687aa666ab6c3af6d59a35a74087a03 +Signature: d1f73ced74fb5c5b7d348ff600475607 UNUSED LICENSES: @@ -839,6 +839,7 @@ FILE: ../../../third_party/skia/infra/bots/assets/armhf_sysroot/VERSION FILE: ../../../third_party/skia/infra/bots/assets/bazel/VERSION FILE: ../../../third_party/skia/infra/bots/assets/bazel_build_task_driver/VERSION FILE: ../../../third_party/skia/infra/bots/assets/bazelisk/VERSION +FILE: ../../../third_party/skia/infra/bots/assets/bazelisk_mac_arm64/VERSION FILE: ../../../third_party/skia/infra/bots/assets/bloaty/VERSION FILE: ../../../third_party/skia/infra/bots/assets/cast_toolchain/VERSION FILE: ../../../third_party/skia/infra/bots/assets/ccache_linux/VERSION From 4063cfb06d9acd2c5bcaf34188223bb13a603bb1 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 1 Aug 2022 15:13:03 -0700 Subject: [PATCH 023/558] Fix detection of Mac target specification as a host build. (#35063) --- tools/gn | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/gn b/tools/gn index 2cfc42920b044..2b8e94f3363fe 100755 --- a/tools/gn +++ b/tools/gn @@ -94,11 +94,17 @@ def cpu_for_target_arch(arch): def is_host_build(args): # If target_os == None, then this is a host build. - # However, for linux arm64 builds, we cross compile from x64 hosts, so the + if args.target_os is None: + return True + # For linux arm64 builds, we cross compile from x64 hosts, so the # target_os='linux' and linux-cpu='arm64' - return args.target_os is None or ( - args.target_os == 'linux' and args.linux_cpu == 'arm64' - ) + if args.target_os == 'linux' and args.linux_cpu == 'arm64': + return True + # The Mac and host targets are redundant. Again, necessary to disambiguate + # during cross-compilation. + if args.target_os == 'mac': + return True + return False # Determines whether a prebuilt Dart SDK can be used instead of building one. From 4450edd2bf7ffd69034b256a926c88b35566108d Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Tue, 2 Aug 2022 06:43:04 +0800 Subject: [PATCH 024/558] Javadoc for background platform chnanels (#34774) --- .../io/flutter/plugin/common/MethodChannel.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java index c13f82d2beb1f..9949167a7ce03 100644 --- a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java +++ b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java @@ -173,8 +173,10 @@ public interface MethodCallHandler { *

Any uncaught exception thrown by this method will be caught by the channel implementation * and logged, and an error result will be sent back to Flutter. * - *

The handler is called on the platform thread (Android main thread). For more details see - * Threading in + *

The handler is called on the platform thread (Android main thread) by default, or + * otherwise on the thread specified by the {@link BinaryMessenger.TaskQueue} provided to the + * associated {@link MethodChannel} when it was created. See also Threading in * the Flutter Engine. * * @param call A {@link MethodCall}. @@ -190,10 +192,7 @@ public interface MethodCallHandler { * Flutter methods provide implementations of this interface for handling results received from * Flutter. * - *

All methods of this class must be called on the platform thread (Android main thread). For - * more details see Threading in the - * Flutter Engine. + *

All methods of this class can be invoked on any thread. */ public interface Result { /** From 56c2ae742e642d26ad5b0f785cdfda3457a8357b Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 1 Aug 2022 16:07:04 -0700 Subject: [PATCH 025/558] Roll buildroot to 0881a07a. (#35067) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 90c22cd86c74c..dc42e082cbb1e 100644 --- a/DEPS +++ b/DEPS @@ -102,7 +102,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + 'cd444824e34d8f735a351f680776bc0479f20677', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '0881a07a2203d23e21712cc5829ec5469ae19e3d', # Fuchsia compatibility # From ebd70e663c668fd3fbc949bebe0ece2e2026bb06 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 19:26:04 -0400 Subject: [PATCH 026/558] Roll Skia from 06ff6f6c64ab to 6e967a35611f (2 revisions) (#35068) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index dc42e082cbb1e..40d8841019f9a 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': '06ff6f6c64ab7562f379b257c6294a84a6aa4804', + 'skia_revision': '6e967a35611f36ae22126453ac5adec2231f23a9', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 3eb7940f6a9dc..bc9df7c1f103c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d1f73ced74fb5c5b7d348ff600475607 +Signature: a20e07eefa93410e1b246a53f87af9ea UNUSED LICENSES: From 4c22c2869ee0836c7e7f0ac3e749e7c6350043f1 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Mon, 1 Aug 2022 17:20:03 -0700 Subject: [PATCH 027/558] Roll Abseil (#35066) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 40d8841019f9a..01ed970edd612 100644 --- a/DEPS +++ b/DEPS @@ -464,7 +464,7 @@ deps = { Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator' + '@' + '7de5cc00de50e71a3aab22dea52fbb7ff4efceb6', 'src/third_party/abseil-cpp': - Var('flutter_git') + '/third_party/abseil-cpp.git' + '@' + 'f92f9effc89af7692436c3b9fbb3a67f2239d893', + Var('flutter_git') + '/third_party/abseil-cpp.git' + '@' + '61833f2c057a2b1993d871e8c51156aed1dd4354', # Dart packages 'src/third_party/pkg/archive': From 137fbd2ca550f8c99161d398c5aa8f63de3acb7e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 20:40:04 -0400 Subject: [PATCH 028/558] Roll Skia from 6e967a35611f to 08ba24a351cf (2 revisions) (#35070) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 01ed970edd612..b1e9c15c4b4f8 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': '6e967a35611f36ae22126453ac5adec2231f23a9', + 'skia_revision': '08ba24a351cfeb2d515e72dcb268d7a37d49b4c2', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index bc9df7c1f103c..07d50b9e63fdd 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: a20e07eefa93410e1b246a53f87af9ea +Signature: e45fa4758b28e29d65360c6748bc93d3 UNUSED LICENSES: From b78baa2ef9aac0e8ce9a3ced99c39248a3ad6a91 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 1 Aug 2022 20:50:04 -0400 Subject: [PATCH 029/558] Roll Dart SDK from ae4da4b1300c to cdad34a03923 (1 revision) (#35071) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b1e9c15c4b4f8..8b2b35206b193 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'ae4da4b1300c8b779d53cccc6ef3ba7435a5b6fd', + 'dart_revision': 'cdad34a0392362c0e580048918cb6ea481e84662', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 46f8bb941583e..57436ca2a1326 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: c2f96fc1357f595ff44a0c8e1c6e4cbb +Signature: 841dff039a0ab89ede7841fc0044be19 UNUSED LICENSES: From ef85495784c6924756462a9f5e26b8b9b5ccdc5f Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 1 Aug 2022 18:05:05 -0700 Subject: [PATCH 030/558] Move Sigma<->Radius conversion to geometry (#35069) --- ci/licenses_golden/licenses_flutter | 2 + .../display_list/display_list_dispatcher.cc | 7 ++- .../entity/contents/filters/filter_contents.h | 52 +---------------- impeller/entity/entity_unittests.cc | 10 ++-- impeller/geometry/BUILD.gn | 2 + impeller/geometry/sigma.cc | 19 +++++++ impeller/geometry/sigma.h | 57 +++++++++++++++++++ 7 files changed, 89 insertions(+), 60 deletions(-) create mode 100644 impeller/geometry/sigma.cc create mode 100644 impeller/geometry/sigma.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index cf00c43c74d5f..e4550afff2c17 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -654,6 +654,8 @@ FILE: ../../../flutter/impeller/geometry/rect.h FILE: ../../../flutter/impeller/geometry/scalar.h FILE: ../../../flutter/impeller/geometry/shear.cc FILE: ../../../flutter/impeller/geometry/shear.h +FILE: ../../../flutter/impeller/geometry/sigma.cc +FILE: ../../../flutter/impeller/geometry/sigma.h FILE: ../../../flutter/impeller/geometry/size.cc FILE: ../../../flutter/impeller/geometry/size.h FILE: ../../../flutter/impeller/geometry/type_traits.cc diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index b06e0ca57a776..dcc4daa9220df 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -21,6 +21,7 @@ #include "impeller/geometry/path.h" #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" @@ -324,7 +325,7 @@ void DisplayListDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) { auto blur = filter->asBlur(); auto style = ToBlurStyle(blur->style()); - auto sigma = FilterContents::Sigma(blur->sigma()); + auto sigma = Sigma(blur->sigma()); paint_.mask_filter = [style, sigma](FilterInput::Ref input, bool is_solid_color) { @@ -350,8 +351,8 @@ static std::optional ToImageFilterProc( switch (filter->type()) { case flutter::DlImageFilterType::kBlur: { auto blur = filter->asBlur(); - auto sigma_x = FilterContents::Sigma(blur->sigma_x()); - auto sigma_y = FilterContents::Sigma(blur->sigma_y()); + auto sigma_x = Sigma(blur->sigma_x()); + auto sigma_y = Sigma(blur->sigma_y()); if (blur->tile_mode() != flutter::DlTileMode::kClamp) { // TODO(105072): Implement tile mode for blur filter. diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 43d2af2512b7f..03231a3d78cba 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -11,6 +11,7 @@ #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/entity/entity.h" +#include "impeller/geometry/sigma.h" #include "impeller/renderer/formats.h" namespace impeller { @@ -30,57 +31,6 @@ class FilterContents : public Contents { kInner, }; - /// For filters that use a Gaussian distribution, this is the `Radius` size to - /// use per `Sigma` (standard deviation). - /// - /// This cutoff (sqrt(3)) is taken from Flutter and Skia (where the - /// multiplicative inverse of this constant is used (1 / sqrt(3)): - /// https://api.flutter.dev/flutter/dart-ui/Shadow/convertRadiusToSigma.html - /// - /// In practice, this value is somewhat arbitrary, and can be changed to a - /// higher number to integrate more of the Gaussian function and render higher - /// quality blurs (with exponentially diminishing returns for the same sigma - /// input). Making this value any lower results in a noticable loss of - /// quality in the blur. - constexpr static float kKernelRadiusPerSigma = 1.73205080757; - - struct Radius; - - /// @brief In filters that use Gaussian distributions, "sigma" is a size of - /// one standard deviation in terms of the local space pixel grid of - /// the filter input. In other words, this determines how wide the - /// distribution stretches. - struct Sigma { - Scalar sigma = 0.0; - - constexpr Sigma() = default; - - explicit constexpr Sigma(Scalar p_sigma) : sigma(p_sigma) {} - - constexpr operator Radius() const { - return Radius{sigma > 0.5f ? (sigma - 0.5f) * kKernelRadiusPerSigma - : 0.0f}; - }; - }; - - /// @brief For convolution filters, the "radius" is the size of the - /// convolution kernel to use on the local space pixel grid of the - /// filter input. - /// For Gaussian blur kernels, this unit has a linear - /// relationship with `Sigma`. See `kKernelRadiusPerSigma` for - /// details on how this relationship works. - struct Radius { - Scalar radius = 0.0; - - constexpr Radius() = default; - - explicit constexpr Radius(Scalar p_radius) : radius(p_radius) {} - - constexpr operator Sigma() const { - return Sigma{radius > 0 ? radius / kKernelRadiusPerSigma + 0.5f : 0.0f}; - }; - }; - static std::shared_ptr MakeBlend( Entity::BlendMode blend_mode, FilterInput::Vector inputs, diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index dca12868062f0..b1f0e0b0c6ab8 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -20,6 +20,7 @@ #include "impeller/entity/entity_playground.h" #include "impeller/geometry/geometry_unittests.h" #include "impeller/geometry/path_builder.h" +#include "impeller/geometry/sigma.h" #include "impeller/playground/playground.h" #include "impeller/playground/widgets.h" #include "impeller/renderer/render_pass.h" @@ -913,13 +914,11 @@ TEST_P(EntityTest, GaussianBlurFilter) { } auto blur = FilterContents::MakeGaussianBlur( - FilterInput::Make(input), FilterContents::Sigma{blur_amount[0]}, - FilterContents::Sigma{blur_amount[1]}, + FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]}, blur_styles[selected_blur_style]); auto mask_blur = FilterContents::MakeBorderMaskBlur( - FilterInput::Make(input), FilterContents::Sigma{blur_amount[0]}, - FilterContents::Sigma{blur_amount[1]}, + FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]}, blur_styles[selected_blur_style]); auto ctm = Matrix::MakeScale(GetContentScale()) * @@ -1033,8 +1032,7 @@ TEST_P(EntityTest, BorderMaskBlurCoverageIsCorrect) { PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath()); fill->SetColor(Color::CornflowerBlue()); auto border_mask_blur = FilterContents::MakeBorderMaskBlur( - FilterInput::Make(fill), FilterContents::Radius{3}, - FilterContents::Radius{4}); + FilterInput::Make(fill), Radius{3}, Radius{4}); { Entity e; diff --git a/impeller/geometry/BUILD.gn b/impeller/geometry/BUILD.gn index 65b99c1290a82..0afe7a6dbd5d0 100644 --- a/impeller/geometry/BUILD.gn +++ b/impeller/geometry/BUILD.gn @@ -29,6 +29,8 @@ impeller_component("geometry") { "scalar.h", "shear.cc", "shear.h", + "sigma.cc", + "sigma.h", "size.cc", "size.h", "type_traits.cc", diff --git a/impeller/geometry/sigma.cc b/impeller/geometry/sigma.cc new file mode 100644 index 0000000000000..a73bcd7cea8bd --- /dev/null +++ b/impeller/geometry/sigma.cc @@ -0,0 +1,19 @@ +// 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/geometry/sigma.h" + +#include + +namespace impeller { + +Sigma::operator Radius() const { + return Radius{sigma > 0.5f ? (sigma - 0.5f) * kKernelRadiusPerSigma : 0.0f}; +} + +Radius::operator Sigma() const { + return Sigma{radius > 0 ? radius / kKernelRadiusPerSigma + 0.5f : 0.0f}; +} + +} // namespace impeller diff --git a/impeller/geometry/sigma.h b/impeller/geometry/sigma.h new file mode 100644 index 0000000000000..c909128be4baa --- /dev/null +++ b/impeller/geometry/sigma.h @@ -0,0 +1,57 @@ +// 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 "impeller/geometry/scalar.h" + +namespace impeller { + +/// For filters that use a Gaussian distribution, this is the `Radius` size to +/// use per `Sigma` (standard deviation). +/// +/// This cutoff (sqrt(3)) is taken from Flutter and Skia (where the +/// multiplicative inverse of this constant is used (1 / sqrt(3)): +/// https://api.flutter.dev/flutter/dart-ui/Shadow/convertRadiusToSigma.html +/// +/// In practice, this value is somewhat arbitrary, and can be changed to a +/// higher number to integrate more of the Gaussian function and render higher +/// quality blurs (with exponentially diminishing returns for the same sigma +/// input). Making this value any lower results in a noticable loss of +/// quality in the blur. +constexpr static float kKernelRadiusPerSigma = 1.73205080757; + +struct Radius; + +/// @brief In filters that use Gaussian distributions, "sigma" is a size of +/// one standard deviation in terms of the local space pixel grid of +/// the filter input. In other words, this determines how wide the +/// distribution stretches. +struct Sigma { + Scalar sigma = 0.0; + + constexpr Sigma() = default; + + explicit constexpr Sigma(Scalar p_sigma) : sigma(p_sigma) {} + + operator Radius() const; // NOLINT(google-explicit-constructor) +}; + +/// @brief For convolution filters, the "radius" is the size of the +/// convolution kernel to use on the local space pixel grid of the +/// filter input. +/// For Gaussian blur kernels, this unit has a linear +/// relationship with `Sigma`. See `kKernelRadiusPerSigma` for +/// details on how this relationship works. +struct Radius { + Scalar radius = 0.0; + + constexpr Radius() = default; + + explicit constexpr Radius(Scalar p_radius) : radius(p_radius) {} + + operator Sigma() const; // NOLINT(google-explicit-constructor) +}; + +} // namespace impeller From 6ac41425c1315d79a465bd1edf6f37266718bd18 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 1 Aug 2022 19:08:25 -0700 Subject: [PATCH 031/558] [Impeller] Add additional trace around acquisition of next Metal drawable. (#35074) --- impeller/renderer/backend/metal/surface_mtl.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/impeller/renderer/backend/metal/surface_mtl.mm b/impeller/renderer/backend/metal/surface_mtl.mm index 0e391544f7eca..dc540bb6e2117 100644 --- a/impeller/renderer/backend/metal/surface_mtl.mm +++ b/impeller/renderer/backend/metal/surface_mtl.mm @@ -24,7 +24,11 @@ return nullptr; } - auto current_drawable = [layer nextDrawable]; + id current_drawable = nil; + { + TRACE_EVENT0("impeller", "WaitForNextDrawable"); + current_drawable = [layer nextDrawable]; + } if (!current_drawable) { VALIDATION_LOG << "Could not acquire current drawable."; From 1c3b1b305ef34abc4a99a5caec78d3268bac1814 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Mon, 1 Aug 2022 20:13:04 -0700 Subject: [PATCH 032/558] Add support relative path support to create_macos_framework. (#35011) --- sky/tools/create_macos_framework.py | 39 +++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/sky/tools/create_macos_framework.py b/sky/tools/create_macos_framework.py index 2f61b8094dabb..42380f97aa42a 100755 --- a/sky/tools/create_macos_framework.py +++ b/sky/tools/create_macos_framework.py @@ -12,11 +12,17 @@ from create_xcframework import create_xcframework +buildroot_dir = os.path.abspath( + os.path.join(os.path.realpath(__file__), '..', '..', '..', '..') +) + DSYMUTIL = os.path.join( os.path.dirname(__file__), '..', '..', '..', 'buildtools', 'mac-x64', 'clang', 'bin', 'dsymutil' ) +out_dir = os.path.join(buildroot_dir, 'out') + def main(): parser = argparse.ArgumentParser( @@ -31,9 +37,22 @@ def main(): args = parser.parse_args() - fat_framework = os.path.join(args.dst, 'FlutterMacOS.framework') - arm64_framework = os.path.join(args.arm64_out_dir, 'FlutterMacOS.framework') - x64_framework = os.path.join(args.x64_out_dir, 'FlutterMacOS.framework') + dst = ( + args.dst + if os.path.isabs(args.dst) else os.path.join(buildroot_dir, args.dst) + ) + arm64_out_dir = ( + args.arm64_out_dir if os.path.isabs(args.arm64_out_dir) else + os.path.join(buildroot_dir, args.arm64_out_dir) + ) + x64_out_dir = ( + args.x64_out_dir if os.path.isabs(args.x64_out_dir) else + os.path.join(buildroot_dir, args.x64_out_dir) + ) + + fat_framework = os.path.join(dst, 'FlutterMacOS.framework') + arm64_framework = os.path.join(arm64_out_dir, 'FlutterMacOS.framework') + x64_framework = os.path.join(x64_out_dir, 'FlutterMacOS.framework') arm64_dylib = os.path.join(arm64_framework, 'FlutterMacOS') x64_dylib = os.path.join(x64_framework, 'FlutterMacOS') @@ -66,20 +85,26 @@ def main(): ) # Create the arm64/x64 fat framework. - subprocess.check_call([ + result = subprocess.run([ 'lipo', arm64_dylib, x64_dylib, '-create', '-output', fat_framework_binary ]) - process_framework(args, fat_framework, fat_framework_binary) + if result.returncode != 0: + print( + 'Error processing command with stdout[%s] and stderr[%s]' % + (result.stdout, result.stderr) + ) + return 1 + process_framework(dst, args, fat_framework, fat_framework_binary) -def process_framework(args, fat_framework, fat_framework_binary): +def process_framework(dst, args, fat_framework, fat_framework_binary): if args.dsym: dsym_out = os.path.splitext(fat_framework)[0] + '.dSYM' subprocess.check_call([DSYMUTIL, '-o', dsym_out, fat_framework_binary]) if args.strip: # copy unstripped - unstripped_out = os.path.join(args.dst, 'FlutterMacOS.unstripped') + unstripped_out = os.path.join(dst, 'FlutterMacOS.unstripped') shutil.copyfile(fat_framework_binary, unstripped_out) subprocess.check_call(["strip", "-x", "-S", fat_framework_binary]) From b6078110efda9ae513ab88c8e504f3fabb2b4fb4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 01:04:04 -0400 Subject: [PATCH 033/558] Roll Dart SDK from cdad34a03923 to 48b50d4a3b1e (1 revision) (#35076) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 8b2b35206b193..f5ca5874a9ed2 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'cdad34a0392362c0e580048918cb6ea481e84662', + 'dart_revision': '48b50d4a3b1ef832cbe1aea869df44886a223d0c', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 3b2bd24a1e0bb385a15d08fe5b730e0ec9da3730 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 01:55:04 -0400 Subject: [PATCH 034/558] Roll Skia from 08ba24a351cf to 81bce3afeb8a (1 revision) (#35077) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f5ca5874a9ed2..14c4b316a2c44 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': '08ba24a351cfeb2d515e72dcb268d7a37d49b4c2', + 'skia_revision': '81bce3afeb8ab447a03f3611280fdf3b9d7c2afc', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 07d50b9e63fdd..07e310cee1c18 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e45fa4758b28e29d65360c6748bc93d3 +Signature: 9d79bfd05488d54763d72cd7ac2d546f UNUSED LICENSES: From 0e5392c4c24839c62fae4042500f27db5bccb89c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 03:19:07 -0400 Subject: [PATCH 035/558] Roll Skia from 81bce3afeb8a to ffdc6195136d (1 revision) (#35079) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 14c4b316a2c44..31798d7d0e9c3 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': '81bce3afeb8ab447a03f3611280fdf3b9d7c2afc', + 'skia_revision': 'ffdc6195136defca0b52578af8e6fc3857c47f1e', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 07e310cee1c18..e81406b0dc71b 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 9d79bfd05488d54763d72cd7ac2d546f +Signature: 4c724287e6a4dcd827b0d3c1a75d0abf UNUSED LICENSES: From 4b192569797ff569fc7bf287ef861f87fca8446a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 03:25:08 -0400 Subject: [PATCH 036/558] Roll Fuchsia Linux SDK from v8t2ulUK5... to u_FbFbg2m... (#35078) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 31798d7d0e9c3..b3b1b857281fd 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'v8t2ulUK5j2G1pxiLp5MQM-TynZ-q6FpeATFYCBRZ_4C' + 'version': 'u_FbFbg2malEPTqZZDE26AOs7L68HUcRat50mggUEV4C' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index c8e596c0df640..ff5b7dfed5f08 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: b69dd228524fa047db35855b5227ca35 +Signature: 754f3f7f9e82cf0a98d522c9b12eee0c UNUSED LICENSES: From 4b262fb2587d542661d84024bd96896942cf0583 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 04:59:05 -0400 Subject: [PATCH 037/558] Roll Skia from ffdc6195136d to 1db5b0b118ef (2 revisions) (#35081) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b3b1b857281fd..192a0b6ccb371 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': 'ffdc6195136defca0b52578af8e6fc3857c47f1e', + 'skia_revision': '1db5b0b118ef54b5720e5e9276e086be0f4ea704', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index e81406b0dc71b..46b815250588c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 4c724287e6a4dcd827b0d3c1a75d0abf +Signature: 41083524f0171db170b1d098932f3014 UNUSED LICENSES: From e0b5edc1131b48415592b32d94c90cf50c369fdf Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 05:22:05 -0400 Subject: [PATCH 038/558] Roll Dart SDK from 48b50d4a3b1e to 73ca8ffc4b5d (1 revision) (#35082) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 192a0b6ccb371..97458eb323bb8 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '48b50d4a3b1ef832cbe1aea869df44886a223d0c', + 'dart_revision': '73ca8ffc4b5d539ddb9341f9d725a88a97fa099d', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 57436ca2a1326..cde3f12d8524e 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 841dff039a0ab89ede7841fc0044be19 +Signature: 203f630cf725dd2a8c057dd8436dcb7c UNUSED LICENSES: From b164c5c86d1ce3601af309a7b4d290f78baa3012 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 09:17:04 -0400 Subject: [PATCH 039/558] Roll Dart SDK from 73ca8ffc4b5d to d2452b2c8380 (1 revision) (#35086) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 97458eb323bb8..aff35c3ce6593 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '73ca8ffc4b5d539ddb9341f9d725a88a97fa099d', + 'dart_revision': 'd2452b2c8380b32be5539429908949901b1b0628', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 08e66f8848ddfaecf39767832833e9a5c89ba36b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 10:26:04 -0400 Subject: [PATCH 040/558] Roll Skia from 1db5b0b118ef to 81eadfa35cd5 (1 revision) (#35088) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index aff35c3ce6593..8d8afb3b2b3cf 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': '1db5b0b118ef54b5720e5e9276e086be0f4ea704', + 'skia_revision': '81eadfa35cd59eabdf48bda6f4e95fdf196cd5d0', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 46b815250588c..aaffbd944f870 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 41083524f0171db170b1d098932f3014 +Signature: e8965d04c44501626ff88f6f3b831f03 UNUSED LICENSES: From 7a5ac4424dc2b4cc2eafc8dba590ed2400416ec0 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 11:38:04 -0400 Subject: [PATCH 041/558] Roll Skia from 81eadfa35cd5 to ae50bb0abc7b (4 revisions) (#35090) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 8d8afb3b2b3cf..87101bde5a6d7 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': '81eadfa35cd59eabdf48bda6f4e95fdf196cd5d0', + 'skia_revision': 'ae50bb0abc7b6efb5e14fcf761eaf9b4a7e1f2de', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index aaffbd944f870..e2565544d5604 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e8965d04c44501626ff88f6f3b831f03 +Signature: 8e06edb0dc21640d00a05e5a9f5be097 UNUSED LICENSES: From 4aa66bdae43965a53c392c31c0ccf6b4112f8c65 Mon Sep 17 00:00:00 2001 From: Xilai Zhang Date: Tue, 2 Aug 2022 08:51:08 -0700 Subject: [PATCH 042/558] [gn] entitlement config for macos framework zip (#34987) --- shell/platform/darwin/macos/BUILD.gn | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 640e340b3ff3a..0381e6feb8a08 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -306,6 +306,10 @@ action("_generate_symlinks") { ":copy_framework_module_map", ":copy_license", ] + metadata = { + macos_framework_without_entitlement = + [ "FlutterMacOS.framework.zip/Versions/A/FlutterMacOS" ] + } } group("flutter_framework") { @@ -332,8 +336,19 @@ zip_bundle("zip_macos_flutter_framework") { ] } +generated_file("macos_framework_without_entitlement_config") { + outputs = [ "$target_gen_dir/framework_without_entitlements.txt" ] + + data_keys = [ "macos_framework_without_entitlement" ] + + deps = [ ":_generate_symlinks" ] +} + zip_bundle("macos_flutter_framework_archive") { - deps = [ ":zip_macos_flutter_framework" ] + deps = [ + ":macos_framework_without_entitlement_config", + ":zip_macos_flutter_framework", + ] prefix = "$full_platform_name-$flutter_runtime_mode/" if (flutter_runtime_mode == "debug") { prefix = "$full_platform_name/" @@ -344,5 +359,9 @@ zip_bundle("macos_flutter_framework_archive") { source = "$root_out_dir/zip_archives/tmp/FlutterMacOS.framework.zip" destination = "FlutterMacOS.framework.zip" }, + { + source = "$target_gen_dir/framework_without_entitlements.txt" + destination = "without_entitlements.txt" + }, ] } From eb2b57bdb7bc9adced54479c1390e6b1c1c5b4e5 Mon Sep 17 00:00:00 2001 From: Xilai Zhang Date: Tue, 2 Aug 2022 08:52:04 -0700 Subject: [PATCH 043/558] [gn] Mac entitlement config for font subset (#34989) --- tools/font-subset/BUILD.gn | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tools/font-subset/BUILD.gn b/tools/font-subset/BUILD.gn index e12e3025bb54b..53df3e102e74e 100644 --- a/tools/font-subset/BUILD.gn +++ b/tools/font-subset/BUILD.gn @@ -22,6 +22,10 @@ executable("_font-subset") { "CoreText.framework", ] } + + metadata = { + font_subset_without_entitlement = [ "font-subset" ] + } } generated_file("_font-subset-license") { @@ -40,6 +44,14 @@ generated_file("_font-subset-license") { ] } +generated_file("font_entitlement_config") { + outputs = [ "$target_gen_dir/font_subset_without_entitlements.txt" ] + + data_keys = [ "font_subset_without_entitlement" ] + + deps = [ ":_font-subset" ] +} + zip_bundle("font-subset") { if (is_mac) { # Mac artifacts sometimes use mac and sometimes darwin. Standardizing the @@ -74,4 +86,13 @@ zip_bundle("font-subset") { ":_font-subset-license", "//flutter/tools/const_finder", ] + if (is_mac) { + deps += [ ":font_entitlement_config" ] + files += [ + { + source = "$target_gen_dir/font_subset_without_entitlements.txt" + destination = "without_entitlements.txt" + }, + ] + } } From d9a677784ad742f9460a0c403e75069121231267 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Tue, 2 Aug 2022 09:20:03 -0700 Subject: [PATCH 044/558] Remove unnecessary exceptions from analysis_options.yaml (#35054) --- analysis_options.yaml | 12 +- lib/ui/compositing.dart | 2 +- lib/ui/painting.dart | 162 +++++++-------- lib/ui/platform_dispatcher.dart | 11 +- lib/ui/plugins.dart | 4 +- lib/ui/text.dart | 2 +- lib/web_ui/dev/browser_process.dart | 38 ++-- lib/web_ui/dev/chrome.dart | 10 +- lib/web_ui/dev/chrome_installer.dart | 10 +- lib/web_ui/dev/edge.dart | 4 +- lib/web_ui/dev/edge_installation.dart | 4 +- lib/web_ui/dev/firefox.dart | 10 +- lib/web_ui/dev/firefox_installer.dart | 12 +- lib/web_ui/dev/safari_ios.dart | 8 +- lib/web_ui/dev/test_platform.dart | 190 +++++++++--------- lib/web_ui/dev/webdriver_browser.dart | 8 +- lib/web_ui/lib/painting.dart | 29 +-- lib/web_ui/lib/platform_dispatcher.dart | 4 +- lib/web_ui/lib/src/engine/assets.dart | 12 +- lib/web_ui/lib/src/engine/canvas_pool.dart | 16 +- .../lib/src/engine/canvaskit/canvas.dart | 94 ++++----- .../engine/canvaskit/canvaskit_canvas.dart | 4 +- .../src/engine/canvaskit/embedded_views.dart | 40 ++-- .../engine/canvaskit/embedded_views_diff.dart | 8 +- .../src/engine/canvaskit/font_fallbacks.dart | 16 +- .../lib/src/engine/canvaskit/fonts.dart | 12 +- .../lib/src/engine/canvaskit/image.dart | 4 +- .../engine/canvaskit/image_web_codecs.dart | 16 +- .../src/engine/canvaskit/interval_tree.dart | 10 +- .../lib/src/engine/canvaskit/layer.dart | 64 +++--- .../engine/canvaskit/layer_scene_builder.dart | 4 +- .../lib/src/engine/canvaskit/layer_tree.dart | 4 +- .../lib/src/engine/canvaskit/picture.dart | 5 +- .../engine/canvaskit/platform_message.dart | 4 +- .../engine/canvaskit/skia_object_cache.dart | 16 +- .../lib/src/engine/canvaskit/surface.dart | 12 +- .../src/engine/canvaskit/surface_factory.dart | 24 +-- lib/web_ui/lib/src/engine/canvaskit/text.dart | 26 +-- .../engine/canvaskit/viewport_metrics.dart | 8 +- lib/web_ui/lib/src/engine/dom.dart | 20 +- lib/web_ui/lib/src/engine/engine_canvas.dart | 9 +- .../lib/src/engine/frame_reference.dart | 2 +- lib/web_ui/lib/src/engine/host_node.dart | 8 +- .../lib/src/engine/html/bitmap_canvas.dart | 68 +++---- lib/web_ui/lib/src/engine/html/canvas.dart | 4 +- .../lib/src/engine/html/color_filter.dart | 4 +- .../lib/src/engine/html/dom_canvas.dart | 4 +- .../lib/src/engine/html/path/conic.dart | 4 +- lib/web_ui/lib/src/engine/html/path/path.dart | 58 +++--- .../src/engine/html/path/path_metrics.dart | 7 +- .../lib/src/engine/html/path/path_ref.dart | 132 ++++++------ .../lib/src/engine/html/path/path_utils.dart | 4 +- .../lib/src/engine/html/platform_view.dart | 4 +- .../lib/src/engine/html/recording_canvas.dart | 164 +++++++-------- .../lib/src/engine/html/render_vertices.dart | 10 +- .../html/shaders/normalized_gradient.dart | 12 +- .../engine/html/shaders/shader_builder.dart | 23 ++- .../lib/src/engine/html_image_codec.dart | 11 +- lib/web_ui/lib/src/engine/keyboard.dart | 32 +-- .../lib/src/engine/keyboard_binding.dart | 8 +- lib/web_ui/lib/src/engine/mouse_cursor.dart | 4 +- .../lib/src/engine/navigation/history.dart | 2 +- .../lib/src/engine/platform_dispatcher.dart | 4 +- .../platform_views/message_handler.dart | 9 +- .../lib/src/engine/pointer_binding.dart | 24 +-- lib/web_ui/lib/src/engine/rrect_renderer.dart | 4 +- .../lib/src/engine/safe_browser_api.dart | 58 +++--- .../src/engine/semantics/accessibility.dart | 12 +- .../lib/src/engine/semantics/checkable.dart | 4 +- .../src/engine/semantics/incrementable.dart | 48 ++--- .../lib/src/engine/semantics/semantics.dart | 2 +- .../lib/src/engine/semantics/text_field.dart | 10 +- .../lib/src/engine/services/buffers.dart | 8 +- .../src/engine/services/message_codecs.dart | 6 +- lib/web_ui/lib/src/engine/test_embedding.dart | 4 +- .../lib/src/engine/text/canvas_paragraph.dart | 2 +- .../lib/src/engine/text/font_collection.dart | 20 +- .../lib/src/engine/text/layout_service.dart | 4 +- .../lib/src/engine/text/word_breaker.dart | 4 +- .../engine/text_editing/autofill_hint.dart | 16 +- .../text_editing/text_capitalization.dart | 4 +- .../src/engine/text_editing/text_editing.dart | 40 ++-- lib/web_ui/lib/src/engine/ulps.dart | 6 +- lib/web_ui/lib/src/engine/vector_math.dart | 126 ++++++------ .../canvaskit/fallback_fonts_golden_test.dart | 4 +- .../canvaskit/skia_objects_cache_test.dart | 8 +- .../test/engine/frame_reference_test.dart | 2 +- .../platform_views/message_handler_test.dart | 2 +- .../test/engine/pointer_binding_test.dart | 2 +- .../engine/semantics/semantics_tester.dart | 22 +- .../surface/path/path_winding_test.dart | 2 +- .../test/engine/surface/surface_test.dart | 4 +- .../test/html/paragraph/text_scuba.dart | 4 +- .../test/html/path_to_svg_golden_test.dart | 6 +- lib/web_ui/test/mock_engine_canvas.dart | 2 +- .../lib/src/touches_scenario.dart | 6 +- 96 files changed, 982 insertions(+), 1010 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index dcbaa56a57069..a6c3786733025 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -9,14 +9,6 @@ analyzer: strict-casts: true strict-raw-types: true errors: - # treat missing required parameters as a warning (not a hint) - missing_required_param: warning - # treat missing returns as a warning (not a hint) - missing_return: warning - # allow having TODO comments in the code - todo: ignore - # allow dart:ui to import dart:_internal - import_internal_library: ignore # DIFFERENT FROM FLUTTER/FLUTTER # allow self-reference to deprecated members (we do this because otherwise we have # to annotate every member in every test, assert, etc, when we deprecate something) deprecated_member_use_from_same_package: ignore @@ -150,7 +142,7 @@ linter: # - prefer_double_quotes # opposite of prefer_single_quotes - prefer_equal_for_default_values # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods - # - prefer_final_fields # DIFFERENT FROM FLUTTER/FLUTTER (we do weird things with private fields, especially on the PlatformDispatcher object) + - prefer_final_fields - prefer_final_in_for_each - prefer_final_locals # - prefer_final_parameters # we should enable this one day when it can be auto-fixed (https://github.com/dart-lang/linter/issues/3104), see also parameter_assignments @@ -185,7 +177,7 @@ linter: # - sized_box_shrink_expand # not yet tested - slash_for_doc_comments - sort_child_properties_last - # - sort_constructors_first # DIFFERENT FROM FLUTTER/FLUTTER (we have private fake constructors) + - sort_constructors_first # - sort_pub_dependencies # prevents separating pinned transitive dependencies - sort_unnamed_constructors_first - test_types_in_equals diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index 0ed1581569aac..528fc027c043a 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -240,7 +240,7 @@ class SceneBuilder extends NativeFieldWrapperClass1 { // // The key is the layer used. The value is the description of what the layer // is used for, e.g. "pushOpacity" or "addRetained". - Map _usedLayers = {}; + final Map _usedLayers = {}; // In debug mode checks that the `layer` is only used once in a given scene. bool _debugCheckUsedOnce(EngineLayer layer, String usage) { diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index bd5e93f5e62ab..5b52122e15726 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1090,6 +1090,14 @@ enum Clip { /// Most APIs on [Canvas] take a [Paint] object to describe the style /// to use for that operation. class Paint { + /// Constructs an empty [Paint] object with all fields initialized to + /// their defaults. + Paint() { + if (enableDithering) { + _dither = true; + } + } + // Paint objects are encoded in two buffers: // // * _data is binary data in four-byte fields, each of which is either a @@ -1150,14 +1158,6 @@ class Paint { static const int _kImageFilterIndex = 2; static const int _kObjectCount = 3; // Must be one larger than the largest index. - /// Constructs an empty [Paint] object with all fields initialized to - /// their defaults. - Paint() { - if (enableDithering) { - _dither = true; - } - } - /// Whether to apply anti-aliasing to lines and images drawn on the /// canvas. /// @@ -1878,7 +1878,7 @@ class _Image extends NativeFieldWrapperClass1 { @FfiNative)>('Image::dispose') external void _dispose(); - Set _handles = {}; + final Set _handles = {}; @override String toString() => '[$width\u00D7$height]'; @@ -2350,9 +2350,6 @@ class Path extends NativeFieldWrapperClass1 { @pragma('vm:entry-point') Path() { _constructor(); } - @FfiNative('Path::Create') - external void _constructor(); - /// Avoids creating a new native backing for the path for methods that will /// create it later, such as [Path.from], [shift] and [transform]. Path._(); @@ -2367,6 +2364,9 @@ class Path extends NativeFieldWrapperClass1 { return clonedPath; } + @FfiNative('Path::Create') + external void _constructor(); + @FfiNative, Handle)>('Path::clone') external void _clone(Path outPath); @@ -2848,7 +2848,7 @@ class PathMetricIterator implements Iterator { PathMetricIterator._(this._pathMeasure) : assert(_pathMeasure != null); PathMetric? _pathMetric; - _PathMeasure _pathMeasure; + final _PathMeasure _pathMeasure; @override PathMetric get current { @@ -3576,9 +3576,6 @@ class _ComposeImageFilter implements ImageFilter { /// ImageFilter, because we want ImageFilter to be efficiently comparable, so that /// widgets can check for ImageFilter equality to avoid repainting. class _ImageFilter extends NativeFieldWrapperClass1 { - @FfiNative('ImageFilter::Create') - external void _constructor(); - /// Creates an image filter that applies a Gaussian blur. _ImageFilter.blur(_GaussianBlurImageFilter filter) : assert(filter != null), @@ -3587,9 +3584,6 @@ class _ImageFilter extends NativeFieldWrapperClass1 { _initBlur(filter.sigmaX, filter.sigmaY, filter.tileMode.index); } - @FfiNative, Double, Double, Int32)>('ImageFilter::initBlur', isLeaf: true) - external void _initBlur(double sigmaX, double sigmaY, int tileMode); - /// Creates an image filter that dilates each input pixel's channel values /// to the max value within the given radii along the x and y axes. _ImageFilter.dilate(_DilateImageFilter filter) @@ -3598,8 +3592,6 @@ class _ImageFilter extends NativeFieldWrapperClass1 { _constructor(); _initDilate(filter.radiusX, filter.radiusY); } - @FfiNative, Double, Double)>('ImageFilter::initDilate', isLeaf: true) - external void _initDilate(double radiusX, double radiusY); /// Create a filter that erodes each input pixel's channel values /// to the minimum channel value within the given radii along the x and y axes. @@ -3609,8 +3601,6 @@ class _ImageFilter extends NativeFieldWrapperClass1 { _constructor(); _initErode(filter.radiusX, filter.radiusY); } - @FfiNative, Double, Double)>('ImageFilter::initErode', isLeaf: true) - external void _initErode(double radiusX, double radiusY); /// Creates an image filter that applies a matrix transformation. /// @@ -3626,9 +3616,6 @@ class _ImageFilter extends NativeFieldWrapperClass1 { _initMatrix(filter.data, filter.filterQuality.index); } - @FfiNative, Handle, Int32)>('ImageFilter::initMatrix') - external void _initMatrix(Float64List matrix4, int filterQuality); - /// Converts a color filter to an image filter. _ImageFilter.fromColorFilter(ColorFilter filter) : assert(filter != null), @@ -3638,9 +3625,6 @@ class _ImageFilter extends NativeFieldWrapperClass1 { _initColorFilter(nativeFilter); } - @FfiNative, Pointer)>('ImageFilter::initColorFilter') - external void _initColorFilter(_ColorFilter? colorFilter); - /// Composes `_innerFilter` with `_outerFilter`. _ImageFilter.composed(_ComposeImageFilter filter) : assert(filter != null), @@ -3651,6 +3635,24 @@ class _ImageFilter extends NativeFieldWrapperClass1 { _initComposed(nativeFilterOuter, nativeFilterInner); } + @FfiNative('ImageFilter::Create') + external void _constructor(); + + @FfiNative, Double, Double, Int32)>('ImageFilter::initBlur', isLeaf: true) + external void _initBlur(double sigmaX, double sigmaY, int tileMode); + + @FfiNative, Double, Double)>('ImageFilter::initDilate', isLeaf: true) + external void _initDilate(double radiusX, double radiusY); + + @FfiNative, Double, Double)>('ImageFilter::initErode', isLeaf: true) + external void _initErode(double radiusX, double radiusY); + + @FfiNative, Handle, Int32)>('ImageFilter::initMatrix') + external void _initMatrix(Float64List matrix4, int filterQuality); + + @FfiNative, Pointer)>('ImageFilter::initColorFilter') + external void _initColorFilter(_ColorFilter? colorFilter); + @FfiNative, Pointer, Pointer)>('ImageFilter::initComposeFilter') external void _initComposed(_ImageFilter outerFilter, _ImageFilter innerFilter); @@ -3803,9 +3805,6 @@ Float32List _encodeTwoPoints(Offset pointA, Offset pointB) { /// * [Gradient](https://api.flutter.dev/flutter/painting/Gradient-class.html), the class in the [painting] library. /// class Gradient extends Shader { - @FfiNative('Gradient::Create') - external void _constructor(); - /// Creates a linear gradient from `from` to `to`. /// /// If `colorStops` is provided, `colorStops[i]` is a number from 0.0 to 1.0 @@ -3849,9 +3848,6 @@ class Gradient extends Shader { _initLinear(endPointsBuffer, colorsBuffer, colorStopsBuffer, tileMode.index, matrix4); } - @FfiNative, Handle, Handle, Handle, Int32, Handle)>('Gradient::initLinear') - external void _initLinear(Float32List endPoints, Int32List colors, Float32List? colorStops, int tileMode, Float64List? matrix4); - /// Creates a radial gradient centered at `center` that ends at `radius` /// distance from the center. /// @@ -3912,30 +3908,6 @@ class Gradient extends Shader { } } - @FfiNative, Double, Double, Double, Handle, Handle, Int32, Handle)>('Gradient::initRadial') - external void _initRadial( - double centerX, - double centerY, - double radius, - Int32List colors, - Float32List? colorStops, - int tileMode, - Float64List? matrix4); - - @FfiNative, Double, Double, Double, Double, Double, Double, Handle, Handle, Int32, Handle)>( - 'Gradient::initTwoPointConical') - external void _initConical( - double startX, - double startY, - double startRadius, - double endX, - double endY, - double endRadius, - Int32List colors, - Float32List? colorStops, - int tileMode, - Float64List? matrix4); - /// Creates a sweep gradient centered at `center` that starts at `startAngle` /// and ends at `endAngle`. /// @@ -3986,6 +3958,36 @@ class Gradient extends Shader { _initSweep(center.dx, center.dy, colorsBuffer, colorStopsBuffer, tileMode.index, startAngle, endAngle, matrix4); } + @FfiNative('Gradient::Create') + external void _constructor(); + + @FfiNative, Handle, Handle, Handle, Int32, Handle)>('Gradient::initLinear') + external void _initLinear(Float32List endPoints, Int32List colors, Float32List? colorStops, int tileMode, Float64List? matrix4); + + @FfiNative, Double, Double, Double, Handle, Handle, Int32, Handle)>('Gradient::initRadial') + external void _initRadial( + double centerX, + double centerY, + double radius, + Int32List colors, + Float32List? colorStops, + int tileMode, + Float64List? matrix4); + + @FfiNative, Double, Double, Double, Double, Double, Double, Handle, Handle, Int32, Handle)>( + 'Gradient::initTwoPointConical') + external void _initConical( + double startX, + double startY, + double startRadius, + double endX, + double endY, + double endRadius, + Int32List colors, + Float32List? colorStops, + int tileMode, + Float64List? matrix4); + @FfiNative, Double, Double, Handle, Handle, Int32, Double, Double, Handle)>('Gradient::initSweep') external void _initSweep( double centerX, @@ -4054,6 +4056,15 @@ class ImageShader extends Shader { /// [A current specification of valid SPIR-V is here.](https://github.com/flutter/engine/blob/main/lib/spirv/README.md) /// class FragmentProgram extends NativeFieldWrapperClass1 { + @pragma('vm:entry-point') + FragmentProgram._fromAsset(String assetKey) { + _constructor(); + final String result = _initFromAsset(assetKey); + if (result.isNotEmpty) { + throw result; // ignore: only_throw_errors + } + } + // TODO(zra): Document custom shaders on the website and add a link to it // here. https://github.com/flutter/flutter/issues/107929. /// Creates a fragment program from the asset with key [assetKey]. @@ -4078,18 +4089,9 @@ class FragmentProgram extends NativeFieldWrapperClass1 { // so that the case where an in-use program is requested again can be fast, // but programs that are no longer referenced are not retained because of the // cache. - static Map> _shaderRegistry = + static final Map> _shaderRegistry = >{}; - @pragma('vm:entry-point') - FragmentProgram._fromAsset(String assetKey) { - _constructor(); - final String result = _initFromAsset(assetKey); - if (result.isNotEmpty) { - throw result; // ignore: only_throw_errors - } - } - static void _reinitializeShader(String assetKey) { // If a shader for the assent isn't already registered, then there's no // need to reinitialize it. The new shader will be loaded and initialized @@ -6010,17 +6012,6 @@ class ImmutableBuffer extends NativeFieldWrapperClass1 { class ImageDescriptor extends NativeFieldWrapperClass1 { ImageDescriptor._(); - /// Creates an image descriptor from encoded data in a supported format. - static Future encoded(ImmutableBuffer buffer) { - final ImageDescriptor descriptor = ImageDescriptor._(); - return _futurize((_Callback callback) { - return descriptor._initEncoded(buffer, callback); - }).then((_) => descriptor); - } - - @FfiNative, Handle)>('ImageDescriptor::initEncoded') - external String? _initEncoded(ImmutableBuffer buffer, _Callback callback); - /// Creates an image descriptor from raw image pixels. /// /// The `pixels` parameter is the pixel data. They are packed in bytes in the @@ -6045,6 +6036,17 @@ class ImageDescriptor extends NativeFieldWrapperClass1 { _initRaw(this, buffer, width, height, rowBytes ?? -1, pixelFormat.index); } + /// Creates an image descriptor from encoded data in a supported format. + static Future encoded(ImmutableBuffer buffer) { + final ImageDescriptor descriptor = ImageDescriptor._(); + return _futurize((_Callback callback) { + return descriptor._initEncoded(buffer, callback); + }).then((_) => descriptor); + } + + @FfiNative, Handle)>('ImageDescriptor::initEncoded') + external String? _initEncoded(ImmutableBuffer buffer, _Callback callback); + @FfiNative('ImageDescriptor::initRaw') external static void _initRaw(ImageDescriptor outDescriptor, ImmutableBuffer buffer, int width, int height, int rowBytes, int pixelFormat); diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index 8f3fa8295a8b2..1a86c5846bf46 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -141,10 +141,10 @@ class PlatformDispatcher { /// /// If any of their configurations change, [onMetricsChanged] will be called. Iterable get views => _views.values; - Map _views = {}; + final Map _views = {}; // A map of opaque platform view identifiers to view configurations. - Map _viewConfigurations = {}; + final Map _viewConfigurations = {}; /// A callback that is invoked whenever the [ViewConfiguration] of any of the /// [views] changes. @@ -1454,8 +1454,6 @@ class FrameTiming { ]); } - static final int _dataLength = FramePhase.values.length + _FrameTimingInfo.values.length; - /// Construct [FrameTiming] with raw timestamps in microseconds. /// /// List [timestamps] must have the same number of elements as @@ -1463,8 +1461,9 @@ class FrameTiming { /// /// This constructor is usually only called by the Flutter engine, or a test. /// To get the [FrameTiming] of your app, see [PlatformDispatcher.onReportTimings]. - FrameTiming._(this._data) - : assert(_data.length == _dataLength); + FrameTiming._(this._data) : assert(_data.length == _dataLength); + + static final int _dataLength = FramePhase.values.length + _FrameTimingInfo.values.length; /// This is a raw timestamp in microseconds from some epoch. The epoch in all /// [FrameTiming] is the same, but it may not match [DateTime]'s epoch. diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index 24948f4b2217b..50543d2acc0bc 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -45,9 +45,9 @@ class PluginUtilities { // extended directly. factory PluginUtilities._() => throw UnsupportedError('Namespace'); - static Map _forwardCache = + static final Map _forwardCache = {}; - static Map _backwardCache = + static final Map _backwardCache = {}; /// Get a handle to a named top-level or static callback function which can diff --git a/lib/ui/text.dart b/lib/ui/text.dart index c9e68c42b6979..4b329608da900 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -2976,7 +2976,7 @@ class ParagraphBuilder extends NativeFieldWrapperClass1 { /// The scales of the placeholders in the paragraph. List get placeholderScales => _placeholderScales; - List _placeholderScales = []; + final List _placeholderScales = []; final TextLeadingDistribution _defaultLeadingDistribution; /// Applies the given style to the added text until [pop] is called. diff --git a/lib/web_ui/dev/browser_process.dart b/lib/web_ui/dev/browser_process.dart index a546540f04533..104dafc51c893 100644 --- a/lib/web_ui/dev/browser_process.dart +++ b/lib/web_ui/dev/browser_process.dart @@ -10,25 +10,6 @@ import 'package:stack_trace/stack_trace.dart'; import 'package:typed_data/typed_buffers.dart'; class BrowserProcess { - /// The underlying process. - /// - /// This will fire once the process has started successfully. - Future get _process => _processCompleter.future; - final Completer _processCompleter = Completer(); - - /// Whether [close] has been called. - bool _closed = false; - - /// A future that completes when the browser exits. - /// - /// If there's a problem starting or running the browser, this will complete - /// with an error. - Future get onExit => _onExitCompleter.future; - final Completer _onExitCompleter = Completer(); - - /// Standard IO streams for the underlying browser process. - final List> _ioSubscriptions = >[]; - /// Creates a new browser. /// /// Clients pass in [startBrowser], which asynchronously returns the browser @@ -103,6 +84,25 @@ class BrowserProcess { }); } + /// The underlying process. + /// + /// This will fire once the process has started successfully. + Future get _process => _processCompleter.future; + final Completer _processCompleter = Completer(); + + /// Whether [close] has been called. + bool _closed = false; + + /// A future that completes when the browser exits. + /// + /// If there's a problem starting or running the browser, this will complete + /// with an error. + Future get onExit => _onExitCompleter.future; + final Completer _onExitCompleter = Completer(); + + /// Standard IO streams for the underlying browser process. + final List> _ioSubscriptions = >[]; + /// Kills the browser process. /// /// Returns the same [Future] as [onExit], except that it won't emit diff --git a/lib/web_ui/dev/chrome.dart b/lib/web_ui/dev/chrome.dart index d41cf6102ee5c..18d8a74a85e2d 100644 --- a/lib/web_ui/dev/chrome.dart +++ b/lib/web_ui/dev/chrome.dart @@ -58,11 +58,6 @@ class ChromeEnvironment implements BrowserEnvironment { /// /// Any errors starting or running the process are reported through [onExit]. class Chrome extends Browser { - final BrowserProcess _process; - - @override - final Future remoteDebuggerUrl; - /// Starts a new instance of Chrome open to the given [url], which may be a /// [Uri] or a [String]. factory Chrome(Uri url, BrowserInstallation installation, {bool debug = false}) { @@ -122,6 +117,11 @@ class Chrome extends Browser { Chrome._(this._process, this.remoteDebuggerUrl); + final BrowserProcess _process; + + @override + final Future remoteDebuggerUrl; + @override Future get onExit => _process.onExit; diff --git a/lib/web_ui/dev/chrome_installer.dart b/lib/web_ui/dev/chrome_installer.dart index 565952aab9328..e5ed8c889fd76 100644 --- a/lib/web_ui/dev/chrome_installer.dart +++ b/lib/web_ui/dev/chrome_installer.dart @@ -100,17 +100,17 @@ class ChromeInstaller { ); } - static Future latest() async { - final String latestVersion = await fetchLatestChromeVersion(); - return ChromeInstaller(version: latestVersion); - } - ChromeInstaller._({ required this.version, required this.chromeInstallationDir, required this.versionDir, }); + static Future latest() async { + final String latestVersion = await fetchLatestChromeVersion(); + return ChromeInstaller(version: latestVersion); + } + /// Chrome version managed by this installer. final String version; diff --git a/lib/web_ui/dev/edge.dart b/lib/web_ui/dev/edge.dart index 61c27c030e3b0..032071ae8b3dc 100644 --- a/lib/web_ui/dev/edge.dart +++ b/lib/web_ui/dev/edge.dart @@ -46,8 +46,6 @@ class EdgeEnvironment implements BrowserEnvironment { /// /// Any errors starting or running the process are reported through [onExit]. class Edge extends Browser { - final BrowserProcess _process; - /// Starts a new instance of Safari open to the given [url], which may be a /// [Uri] or a [String]. factory Edge(Uri url) { @@ -75,6 +73,8 @@ class Edge extends Browser { Edge._(this._process); + final BrowserProcess _process; + @override Future get onExit => _process.onExit; diff --git a/lib/web_ui/dev/edge_installation.dart b/lib/web_ui/dev/edge_installation.dart index c10e220cb0985..28e3e0599175c 100644 --- a/lib/web_ui/dev/edge_installation.dart +++ b/lib/web_ui/dev/edge_installation.dart @@ -70,6 +70,8 @@ Future getEdgeInstallation( /// /// See: https://github.com/MicrosoftEdge/edge-launcher class EdgeLauncher { + EdgeLauncher(); + /// Path to the directory that contains `MicrosoftEdgeLauncher.exe`. io.Directory get launcherInstallationDir => io.Directory( path.join(environment.webUiDartToolDir.path, 'microsoftedgelauncher', @@ -90,8 +92,6 @@ class EdgeLauncher { String get windowsEdgeLauncherDownloadUrl => 'https://github.com/MicrosoftEdge/edge-launcher/releases/download/$version/MicrosoftEdgeLauncher.exe'; - EdgeLauncher(); - /// Install the launcher if it does not exist in this system. Future install() async { // Checks if the `MicrosoftEdgeLauncher` executable exists. diff --git a/lib/web_ui/dev/firefox.dart b/lib/web_ui/dev/firefox.dart index de0c7fe13b53b..48772f59cd857 100644 --- a/lib/web_ui/dev/firefox.dart +++ b/lib/web_ui/dev/firefox.dart @@ -54,11 +54,6 @@ class FirefoxEnvironment implements BrowserEnvironment { /// /// Any errors starting or running the process are reported through [onExit]. class Firefox extends Browser { - final BrowserProcess _process; - - @override - final Future remoteDebuggerUrl; - /// Starts a new instance of Firefox open to the given [url], which may be a /// [Uri] or a [String]. factory Firefox(Uri url, FirefoxEnvironment firefoxEnvironment, {bool debug = false}) { @@ -116,6 +111,11 @@ user_pref("dom.max_script_run_time", 0); Firefox._(this._process, this.remoteDebuggerUrl); + final BrowserProcess _process; + + @override + final Future remoteDebuggerUrl; + @override Future get onExit => _process.onExit; diff --git a/lib/web_ui/dev/firefox_installer.dart b/lib/web_ui/dev/firefox_installer.dart index 2d48c16e025ce..3f074b5b27db9 100644 --- a/lib/web_ui/dev/firefox_installer.dart +++ b/lib/web_ui/dev/firefox_installer.dart @@ -91,6 +91,12 @@ class FirefoxInstaller { ); } + FirefoxInstaller._({ + required this.version, + required this.firefoxInstallationDir, + required this.versionDir, + }); + static Future latest() async { final String latestVersion = io.Platform.isLinux ? await fetchLatestFirefoxVersionLinux() @@ -98,12 +104,6 @@ class FirefoxInstaller { return FirefoxInstaller(version: latestVersion); } - FirefoxInstaller._({ - required this.version, - required this.firefoxInstallationDir, - required this.versionDir, - }); - /// Firefox version managed by this installer. final String version; diff --git a/lib/web_ui/dev/safari_ios.dart b/lib/web_ui/dev/safari_ios.dart index df856de4fff83..c180e3832d218 100644 --- a/lib/web_ui/dev/safari_ios.dart +++ b/lib/web_ui/dev/safari_ios.dart @@ -22,11 +22,11 @@ import 'utils.dart'; /// /// This is used to properly take screenshots of the browser. class SafariScreenInfo { + SafariScreenInfo(this.heightOfHeader, this.heightOfFooter, this.scaleFactor); + final int heightOfHeader; final int heightOfFooter; final double scaleFactor; - - SafariScreenInfo(this.heightOfHeader, this.heightOfFooter, this.scaleFactor); } /// Provides an environment for the mobile variant of Safari running in an iOS @@ -78,8 +78,6 @@ class SafariIosEnvironment implements BrowserEnvironment { /// /// Any errors starting or running the process are reported through [onExit]. class SafariIos extends Browser { - final BrowserProcess _process; - final SafariScreenInfo _screenInfo; /// Starts a new instance of Safari open to the given [url], which may be a /// [Uri]. @@ -101,6 +99,8 @@ class SafariIos extends Browser { } SafariIos._(this._process, this._screenInfo); + final BrowserProcess _process; + final SafariScreenInfo _screenInfo; @override Future get onExit => _process.onExit; diff --git a/lib/web_ui/dev/test_platform.dart b/lib/web_ui/dev/test_platform.dart index ad15dce141bbf..2c33c2e2d2180 100644 --- a/lib/web_ui/dev/test_platform.dart +++ b/lib/web_ui/dev/test_platform.dart @@ -43,6 +43,57 @@ import 'environment.dart' as env; /// Custom test platform that serves web engine unit tests. class BrowserPlatform extends PlatformPlugin { + BrowserPlatform._({ + required this.browserEnvironment, + required this.server, + required this.isDebug, + required this.doUpdateScreenshotGoldens, + required this.packageConfig, + required this.skiaClient, + required this.overridePathToCanvasKit, + }) { + // The cascade of request handlers. + final shelf.Cascade cascade = shelf.Cascade() + // The web socket that carries the test channels for running tests and + // reporting restuls. See [_browserManagerFor] and [BrowserManager.start] + // for details on how the channels are established. + .add(_webSocketHandler.handler) + + // Serves /packages/* requests; fetches files and sources from + // pubspec dependencies. + // + // Includes: + // * Requests for Dart sources from source maps + // * Assets that are part of the engine sources, such as Ahem.ttf + .add(_packageUrlHandler) + .add(_canvasKitOverrideHandler) + + // Serves files from the web_ui/build/ directory at the root (/) URL path. + .add(buildDirectoryHandler) + .add(_testImageListingHandler) + + // Serves the initial HTML for the test. + .add(_testBootstrapHandler) + + // Serves files from the root of web_ui. + // + // This is needed because sourcemaps refer to local files, i.e. those + // that don't come from package dependencies, relative to web_ui/. + // + // Examples of URLs that this handles: + // * /test/alarm_clock_test.dart + // * /lib/src/engine/alarm_clock.dart + .add(createStaticHandler(env.environment.webUiRootDir.path)) + + // Serves absolute package URLs (i.e. not /packages/* but /Users/user/*/hosted/pub.dartlang.org/*). + // This handler goes last, after all more specific handlers failed to handle the request. + .add(_createAbsolutePackageUrlHandler()) + .add(_screenshotHandler) + .add(_fileNotFoundCatcher); + + server.mount(cascade.handler); + } + /// Starts the server. /// /// [browserEnvironment] provides the browser environment to run the test. @@ -105,57 +156,6 @@ class BrowserPlatform extends PlatformPlugin { final String? overridePathToCanvasKit; - BrowserPlatform._({ - required this.browserEnvironment, - required this.server, - required this.isDebug, - required this.doUpdateScreenshotGoldens, - required this.packageConfig, - required this.skiaClient, - required this.overridePathToCanvasKit, - }) { - // The cascade of request handlers. - final shelf.Cascade cascade = shelf.Cascade() - // The web socket that carries the test channels for running tests and - // reporting restuls. See [_browserManagerFor] and [BrowserManager.start] - // for details on how the channels are established. - .add(_webSocketHandler.handler) - - // Serves /packages/* requests; fetches files and sources from - // pubspec dependencies. - // - // Includes: - // * Requests for Dart sources from source maps - // * Assets that are part of the engine sources, such as Ahem.ttf - .add(_packageUrlHandler) - .add(_canvasKitOverrideHandler) - - // Serves files from the web_ui/build/ directory at the root (/) URL path. - .add(buildDirectoryHandler) - .add(_testImageListingHandler) - - // Serves the initial HTML for the test. - .add(_testBootstrapHandler) - - // Serves files from the root of web_ui. - // - // This is needed because sourcemaps refer to local files, i.e. those - // that don't come from package dependencies, relative to web_ui/. - // - // Examples of URLs that this handles: - // * /test/alarm_clock_test.dart - // * /lib/src/engine/alarm_clock.dart - .add(createStaticHandler(env.environment.webUiRootDir.path)) - - // Serves absolute package URLs (i.e. not /packages/* but /Users/user/*/hosted/pub.dartlang.org/*). - // This handler goes last, after all more specific handlers failed to handle the request. - .add(_createAbsolutePackageUrlHandler()) - .add(_screenshotHandler) - .add(_fileNotFoundCatcher); - - server.mount(cascade.handler); - } - /// If a path to a custom local build of CanvasKit was specified, serve from /// there instead of serving the default CanvasKit in the build/ directory. Future _canvasKitOverrideHandler( @@ -629,6 +629,47 @@ class OneOffHandler { /// This is in charge of telling the browser which test suites to load and /// converting its responses into [Suite] objects. class BrowserManager { + /// Creates a new BrowserManager that communicates with the browser over + /// [webSocket]. + BrowserManager._(this.packageConfig, this._browser, this._browserEnvironment, + WebSocketChannel webSocket) { + // The duration should be short enough that the debugging console is open as + // soon as the user is done setting breakpoints, but long enough that a test + // doing a lot of synchronous work doesn't trigger a false positive. + // + // Start this canceled because we don't want it to start ticking until we + // get some response from the iframe. + _timer = RestartableTimer(const Duration(seconds: 3), () { + for (final RunnerSuiteController controller in _controllers) { + controller.setDebugging(true); + } + }) + ..cancel(); + + // Whenever we get a message, no matter which child channel it's for, we the + // know browser is still running code which means the user isn't debugging. + _channel = MultiChannel(webSocket + .cast() + .transform(jsonDocument) + .changeStream((Stream stream) { + return stream.map((Object? message) { + if (!_closed) { + _timer.reset(); + } + for (final RunnerSuiteController controller in _controllers) { + controller.setDebugging(false); + } + + return message; + }); + })); + + _environment = _loadBrowserEnvironment(); + _channel.stream.listen( + (dynamic message) => _onMessage(message as Map), + onDone: close); + } + final PackageConfig packageConfig; /// The browser instance that this is connected to via [_channel]. @@ -762,47 +803,6 @@ class BrowserManager { return browserEnvironment.launchBrowserInstance(url, debug: debug); } - /// Creates a new BrowserManager that communicates with the browser over - /// [webSocket]. - BrowserManager._(this.packageConfig, this._browser, this._browserEnvironment, - WebSocketChannel webSocket) { - // The duration should be short enough that the debugging console is open as - // soon as the user is done setting breakpoints, but long enough that a test - // doing a lot of synchronous work doesn't trigger a false positive. - // - // Start this canceled because we don't want it to start ticking until we - // get some response from the iframe. - _timer = RestartableTimer(const Duration(seconds: 3), () { - for (final RunnerSuiteController controller in _controllers) { - controller.setDebugging(true); - } - }) - ..cancel(); - - // Whenever we get a message, no matter which child channel it's for, we the - // know browser is still running code which means the user isn't debugging. - _channel = MultiChannel(webSocket - .cast() - .transform(jsonDocument) - .changeStream((Stream stream) { - return stream.map((Object? message) { - if (!_closed) { - _timer.reset(); - } - for (final RunnerSuiteController controller in _controllers) { - controller.setDebugging(false); - } - - return message; - }); - })); - - _environment = _loadBrowserEnvironment(); - _channel.stream.listen( - (dynamic message) => _onMessage(message as Map), - onDone: close); - } - /// Loads [_BrowserEnvironment]. Future<_BrowserEnvironment> _loadBrowserEnvironment() async { return _BrowserEnvironment(this, await _browser.observatoryUrl, @@ -954,6 +954,9 @@ class BrowserManager { /// /// All methods forward directly to [BrowserManager]. class _BrowserEnvironment implements Environment { + _BrowserEnvironment(this._manager, this.observatoryUrl, + this.remoteDebuggerUrl, this.onRestart); + final BrowserManager _manager; @override @@ -968,9 +971,6 @@ class _BrowserEnvironment implements Environment { @override final Stream onRestart; - _BrowserEnvironment(this._manager, this.observatoryUrl, - this.remoteDebuggerUrl, this.onRestart); - @override CancelableOperation displayPause() => _manager._displayPause(); } diff --git a/lib/web_ui/dev/webdriver_browser.dart b/lib/web_ui/dev/webdriver_browser.dart index 1f17bf1101100..8c1c82a9b01c1 100644 --- a/lib/web_ui/dev/webdriver_browser.dart +++ b/lib/web_ui/dev/webdriver_browser.dart @@ -79,14 +79,14 @@ abstract class WebDriverBrowserEnvironment extends BrowserEnvironment { } class WebDriverBrowser extends Browser { - final WebDriver _driver; - final Uri _url; - final Completer _onExitCompleter = Completer(); - WebDriverBrowser(this._driver, this._url) { _driver.get(_url); } + final WebDriver _driver; + final Uri _url; + final Completer _onExitCompleter = Completer(); + @override Future close() async { await (await _driver.window).close(); diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 1c562648e899c..c5873c1dd4a11 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -768,7 +768,7 @@ class ImmutableBuffer { Uint8List? _list; int get length => _length; - int _length; + final int _length; bool get debugDisposed { late bool disposed; @@ -782,17 +782,6 @@ class ImmutableBuffer { } class ImageDescriptor { - ImageDescriptor._() - : _width = null, - _height = null, - _rowBytes = null, - _format = null; - static Future encoded(ImmutableBuffer buffer) async { - final ImageDescriptor descriptor = ImageDescriptor._(); - descriptor._data = buffer._list; - return descriptor; - } - // Not async because there's no expensive work to do here. ImageDescriptor.raw( ImmutableBuffer buffer, { @@ -807,6 +796,18 @@ class ImageDescriptor { _data = buffer._list; } + ImageDescriptor._() + : _width = null, + _height = null, + _rowBytes = null, + _format = null; + + static Future encoded(ImmutableBuffer buffer) async { + final ImageDescriptor descriptor = ImageDescriptor._(); + descriptor._data = buffer._list; + return descriptor; + } + Uint8List? _data; final int? _width; final int? _height; @@ -840,6 +841,8 @@ class ImageDescriptor { } class FragmentProgram { + FragmentProgram._(); + static Future fromAsset(String assetKey) { throw UnsupportedError('FragmentProgram is not supported for the CanvasKit or HTML renderers.'); } @@ -848,8 +851,6 @@ class FragmentProgram { return Future.microtask(() => FragmentProgram.fromAsset(assetKey)); } - FragmentProgram._(); - Shader shader({ Float32List? floatUniforms, List? samplerUniforms, diff --git a/lib/web_ui/lib/platform_dispatcher.dart b/lib/web_ui/lib/platform_dispatcher.dart index c3cfcb4389e98..9c5bbb749d5ac 100644 --- a/lib/web_ui/lib/platform_dispatcher.dart +++ b/lib/web_ui/lib/platform_dispatcher.dart @@ -265,11 +265,11 @@ class FrameTiming { ]); } - static final int _dataLength = FramePhase.values.length + _FrameTimingInfo.values.length; - FrameTiming._(this._data) : assert(_data.length == _dataLength); + static final int _dataLength = FramePhase.values.length + _FrameTimingInfo.values.length; + int timestampInMicroseconds(FramePhase phase) => _data[phase.index]; Duration _rawDuration(FramePhase phase) => Duration(microseconds: _data[phase.index]); diff --git a/lib/web_ui/lib/src/engine/assets.dart b/lib/web_ui/lib/src/engine/assets.dart index 2a3617f036eff..ed87697b6e9f6 100644 --- a/lib/web_ui/lib/src/engine/assets.dart +++ b/lib/web_ui/lib/src/engine/assets.dart @@ -14,14 +14,14 @@ import 'util.dart'; /// The assets are resolved relative to [assetsDir] inside the directory /// containing the currently executing JS script. class AssetManager { + /// Initializes [AssetManager] with path to assets relative to baseUrl. + const AssetManager({this.assetsDir = _defaultAssetsDir}); + static const String _defaultAssetsDir = 'assets'; /// The directory containing the assets. final String assetsDir; - /// Initializes [AssetManager] with path to assets relative to baseUrl. - const AssetManager({this.assetsDir = _defaultAssetsDir}); - String? get _baseUrl { return domWindow.document .querySelectorAll('meta') @@ -92,15 +92,15 @@ class AssetManager { /// Thrown to indicate http failure during asset loading. class AssetManagerException implements Exception { + /// Initializes exception with request url and http status. + AssetManagerException(this.url, this.httpStatus); + /// Http request url for asset. final String url; /// Http status of response. final int httpStatus; - /// Initializes exception with request url and http status. - AssetManagerException(this.url, this.httpStatus); - @override String toString() => 'Failed to load asset at "$url" ($httpStatus)'; } diff --git a/lib/web_ui/lib/src/engine/canvas_pool.dart b/lib/web_ui/lib/src/engine/canvas_pool.dart index dd59a4d141e9f..08e8aca82172d 100644 --- a/lib/web_ui/lib/src/engine/canvas_pool.dart +++ b/lib/web_ui/lib/src/engine/canvas_pool.dart @@ -45,6 +45,10 @@ import 'window.dart'; /// can be reused, [CanvasPool] will move canvas(s) from pool to reusablePool /// to prevent reallocation. class CanvasPool extends _SaveStackTracking { + /// Initializes canvas pool for target size and dpi. + CanvasPool(this._widthInBitmapPixels, this._heightInBitmapPixels, + this._density); + DomCanvasRenderingContext2D? _context; ContextStateHandle? _contextHandle; final int _widthInBitmapPixels, _heightInBitmapPixels; @@ -59,10 +63,6 @@ class CanvasPool extends _SaveStackTracking { int _saveContextCount = 0; final double _density; - /// Initializes canvas pool for target size and dpi. - CanvasPool(this._widthInBitmapPixels, this._heightInBitmapPixels, - this._density); - /// Initializes canvas pool to be hosted on a surface. void mount(DomHTMLElement rootElement) { _rootElement = rootElement; @@ -607,7 +607,7 @@ class CanvasPool extends _SaveStackTracking { } // Float buffer used for path iteration. - static Float32List _runBuffer = Float32List(PathRefIterator.kMaxBufferSize); + static final Float32List _runBuffer = Float32List(PathRefIterator.kMaxBufferSize); /// 'Runs' the given [path] by applying all of its commands to the canvas. void _runPath(DomCanvasRenderingContext2D ctx, SurfacePath path) { @@ -872,14 +872,14 @@ class CanvasPool extends _SaveStackTracking { /// See https://www.w3.org/TR/2dcontext/ for defaults used in this class /// to initialize current values. class ContextStateHandle { + /// Initializes context state for a [CanvasPool]. + ContextStateHandle(this._canvasPool, this.context, this.density); + /// Associated canvas element context tracked by this context state. final DomCanvasRenderingContext2D context; final CanvasPool _canvasPool; /// Dpi of context. final double density; - - /// Initializes context state for a [CanvasPool]. - ContextStateHandle(this._canvasPool, this.context, this.density); ui.BlendMode? _currentBlendMode = ui.BlendMode.srcOver; ui.StrokeCap? _currentStrokeCap = ui.StrokeCap.butt; ui.StrokeJoin? _currentStrokeJoin = ui.StrokeJoin.miter; diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvas.dart b/lib/web_ui/lib/src/engine/canvaskit/canvas.dart index eacb0db6831b4..2c26d0b7ddbc8 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvas.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvas.dart @@ -27,6 +27,8 @@ final SkClipOp _clipOpIntersect = canvasKit.ClipOp.Intersect; /// This is intentionally not memory-managing the underlying [SkCanvas]. See /// the docs on [SkCanvas], which explain the reason. class CkCanvas { + CkCanvas(this.skCanvas); + // Cubic equation coefficients recommended by Mitchell & Netravali // in their paper on cubic interpolation. static const double _kMitchellNetravali_B = 1.0 / 3.0; @@ -34,8 +36,6 @@ class CkCanvas { final SkCanvas skCanvas; - CkCanvas(this.skCanvas); - int? get saveCount => skCanvas.getSaveCount(); void clear(ui.Color color) { @@ -654,11 +654,11 @@ class CkRestoreToCountCommand extends CkPaintCommand { } class CkTranslateCommand extends CkPaintCommand { + CkTranslateCommand(this.dx, this.dy); + final double dx; final double dy; - CkTranslateCommand(this.dx, this.dy); - @override void apply(SkCanvas canvas) { canvas.translate(dx, dy); @@ -666,11 +666,11 @@ class CkTranslateCommand extends CkPaintCommand { } class CkScaleCommand extends CkPaintCommand { + CkScaleCommand(this.sx, this.sy); + final double sx; final double sy; - CkScaleCommand(this.sx, this.sy); - @override void apply(SkCanvas canvas) { canvas.scale(sx, sy); @@ -678,10 +678,10 @@ class CkScaleCommand extends CkPaintCommand { } class CkRotateCommand extends CkPaintCommand { - final double radians; - CkRotateCommand(this.radians); + final double radians; + @override void apply(SkCanvas canvas) { canvas.rotate(radians * 180.0 / math.pi, 0.0, 0.0); @@ -689,10 +689,10 @@ class CkRotateCommand extends CkPaintCommand { } class CkTransformCommand extends CkPaintCommand { - final Float32List matrix4; - CkTransformCommand(this.matrix4); + final Float32List matrix4; + @override void apply(SkCanvas canvas) { canvas.concat(toSkM44FromFloat32(matrix4)); @@ -700,11 +700,11 @@ class CkTransformCommand extends CkPaintCommand { } class CkSkewCommand extends CkPaintCommand { + CkSkewCommand(this.sx, this.sy); + final double sx; final double sy; - CkSkewCommand(this.sx, this.sy); - @override void apply(SkCanvas canvas) { canvas.skew(sx, sy); @@ -712,12 +712,12 @@ class CkSkewCommand extends CkPaintCommand { } class CkClipRectCommand extends CkPaintCommand { + CkClipRectCommand(this.rect, this.clipOp, this.doAntiAlias); + final ui.Rect rect; final ui.ClipOp clipOp; final bool doAntiAlias; - CkClipRectCommand(this.rect, this.clipOp, this.doAntiAlias); - @override void apply(SkCanvas canvas) { canvas.clipRect( @@ -776,11 +776,11 @@ class CkDrawAtlasCommand extends CkPaintCommand { } class CkClipRRectCommand extends CkPaintCommand { + CkClipRRectCommand(this.rrect, this.doAntiAlias); + final ui.RRect rrect; final bool doAntiAlias; - CkClipRRectCommand(this.rrect, this.doAntiAlias); - @override void apply(SkCanvas canvas) { canvas.clipRRect( @@ -792,11 +792,11 @@ class CkClipRRectCommand extends CkPaintCommand { } class CkClipPathCommand extends CkPaintCommand { + CkClipPathCommand(this.path, this.doAntiAlias); + final CkPath path; final bool doAntiAlias; - CkClipPathCommand(this.path, this.doAntiAlias); - @override void apply(SkCanvas canvas) { canvas.clipPath( @@ -808,11 +808,11 @@ class CkClipPathCommand extends CkPaintCommand { } class CkDrawColorCommand extends CkPaintCommand { + CkDrawColorCommand(this.color, this.blendMode); + final ui.Color color; final ui.BlendMode blendMode; - CkDrawColorCommand(this.color, this.blendMode); - @override void apply(SkCanvas canvas) { canvas.drawColorInt( @@ -823,12 +823,12 @@ class CkDrawColorCommand extends CkPaintCommand { } class CkDrawLineCommand extends CkPaintCommand { + CkDrawLineCommand(this.p1, this.p2, this.paint); + final ui.Offset p1; final ui.Offset p2; final CkPaint paint; - CkDrawLineCommand(this.p1, this.p2, this.paint); - @override void apply(SkCanvas canvas) { canvas.drawLine( @@ -842,10 +842,10 @@ class CkDrawLineCommand extends CkPaintCommand { } class CkDrawPaintCommand extends CkPaintCommand { - final CkPaint paint; - CkDrawPaintCommand(this.paint); + final CkPaint paint; + @override void apply(SkCanvas canvas) { canvas.drawPaint(paint.skiaObject); @@ -853,10 +853,11 @@ class CkDrawPaintCommand extends CkPaintCommand { } class CkDrawVerticesCommand extends CkPaintCommand { + CkDrawVerticesCommand(this.vertices, this.blendMode, this.paint); + final CkVertices vertices; final ui.BlendMode blendMode; final CkPaint paint; - CkDrawVerticesCommand(this.vertices, this.blendMode, this.paint); @override void apply(SkCanvas canvas) { @@ -869,10 +870,11 @@ class CkDrawVerticesCommand extends CkPaintCommand { } class CkDrawPointsCommand extends CkPaintCommand { + CkDrawPointsCommand(this.pointMode, this.points, this.paint); + final Float32List points; final ui.PointMode pointMode; final CkPaint paint; - CkDrawPointsCommand(this.pointMode, this.points, this.paint); @override void apply(SkCanvas canvas) { @@ -885,11 +887,11 @@ class CkDrawPointsCommand extends CkPaintCommand { } class CkDrawRectCommand extends CkPaintCommand { + CkDrawRectCommand(this.rect, this.paint); + final ui.Rect rect; final CkPaint paint; - CkDrawRectCommand(this.rect, this.paint); - @override void apply(SkCanvas canvas) { canvas.drawRect(toSkRect(rect), paint.skiaObject); @@ -897,11 +899,11 @@ class CkDrawRectCommand extends CkPaintCommand { } class CkDrawRRectCommand extends CkPaintCommand { + CkDrawRRectCommand(this.rrect, this.paint); + final ui.RRect rrect; final CkPaint paint; - CkDrawRRectCommand(this.rrect, this.paint); - @override void apply(SkCanvas canvas) { canvas.drawRRect( @@ -912,12 +914,12 @@ class CkDrawRRectCommand extends CkPaintCommand { } class CkDrawDRRectCommand extends CkPaintCommand { + CkDrawDRRectCommand(this.outer, this.inner, this.paint); + final ui.RRect outer; final ui.RRect inner; final CkPaint paint; - CkDrawDRRectCommand(this.outer, this.inner, this.paint); - @override void apply(SkCanvas canvas) { canvas.drawDRRect( @@ -929,11 +931,11 @@ class CkDrawDRRectCommand extends CkPaintCommand { } class CkDrawOvalCommand extends CkPaintCommand { + CkDrawOvalCommand(this.rect, this.paint); + final ui.Rect rect; final CkPaint paint; - CkDrawOvalCommand(this.rect, this.paint); - @override void apply(SkCanvas canvas) { canvas.drawOval( @@ -944,12 +946,12 @@ class CkDrawOvalCommand extends CkPaintCommand { } class CkDrawCircleCommand extends CkPaintCommand { + CkDrawCircleCommand(this.c, this.radius, this.paint); + final ui.Offset c; final double radius; final CkPaint paint; - CkDrawCircleCommand(this.c, this.radius, this.paint); - @override void apply(SkCanvas canvas) { canvas.drawCircle( @@ -962,11 +964,11 @@ class CkDrawCircleCommand extends CkPaintCommand { } class CkDrawPathCommand extends CkPaintCommand { + CkDrawPathCommand(this.path, this.paint); + final CkPath path; final CkPaint paint; - CkDrawPathCommand(this.path, this.paint); - @override void apply(SkCanvas canvas) { canvas.drawPath(path.skiaObject, paint.skiaObject); @@ -990,13 +992,13 @@ class CkDrawShadowCommand extends CkPaintCommand { } class CkDrawImageCommand extends CkPaintCommand { + CkDrawImageCommand(CkImage ckImage, this.offset, this.paint) + : image = ckImage.clone(); + final CkImage image; final ui.Offset offset; final CkPaint paint; - CkDrawImageCommand(CkImage ckImage, this.offset, this.paint) - : image = ckImage.clone(); - @override void apply(SkCanvas canvas) { final ui.FilterQuality filterQuality = paint.filterQuality; @@ -1028,14 +1030,14 @@ class CkDrawImageCommand extends CkPaintCommand { } class CkDrawImageRectCommand extends CkPaintCommand { + CkDrawImageRectCommand(CkImage ckImage, this.src, this.dst, this.paint) + : image = ckImage.clone(); + final CkImage image; final ui.Rect src; final ui.Rect dst; final CkPaint paint; - CkDrawImageRectCommand(CkImage ckImage, this.src, this.dst, this.paint) - : image = ckImage.clone(); - @override void apply(SkCanvas canvas) { final ui.FilterQuality filterQuality = paint.filterQuality; @@ -1093,11 +1095,11 @@ class CkDrawImageNineCommand extends CkPaintCommand { } class CkDrawParagraphCommand extends CkPaintCommand { + CkDrawParagraphCommand(this.paragraph, this.offset); + final CkParagraph paragraph; final ui.Offset offset; - CkDrawParagraphCommand(this.paragraph, this.offset); - @override void apply(SkCanvas canvas) { canvas.drawParagraph( diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart index ccb3268f47918..a1c8c85473b2f 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart @@ -21,8 +21,6 @@ import 'vertices.dart'; /// An implementation of [ui.Canvas] that is backed by a CanvasKit canvas. class CanvasKitCanvas implements ui.Canvas { - final CkCanvas _canvas; - factory CanvasKitCanvas(ui.PictureRecorder recorder, [ui.Rect? cullRect]) { assert(recorder != null); // ignore: unnecessary_null_comparison if (recorder.isRecording) { @@ -36,6 +34,8 @@ class CanvasKitCanvas implements ui.Canvas { CanvasKitCanvas._(this._canvas); + final CkCanvas _canvas; + @override void save() { _canvas.save(); diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index c3ef04ac63a95..8390316ec90bd 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -23,11 +23,11 @@ import 'surface_factory.dart'; /// This composites HTML views into the [ui.Scene]. class HtmlViewEmbedder { + HtmlViewEmbedder._(); + /// The [HtmlViewEmbedder] singleton. static HtmlViewEmbedder instance = HtmlViewEmbedder._(); - HtmlViewEmbedder._(); - /// Force the view embedder to disable overlays. /// /// This should never be used outside of tests. @@ -92,10 +92,10 @@ class HtmlViewEmbedder { final Set _viewsToRecomposite = {}; /// The list of view ids that should be composited, in order. - List _compositionOrder = []; + final List _compositionOrder = []; /// The most recent composition order. - List _activeCompositionOrder = []; + final List _activeCompositionOrder = []; /// The size of the frame, in physical pixels. ui.Size _frameSize = ui.window.physicalSize; @@ -398,7 +398,7 @@ class HtmlViewEmbedder { DomElement? _svgPathDefs; /// The nodes containing the SVG clip definitions needed to clip this view. - Map> _svgClipDefs = >{}; + final Map> _svgClipDefs = >{}; /// Ensures we add a container of SVG path defs to the DOM so they can /// be referred to in clip-path: url(#blah). @@ -714,14 +714,14 @@ class HtmlViewEmbedder { /// * The slot view in the stack (the actual contents of the platform view). /// * The number of clipping elements used last time the view was composited. class ViewClipChain { - DomElement _root; - DomElement _slot; - int _clipCount = -1; - ViewClipChain({required DomElement view}) : _root = view, _slot = view; + DomElement _root; + final DomElement _slot; + int _clipCount = -1; + DomElement get root => _root; DomElement get slot => _slot; int get clipCount => _clipCount; @@ -766,6 +766,17 @@ enum MutatorType { /// Stores mutation information like clipping or transform. class Mutator { + const Mutator.clipRect(ui.Rect rect) + : this._(MutatorType.clipRect, rect, null, null, null, null); + const Mutator.clipRRect(ui.RRect rrect) + : this._(MutatorType.clipRRect, null, rrect, null, null, null); + const Mutator.clipPath(ui.Path path) + : this._(MutatorType.clipPath, null, null, path, null, null); + const Mutator.transform(Matrix4 matrix) + : this._(MutatorType.transform, null, null, null, matrix, null); + const Mutator.opacity(int alpha) + : this._(MutatorType.opacity, null, null, null, null, alpha); + const Mutator._( this.type, this.rect, @@ -782,17 +793,6 @@ class Mutator { final Matrix4? matrix; final int? alpha; - const Mutator.clipRect(ui.Rect rect) - : this._(MutatorType.clipRect, rect, null, null, null, null); - const Mutator.clipRRect(ui.RRect rrect) - : this._(MutatorType.clipRRect, null, rrect, null, null, null); - const Mutator.clipPath(ui.Path path) - : this._(MutatorType.clipPath, null, null, path, null, null); - const Mutator.transform(Matrix4 matrix) - : this._(MutatorType.transform, null, null, null, matrix, null); - const Mutator.opacity(int alpha) - : this._(MutatorType.opacity, null, null, null, null, alpha); - bool get isClipType => type == MutatorType.clipRect || type == MutatorType.clipRRect || diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views_diff.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views_diff.dart index f5cce723f2f9d..b07cc97711782 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views_diff.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views_diff.dart @@ -5,6 +5,10 @@ /// The results of diffing the current composition order with the active /// composition order. class ViewListDiffResult { + const ViewListDiffResult( + this.viewsToRemove, this.viewsToAdd, this.addToBeginning, + {this.viewToInsertBefore}); + /// Views which should be removed from the scene. final List viewsToRemove; @@ -20,10 +24,6 @@ class ViewListDiffResult { /// /// `null` if [addToBeginning] is `false`. final int? viewToInsertBefore; - - const ViewListDiffResult( - this.viewsToRemove, this.viewsToAdd, this.addToBeginning, - {this.viewToInsertBefore}); } /// Diff the composition order with the active composition order. It is diff --git a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart index 926592249aa1c..40a915f44876c 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart @@ -547,14 +547,14 @@ Set findMinimumFontsForCodeUnits( } class NotoFont { + NotoFont(this.name, this.approximateUnicodeRanges); + final String name; final List approximateUnicodeRanges; Completer? _decodingCompleter; _ResolvedNotoFont? resolvedFont; - NotoFont(this.name, this.approximateUnicodeRanges); - String get googleFontsCssUrl => 'https://fonts.googleapis.com/css2?family=${name.replaceAll(' ', '+')}'; @@ -581,11 +581,11 @@ class NotoFont { } class CodeunitRange { + const CodeunitRange(this.start, this.end); + final int start; final int end; - const CodeunitRange(this.start, this.end); - bool contains(int codeUnit) { return start <= codeUnit && codeUnit <= end; } @@ -607,20 +607,20 @@ class CodeunitRange { } class _ResolvedNotoFont { + const _ResolvedNotoFont(this.name, this.subsets, this.tree); + final String name; final List<_ResolvedNotoSubset> subsets; final IntervalTree<_ResolvedNotoSubset> tree; - - const _ResolvedNotoFont(this.name, this.subsets, this.tree); } class _ResolvedNotoSubset { + _ResolvedNotoSubset(this.url, this.family, this.ranges); + final String url; final String family; final List ranges; - _ResolvedNotoSubset(this.url, this.family, this.ranges); - @override String toString() => '_ResolvedNotoSubset($family, $url)'; } diff --git a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart index 536bfe41471fa..4f8d156e00d9d 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart @@ -222,6 +222,12 @@ class SkiaFontCollection { /// Represents a font that has been registered. class RegisteredFont { + RegisteredFont(this.bytes, this.family, this.typeface) { + // This is a hack which causes Skia to cache the decoded font. + final SkFont skFont = SkFont(typeface); + skFont.getGlyphBounds([0], null, null); + } + /// The font family name for this font. final String family; @@ -232,10 +238,4 @@ class RegisteredFont { /// /// This is used to determine which code points are supported by this font. final SkTypeface typeface; - - RegisteredFont(this.bytes, this.family, this.typeface) { - // This is a hack which causes Skia to cache the decoded font. - final SkFont skFont = SkFont(typeface); - skFont.getGlyphBounds([0], null, null); - } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/image.dart b/lib/web_ui/lib/src/engine/canvaskit/image.dart index 3f98f10bd4e7f..f3f84e2c4400b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -345,11 +345,11 @@ class CkImage implements ui.Image, StackTraceDebugger { /// Data for a single frame of an animated image. class AnimatedImageFrameInfo implements ui.FrameInfo { + AnimatedImageFrameInfo(this._duration, this._image); + final Duration _duration; final CkImage _image; - AnimatedImageFrameInfo(this._duration, this._image); - @override Duration get duration => _duration; 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 2eda07a20f465..c3ffcc7719fc9 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 @@ -42,6 +42,14 @@ void debugRestoreWebDecoderExpireDuration() { /// Image decoder backed by the browser's `ImageDecoder`. class CkBrowserImageDecoder implements ui.Codec { + CkBrowserImageDecoder._({ + required this.contentType, + required this.targetWidth, + required this.targetHeight, + required this.data, + required this.debugSource, + }); + static Future create({ required Uint8List data, required String debugSource, @@ -79,14 +87,6 @@ class CkBrowserImageDecoder implements ui.Codec { return decoder; } - CkBrowserImageDecoder._({ - required this.contentType, - required this.targetWidth, - required this.targetHeight, - required this.data, - required this.debugSource, - }); - final String contentType; final int? targetWidth; final int? targetHeight; diff --git a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart index bcf5b73d00ec3..29d16421bbb5b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart @@ -8,9 +8,6 @@ import 'font_fallbacks.dart' show CodeunitRange; /// A tree which stores a set of intervals that can be queried for intersection. class IntervalTree { - /// The root node of the interval tree. - final IntervalTreeNode root; - IntervalTree._(this.root); /// Creates an interval tree from a mapping of [T] values to a list of ranges. @@ -76,6 +73,9 @@ class IntervalTree { return IntervalTree._(root); } + /// The root node of the interval tree. + final IntervalTreeNode root; + /// Returns the list of objects which have been associated with intervals that /// intersect with [x]. List intersections(int x) { @@ -91,6 +91,8 @@ class IntervalTree { } class IntervalTreeNode { + IntervalTreeNode(this.value, this.low, this.high) : computedHigh = high; + final T value; final int low; final int high; @@ -99,8 +101,6 @@ class IntervalTreeNode { IntervalTreeNode? left; IntervalTreeNode? right; - IntervalTreeNode(this.value, this.low, this.high) : computedHigh = high; - Iterable enumerateAllElements() sync* { if (left != null) { yield* left!.enumerateAllElements(); diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer.dart b/lib/web_ui/lib/src/engine/canvaskit/layer.dart index c81b4458aee18..79e6ac36b8079 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer.dart @@ -47,6 +47,8 @@ abstract class Layer implements ui.EngineLayer { /// A context shared by all layers during the preroll pass. class PrerollContext { + PrerollContext(this.rasterCache, this.viewEmbedder); + /// A raster cache. Used to register candidates for caching. final RasterCache? rasterCache; @@ -55,8 +57,6 @@ class PrerollContext { final MutatorsStack mutatorsStack = MutatorsStack(); - PrerollContext(this.rasterCache, this.viewEmbedder); - ui.Rect get cullRect { ui.Rect cullRect = ui.Rect.largest; for (final Mutator m in mutatorsStack) { @@ -82,6 +82,13 @@ class PrerollContext { /// A context shared by all layers during the paint pass. class PaintContext { + PaintContext( + this.internalNodesCanvas, + this.leafNodesCanvas, + this.rasterCache, + this.viewEmbedder, + ); + /// A multi-canvas that applies clips, transforms, and opacity /// operations to all canvases (root canvas and overlay canvases for the /// platform views). @@ -95,13 +102,6 @@ class PaintContext { /// A compositor for embedded HTML views. final HtmlViewEmbedder? viewEmbedder; - - PaintContext( - this.internalNodesCanvas, - this.leafNodesCanvas, - this.rasterCache, - this.viewEmbedder, - ); } /// A layer that contains child layers. @@ -167,11 +167,11 @@ class RootLayer extends ContainerLayer { class BackdropFilterEngineLayer extends ContainerLayer implements ui.BackdropFilterEngineLayer { + BackdropFilterEngineLayer(this._filter, this._blendMode); + final ui.ImageFilter _filter; final ui.BlendMode _blendMode; - BackdropFilterEngineLayer(this._filter, this._blendMode); - @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { final ui.Rect childBounds = prerollChildren(prerollContext, matrix); @@ -194,13 +194,13 @@ class BackdropFilterEngineLayer extends ContainerLayer /// A layer that clips its child layers by a given [Path]. class ClipPathEngineLayer extends ContainerLayer implements ui.ClipPathEngineLayer { + ClipPathEngineLayer(this._clipPath, this._clipBehavior) + : assert(_clipBehavior != ui.Clip.none); + /// The path used to clip child layers. final CkPath _clipPath; final ui.Clip _clipBehavior; - ClipPathEngineLayer(this._clipPath, this._clipBehavior) - : assert(_clipBehavior != ui.Clip.none); - @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { prerollContext.mutatorsStack.pushClipPath(_clipPath); @@ -234,13 +234,13 @@ class ClipPathEngineLayer extends ContainerLayer /// A layer that clips its child layers by a given [Rect]. class ClipRectEngineLayer extends ContainerLayer implements ui.ClipRectEngineLayer { + ClipRectEngineLayer(this._clipRect, this._clipBehavior) + : assert(_clipBehavior != ui.Clip.none); + /// The rectangle used to clip child layers. final ui.Rect _clipRect; final ui.Clip _clipBehavior; - ClipRectEngineLayer(this._clipRect, this._clipBehavior) - : assert(_clipBehavior != ui.Clip.none); - @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { prerollContext.mutatorsStack.pushClipRect(_clipRect); @@ -275,13 +275,13 @@ class ClipRectEngineLayer extends ContainerLayer /// A layer that clips its child layers by a given [RRect]. class ClipRRectEngineLayer extends ContainerLayer implements ui.ClipRRectEngineLayer { + ClipRRectEngineLayer(this._clipRRect, this._clipBehavior) + : assert(_clipBehavior != ui.Clip.none); + /// The rounded rectangle used to clip child layers. final ui.RRect _clipRRect; final ui.Clip? _clipBehavior; - ClipRRectEngineLayer(this._clipRRect, this._clipBehavior) - : assert(_clipBehavior != ui.Clip.none); - @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { prerollContext.mutatorsStack.pushClipRRect(_clipRRect); @@ -313,11 +313,11 @@ class ClipRRectEngineLayer extends ContainerLayer /// A layer that paints its children with the given opacity. class OpacityEngineLayer extends ContainerLayer implements ui.OpacityEngineLayer { + OpacityEngineLayer(this._alpha, this._offset); + final int _alpha; final ui.Offset _offset; - OpacityEngineLayer(this._alpha, this._offset); - @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { final Matrix4 childMatrix = Matrix4.copy(matrix); @@ -354,11 +354,11 @@ class OpacityEngineLayer extends ContainerLayer /// A layer that transforms its child layers by the given transform matrix. class TransformEngineLayer extends ContainerLayer implements ui.TransformEngineLayer { + TransformEngineLayer(this._transform); + /// The matrix with which to transform the child layers. final Matrix4 _transform; - TransformEngineLayer(this._transform); - @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { final Matrix4 childMatrix = matrix.multiplied(_transform); @@ -447,6 +447,8 @@ class ShaderMaskEngineLayer extends ContainerLayer /// A layer containing a [Picture]. class PictureLayer extends Layer { + PictureLayer(this.picture, this.offset, this.isComplex, this.willChange); + /// The picture to paint into the canvas. final CkPicture picture; @@ -459,8 +461,6 @@ class PictureLayer extends Layer { /// A hint to the compositor that this picture is likely to change. final bool willChange; - PictureLayer(this.picture, this.offset, this.isComplex, this.willChange); - @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { paintBounds = picture.cullRect!.shift(offset); @@ -485,12 +485,6 @@ class PictureLayer extends Layer { /// on the given elevation. class PhysicalShapeEngineLayer extends ContainerLayer implements ui.PhysicalShapeEngineLayer { - final double _elevation; - final ui.Color _color; - final ui.Color? _shadowColor; // ignore: use_late_for_private_fields_and_variables - final CkPath _path; - final ui.Clip _clipBehavior; - PhysicalShapeEngineLayer( this._elevation, this._color, @@ -499,6 +493,12 @@ class PhysicalShapeEngineLayer extends ContainerLayer this._clipBehavior, ); + final double _elevation; + final ui.Color _color; + final ui.Color? _shadowColor; // ignore: use_late_for_private_fields_and_variables + final CkPath _path; + final ui.Clip _clipBehavior; + @override void preroll(PrerollContext prerollContext, Matrix4 matrix) { prerollChildren(prerollContext, matrix); 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 eb6d860a0e072..153cd17c1cab9 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 @@ -13,10 +13,10 @@ import 'path.dart'; import 'picture.dart'; class LayerScene implements ui.Scene { - final LayerTree layerTree; - LayerScene(RootLayer rootLayer) : layerTree = LayerTree(rootLayer); + final LayerTree layerTree; + @override void dispose() {} diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart b/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart index 8edcbc56d14da..576e1b2533221 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart @@ -86,6 +86,8 @@ class LayerTree { /// A single frame to be rendered. class Frame { + Frame(this.canvas, this.rasterCache, this.viewEmbedder); + /// The canvas to render this frame to. final CkCanvas canvas; @@ -95,8 +97,6 @@ class Frame { /// The platform view embedder. final HtmlViewEmbedder? viewEmbedder; - Frame(this.canvas, this.rasterCache, this.viewEmbedder); - /// Rasterize the given layer tree into this frame. bool raster(LayerTree layerTree, {bool ignoreRasterCache = false}) { timeAction(kProfilePrerollFrame, () { diff --git a/lib/web_ui/lib/src/engine/canvaskit/picture.dart b/lib/web_ui/lib/src/engine/canvaskit/picture.dart index 9a63d33e9659b..0e55fe8f8634e 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/picture.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/picture.dart @@ -17,9 +17,6 @@ import 'skia_object_cache.dart'; /// class may have their Skia counterparts deleted before finalization registry /// or [SkiaObjectCache] decide to delete it. class CkPicture extends ManagedSkiaObject implements ui.Picture { - final ui.Rect? cullRect; - final CkPictureSnapshot? _snapshot; - CkPicture(SkPicture super.picture, this.cullRect, this._snapshot) : assert( browserSupportsFinalizationRegistry && _snapshot == null || @@ -27,6 +24,8 @@ class CkPicture extends ManagedSkiaObject implements ui.Picture { 'If the browser does not support FinalizationRegistry (WeakRef), then we must have a picture snapshot to be able to resurrect it.', ); + final ui.Rect? cullRect; + final CkPictureSnapshot? _snapshot; @override int get approximateBytesUsed => 0; diff --git a/lib/web_ui/lib/src/engine/canvaskit/platform_message.dart b/lib/web_ui/lib/src/engine/canvaskit/platform_message.dart index dea8d0ba14fab..07ad515e08049 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/platform_message.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/platform_message.dart @@ -6,11 +6,11 @@ import 'dart:typed_data'; // TODO(hterkelsen): Delete this once the slots change lands? class PlatformMessage { + PlatformMessage(this.channel, this.data, this.response); + final String channel; final ByteData data; final PlatformMessageResponse response; - - PlatformMessage(this.channel, this.data, this.response); } class PlatformMessageResponse { diff --git a/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart b/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart index d05a262c6df57..7ec5e1aef9262 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart @@ -25,6 +25,10 @@ import 'canvaskit_api.dart'; /// JS-managed data structure when they are deleted so that when the associated /// object is garbage collected, so is the serialized data. class SkiaObjectCache { + SkiaObjectCache(this.maximumSize) + : _itemQueue = DoubleLinkedQueue>(), + _itemMap = , DoubleLinkedQueueEntry>>{}; + final int maximumSize; /// A doubly linked list of the objects in the cache. @@ -38,10 +42,6 @@ class SkiaObjectCache { /// move the object to the front of the queue. final Map, DoubleLinkedQueueEntry>> _itemMap; - SkiaObjectCache(this.maximumSize) - : _itemQueue = DoubleLinkedQueue>(), - _itemMap = , DoubleLinkedQueueEntry>>{}; - /// The number of objects in the cache. int get length => _itemQueue.length; @@ -90,6 +90,10 @@ class SkiaObjectCache { /// Like [SkiaObjectCache] but enforces the [maximumSize] of the cache /// synchronously instead of waiting until a post-frame callback. class SynchronousSkiaObjectCache { + SynchronousSkiaObjectCache(this.maximumSize) + : _itemQueue = DoubleLinkedQueue>(), + _itemMap = , DoubleLinkedQueueEntry>>{}; + /// This cache will never exceed this limit, even temporarily. final int maximumSize; @@ -104,10 +108,6 @@ class SynchronousSkiaObjectCache { /// move the object to the front of the queue. final Map, DoubleLinkedQueueEntry>> _itemMap; - SynchronousSkiaObjectCache(this.maximumSize) - : _itemQueue = DoubleLinkedQueue>(), - _itemMap = , DoubleLinkedQueueEntry>>{}; - /// The number of objects in the cache. int get length => _itemQueue.length; diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index 2173506699c59..189a06158d35d 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -26,14 +26,14 @@ typedef SubmitCallback = bool Function(SurfaceFrame, CkCanvas); /// A frame which contains a canvas to be drawn into. class SurfaceFrame { - final CkSurface skiaSurface; - final SubmitCallback submitCallback; - bool _submitted; - SurfaceFrame(this.skiaSurface, this.submitCallback) : _submitted = false, - assert(skiaSurface != null), // ignore: unnecessary_null_comparison - assert(submitCallback != null); // ignore: unnecessary_null_comparison + assert(skiaSurface != null), + assert(submitCallback != null); + + final CkSurface skiaSurface; + final SubmitCallback submitCallback; + final bool _submitted; /// Submit this frame to be drawn. bool submit() { diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface_factory.dart b/lib/web_ui/lib/src/engine/canvaskit/surface_factory.dart index 0ea08af2cc2ef..2165287ef169e 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface_factory.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface_factory.dart @@ -9,6 +9,18 @@ import '../../engine.dart'; /// Caches surfaces used to overlay platform views. class SurfaceFactory { + SurfaceFactory(int maximumSurfaces) + : maximumSurfaces = math.max(maximumSurfaces, 1) { + if (assertionsEnabled) { + if (maximumSurfaces < 1) { + printWarning('Attempted to create a $SurfaceFactory with ' + '$maximumSurfaces maximum surfaces. At least 1 surface is required ' + 'for rendering.'); + } + registerHotRestartListener(debugClear); + } + } + /// The lazy-initialized singleton surface factory. /// /// [debugClear] causes this singleton to be reinitialized. @@ -29,18 +41,6 @@ class SurfaceFactory { static SurfaceFactory? _instance; - SurfaceFactory(int maximumSurfaces) - : maximumSurfaces = math.max(maximumSurfaces, 1) { - if (assertionsEnabled) { - if (maximumSurfaces < 1) { - printWarning('Attempted to create a $SurfaceFactory with ' - '$maximumSurfaces maximum surfaces. At least 1 surface is required ' - 'for rendering.'); - } - registerHotRestartListener(debugClear); - } - } - /// The base surface to paint on. This is the default surface which will be /// painted to. If there are no platform views, then this surface will receive /// all painting commands. diff --git a/lib/web_ui/lib/src/engine/canvaskit/text.dart b/lib/web_ui/lib/src/engine/canvaskit/text.dart index a9a703c905a9d..1722f77c389c8 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/text.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/text.dart @@ -637,7 +637,7 @@ class CkParagraph extends SkiaObject implements ui.Paragraph { // lot of paragraphs are laid out _and_ rendered. To support // this use-case without blowing up memory usage we need this: // https://github.com/flutter/flutter/issues/81224 - static SynchronousSkiaObjectCache _paragraphCache = + static final SynchronousSkiaObjectCache _paragraphCache = SynchronousSkiaObjectCache(500); /// Marks this paragraph as having been used this frame. @@ -835,13 +835,6 @@ class CkLineMetrics implements ui.LineMetrics { } class CkParagraphBuilder implements ui.ParagraphBuilder { - final SkParagraphBuilder _paragraphBuilder; - final CkParagraphStyle _style; - final List<_ParagraphCommand> _commands; - int _placeholderCount; - final List _placeholderScales; - final List _styleStack; - CkParagraphBuilder(ui.ParagraphStyle style) : _commands = <_ParagraphCommand>[], _style = style as CkParagraphStyle, @@ -855,6 +848,13 @@ class CkParagraphBuilder implements ui.ParagraphBuilder { _styleStack.add(_style.getTextStyle()); } + final SkParagraphBuilder _paragraphBuilder; + final CkParagraphStyle _style; + final List<_ParagraphCommand> _commands; + int _placeholderCount; + final List _placeholderScales; + final List _styleStack; + @override void addPlaceholder( double width, @@ -1019,11 +1019,6 @@ class _CkParagraphPlaceholder { } class _ParagraphCommand { - final _ParagraphCommandType type; - final String? text; - final CkTextStyle? style; - final _CkParagraphPlaceholder? placeholderStyle; - const _ParagraphCommand._( this.type, this.text, @@ -1044,6 +1039,11 @@ class _ParagraphCommand { _CkParagraphPlaceholder placeholderStyle) : this._( _ParagraphCommandType.addPlaceholder, null, null, placeholderStyle); + + final _ParagraphCommandType type; + final String? text; + final CkTextStyle? style; + final _CkParagraphPlaceholder? placeholderStyle; } enum _ParagraphCommandType { diff --git a/lib/web_ui/lib/src/engine/canvaskit/viewport_metrics.dart b/lib/web_ui/lib/src/engine/canvaskit/viewport_metrics.dart index 99347d356dbf9..255ab30bf0f82 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/viewport_metrics.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/viewport_metrics.dart @@ -3,13 +3,13 @@ // found in the LICENSE file. class ViewportMetrics { - final double devicePixelRatio; - final double physicalWidth; - final double physicalHeight; - const ViewportMetrics( this.devicePixelRatio, this.physicalWidth, this.physicalHeight, ); + + final double devicePixelRatio; + final double physicalWidth; + final double physicalHeight; } diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index ec1c03f7ec427..3c6bac0aa0b31 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -1309,22 +1309,22 @@ extension DomScreenOrientationExtension on DomScreenOrientation { // remove the listener. Caller is still responsible for calling [allowInterop] // on the listener before creating the subscription. class DomSubscription { - final String type; - final DomEventTarget target; - final DomEventListener listener; - DomSubscription(this.target, this.type, this.listener) { target.addEventListener(type, listener); } + final String type; + final DomEventTarget target; + final DomEventListener listener; + void cancel() => target.removeEventListener(type, listener); } class DomPoint { + DomPoint(this.x, this.y); + final num x; final num y; - - DomPoint(this.x, this.y); } @JS() @@ -1422,11 +1422,11 @@ extension DomListExtension on _DomList { } class _DomListIterator extends Iterator { + _DomListIterator(this.list); + final _DomList list; int index = -1; - _DomListIterator(this.list); - @override bool moveNext() { index++; @@ -1441,10 +1441,10 @@ class _DomListIterator extends Iterator { } class _DomListWrapper extends Iterable { - final _DomList list; - _DomListWrapper._(this.list); + final _DomList list; + @override Iterator get iterator => _DomListIterator(list); diff --git a/lib/web_ui/lib/src/engine/engine_canvas.dart b/lib/web_ui/lib/src/engine/engine_canvas.dart index bd491fb87c790..14a952dfc471c 100644 --- a/lib/web_ui/lib/src/engine/engine_canvas.dart +++ b/lib/web_ui/lib/src/engine/engine_canvas.dart @@ -116,10 +116,6 @@ class SaveStackEntry { /// Tagged union of clipping parameters used for canvas. class SaveClipEntry { - final ui.Rect? rect; - final ui.RRect? rrect; - final ui.Path? path; - final Matrix4 currentTransform; SaveClipEntry.rect(this.rect, this.currentTransform) : rrect = null, path = null; @@ -129,6 +125,11 @@ class SaveClipEntry { SaveClipEntry.path(this.path, this.currentTransform) : rect = null, rrect = null; + + final ui.Rect? rect; + final ui.RRect? rrect; + final ui.Path? path; + final Matrix4 currentTransform; } /// Provides save stack tracking functionality to implementations of diff --git a/lib/web_ui/lib/src/engine/frame_reference.dart b/lib/web_ui/lib/src/engine/frame_reference.dart index c711b18100e14..4384840365202 100644 --- a/lib/web_ui/lib/src/engine/frame_reference.dart +++ b/lib/web_ui/lib/src/engine/frame_reference.dart @@ -86,9 +86,9 @@ class CrossFrameCache { } class _CrossFrameCacheItem { + _CrossFrameCacheItem(this.value, this.evictCallback); final T value; final CrossFrameCacheEvictCallback? evictCallback; - _CrossFrameCacheItem(this.value, this.evictCallback); void evict() { if (evictCallback != null) { evictCallback!(value); diff --git a/lib/web_ui/lib/src/engine/host_node.dart b/lib/web_ui/lib/src/engine/host_node.dart index dee8ffb1c45dd..59a91e697fabf 100644 --- a/lib/web_ui/lib/src/engine/host_node.dart +++ b/lib/web_ui/lib/src/engine/host_node.dart @@ -86,8 +86,6 @@ abstract class HostNode { /// supported in the current environment. In this case, a fallback [ElementHostNode] /// should be created instead. class ShadowDomHostNode implements HostNode { - late DomShadowRoot _shadow; - /// Build a HostNode by attaching a [DomShadowRoot] to the `root` element. /// /// This also calls [applyGlobalCssRulesToSheet], defined in dom_renderer. @@ -115,6 +113,8 @@ class ShadowDomHostNode implements HostNode { ); } + late DomShadowRoot _shadow; + @override DomElement? get activeElement => _shadow.activeElement; @@ -150,14 +150,14 @@ class ShadowDomHostNode implements HostNode { /// This is a fallback implementation, in case [ShadowDomHostNode] fails when /// being constructed. class ElementHostNode implements HostNode { - late DomElement _element; - /// Build a HostNode by attaching a child [DomElement] to the `root` element. ElementHostNode(DomElement root) { _element = domDocument.createElement('flt-element-host-node'); root.appendChild(_element); } + late DomElement _element; + @override DomElement? get activeElement => _element.ownerDocument?.activeElement; diff --git a/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart b/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart index 0f901d28e0067..0bc8528595c1d 100644 --- a/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart @@ -31,6 +31,39 @@ import 'shaders/image_shader.dart'; /// A raw HTML canvas that is directly written to. class BitmapCanvas extends EngineCanvas { + /// Allocates a canvas with enough memory to paint a picture within the given + /// [bounds]. + /// + /// This canvas can be reused by pictures with different paint bounds as long + /// as the [Rect.size] of the bounds fully fit within the size used to + /// initialize this canvas. + BitmapCanvas(this._bounds, RenderStrategy renderStrategy, + {double density = 1.0}) + : assert(_bounds != null), // ignore: unnecessary_null_comparison + _density = density, + _renderStrategy = renderStrategy, + widthInBitmapPixels = widthToPhysical(_bounds.width), + heightInBitmapPixels = heightToPhysical(_bounds.height), + _canvasPool = CanvasPool(widthToPhysical(_bounds.width), + heightToPhysical(_bounds.height), density) { + rootElement.style.position = 'absolute'; + // Adds one extra pixel to the requested size. This is to compensate for + // _initializeViewport() snapping canvas position to 1 pixel, causing + // painting to overflow by at most 1 pixel. + _canvasPositionX = _bounds.left.floor() - kPaddingPixels; + _canvasPositionY = _bounds.top.floor() - kPaddingPixels; + _updateRootElementTransform(); + _canvasPool.mount(rootElement as DomHTMLElement); + _setupInitialTransform(); + } + + /// Constructs bitmap canvas to capture image data. + factory BitmapCanvas.imageData(ui.Rect bounds) { + final BitmapCanvas bitmapCanvas = BitmapCanvas(bounds, RenderStrategy()); + bitmapCanvas._preserveImageData = true; + return bitmapCanvas; + } + /// The rectangle positioned relative to the parent layer's coordinate /// system's origin, within which this canvas paints. /// @@ -136,39 +169,6 @@ class BitmapCanvas extends EngineCanvas { final RenderStrategy _renderStrategy; - /// Allocates a canvas with enough memory to paint a picture within the given - /// [bounds]. - /// - /// This canvas can be reused by pictures with different paint bounds as long - /// as the [Rect.size] of the bounds fully fit within the size used to - /// initialize this canvas. - BitmapCanvas(this._bounds, RenderStrategy renderStrategy, - {double density = 1.0}) - : assert(_bounds != null), // ignore: unnecessary_null_comparison - _density = density, - _renderStrategy = renderStrategy, - widthInBitmapPixels = widthToPhysical(_bounds.width), - heightInBitmapPixels = heightToPhysical(_bounds.height), - _canvasPool = CanvasPool(widthToPhysical(_bounds.width), - heightToPhysical(_bounds.height), density) { - rootElement.style.position = 'absolute'; - // Adds one extra pixel to the requested size. This is to compensate for - // _initializeViewport() snapping canvas position to 1 pixel, causing - // painting to overflow by at most 1 pixel. - _canvasPositionX = _bounds.left.floor() - kPaddingPixels; - _canvasPositionY = _bounds.top.floor() - kPaddingPixels; - _updateRootElementTransform(); - _canvasPool.mount(rootElement as DomHTMLElement); - _setupInitialTransform(); - } - - /// Constructs bitmap canvas to capture image data. - factory BitmapCanvas.imageData(ui.Rect bounds) { - final BitmapCanvas bitmapCanvas = BitmapCanvas(bounds, RenderStrategy()); - bitmapCanvas._preserveImageData = true; - return bitmapCanvas; - } - /// Setup cache for reusing DOM elements across frames. void setElementCache(CrossFrameCache? cache) { _elementCache = cache; @@ -1036,7 +1036,7 @@ class BitmapCanvas extends EngineCanvas { /// Stores paint data used by [drawPoints]. We cannot use the original paint /// data object because painting style is determined by [ui.PointMode] and /// not by [SurfacePointData.style]. - static SurfacePaintData _drawPointsPaint = SurfacePaintData() + static final SurfacePaintData _drawPointsPaint = SurfacePaintData() ..strokeCap = ui.StrokeCap.round ..strokeJoin = ui.StrokeJoin.round ..blendMode = ui.BlendMode.srcOver; diff --git a/lib/web_ui/lib/src/engine/html/canvas.dart b/lib/web_ui/lib/src/engine/html/canvas.dart index 9a422ff8eed52..867504f7b9e4c 100644 --- a/lib/web_ui/lib/src/engine/html/canvas.dart +++ b/lib/web_ui/lib/src/engine/html/canvas.dart @@ -16,8 +16,6 @@ import 'recording_canvas.dart'; import 'render_vertices.dart'; class SurfaceCanvas implements ui.Canvas { - RecordingCanvas _canvas; - factory SurfaceCanvas(EnginePictureRecorder recorder, [ui.Rect? cullRect]) { if (recorder.isRecording) { throw ArgumentError( @@ -29,6 +27,8 @@ class SurfaceCanvas implements ui.Canvas { SurfaceCanvas._(this._canvas); + RecordingCanvas _canvas; + @override void save() { _canvas.save(); diff --git a/lib/web_ui/lib/src/engine/html/color_filter.dart b/lib/web_ui/lib/src/engine/html/color_filter.dart index 5912f6962f9e9..8b6507a8a8553 100644 --- a/lib/web_ui/lib/src/engine/html/color_filter.dart +++ b/lib/web_ui/lib/src/engine/html/color_filter.dart @@ -252,8 +252,6 @@ const int kOperatorArithmetic = 6; /// Builds an [SvgFilter]. class SvgFilterBuilder { - static int _filterIdCounter = 0; - SvgFilterBuilder() : id = '_fcf${++_filterIdCounter}' { filter.id = id; @@ -268,6 +266,8 @@ class SvgFilterBuilder { filter.height!.baseVal!.valueAsString = '100%'; } + static int _filterIdCounter = 0; + final String id; final SVGSVGElement root = kSvgResourceHeader.cloneNode(false) as SVGSVGElement; diff --git a/lib/web_ui/lib/src/engine/html/dom_canvas.dart b/lib/web_ui/lib/src/engine/html/dom_canvas.dart index 34c9bec699cc3..41956fd11f064 100644 --- a/lib/web_ui/lib/src/engine/html/dom_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/dom_canvas.dart @@ -22,11 +22,11 @@ import 'shaders/shader.dart'; /// A canvas that renders to DOM elements and CSS properties. class DomCanvas extends EngineCanvas with SaveElementStackTracking { + DomCanvas(this.rootElement); + @override final DomElement rootElement; - DomCanvas(this.rootElement); - /// Prepare to reuse this canvas by clearing it's current contents. @override void clear() { diff --git a/lib/web_ui/lib/src/engine/html/path/conic.dart b/lib/web_ui/lib/src/engine/html/path/conic.dart index 9a385a5969155..fa8a338dcabfb 100644 --- a/lib/web_ui/lib/src/engine/html/path/conic.dart +++ b/lib/web_ui/lib/src/engine/html/path/conic.dart @@ -17,12 +17,12 @@ import 'path_utils.dart'; /// Skia implementation reference: /// https://github.com/google/skia/blob/main/src/core/SkGeometry.cpp class Conic { + Conic(this.p0x, this.p0y, this.p1x, this.p1y, this.p2x, this.p2y, this.fW); + double p0x, p0y, p1x, p1y, p2x, p2y; final double fW; static const int _maxSubdivisionCount = 5; - Conic(this.p0x, this.p0y, this.p1x, this.p1y, this.p2x, this.p2y, this.fW); - /// Returns array of points for the approximation of the conic as quad(s). /// /// First offset is start Point. Each pair of offsets after are quadratic diff --git a/lib/web_ui/lib/src/engine/html/path/path.dart b/lib/web_ui/lib/src/engine/html/path/path.dart index fb49a1ae7e8cd..5ced01bb17000 100644 --- a/lib/web_ui/lib/src/engine/html/path/path.dart +++ b/lib/web_ui/lib/src/engine/html/path/path.dart @@ -35,15 +35,33 @@ import 'tangent.dart'; /// 3. if we encounter Move without a preceding Close, and forceClose is true, goto #2 /// 4. if we encounter Line | Quad | Cubic after Close, cons up a Move class SurfacePath implements ui.Path { + SurfacePath() : pathRef = PathRef() { + _resetFields(); + } + + /// Creates a copy of another [Path]. + SurfacePath.from(SurfacePath source) + : pathRef = PathRef()..copy(source.pathRef, 0, 0) { + _copyFields(source); + } + + /// Creates a shifted copy of another [Path]. + SurfacePath.shiftedFrom(SurfacePath source, double offsetX, double offsetY) + : pathRef = PathRef.shiftedFrom(source.pathRef, offsetX, offsetY) { + _copyFields(source); + } + + SurfacePath.shallowCopy(SurfacePath source) + : pathRef = PathRef.shallowCopy(source.pathRef) { + _copyFields(source); + } + // Initial valid of last move to index so we can detect if a move to // needs to be inserted after contour closure. See [close]. static const int kInitialLastMoveToIndexValue = 0; PathRef pathRef; ui.PathFillType _fillType = ui.PathFillType.nonZero; - // Skia supports inverse winding as part of path fill type. - // For Flutter inverse is always false. - bool _isInverseFillType = false; // Store point index + 1 of last moveTo instruction. // If contour has been closed or path is in initial state, the value is // negated. @@ -51,10 +69,6 @@ class SurfacePath implements ui.Path { int _convexityType = SPathConvexityType.kUnknown; int _firstDirection = SPathDirection.kUnknown; - SurfacePath() : pathRef = PathRef() { - _resetFields(); - } - void _resetFields() { fLastMoveToIndex = kInitialLastMoveToIndexValue; _fillType = ui.PathFillType.nonZero; @@ -66,23 +80,6 @@ class SurfacePath implements ui.Path { _firstDirection = SPathDirection.kUnknown; } - /// Creates a copy of another [Path]. - SurfacePath.from(SurfacePath source) - : pathRef = PathRef()..copy(source.pathRef, 0, 0) { - _copyFields(source); - } - - /// Creates a shifted copy of another [Path]. - SurfacePath.shiftedFrom(SurfacePath source, double offsetX, double offsetY) - : pathRef = PathRef.shiftedFrom(source.pathRef, offsetX, offsetY) { - _copyFields(source); - } - - SurfacePath.shallowCopy(SurfacePath source) - : pathRef = PathRef.shallowCopy(source.pathRef) { - _copyFields(source); - } - void _copyFields(SurfacePath source) { _fillType = source._fillType; fLastMoveToIndex = source.fLastMoveToIndex; @@ -1209,9 +1206,8 @@ class SurfacePath implements ui.Path { @override bool contains(ui.Offset point) { assert(offsetIsValid(point)); - final bool isInverse = _isInverseFillType; if (pathRef.isEmpty) { - return isInverse; + return false; } // Check bounds including right/bottom. final ui.Rect bounds = getBounds(); @@ -1219,7 +1215,7 @@ class SurfacePath implements ui.Path { final double y = point.dy; if (x < bounds.left || y < bounds.top || x > bounds.right || y > bounds.bottom) { - return isInverse; + return false; } final PathWinding windings = PathWinding(pathRef, point.dx, point.dy); final bool evenOddFill = ui.PathFillType.evenOdd == _fillType; @@ -1228,14 +1224,14 @@ class SurfacePath implements ui.Path { w &= 1; } if (w != 0) { - return !isInverse; + return true; } final int onCurveCount = windings.onCurveCount; if (onCurveCount <= 1) { - return (onCurveCount != 0) ^ isInverse; + return onCurveCount != 0; } if ((onCurveCount & 1) != 0 || evenOddFill) { - return (onCurveCount & 1) != 0 ^ (isInverse ? 1 : 0); + return (onCurveCount & 1) != 0; } // If the point touches an even number of curves, and the fill is winding, // check for coincidence. Count coincidence as places where the on curve @@ -1288,7 +1284,7 @@ class SurfacePath implements ui.Path { } } } while (!done); - return tangents.isEmpty ? isInverse : !isInverse; + return tangents.isNotEmpty; } /// Returns a copy of the path with all the segments of every diff --git a/lib/web_ui/lib/src/engine/html/path/path_metrics.dart b/lib/web_ui/lib/src/engine/html/path/path_metrics.dart index 683050e92edf2..d0d2e647de47f 100644 --- a/lib/web_ui/lib/src/engine/html/path/path_metrics.dart +++ b/lib/web_ui/lib/src/engine/html/path/path_metrics.dart @@ -52,7 +52,7 @@ class _SurfacePathMeasure { _pathIterator = PathIterator(_path, forceClosed); final PathRef _path; - PathIterator _pathIterator; + final PathIterator _pathIterator; final List<_PathContourMeasure> _contours = <_PathContourMeasure>[]; // If the contour ends with a call to [Path.close] (which may @@ -494,7 +494,7 @@ class SurfacePathMetricIterator implements Iterator { SurfacePathMetricIterator._(this._pathMeasure); SurfacePathMetric? _pathMetric; - _SurfacePathMeasure _pathMeasure; + final _SurfacePathMeasure _pathMeasure; @override SurfacePathMetric get current => _pathMetric!; @@ -693,7 +693,6 @@ class _PathSegment { // Evaluates A * t^3 + B * t^2 + Ct + D = 0 for cubic curve. class _SkCubicCoefficients { - final double ax, ay, bx, by, cx, cy, dx, dy; _SkCubicCoefficients(double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3) : ax = x3 + (3 * (x1 - x2)) - x0, @@ -705,6 +704,8 @@ class _SkCubicCoefficients { dx = x0, dy = y0; + final double ax, ay, bx, by, cx, cy, dx, dy; + double evalX(double t) => (((ax * t + bx) * t) + cx) * t + dx; double evalY(double t) => (((ay * t + by) * t) + cy) * t + dy; diff --git a/lib/web_ui/lib/src/engine/html/path/path_ref.dart b/lib/web_ui/lib/src/engine/html/path/path_ref.dart index 836a2ffed788d..6bafcb02459b3 100644 --- a/lib/web_ui/lib/src/engine/html/path/path_ref.dart +++ b/lib/web_ui/lib/src/engine/html/path/path_ref.dart @@ -27,6 +27,67 @@ class PathRef { _resetFields(); } + /// Creates a copy of the path by pointing new path to a current + /// points,verbs and weights arrays. If original path is mutated by adding + /// more verbs, this copy only returns path at the time of copy and shares + /// typed arrays of original path. + PathRef.shallowCopy(PathRef ref) + : fPoints = ref.fPoints, + _fVerbs = ref._fVerbs { + _fVerbsCapacity = ref._fVerbsCapacity; + _fVerbsLength = ref._fVerbsLength; + + _fPointsCapacity = ref._fPointsCapacity; + _fPointsLength = ref._fPointsLength; + + _conicWeightsCapacity = ref._conicWeightsCapacity; + _conicWeightsLength = ref._conicWeightsLength; + _conicWeights = ref._conicWeights; + fBoundsIsDirty = ref.fBoundsIsDirty; + if (!fBoundsIsDirty) { + fBounds = ref.fBounds; + cachedBounds = ref.cachedBounds; + fIsFinite = ref.fIsFinite; + } + fSegmentMask = ref.fSegmentMask; + fIsOval = ref.fIsOval; + fIsRRect = ref.fIsRRect; + fIsRect = ref.fIsRect; + fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW; + fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx; + debugValidate(); + } + + /// Returns a new path by translating [source] by [offsetX], [offsetY]. + PathRef.shiftedFrom(PathRef source, double offsetX, double offsetY) + : fPoints = _fPointsFromSource(source, offsetX, offsetY), + _fVerbs = _fVerbsFromSource(source) { + _conicWeightsCapacity = source._conicWeightsCapacity; + _conicWeightsLength = source._conicWeightsLength; + if (source._conicWeights != null) { + _conicWeights = Float32List(_conicWeightsCapacity); + _conicWeights!.setAll(0, source._conicWeights!); + } + _fVerbsCapacity = source._fVerbsCapacity; + _fVerbsLength = source._fVerbsLength; + + _fPointsCapacity = source._fPointsCapacity; + _fPointsLength = source._fPointsLength; + fBoundsIsDirty = source.fBoundsIsDirty; + if (!fBoundsIsDirty) { + fBounds = source.fBounds!.translate(offsetX, offsetY); + cachedBounds = source.cachedBounds?.translate(offsetX, offsetY); + fIsFinite = source.fIsFinite; + } + fSegmentMask = source.fSegmentMask; + fIsOval = source.fIsOval; + fIsRRect = source.fIsRRect; + fIsRect = source.fIsRect; + fRRectOrOvalIsCCW = source.fRRectOrOvalIsCCW; + fRRectOrOvalStartIdx = source.fRRectOrOvalStartIdx; + debugValidate(); + } + // Value to use to check against to insert move(0,0) when a command // is added without moveTo. static const int kInitialLastMoveToIndex = -1; @@ -85,37 +146,6 @@ class PathRef { fPoints[index + 1] = y; } - /// Creates a copy of the path by pointing new path to a current - /// points,verbs and weights arrays. If original path is mutated by adding - /// more verbs, this copy only returns path at the time of copy and shares - /// typed arrays of original path. - PathRef.shallowCopy(PathRef ref) - : fPoints = ref.fPoints, - _fVerbs = ref._fVerbs { - _fVerbsCapacity = ref._fVerbsCapacity; - _fVerbsLength = ref._fVerbsLength; - - _fPointsCapacity = ref._fPointsCapacity; - _fPointsLength = ref._fPointsLength; - - _conicWeightsCapacity = ref._conicWeightsCapacity; - _conicWeightsLength = ref._conicWeightsLength; - _conicWeights = ref._conicWeights; - fBoundsIsDirty = ref.fBoundsIsDirty; - if (!fBoundsIsDirty) { - fBounds = ref.fBounds; - cachedBounds = ref.cachedBounds; - fIsFinite = ref.fIsFinite; - } - fSegmentMask = ref.fSegmentMask; - fIsOval = ref.fIsOval; - fIsRRect = ref.fIsRRect; - fIsRect = ref.fIsRect; - fRRectOrOvalIsCCW = ref.fRRectOrOvalIsCCW; - fRRectOrOvalStartIdx = ref.fRRectOrOvalStartIdx; - debugValidate(); - } - Float32List get points => fPoints; Float32List? get conicWeights => _conicWeights; @@ -395,36 +425,6 @@ class PathRef { return verbs; } - /// Returns a new path by translating [source] by [offsetX], [offsetY]. - PathRef.shiftedFrom(PathRef source, double offsetX, double offsetY) - : fPoints = _fPointsFromSource(source, offsetX, offsetY), - _fVerbs = _fVerbsFromSource(source) { - _conicWeightsCapacity = source._conicWeightsCapacity; - _conicWeightsLength = source._conicWeightsLength; - if (source._conicWeights != null) { - _conicWeights = Float32List(_conicWeightsCapacity); - _conicWeights!.setAll(0, source._conicWeights!); - } - _fVerbsCapacity = source._fVerbsCapacity; - _fVerbsLength = source._fVerbsLength; - - _fPointsCapacity = source._fPointsCapacity; - _fPointsLength = source._fPointsLength; - fBoundsIsDirty = source.fBoundsIsDirty; - if (!fBoundsIsDirty) { - fBounds = source.fBounds!.translate(offsetX, offsetY); - cachedBounds = source.cachedBounds?.translate(offsetX, offsetY); - fIsFinite = source.fIsFinite; - } - fSegmentMask = source.fSegmentMask; - fIsOval = source.fIsOval; - fIsRRect = source.fIsRRect; - fIsRect = source.fIsRect; - fRRectOrOvalIsCCW = source.fRRectOrOvalIsCCW; - fRRectOrOvalStartIdx = source.fRRectOrOvalStartIdx; - debugValidate(); - } - /// Copies contents from a source path [ref]. void copy( PathRef ref, int additionalReserveVerbs, int additionalReservePoints) { @@ -948,11 +948,6 @@ class PathRef { } class PathRefIterator { - final PathRef pathRef; - int _conicWeightIndex = -1; - int _verbIndex = 0; - int _pointIndex = 0; - PathRefIterator(this.pathRef) { _pointIndex = 0; if (!pathRef.isFinite) { @@ -962,6 +957,11 @@ class PathRefIterator { } } + final PathRef pathRef; + int _conicWeightIndex = -1; + int _verbIndex = 0; + int _pointIndex = 0; + /// Maximum buffer size required for points in [next] calls. static const int kMaxBufferSize = 8; diff --git a/lib/web_ui/lib/src/engine/html/path/path_utils.dart b/lib/web_ui/lib/src/engine/html/path/path_utils.dart index fde50c5e4156f..0f7dacda7c715 100644 --- a/lib/web_ui/lib/src/engine/html/path/path_utils.dart +++ b/lib/web_ui/lib/src/engine/html/path/path_utils.dart @@ -115,11 +115,11 @@ class SPathSegmentState { /// x1 = Q / A /// x2 = C / Q class QuadRoots { + QuadRoots(); + double? root0; double? root1; - QuadRoots(); - /// Returns roots as list. List get roots => (root0 == null) ? [] diff --git a/lib/web_ui/lib/src/engine/html/platform_view.dart b/lib/web_ui/lib/src/engine/html/platform_view.dart index 108ac19435b05..d35ec97995207 100644 --- a/lib/web_ui/lib/src/engine/html/platform_view.dart +++ b/lib/web_ui/lib/src/engine/html/platform_view.dart @@ -8,14 +8,14 @@ import 'surface.dart'; /// A surface containing a platform view, which is an HTML element. class PersistedPlatformView extends PersistedLeafSurface { + PersistedPlatformView(this.viewId, this.dx, this.dy, this.width, this.height); + final int viewId; final double dx; final double dy; final double width; final double height; - PersistedPlatformView(this.viewId, this.dx, this.dy, this.width, this.height); - @override DomElement createElement() { return createPlatformViewSlot(viewId); diff --git a/lib/web_ui/lib/src/engine/html/recording_canvas.dart b/lib/web_ui/lib/src/engine/html/recording_canvas.dart index 2e93839475a41..970009ef563f8 100644 --- a/lib/web_ui/lib/src/engine/html/recording_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/recording_canvas.dart @@ -14,7 +14,6 @@ import '../shadow.dart'; import '../text/canvas_paragraph.dart'; import '../util.dart'; import '../vector_math.dart'; -import 'bitmap_canvas.dart'; import 'painting.dart'; import 'path/path.dart'; import 'path/path_utils.dart'; @@ -35,34 +34,13 @@ double _measureBorderRadius(double x, double y) { return clampedX * clampedX + clampedY * clampedY; } -class RawRecordingCanvas extends BitmapCanvas implements ui.PictureRecorder { - RawRecordingCanvas(ui.Size size) - : super(ui.Offset.zero & size, RenderStrategy()); - - @override - void dispose() { - clear(); - } - - RecordingCanvas beginRecording(ui.Rect bounds) => throw UnsupportedError(''); - - @override - ui.Picture endRecording() => throw UnsupportedError(''); - - late RecordingCanvas _canvas; // ignore: unused_field - - bool _isRecording = true; // ignore: unused_field - - @override - bool get isRecording => true; - - ui.Rect? cullRect; -} - /// Records canvas commands to be applied to a [EngineCanvas]. /// /// See [Canvas] for docs for these methods. class RecordingCanvas { + RecordingCanvas(ui.Rect? bounds) + : _paintBounds = _PaintBounds(bounds ?? ui.Rect.largest); + /// Computes [_pictureBounds]. final _PaintBounds _paintBounds; @@ -91,9 +69,6 @@ class RecordingCanvas { throw UnsupportedError('For debugging only.'); } - RecordingCanvas(ui.Rect? bounds) - : _paintBounds = _PaintBounds(bounds ?? ui.Rect.largest); - final RenderStrategy renderStrategy = RenderStrategy(); /// Forces arbitrary paint even for simple pictures. @@ -770,11 +745,11 @@ class PaintRestore extends PaintCommand { } class PaintTranslate extends PaintCommand { + PaintTranslate(this.dx, this.dy); + final double dx; final double dy; - PaintTranslate(this.dx, this.dy); - @override void apply(EngineCanvas canvas) { canvas.translate(dx, dy); @@ -791,11 +766,11 @@ class PaintTranslate extends PaintCommand { } class PaintScale extends PaintCommand { + PaintScale(this.sx, this.sy); + final double sx; final double sy; - PaintScale(this.sx, this.sy); - @override void apply(EngineCanvas canvas) { canvas.scale(sx, sy); @@ -812,10 +787,10 @@ class PaintScale extends PaintCommand { } class PaintRotate extends PaintCommand { - final double radians; - PaintRotate(this.radians); + final double radians; + @override void apply(EngineCanvas canvas) { canvas.rotate(radians); @@ -832,10 +807,10 @@ class PaintRotate extends PaintCommand { } class PaintTransform extends PaintCommand { - final Float32List matrix4; - PaintTransform(this.matrix4); + final Float32List matrix4; + @override void apply(EngineCanvas canvas) { canvas.transform(matrix4); @@ -852,11 +827,11 @@ class PaintTransform extends PaintCommand { } class PaintSkew extends PaintCommand { + PaintSkew(this.sx, this.sy); + final double sx; final double sy; - PaintSkew(this.sx, this.sy); - @override void apply(EngineCanvas canvas) { canvas.skew(sx, sy); @@ -873,11 +848,11 @@ class PaintSkew extends PaintCommand { } class PaintClipRect extends DrawCommand { + PaintClipRect(this.rect, this.clipOp); + final ui.Rect rect; final ui.ClipOp clipOp; - PaintClipRect(this.rect, this.clipOp); - @override void apply(EngineCanvas canvas) { canvas.clipRect(rect, clipOp); @@ -894,10 +869,10 @@ class PaintClipRect extends DrawCommand { } class PaintClipRRect extends DrawCommand { - final ui.RRect rrect; - PaintClipRRect(this.rrect); + final ui.RRect rrect; + @override void apply(EngineCanvas canvas) { canvas.clipRRect(rrect); @@ -914,10 +889,10 @@ class PaintClipRRect extends DrawCommand { } class PaintClipPath extends DrawCommand { - final SurfacePath path; - PaintClipPath(this.path); + final SurfacePath path; + @override void apply(EngineCanvas canvas) { canvas.clipPath(path); @@ -934,11 +909,11 @@ class PaintClipPath extends DrawCommand { } class PaintDrawColor extends DrawCommand { + PaintDrawColor(this.color, this.blendMode); + final ui.Color color; final ui.BlendMode blendMode; - PaintDrawColor(this.color, this.blendMode); - @override void apply(EngineCanvas canvas) { canvas.drawColor(color, blendMode); @@ -955,12 +930,12 @@ class PaintDrawColor extends DrawCommand { } class PaintDrawLine extends DrawCommand { + PaintDrawLine(this.p1, this.p2, this.paint); + final ui.Offset p1; final ui.Offset p2; final SurfacePaintData paint; - PaintDrawLine(this.p1, this.p2, this.paint); - @override void apply(EngineCanvas canvas) { canvas.drawLine(p1, p2, paint); @@ -977,10 +952,10 @@ class PaintDrawLine extends DrawCommand { } class PaintDrawPaint extends DrawCommand { - final SurfacePaintData paint; - PaintDrawPaint(this.paint); + final SurfacePaintData paint; + @override void apply(EngineCanvas canvas) { canvas.drawPaint(paint); @@ -997,10 +972,11 @@ class PaintDrawPaint extends DrawCommand { } class PaintDrawVertices extends DrawCommand { + PaintDrawVertices(this.vertices, this.blendMode, this.paint); + final ui.Vertices vertices; final ui.BlendMode blendMode; final SurfacePaintData paint; - PaintDrawVertices(this.vertices, this.blendMode, this.paint); @override void apply(EngineCanvas canvas) { @@ -1018,10 +994,11 @@ class PaintDrawVertices extends DrawCommand { } class PaintDrawPoints extends DrawCommand { + PaintDrawPoints(this.pointMode, this.points, this.paint); + final Float32List points; final ui.PointMode pointMode; final SurfacePaintData paint; - PaintDrawPoints(this.pointMode, this.points, this.paint); @override void apply(EngineCanvas canvas) { @@ -1039,11 +1016,11 @@ class PaintDrawPoints extends DrawCommand { } class PaintDrawRect extends DrawCommand { + PaintDrawRect(this.rect, this.paint); + final ui.Rect rect; final SurfacePaintData paint; - PaintDrawRect(this.rect, this.paint); - @override void apply(EngineCanvas canvas) { canvas.drawRect(rect, paint); @@ -1060,11 +1037,11 @@ class PaintDrawRect extends DrawCommand { } class PaintDrawRRect extends DrawCommand { + PaintDrawRRect(this.rrect, this.paint); + final ui.RRect rrect; final SurfacePaintData paint; - PaintDrawRRect(this.rrect, this.paint); - @override void apply(EngineCanvas canvas) { canvas.drawRRect(rrect, paint); @@ -1081,10 +1058,6 @@ class PaintDrawRRect extends DrawCommand { } class PaintDrawDRRect extends DrawCommand { - final ui.RRect outer; - final ui.RRect inner; - final SurfacePaintData paint; - ui.Path? path; PaintDrawDRRect(this.outer, this.inner, this.paint) { path = ui.Path() ..fillType = ui.PathFillType.evenOdd @@ -1093,6 +1066,11 @@ class PaintDrawDRRect extends DrawCommand { ..close(); } + final ui.RRect outer; + final ui.RRect inner; + final SurfacePaintData paint; + ui.Path? path; + @override void apply(EngineCanvas canvas) { paint.style ??= ui.PaintingStyle.fill; @@ -1110,11 +1088,11 @@ class PaintDrawDRRect extends DrawCommand { } class PaintDrawOval extends DrawCommand { + PaintDrawOval(this.rect, this.paint); + final ui.Rect rect; final SurfacePaintData paint; - PaintDrawOval(this.rect, this.paint); - @override void apply(EngineCanvas canvas) { canvas.drawOval(rect, paint); @@ -1131,12 +1109,12 @@ class PaintDrawOval extends DrawCommand { } class PaintDrawCircle extends DrawCommand { + PaintDrawCircle(this.c, this.radius, this.paint); + final ui.Offset c; final double radius; final SurfacePaintData paint; - PaintDrawCircle(this.c, this.radius, this.paint); - @override void apply(EngineCanvas canvas) { canvas.drawCircle(c, radius, paint); @@ -1153,11 +1131,11 @@ class PaintDrawCircle extends DrawCommand { } class PaintDrawPath extends DrawCommand { + PaintDrawPath(this.path, this.paint); + final SurfacePath path; final SurfacePaintData paint; - PaintDrawPath(this.path, this.paint); - @override void apply(EngineCanvas canvas) { canvas.drawPath(path, paint); @@ -1198,12 +1176,12 @@ class PaintDrawShadow extends DrawCommand { } class PaintDrawImage extends DrawCommand { + PaintDrawImage(this.image, this.offset, this.paint); + final ui.Image image; final ui.Offset offset; final SurfacePaintData paint; - PaintDrawImage(this.image, this.offset, this.paint); - @override void apply(EngineCanvas canvas) { canvas.drawImage(image, offset, paint); @@ -1220,13 +1198,13 @@ class PaintDrawImage extends DrawCommand { } class PaintDrawImageRect extends DrawCommand { + PaintDrawImageRect(this.image, this.src, this.dst, this.paint); + final ui.Image image; final ui.Rect src; final ui.Rect dst; final SurfacePaintData paint; - PaintDrawImageRect(this.image, this.src, this.dst, this.paint); - @override void apply(EngineCanvas canvas) { canvas.drawImageRect(image, src, dst, paint); @@ -1243,11 +1221,11 @@ class PaintDrawImageRect extends DrawCommand { } class PaintDrawParagraph extends DrawCommand { + PaintDrawParagraph(this.paragraph, this.offset); + final CanvasParagraph paragraph; final ui.Offset offset; - PaintDrawParagraph(this.paragraph, this.offset); - @override void apply(EngineCanvas canvas) { canvas.drawParagraph(paragraph, offset); @@ -1264,6 +1242,8 @@ class PaintDrawParagraph extends DrawCommand { } class Subpath { + Subpath(this.startX, this.startY) : commands = []; + double startX = 0.0; double startY = 0.0; double currentX = 0.0; @@ -1271,8 +1251,6 @@ class Subpath { final List commands; - Subpath(this.startX, this.startY) : commands = []; - Subpath shift(ui.Offset offset) { final Subpath result = Subpath(startX + offset.dx, startY + offset.dy) ..currentX = currentX + offset.dx @@ -1310,11 +1288,11 @@ abstract class PathCommand { } class MoveTo extends PathCommand { + const MoveTo(this.x, this.y); + final double x; final double y; - const MoveTo(this.x, this.y); - @override MoveTo shifted(ui.Offset offset) { return MoveTo(x + offset.dx, y + offset.dy); @@ -1337,11 +1315,11 @@ class MoveTo extends PathCommand { } class LineTo extends PathCommand { + const LineTo(this.x, this.y); + final double x; final double y; - const LineTo(this.x, this.y); - @override LineTo shifted(ui.Offset offset) { return LineTo(x + offset.dx, y + offset.dy); @@ -1364,6 +1342,9 @@ class LineTo extends PathCommand { } class Ellipse extends PathCommand { + const Ellipse(this.x, this.y, this.radiusX, this.radiusY, this.rotation, + this.startAngle, this.endAngle, this.anticlockwise); + final double x; final double y; final double radiusX; @@ -1373,9 +1354,6 @@ class Ellipse extends PathCommand { final double endAngle; final bool anticlockwise; - const Ellipse(this.x, this.y, this.radiusX, this.radiusY, this.rotation, - this.startAngle, this.endAngle, this.anticlockwise); - @override Ellipse shifted(ui.Offset offset) { return Ellipse(x + offset.dx, y + offset.dy, radiusX, radiusY, rotation, @@ -1496,13 +1474,13 @@ class Ellipse extends PathCommand { } class QuadraticCurveTo extends PathCommand { + const QuadraticCurveTo(this.x1, this.y1, this.x2, this.y2); + final double x1; final double y1; final double x2; final double y2; - const QuadraticCurveTo(this.x1, this.y1, this.x2, this.y2); - @override QuadraticCurveTo shifted(ui.Offset offset) { return QuadraticCurveTo( @@ -1536,6 +1514,8 @@ class QuadraticCurveTo extends PathCommand { } class BezierCurveTo extends PathCommand { + const BezierCurveTo(this.x1, this.y1, this.x2, this.y2, this.x3, this.y3); + final double x1; final double y1; final double x2; @@ -1543,8 +1523,6 @@ class BezierCurveTo extends PathCommand { final double x3; final double y3; - const BezierCurveTo(this.x1, this.y1, this.x2, this.y2, this.x3, this.y3); - @override BezierCurveTo shifted(ui.Offset offset) { return BezierCurveTo(x1 + offset.dx, y1 + offset.dy, x2 + offset.dx, @@ -1580,13 +1558,13 @@ class BezierCurveTo extends PathCommand { } class RectCommand extends PathCommand { + const RectCommand(this.x, this.y, this.width, this.height); + final double x; final double y; final double width; final double height; - const RectCommand(this.x, this.y, this.width, this.height); - @override RectCommand shifted(ui.Offset offset) { return RectCommand(x + offset.dx, y + offset.dy, width, height); @@ -1637,10 +1615,10 @@ class RectCommand extends PathCommand { } class RRectCommand extends PathCommand { - final ui.RRect rrect; - const RRectCommand(this.rrect); + final ui.RRect rrect; + @override RRectCommand shifted(ui.Offset offset) { return RRectCommand(rrect.shift(offset)); @@ -1685,6 +1663,8 @@ class CloseCommand extends PathCommand { } class _PaintBounds { + _PaintBounds(this.maxPaintBounds); + // Bounds of maximum area that is paintable by canvas ops. final ui.Rect maxPaintBounds; @@ -1709,8 +1689,6 @@ class _PaintBounds { _currentClipRight = 0.0, _currentClipBottom = 0.0; - _PaintBounds(this.maxPaintBounds); - void translate(double dx, double dy) { if (dx != 0.0 || dy != 0.0) { _currentMatrixIsIdentity = false; @@ -2045,6 +2023,8 @@ double _getPaintSpread(SurfacePaint paint) { /// Contains metrics collected by recording canvas to provide data for /// rendering heuristics (canvas use vs DOM). class RenderStrategy { + RenderStrategy(); + /// Whether paint commands contain image elements. bool hasImageElements = false; @@ -2064,8 +2044,6 @@ class RenderStrategy { /// bitmap canvas and instead render using dom primitives and svg only. bool isInsideSvgFilterTree = false; - RenderStrategy(); - /// Merges render strategy settings from a child recording. void merge(RenderStrategy childStrategy) { hasImageElements |= childStrategy.hasImageElements; diff --git a/lib/web_ui/lib/src/engine/html/render_vertices.dart b/lib/web_ui/lib/src/engine/html/render_vertices.dart index 2291da63562e3..1c05b349f84ab 100644 --- a/lib/web_ui/lib/src/engine/html/render_vertices.dart +++ b/lib/web_ui/lib/src/engine/html/render_vertices.dart @@ -21,11 +21,6 @@ import 'shaders/vertex_shaders.dart'; GlRenderer? glRenderer; class SurfaceVertices implements ui.Vertices { - final ui.VertexMode mode; - final Float32List positions; - final Int32List? colors; - final Uint16List? indices; // ignore: unused_field - SurfaceVertices( this.mode, List positions, { @@ -52,6 +47,11 @@ class SurfaceVertices implements ui.Vertices { initWebGl(); } + final ui.VertexMode mode; + final Float32List positions; + final Int32List? colors; + final Uint16List? indices; // ignore: unused_field + static Int32List _int32ListFromColors(List colors) { final Int32List list = Int32List(colors.length); final int len = colors.length; diff --git a/lib/web_ui/lib/src/engine/html/shaders/normalized_gradient.dart b/lib/web_ui/lib/src/engine/html/shaders/normalized_gradient.dart index 138f207d2d058..e3c9261fa21dc 100644 --- a/lib/web_ui/lib/src/engine/html/shaders/normalized_gradient.dart +++ b/lib/web_ui/lib/src/engine/html/shaders/normalized_gradient.dart @@ -22,12 +22,6 @@ import 'shader_builder.dart'; /// scale = (c2 - c1) / (t2 - t1) /// bias = c1 - t1 / (t2 - t1) * (c2 - c1) class NormalizedGradient { - final Float32List _thresholds; - final Float32List _bias; - final Float32List _scale; - final int thresholdCount; - final bool isOpaque; - factory NormalizedGradient(List colors, {List? stops}) { // If colorStops is not provided, then only two stops, at 0.0 and 1.0, // are implied (and colors must therefore only have two entries). @@ -102,6 +96,12 @@ class NormalizedGradient { NormalizedGradient._( this.thresholdCount, this._thresholds, this._scale, this._bias, this.isOpaque); + final Float32List _thresholds; + final Float32List _bias; + final Float32List _scale; + final int thresholdCount; + final bool isOpaque; + /// Sets uniforms for threshold, bias and scale for program. void setupUniforms(GlContext gl, GlProgram glProgram) { for (int i = 0; i < thresholdCount; i++) { diff --git a/lib/web_ui/lib/src/engine/html/shaders/shader_builder.dart b/lib/web_ui/lib/src/engine/html/shaders/shader_builder.dart index aa30126692699..a1e49359a4f5a 100644 --- a/lib/web_ui/lib/src/engine/html/shaders/shader_builder.dart +++ b/lib/web_ui/lib/src/engine/html/shaders/shader_builder.dart @@ -28,6 +28,13 @@ import '../../util.dart'; /// method.addStatement('${u1.name} = vec4(1.0, 1.0, 1.0, 0.0);'); /// source = builder.build(); class ShaderBuilder { + ShaderBuilder(this.version) : isWebGl2 = version == WebGLVersion.webgl2, + _isFragmentShader = false; + + ShaderBuilder.fragment(this.version) : + isWebGl2 = version == WebGLVersion.webgl2, + _isFragmentShader = true; + /// WebGL version. final int version; final List declarations = []; @@ -59,13 +66,6 @@ class ShaderBuilder { /// Lazily allocated fragment color output. ShaderDeclaration? _fragmentColorDeclaration; - ShaderBuilder(this.version) : isWebGl2 = version == WebGLVersion.webgl2, - _isFragmentShader = false; - - ShaderBuilder.fragment(this.version) : - isWebGl2 = version == WebGLVersion.webgl2, - _isFragmentShader = true; - /// Returns fragment color declaration for fragment shader. /// /// This is hard coded for webgl1 as gl_FragColor. @@ -345,10 +345,6 @@ abstract class ShaderStorageQualifier { /// Shader variable and constant declaration. class ShaderDeclaration { - final String name; - final int dataType; - final int storage; - final String constValue; ShaderDeclaration(this.name, this.dataType, this.storage) : assert(!_isGLSLReservedWord(name)), constValue = ''; @@ -356,6 +352,11 @@ class ShaderDeclaration { /// Constructs a constant. ShaderDeclaration.constant(this.name, this.dataType, this.constValue) : storage = ShaderStorageQualifier.kConst; + + final String name; + final int dataType; + final int storage; + final String constValue; } // These are used only in debug mode to assert if used as variable name. 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 b3b20a9eda102..0011196fafac5 100644 --- a/lib/web_ui/lib/src/engine/html_image_codec.dart +++ b/lib/web_ui/lib/src/engine/html_image_codec.dart @@ -25,11 +25,11 @@ typedef WebOnlyImageCodecChunkCallback = void Function( int cumulativeBytesLoaded, int expectedTotalBytes); class HtmlCodec implements ui.Codec { + HtmlCodec(this.src, {this.chunkCallback}); + final String src; final WebOnlyImageCodecChunkCallback? chunkCallback; - HtmlCodec(this.src, {this.chunkCallback}); - @override int get frameCount => 1; @@ -119,10 +119,10 @@ class HtmlCodec implements ui.Codec { } class HtmlBlobCodec extends HtmlCodec { - final DomBlob blob; - HtmlBlobCodec(this.blob) : super(domWindow.URL.createObjectURL(blob)); + final DomBlob blob; + @override void dispose() { domWindow.URL.revokeObjectURL(src); @@ -140,9 +140,10 @@ class SingleFrameInfo implements ui.FrameInfo { } class HtmlImage implements ui.Image { + HtmlImage(this.imgElement, this.width, this.height); + final DomHTMLImageElement imgElement; bool _requiresClone = false; - HtmlImage(this.imgElement, this.width, this.height); bool _disposed = false; @override diff --git a/lib/web_ui/lib/src/engine/keyboard.dart b/lib/web_ui/lib/src/engine/keyboard.dart index 8e14ca66f2250..440f249850e83 100644 --- a/lib/web_ui/lib/src/engine/keyboard.dart +++ b/lib/web_ui/lib/src/engine/keyboard.dart @@ -13,6 +13,21 @@ import 'services.dart'; /// Provides keyboard bindings, such as the `flutter/keyevent` channel. class Keyboard { + Keyboard._(this._onMacOs) { + _keydownListener = allowInterop((DomEvent event) { + _handleHtmlEvent(event); + }); + domWindow.addEventListener('keydown', _keydownListener); + + _keyupListener = allowInterop((DomEvent event) { + _handleHtmlEvent(event); + }); + domWindow.addEventListener('keyup', _keyupListener); + registerHotRestartListener(() { + dispose(); + }); + } + /// Initializes the [Keyboard] singleton. /// /// Use the [instance] getter to get the singleton after calling this method. @@ -33,21 +48,6 @@ class Keyboard { DomEventListener? _keydownListener; DomEventListener? _keyupListener; - Keyboard._(this._onMacOs) { - _keydownListener = allowInterop((DomEvent event) { - _handleHtmlEvent(event); - }); - domWindow.addEventListener('keydown', _keydownListener); - - _keyupListener = allowInterop((DomEvent event) { - _handleHtmlEvent(event); - }); - domWindow.addEventListener('keyup', _keyupListener); - registerHotRestartListener(() { - dispose(); - }); - } - /// Uninitializes the [Keyboard] singleton. /// /// After calling this method this object becomes unusable and [instance] @@ -73,7 +73,7 @@ class Keyboard { /// Initializing with `0x0` which means no meta keys are pressed. int _lastMetaState = 0x0; - bool _onMacOs; + final bool _onMacOs; // When the user enters a browser/system shortcut (e.g. `cmd+alt+i`) on macOS, // the browser doesn't send a keyup for it. This puts the framework in a diff --git a/lib/web_ui/lib/src/engine/keyboard_binding.dart b/lib/web_ui/lib/src/engine/keyboard_binding.dart index f72dfd55b9b9e..9a500efea9311 100644 --- a/lib/web_ui/lib/src/engine/keyboard_binding.dart +++ b/lib/web_ui/lib/src/engine/keyboard_binding.dart @@ -88,6 +88,10 @@ Duration _eventTimeStampToDuration(num milliseconds) { } class KeyboardBinding { + KeyboardBinding._(this.glassPaneElement) { + _setup(); + } + /// The singleton instance of this object. static KeyboardBinding? get instance => _instance; static KeyboardBinding? _instance; @@ -102,10 +106,6 @@ class KeyboardBinding { } } - KeyboardBinding._(this.glassPaneElement) { - _setup(); - } - final DomElement glassPaneElement; late KeyboardConverter _converter; final Map _listeners = {}; diff --git a/lib/web_ui/lib/src/engine/mouse_cursor.dart b/lib/web_ui/lib/src/engine/mouse_cursor.dart index 3e5979bdedd86..009ca0f2110ed 100644 --- a/lib/web_ui/lib/src/engine/mouse_cursor.dart +++ b/lib/web_ui/lib/src/engine/mouse_cursor.dart @@ -7,6 +7,8 @@ import 'util.dart'; /// Provides mouse cursor bindings, such as the `flutter/mousecursor` channel. class MouseCursor { + MouseCursor._(); + /// Initializes the [MouseCursor] singleton. /// /// Use the [instance] getter to get the singleton after calling this method. @@ -18,8 +20,6 @@ class MouseCursor { static MouseCursor? get instance => _instance; static MouseCursor? _instance; - MouseCursor._(); - // Map from Flutter's kind values to CSS's cursor values. // // This map must be kept in sync with Flutter framework's diff --git a/lib/web_ui/lib/src/engine/navigation/history.dart b/lib/web_ui/lib/src/engine/navigation/history.dart index 7921f88abc5b2..3110e2deef049 100644 --- a/lib/web_ui/lib/src/engine/navigation/history.dart +++ b/lib/web_ui/lib/src/engine/navigation/history.dart @@ -287,7 +287,7 @@ class SingleEntryBrowserHistory extends BrowserHistory { return originState['state']; } - Map _flutterState = {_kFlutterTag: true}; + final Map _flutterState = {_kFlutterTag: true}; /// The origin entry is the history entry that the Flutter app landed on. It's /// created by the browser when the user navigates to the url of the app. diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index 05cbafd311d7e..e195aec769295 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -142,14 +142,14 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { @override Iterable get views => _windows.values; Map get windows => _windows; - Map _windows = {}; + final Map _windows = {}; /// A map of opaque platform window identifiers to window configurations. /// /// This should be considered a protected member, only to be used by /// [PlatformDispatcher] subclasses. Map get windowConfigurations => _windowConfigurations; - Map _windowConfigurations = + final Map _windowConfigurations = {}; /// A callback that is invoked whenever the platform's [devicePixelRatio], diff --git a/lib/web_ui/lib/src/engine/platform_views/message_handler.dart b/lib/web_ui/lib/src/engine/platform_views/message_handler.dart index 722ce618b6ef7..30658e57f6c91 100644 --- a/lib/web_ui/lib/src/engine/platform_views/message_handler.dart +++ b/lib/web_ui/lib/src/engine/platform_views/message_handler.dart @@ -39,17 +39,16 @@ typedef PlatformViewContentHandler = void Function(DomElement); /// some extra cleanup of its internal state, but it can do it automatically. See /// [HtmlViewEmbedder.disposeViews] class PlatformViewMessageHandler { - final MethodCodec _codec = const StandardMethodCodec(); - - final PlatformViewManager _contentManager; - final PlatformViewContentHandler? _contentHandler; - PlatformViewMessageHandler({ required PlatformViewManager contentManager, PlatformViewContentHandler? contentHandler, }) : _contentManager = contentManager, _contentHandler = contentHandler; + final MethodCodec _codec = const StandardMethodCodec(); + final PlatformViewManager _contentManager; + final PlatformViewContentHandler? _contentHandler; + /// Handle a `create` Platform View message. /// /// This will attempt to render the `contents` and of a Platform View, if its diff --git a/lib/web_ui/lib/src/engine/pointer_binding.dart b/lib/web_ui/lib/src/engine/pointer_binding.dart index 02032999fecd7..9fbea7793eae5 100644 --- a/lib/web_ui/lib/src/engine/pointer_binding.dart +++ b/lib/web_ui/lib/src/engine/pointer_binding.dart @@ -73,6 +73,15 @@ class SafariPointerEventWorkaround { } class PointerBinding { + PointerBinding(this.glassPaneElement) + : _pointerDataConverter = PointerDataConverter(), + _detector = const PointerSupportDetector() { + if (isIosSafari) { + SafariPointerEventWorkaround.instance.workAroundMissingPointerEvents(); + } + _adapter = _createAdapter(); + } + /// The singleton instance of this object. static PointerBinding? get instance => _instance; static PointerBinding? _instance; @@ -94,19 +103,10 @@ class PointerBinding { _pointerDataConverter.clearPointerState(); } - PointerBinding(this.glassPaneElement) - : _pointerDataConverter = PointerDataConverter(), - _detector = const PointerSupportDetector() { - if (isIosSafari) { - SafariPointerEventWorkaround.instance.workAroundMissingPointerEvents(); - } - _adapter = _createAdapter(); - } - final DomElement glassPaneElement; PointerSupportDetector _detector; - PointerDataConverter _pointerDataConverter; + final PointerDataConverter _pointerDataConverter; late _BaseAdapter _adapter; /// Should be used in tests to define custom detection of pointer support. @@ -245,8 +245,8 @@ abstract class _BaseAdapter { final List<_Listener> _listeners = <_Listener>[]; final DomElement glassPaneElement; - _PointerDataCallback _callback; - PointerDataConverter _pointerDataConverter; + final _PointerDataCallback _callback; + final PointerDataConverter _pointerDataConverter; /// Each subclass is expected to override this method to attach its own event /// listeners and convert events into pointer events. diff --git a/lib/web_ui/lib/src/engine/rrect_renderer.dart b/lib/web_ui/lib/src/engine/rrect_renderer.dart index 829ad367d0bfc..91ead1328414e 100644 --- a/lib/web_ui/lib/src/engine/rrect_renderer.dart +++ b/lib/web_ui/lib/src/engine/rrect_renderer.dart @@ -183,8 +183,8 @@ abstract class RRectRenderer { /// Renders RRect to a 2d canvas. class RRectToCanvasRenderer extends RRectRenderer { - final DomCanvasRenderingContext2D context; RRectToCanvasRenderer(this.context); + final DomCanvasRenderingContext2D context; @override void beginPath() { context.beginPath(); @@ -210,8 +210,8 @@ class RRectToCanvasRenderer extends RRectRenderer { /// Renders RRect to a path. class RRectToPathRenderer extends RRectRenderer { - final ui.Path path; RRectToPathRenderer(this.path); + final ui.Path path; @override void beginPath() {} 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 05c1e691412e4..3029fb06ba566 100644 --- a/lib/web_ui/lib/src/engine/safe_browser_api.dart +++ b/lib/web_ui/lib/src/engine/safe_browser_api.dart @@ -403,12 +403,34 @@ void vertexAttribPointerGlContext( /// Compiled and cached gl program. class GlProgram { - final Object program; GlProgram(this.program); + final Object program; } /// JS Interop helper for webgl apis. class GlContext { + factory GlContext(OffScreenCanvas offScreenCanvas) { + return OffScreenCanvas.supported + ? GlContext._fromOffscreenCanvas(offScreenCanvas.offScreenCanvas!) + : GlContext._fromCanvasElement( + offScreenCanvas.canvasElement!, webGLVersion == WebGLVersion.webgl1); + } + + GlContext._fromOffscreenCanvas(DomOffscreenCanvas canvas) + : glContext = canvas.getContext('webgl2', {'premultipliedAlpha': false})!, + isOffscreen = true { + _programCache = {}; + _canvas = canvas; + } + + GlContext._fromCanvasElement(DomCanvasElement canvas, bool useWebGl1) + : glContext = canvas.getContext(useWebGl1 ? 'webgl' : 'webgl2', + {'premultipliedAlpha': false})!, + isOffscreen = false { + _programCache = {}; + _canvas = canvas; + } + final Object glContext; final bool isOffscreen; Object? _kCompileStatus; @@ -437,28 +459,6 @@ class GlContext { int? _heightInPixels; static late Map _programCache; - factory GlContext(OffScreenCanvas offScreenCanvas) { - return OffScreenCanvas.supported - ? GlContext._fromOffscreenCanvas(offScreenCanvas.offScreenCanvas!) - : GlContext._fromCanvasElement( - offScreenCanvas.canvasElement!, webGLVersion == WebGLVersion.webgl1); - } - - GlContext._fromOffscreenCanvas(DomOffscreenCanvas canvas) - : glContext = canvas.getContext('webgl2', {'premultipliedAlpha': false})!, - isOffscreen = true { - _programCache = {}; - _canvas = canvas; - } - - GlContext._fromCanvasElement(DomCanvasElement canvas, bool useWebGl1) - : glContext = canvas.getContext(useWebGl1 ? 'webgl' : 'webgl2', - {'premultipliedAlpha': false})!, - isOffscreen = false { - _programCache = {}; - _canvas = canvas; - } - void setViewportSize(int width, int height) { _widthInPixels = width; _heightInPixels = height; @@ -949,12 +949,6 @@ dynamic tileModeToGlWrapping(GlContext gl, ui.TileMode tileMode) { /// Polyfill for DomOffscreenCanvas that is not supported on some browsers. class OffScreenCanvas { - DomOffscreenCanvas? offScreenCanvas; - DomCanvasElement? canvasElement; - int width; - int height; - static bool? _supported; - OffScreenCanvas(this.width, this.height) { if (OffScreenCanvas.supported) { offScreenCanvas = createDomOffscreenCanvas(width, height); @@ -968,6 +962,12 @@ class OffScreenCanvas { } } + DomOffscreenCanvas? offScreenCanvas; + DomCanvasElement? canvasElement; + int width; + int height; + static bool? _supported; + void _updateCanvasCssSize(DomCanvasElement element) { final double cssWidth = width / EnginePlatformDispatcher.browserDevicePixelRatio; final double cssHeight = height / EnginePlatformDispatcher.browserDevicePixelRatio; diff --git a/lib/web_ui/lib/src/engine/semantics/accessibility.dart b/lib/web_ui/lib/src/engine/semantics/accessibility.dart index abae46b6dd7a5..22d93833b8ec8 100644 --- a/lib/web_ui/lib/src/engine/semantics/accessibility.dart +++ b/lib/web_ui/lib/src/engine/semantics/accessibility.dart @@ -27,6 +27,12 @@ final AccessibilityAnnouncements accessibilityAnnouncements = /// Attaches accessibility announcements coming from the 'flutter/accessibility' /// channel as temporary elements to the DOM. class AccessibilityAnnouncements { + AccessibilityAnnouncements._() { + registerHotRestartListener(() { + _removeElementTimer?.cancel(); + }); + } + /// Initializes the [AccessibilityAnnouncements] singleton if it is not /// already initialized. static AccessibilityAnnouncements get instance { @@ -35,12 +41,6 @@ class AccessibilityAnnouncements { static AccessibilityAnnouncements? _instance; - AccessibilityAnnouncements._() { - registerHotRestartListener(() { - _removeElementTimer?.cancel(); - }); - } - /// Timer that times when the accessibility element should be removed from the /// DOM. /// diff --git a/lib/web_ui/lib/src/engine/semantics/checkable.dart b/lib/web_ui/lib/src/engine/semantics/checkable.dart index 2cb442f205095..a4c7de151c6f6 100644 --- a/lib/web_ui/lib/src/engine/semantics/checkable.dart +++ b/lib/web_ui/lib/src/engine/semantics/checkable.dart @@ -50,12 +50,12 @@ _CheckableKind _checkableKindFromSemanticsFlag( /// [ui.SemanticsFlag.isInMutuallyExclusiveGroup], [ui.SemanticsFlag.isToggled], /// [ui.SemanticsFlag.hasToggledState] class Checkable extends RoleManager { - final _CheckableKind _kind; - Checkable(SemanticsObject semanticsObject) : _kind = _checkableKindFromSemanticsFlag(semanticsObject), super(Role.checkable, semanticsObject); + final _CheckableKind _kind; + @override void update() { if (semanticsObject.isFlagsDirty) { diff --git a/lib/web_ui/lib/src/engine/semantics/incrementable.dart b/lib/web_ui/lib/src/engine/semantics/incrementable.dart index fd777014ed575..6cfeb6c37f80a 100644 --- a/lib/web_ui/lib/src/engine/semantics/incrementable.dart +++ b/lib/web_ui/lib/src/engine/semantics/incrementable.dart @@ -19,30 +19,6 @@ import 'semantics.dart'; /// events. This is to prevent the browser from taking over drag gestures. Drag /// gestures must be interpreted by the Flutter framework. class Incrementable extends RoleManager { - /// The HTML element used to render semantics to the browser. - final DomHTMLInputElement _element = createDomHTMLInputElement(); - - /// The value used by the input element. - /// - /// Flutter values are strings, and are not necessarily numbers. In order to - /// convey to the browser what the available "range" of values is we - /// substitute the framework value with a generated `int` surrogate. - /// "aria-valuetext" attribute is used to cause the browser to announce the - /// framework value to the user. - int _currentSurrogateValue = 1; - - /// Disables the input [_element] when the gesture mode switches to - /// [GestureMode.pointerEvents], and enables it when the mode switches back to - /// [GestureMode.browserGestures]. - GestureModeCallback? _gestureModeListener; - - /// Whether we forwarded a semantics action to the framework and awaiting an - /// update. - /// - /// This field is used to determine whether the HTML DOM of the semantics - /// tree should be updated. - bool _pendingResync = false; - Incrementable(SemanticsObject semanticsObject) : super(Role.incrementable, semanticsObject) { semanticsObject.element.append(_element); @@ -74,6 +50,30 @@ class Incrementable extends RoleManager { semanticsObject.owner.addGestureModeListener(_gestureModeListener); } + /// The HTML element used to render semantics to the browser. + final DomHTMLInputElement _element = createDomHTMLInputElement(); + + /// The value used by the input element. + /// + /// Flutter values are strings, and are not necessarily numbers. In order to + /// convey to the browser what the available "range" of values is we + /// substitute the framework value with a generated `int` surrogate. + /// "aria-valuetext" attribute is used to cause the browser to announce the + /// framework value to the user. + int _currentSurrogateValue = 1; + + /// Disables the input [_element] when the gesture mode switches to + /// [GestureMode.pointerEvents], and enables it when the mode switches back to + /// [GestureMode.browserGestures]. + GestureModeCallback? _gestureModeListener; + + /// Whether we forwarded a semantics action to the framework and awaiting an + /// update. + /// + /// This field is used to determine whether the HTML DOM of the semantics + /// tree should be updated. + bool _pendingResync = false; + @override void update() { switch (semanticsObject.owner.gestureMode) { diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index d19efbe908d48..de91d2a6fa86c 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -1724,7 +1724,7 @@ class EngineSemanticsOwner { /// Callbacks are called synchronously. HTML DOM updates made in a callback /// take effect in the current animation frame and/or the current message loop /// event. - List _gestureModeListeners = []; + final List _gestureModeListeners = []; /// Calls the [callback] every time the current [GestureMode] changes. /// 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 a3502c9cf0035..9aff262f7ea8a 100644 --- a/lib/web_ui/lib/src/engine/semantics/text_field.dart +++ b/lib/web_ui/lib/src/engine/semantics/text_field.dart @@ -21,6 +21,11 @@ import 'semantics.dart'; /// This class is still responsible for hooking up the DOM element with the /// [HybridTextEditing] instance so that changes are communicated to Flutter. class SemanticsTextEditingStrategy extends DefaultTextEditingStrategy { + /// Creates a [SemanticsTextEditingStrategy] that eagerly instantiates + /// [domElement] so the caller can insert it before calling + /// [SemanticsTextEditingStrategy.enable]. + SemanticsTextEditingStrategy(super.owner); + /// Initializes the [SemanticsTextEditingStrategy] singleton. /// /// This method must be called prior to accessing [instance]. @@ -35,11 +40,6 @@ class SemanticsTextEditingStrategy extends DefaultTextEditingStrategy { static SemanticsTextEditingStrategy get instance => _instance!; static SemanticsTextEditingStrategy? _instance; - /// Creates a [SemanticsTextEditingStrategy] that eagerly instantiates - /// [domElement] so the caller can insert it before calling - /// [SemanticsTextEditingStrategy.enable]. - SemanticsTextEditingStrategy(super.owner); - /// The text field whose DOM element is currently used for editing. /// /// If this field is null, no editing takes place. diff --git a/lib/web_ui/lib/src/engine/services/buffers.dart b/lib/web_ui/lib/src/engine/services/buffers.dart index b581dc2111e5d..725ad2a12772f 100644 --- a/lib/web_ui/lib/src/engine/services/buffers.dart +++ b/lib/web_ui/lib/src/engine/services/buffers.dart @@ -6,6 +6,10 @@ import 'dart:collection'; import 'dart:typed_data'; abstract class _TypedDataBuffer extends ListBase { + _TypedDataBuffer(List buffer) + : _buffer = buffer, + _length = buffer.length; + static const int _initialLength = 8; /// The underlying data buffer. @@ -20,10 +24,6 @@ abstract class _TypedDataBuffer extends ListBase { /// The length of the list being built. int _length; - _TypedDataBuffer(List buffer) - : _buffer = buffer, - _length = buffer.length; - @override int get length => _length; diff --git a/lib/web_ui/lib/src/engine/services/message_codecs.dart b/lib/web_ui/lib/src/engine/services/message_codecs.dart index 7beefc5f9d2b2..dc6a221119efd 100644 --- a/lib/web_ui/lib/src/engine/services/message_codecs.dart +++ b/lib/web_ui/lib/src/engine/services/message_codecs.dart @@ -212,6 +212,9 @@ class JSONMethodCodec implements MethodCodec { /// The codec is extensible by subclasses overriding [writeValue] and /// [readValueOfType]. class StandardMessageCodec implements MessageCodec { + /// Creates a [MessageCodec] using the Flutter standard binary encoding. + const StandardMessageCodec(); + // The codec serializes messages as outlined below. This format must // match the Android and iOS counterparts. // @@ -264,9 +267,6 @@ class StandardMessageCodec implements MessageCodec { static const int _valueList = 12; static const int _valueMap = 13; - /// Creates a [MessageCodec] using the Flutter standard binary encoding. - const StandardMessageCodec(); - @override ByteData? encodeMessage(dynamic message) { if (message == null) { diff --git a/lib/web_ui/lib/src/engine/test_embedding.dart b/lib/web_ui/lib/src/engine/test_embedding.dart index 5d86744a0086b..8f28532a50539 100644 --- a/lib/web_ui/lib/src/engine/test_embedding.dart +++ b/lib/web_ui/lib/src/engine/test_embedding.dart @@ -37,12 +37,12 @@ Future initializeTestFlutterViewEmbedder({double devicePixelRatio = 3.0}) const bool _debugLogHistoryActions = false; class TestHistoryEntry { + const TestHistoryEntry(this.state, this.title, this.url); + final dynamic state; final String? title; final String url; - const TestHistoryEntry(this.state, this.title, this.url); - @override String toString() { return '$runtimeType(state:$state, title:"$title", url:"$url")'; diff --git a/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart b/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart index 10a102ce161b9..4b35410321ef1 100644 --- a/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart +++ b/lib/web_ui/lib/src/engine/text/canvas_paragraph.dart @@ -567,7 +567,7 @@ class CanvasParagraphBuilder implements ui.ParagraphBuilder { final List _spans = []; final List _styleStack = []; - RootStyleNode _rootStyleNode; + final RootStyleNode _rootStyleNode; StyleNode get _currentStyleNode => _styleStack.isEmpty ? _rootStyleNode : _styleStack[_styleStack.length - 1]; diff --git a/lib/web_ui/lib/src/engine/text/font_collection.dart b/lib/web_ui/lib/src/engine/text/font_collection.dart index 04c856edf50de..8eda9e38319ad 100644 --- a/lib/web_ui/lib/src/engine/text/font_collection.dart +++ b/lib/web_ui/lib/src/engine/text/font_collection.dart @@ -112,6 +112,16 @@ class FontCollection { /// Manages a collection of fonts and ensures they are loaded. class FontManager { + factory FontManager() { + if (supportsFontLoadingApi) { + return FontManager._(); + } else { + return _PolyfillFontManager(); + } + } + + FontManager._(); + final List> _fontLoadingFutures = >[]; // Regular expression to detect a string with no punctuations. @@ -124,16 +134,6 @@ class FontManager { // category. static final RegExp startWithDigit = RegExp(r'\b\d'); - factory FontManager() { - if (supportsFontLoadingApi) { - return FontManager._(); - } else { - return _PolyfillFontManager(); - } - } - - FontManager._(); - /// Registers assets to Flutter Web Engine. /// /// Browsers and browsers versions differ significantly on how a valid font diff --git a/lib/web_ui/lib/src/engine/text/layout_service.dart b/lib/web_ui/lib/src/engine/text/layout_service.dart index 721caef1e8b5d..a5b91bd016cd7 100644 --- a/lib/web_ui/lib/src/engine/text/layout_service.dart +++ b/lib/web_ui/lib/src/engine/text/layout_service.dart @@ -1582,9 +1582,9 @@ class Spanometer { final CanvasParagraph paragraph; final DomCanvasRenderingContext2D context; - static RulerHost _rulerHost = RulerHost(); + static final RulerHost _rulerHost = RulerHost(); - static Map _rulers = + static final Map _rulers = {}; @visibleForTesting diff --git a/lib/web_ui/lib/src/engine/text/word_breaker.dart b/lib/web_ui/lib/src/engine/text/word_breaker.dart index c90e5d45dcf8e..1e4fd51920006 100644 --- a/lib/web_ui/lib/src/engine/text/word_breaker.dart +++ b/lib/web_ui/lib/src/engine/text/word_breaker.dart @@ -6,11 +6,11 @@ import '../util.dart'; import 'word_break_properties.dart'; class _FindBreakDirection { + const _FindBreakDirection({required this.step}); + static const _FindBreakDirection forward = _FindBreakDirection(step: 1); static const _FindBreakDirection backward = _FindBreakDirection(step: -1); - const _FindBreakDirection({required this.step}); - final int step; } diff --git a/lib/web_ui/lib/src/engine/text_editing/autofill_hint.dart b/lib/web_ui/lib/src/engine/text_editing/autofill_hint.dart index 3059f63ee110a..7ee1cfb732431 100644 --- a/lib/web_ui/lib/src/engine/text_editing/autofill_hint.dart +++ b/lib/web_ui/lib/src/engine/text_editing/autofill_hint.dart @@ -7,14 +7,6 @@ /// See: https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/services/autofill.dart /// See: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete class BrowserAutofillHints { - static final BrowserAutofillHints _singletonInstance = - BrowserAutofillHints._(); - - /// The [BrowserAutofillHints] singleton. - static BrowserAutofillHints get instance => _singletonInstance; - - final Map _flutterToEngineMap; - BrowserAutofillHints._() : _flutterToEngineMap = { 'birthday': 'bday', @@ -73,6 +65,14 @@ class BrowserAutofillHints { 'username': 'username', }; + static final BrowserAutofillHints _singletonInstance = + BrowserAutofillHints._(); + + /// The [BrowserAutofillHints] singleton. + static BrowserAutofillHints get instance => _singletonInstance; + + final Map _flutterToEngineMap; + /// Converts the Flutter AutofillHint to the autofill hint value used by the /// browsers. /// See: https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/services/autofill.dart diff --git a/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart b/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart index f6204578d98fe..b871b737d7e7f 100644 --- a/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart +++ b/lib/web_ui/lib/src/engine/text_editing/text_capitalization.dart @@ -32,8 +32,6 @@ enum TextCapitalization { /// See: https://developers.google.com/web/updates/2015/04/autocapitalize /// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autocapitalize class TextCapitalizationConfig { - final TextCapitalization textCapitalization; - const TextCapitalizationConfig.defaultCapitalization() : textCapitalization = TextCapitalization.none; @@ -47,6 +45,8 @@ class TextCapitalizationConfig { ? TextCapitalization.sentences : TextCapitalization.none; + final TextCapitalization textCapitalization; + /// Sets `autocapitalize` attribute on input elements. /// /// This attribute is only available for mobile browsers. 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 5c09019cd61be..4b4b227eada63 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 @@ -352,6 +352,24 @@ class AutofillInfo { this.placeholder, }); + factory AutofillInfo.fromFrameworkMessage(Map autofill, + {TextCapitalizationConfig textCapitalization = + const TextCapitalizationConfig.defaultCapitalization()}) { + assert(autofill != null); // ignore: unnecessary_null_comparison + final String uniqueIdentifier = autofill.readString('uniqueIdentifier'); + final List? hintsList = autofill.tryList('hints'); + final String? firstHint = (hintsList == null || hintsList.isEmpty) ? null : hintsList.first as String; + final EditingState editingState = + EditingState.fromFrameworkMessage(autofill.readJson('editingValue')); + return AutofillInfo( + uniqueIdentifier: uniqueIdentifier, + autofillHint: (firstHint != null) ? BrowserAutofillHints.instance.flutterToEngine(firstHint) : null, + editingState: editingState, + placeholder: autofill.tryString('hintText'), + textCapitalization: textCapitalization, + ); + } + /// The current text and selection state of a text field. final EditingState editingState; @@ -390,24 +408,6 @@ class AutofillInfo { /// information is expected in this field. final String? placeholder; - factory AutofillInfo.fromFrameworkMessage(Map autofill, - {TextCapitalizationConfig textCapitalization = - const TextCapitalizationConfig.defaultCapitalization()}) { - assert(autofill != null); // ignore: unnecessary_null_comparison - final String uniqueIdentifier = autofill.readString('uniqueIdentifier'); - final List? hintsList = autofill.tryList('hints'); - final String? firstHint = (hintsList == null || hintsList.isEmpty) ? null : hintsList.first as String; - final EditingState editingState = - EditingState.fromFrameworkMessage(autofill.readJson('editingValue')); - return AutofillInfo( - uniqueIdentifier: uniqueIdentifier, - autofillHint: (firstHint != null) ? BrowserAutofillHints.instance.flutterToEngine(firstHint) : null, - editingState: editingState, - placeholder: autofill.tryString('hintText'), - textCapitalization: textCapitalization, - ); - } - void applyToDomElement(DomHTMLElement domElement, {bool focusedElement = false}) { final String? autofillHint = this.autofillHint; @@ -1084,10 +1084,10 @@ class SafariDesktopTextEditingStrategy extends DefaultTextEditingStrategy { /// Unless a formfactor/browser requires specific implementation for a specific /// strategy the methods in this class should be used. abstract class DefaultTextEditingStrategy with CompositionAwareMixin implements TextEditingStrategy { - final HybridTextEditing owner; - DefaultTextEditingStrategy(this.owner); + final HybridTextEditing owner; + bool isEnabled = false; /// The DOM element used for editing, if any. diff --git a/lib/web_ui/lib/src/engine/ulps.dart b/lib/web_ui/lib/src/engine/ulps.dart index 10677dc96ba43..65db11f5e7018 100644 --- a/lib/web_ui/lib/src/engine/ulps.dart +++ b/lib/web_ui/lib/src/engine/ulps.dart @@ -48,9 +48,6 @@ int twosComplimentToSignBit(int x) { } class _FloatBitConverter { - final Float32List float32List; - final Int32List int32List; - factory _FloatBitConverter() { final Float32List float32List = Float32List(1); return _FloatBitConverter._( @@ -59,6 +56,9 @@ class _FloatBitConverter { _FloatBitConverter._(this.float32List, this.int32List); + final Float32List float32List; + final Int32List int32List; + int toInt(Float32List source, int index) { float32List[0] = source[index]; return int32List[0]; diff --git a/lib/web_ui/lib/src/engine/vector_math.dart b/lib/web_ui/lib/src/engine/vector_math.dart index 08b708a27fb41..28fb5f70c6000 100644 --- a/lib/web_ui/lib/src/engine/vector_math.dart +++ b/lib/web_ui/lib/src/engine/vector_math.dart @@ -8,41 +8,6 @@ import 'dart:typed_data'; import 'util.dart'; class Matrix4 { - final Float32List _m4storage; - - /// The components of the matrix. - Float32List get storage => _m4storage; - - /// Returns a matrix that is the inverse of [other] if [other] is invertible, - /// otherwise `null`. - static Matrix4? tryInvert(Matrix4 other) { - final Matrix4 r = Matrix4.zero(); - final double determinant = r.copyInverse(other); - if (determinant == 0.0) { - return null; - } - return r; - } - - /// Return index in storage for [row], [col] value. - int index(int row, int col) => (col * 4) + row; - - /// Value at [row], [col]. - double entry(int row, int col) { - assert((row >= 0) && (row < dimension)); - assert((col >= 0) && (col < dimension)); - - return _m4storage[index(row, col)]; - } - - /// Set value at [row], [col] to be [v]. - void setEntry(int row, int col, double v) { - assert((row >= 0) && (row < dimension)); - assert((col >= 0) && (col < dimension)); - - _m4storage[index(row, col)] = v; - } - /// Constructs a new mat4. factory Matrix4( double arg0, @@ -129,6 +94,41 @@ class Matrix4 { Matrix4.fromBuffer(ByteBuffer buffer, int offset) : _m4storage = Float32List.view(buffer, offset, 16); + final Float32List _m4storage; + + /// The components of the matrix. + Float32List get storage => _m4storage; + + /// Returns a matrix that is the inverse of [other] if [other] is invertible, + /// otherwise `null`. + static Matrix4? tryInvert(Matrix4 other) { + final Matrix4 r = Matrix4.zero(); + final double determinant = r.copyInverse(other); + if (determinant == 0.0) { + return null; + } + return r; + } + + /// Return index in storage for [row], [col] value. + int index(int row, int col) => (col * 4) + row; + + /// Value at [row], [col]. + double entry(int row, int col) { + assert((row >= 0) && (row < dimension)); + assert((col >= 0) && (col < dimension)); + + return _m4storage[index(row, col)]; + } + + /// Set value at [row], [col] to be [v]. + void setEntry(int row, int col, double v) { + assert((row >= 0) && (row < dimension)); + assert((col >= 0) && (col < dimension)); + + _m4storage[index(row, col)] = v; + } + /// Sets the matrix with specified values. void setValues( double arg0, @@ -1087,6 +1087,34 @@ class Matrix4 { /// 3D column vector. class Vector3 { + /// Construct a new vector with the specified values. + factory Vector3(double x, double y, double z) => + Vector3.zero()..setValues(x, y, z); + + /// Zero vector. + Vector3.zero() : _v3storage = Float32List(3); + + /// Splat [value] into all lanes of the vector. + factory Vector3.all(double value) => Vector3.zero()..splat(value); + + /// Copy of [other]. + factory Vector3.copy(Vector3 other) => Vector3.zero()..setFrom(other); + + /// Constructs Vector3 with given Float32List as [storage]. + Vector3.fromFloat32List(this._v3storage); + + /// Constructs Vector3 with a [storage] that views given [buffer] starting at + /// [offset]. [offset] has to be multiple of [Float32List.bytesPerElement]. + Vector3.fromBuffer(ByteBuffer buffer, int offset) + : _v3storage = Float32List.view(buffer, offset, 3); + + /// Generate random vector in the range (0, 0, 0) to (1, 1, 1). You can + /// optionally pass your own random number generator. + factory Vector3.random([math.Random? rng]) { + rng ??= math.Random(); + return Vector3(rng.nextDouble(), rng.nextDouble(), rng.nextDouble()); + } + final Float32List _v3storage; /// The components of the vector. @@ -1117,34 +1145,6 @@ class Vector3 { ..z = min.z + a * (max.z - min.z); } - /// Construct a new vector with the specified values. - factory Vector3(double x, double y, double z) => - Vector3.zero()..setValues(x, y, z); - - /// Zero vector. - Vector3.zero() : _v3storage = Float32List(3); - - /// Splat [value] into all lanes of the vector. - factory Vector3.all(double value) => Vector3.zero()..splat(value); - - /// Copy of [other]. - factory Vector3.copy(Vector3 other) => Vector3.zero()..setFrom(other); - - /// Constructs Vector3 with given Float32List as [storage]. - Vector3.fromFloat32List(this._v3storage); - - /// Constructs Vector3 with a [storage] that views given [buffer] starting at - /// [offset]. [offset] has to be multiple of [Float32List.bytesPerElement]. - Vector3.fromBuffer(ByteBuffer buffer, int offset) - : _v3storage = Float32List.view(buffer, offset, 3); - - /// Generate random vector in the range (0, 0, 0) to (1, 1, 1). You can - /// optionally pass your own random number generator. - factory Vector3.random([math.Random? rng]) { - rng ??= math.Random(); - return Vector3(rng.nextDouble(), rng.nextDouble(), rng.nextDouble()); - } - /// Set the values of the vector. void setValues(double x, double y, double z) { _v3storage[0] = x; diff --git a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart index e8cf7cb60d485..c0b731620672d 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -374,10 +374,10 @@ class TestDownloader extends NotoDownloader { } class LoggingDownloader implements NotoDownloader { - final List log = []; - LoggingDownloader(this.delegate); + final List log = []; + final NotoDownloader delegate; @override diff --git a/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart b/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart index 0ba042dc2cc98..4602cc279987f 100644 --- a/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart +++ b/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart @@ -317,8 +317,6 @@ void _tests() { /// /// Can be [clone]d such that the clones share the same ref counted box. class TestBoxWrapper implements StackTraceDebugger { - static int resurrectCount = 0; - TestBoxWrapper() { if (assertionsEnabled) { _debugStackTrace = StackTrace.current; @@ -337,6 +335,8 @@ class TestBoxWrapper implements StackTraceDebugger { box.ref(this); } + static int resurrectCount = 0; + @override StackTrace get debugStackTrace => _debugStackTrace; late StackTrace _debugStackTrace; @@ -393,14 +393,14 @@ class TestJsConstructor implements JsConstructor { } class TestSkiaObject extends ManagedSkiaObject { + TestSkiaObject({this.isExpensive = false}); + int createDefaultCount = 0; int resurrectCount = 0; int deleteCount = 0; final bool isExpensive; - TestSkiaObject({this.isExpensive = false}); - @override SkPaint createDefault() { createDefaultCount++; diff --git a/lib/web_ui/test/engine/frame_reference_test.dart b/lib/web_ui/test/engine/frame_reference_test.dart index e241d62fd38aa..5e3c37ed1bc17 100644 --- a/lib/web_ui/test/engine/frame_reference_test.dart +++ b/lib/web_ui/test/engine/frame_reference_test.dart @@ -75,6 +75,6 @@ void testMain() { } class TestItem { - final String label; TestItem(this.label); + final String label; } diff --git a/lib/web_ui/test/engine/platform_views/message_handler_test.dart b/lib/web_ui/test/engine/platform_views/message_handler_test.dart index 9698a25502ca8..429779ac09a34 100644 --- a/lib/web_ui/test/engine/platform_views/message_handler_test.dart +++ b/lib/web_ui/test/engine/platform_views/message_handler_test.dart @@ -154,7 +154,7 @@ class _FakePlatformViewManager extends PlatformViewManager { _FakePlatformViewManager(void Function(int) clearFunction) : _clearPlatformView = clearFunction; - void Function(int) _clearPlatformView; + final void Function(int) _clearPlatformView; @override void clearPlatformView(int viewId) { diff --git a/lib/web_ui/test/engine/pointer_binding_test.dart b/lib/web_ui/test/engine/pointer_binding_test.dart index f73dd87419a29..6d843e6d0449b 100644 --- a/lib/web_ui/test/engine/pointer_binding_test.dart +++ b/lib/web_ui/test/engine/pointer_binding_test.dart @@ -2497,7 +2497,7 @@ class _TouchEventContext extends _BasicEventContext @override bool get hasMouseEvents => false; - DomEventTarget _target; + final DomEventTarget _target; DomTouch _createTouch({ int? identifier, diff --git a/lib/web_ui/test/engine/semantics/semantics_tester.dart b/lib/web_ui/test/engine/semantics/semantics_tester.dart index 293785d8da313..04d5d19d1ec41 100644 --- a/lib/web_ui/test/engine/semantics/semantics_tester.dart +++ b/lib/web_ui/test/engine/semantics/semantics_tester.dart @@ -380,17 +380,6 @@ DomElement? findScrollable() { /// Logs semantics actions dispatched to [ui.window]. class SemanticsActionLogger { - late StreamController _idLogController; - late StreamController _actionLogController; - - /// Semantics object ids that dispatched the actions. - Stream get idLog => _idLog; - late Stream _idLog; - - /// The actions that were dispatched to [ui.window]. - Stream get actionLog => _actionLog; - late Stream _actionLog; - SemanticsActionLogger() { _idLogController = StreamController(); _actionLogController = StreamController(); @@ -411,4 +400,15 @@ class SemanticsActionLogger { }); }; } + + late StreamController _idLogController; + late StreamController _actionLogController; + + /// Semantics object ids that dispatched the actions. + Stream get idLog => _idLog; + late Stream _idLog; + + /// The actions that were dispatched to [ui.window]. + Stream get actionLog => _actionLog; + late Stream _actionLog; } diff --git a/lib/web_ui/test/engine/surface/path/path_winding_test.dart b/lib/web_ui/test/engine/surface/path/path_winding_test.dart index a6f788a509ca5..6c1dc06169a11 100644 --- a/lib/web_ui/test/engine/surface/path/path_winding_test.dart +++ b/lib/web_ui/test/engine/surface/path/path_winding_test.dart @@ -442,10 +442,10 @@ void testMain() { } class LineTestCase { + LineTestCase(this.pathContent, this.convexity, this.direction); final String pathContent; final int convexity; final int? direction; - LineTestCase(this.pathContent, this.convexity, this.direction); } /// Parses a string of the format "mx my lx1 ly1 lx2 ly2..." into a path diff --git a/lib/web_ui/test/engine/surface/surface_test.dart b/lib/web_ui/test/engine/surface/surface_test.dart index 189b37041f0bc..702ada6b5db38 100644 --- a/lib/web_ui/test/engine/surface/surface_test.dart +++ b/lib/web_ui/test/engine/surface/surface_test.dart @@ -378,10 +378,10 @@ void testMain() { } class _LoggingTestSurface extends PersistedContainerSurface { - final List log = []; - _LoggingTestSurface() : super(null); + final List log = []; + @override void build() { log.add('build'); diff --git a/lib/web_ui/test/html/paragraph/text_scuba.dart b/lib/web_ui/test/html/paragraph/text_scuba.dart index 4a0ccaef76a55..765ce121e1b59 100644 --- a/lib/web_ui/test/html/paragraph/text_scuba.dart +++ b/lib/web_ui/test/html/paragraph/text_scuba.dart @@ -14,11 +14,11 @@ import 'package:web_engine_tester/golden_tester.dart'; /// /// (For Googlers: Not really related with internal Scuba anymore) class EngineScubaTester { + EngineScubaTester(this.viewportSize); + /// The size of the browser window used in this scuba test. final ui.Size viewportSize; - EngineScubaTester(this.viewportSize); - static Future initialize( {ui.Size viewportSize = const ui.Size(2400, 1800)}) async { assert(() { diff --git a/lib/web_ui/test/html/path_to_svg_golden_test.dart b/lib/web_ui/test/html/path_to_svg_golden_test.dart index 41e02c915c557..5dae71c1984ae 100644 --- a/lib/web_ui/test/html/path_to_svg_golden_test.dart +++ b/lib/web_ui/test/html/path_to_svg_golden_test.dart @@ -210,14 +210,14 @@ DomElement pathToSvgElement(Path path, Paint paint, bool enableFill) { } class ArcSample { + ArcSample(this.offset, + {this.largeArc = false, this.clockwise = false, this.distance = 0}); + final Offset offset; final bool largeArc; final bool clockwise; final double distance; - ArcSample(this.offset, - {this.largeArc = false, this.clockwise = false, this.distance = 0}); - Path createPath() { final Offset startP = Offset(75 - distance + offset.dx, 75 - distance + offset.dy); diff --git a/lib/web_ui/test/mock_engine_canvas.dart b/lib/web_ui/test/mock_engine_canvas.dart index 39eb200081981..59c4c81680372 100644 --- a/lib/web_ui/test/mock_engine_canvas.dart +++ b/lib/web_ui/test/mock_engine_canvas.dart @@ -34,7 +34,7 @@ class MockEngineCanvas implements EngineCanvas { @override DomElement get rootElement => _rootElement; - DomElement _rootElement = createDomHTMLDivElement(); + final DomElement _rootElement = createDomHTMLDivElement(); void _called(String methodName, {dynamic arguments}) { methodCallLog.add(MockCanvasCall._( diff --git a/testing/scenario_app/lib/src/touches_scenario.dart b/testing/scenario_app/lib/src/touches_scenario.dart index a20355108764e..4b289d2af41c2 100644 --- a/testing/scenario_app/lib/src/touches_scenario.dart +++ b/testing/scenario_app/lib/src/touches_scenario.dart @@ -9,12 +9,12 @@ import 'scenario.dart'; /// A scenario that sends back messages when touches are received. class TouchesScenario extends Scenario { - final Map _knownDevices = {}; - int _sequenceNo = 0; - /// Constructor for `TouchesScenario`. TouchesScenario(PlatformDispatcher dispatcher) : super(dispatcher); + final Map _knownDevices = {}; + int _sequenceNo = 0; + @override void onBeginFrame(Duration duration) { // It is necessary to render frames for touch events to work properly on iOS From 978d8e2dbe352901afc2777be7eb6e971565c5fc Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Tue, 2 Aug 2022 10:06:04 -0700 Subject: [PATCH 045/558] Remove ffi_native_unexpected_number_of_parameters ignore (#35093) --- analysis_options.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index a6c3786733025..de29de16689b8 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -14,8 +14,6 @@ analyzer: deprecated_member_use_from_same_package: ignore # Turned off until null-safe rollout is complete. unnecessary_null_comparison: ignore - # TODO(goderbauer): remove when https://github.com/dart-lang/sdk/issues/49563 is fixed. - ffi_native_unexpected_number_of_parameters: ignore # DIFFERENT FROM FLUTTER/FLUTTER exclude: # DIFFERENT FROM FLUTTER/FLUTTER # Fixture depends on dart:ui and raises false positives. - flutter_frontend_server/test/fixtures/lib/main.dart From 9bf295c777ad20cb6daa5ee9859b68b70284688d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 13:14:06 -0400 Subject: [PATCH 046/558] Roll Dart SDK from d2452b2c8380 to 9b8f6f48deb7 (1 revision) (#35094) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 87101bde5a6d7..20cd61ae1515f 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'd2452b2c8380b32be5539429908949901b1b0628', + 'dart_revision': '9b8f6f48deb701f15a8a190953b17d6e77b1d0c7', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 93ef6b1adca965cdddc624f6fbe8af1932381373 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 13:32:04 -0400 Subject: [PATCH 047/558] Roll Skia from ae50bb0abc7b to df16e5713326 (4 revisions) (#35095) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 20cd61ae1515f..092c06e0461a7 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': 'ae50bb0abc7b6efb5e14fcf761eaf9b4a7e1f2de', + 'skia_revision': 'df16e5713326301bf47952e29fed3ff175929b30', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index e2565544d5604..0252fac8745d0 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 8e06edb0dc21640d00a05e5a9f5be097 +Signature: c94e796c85e69ba0fe547921f7df9858 UNUSED LICENSES: From ffac56a7898b7b63cdff81b77a32c1173e03929b Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Tue, 2 Aug 2022 14:01:05 -0400 Subject: [PATCH 048/558] [Impeller] [Vulkan] Generate descriptor set layouts in backend agnostic way (#35091) --- ci/licenses_golden/licenses_flutter | 1 + impeller/compiler/code_gen_template.h | 30 +++++++++++------------ impeller/renderer/BUILD.gn | 1 + impeller/renderer/descriptor_set_layout.h | 27 ++++++++++++++++++++ impeller/renderer/pipeline_builder.h | 7 ++++++ impeller/renderer/vertex_descriptor.cc | 15 ++++++++++++ impeller/renderer/vertex_descriptor.h | 13 ++++++++++ 7 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 impeller/renderer/descriptor_set_layout.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e4550afff2c17..1e5fa58c911ea 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -800,6 +800,7 @@ FILE: ../../../flutter/impeller/renderer/command_buffer.cc FILE: ../../../flutter/impeller/renderer/command_buffer.h FILE: ../../../flutter/impeller/renderer/context.cc FILE: ../../../flutter/impeller/renderer/context.h +FILE: ../../../flutter/impeller/renderer/descriptor_set_layout.h FILE: ../../../flutter/impeller/renderer/device_buffer.cc FILE: ../../../flutter/impeller/renderer/device_buffer.h FILE: ../../../flutter/impeller/renderer/device_buffer_unittests.cc diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index 4a061fcadb5ad..7769f02779524 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -16,15 +16,17 @@ constexpr std::string_view kReflectionHeaderTemplate = {# Note: The nogncheck decorations are only to make GN not mad at the template#} {# this file is generated from. There are no GN rule violations in the generated#} {# file itself and the no-check declarations will be stripped in generated files.#} -#include "impeller/renderer/buffer_view.h" {# // nogncheck #} +#include "impeller/renderer/buffer_view.h" {# // nogncheck #} -#include "impeller/renderer/command.h" {# // nogncheck #} +#include "impeller/renderer/command.h" {# // nogncheck #} -#include "impeller/renderer/sampler.h" {# // nogncheck #} +#include "impeller/renderer/descriptor_set_layout.h" {# // nogncheck #} -#include "impeller/renderer/shader_types.h" {# // nogncheck #} +#include "impeller/renderer/sampler.h" {# // nogncheck #} -#include "impeller/renderer/texture.h" {# // nogncheck #} +#include "impeller/renderer/shader_types.h" {# // nogncheck #} + +#include "impeller/renderer/texture.h" {# // nogncheck #} namespace impeller { @@ -150,30 +152,26 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} // =========================================================================== // Metadata for Vulkan ======================================================= // =========================================================================== -#ifdef IMPELLER_ENABLE_VULKAN_REFLECTION {% if length(buffers)+length(sampled_images) > 0 %} - static constexpr std::array kDescriptorSetLayouts{ + static constexpr std::array kDescriptorSetLayouts{ {% for buffer in buffers %} - VkDescriptorSetLayoutBinding{ + DescriptorSetLayout{ {{buffer.binding}}, // binding = {{buffer.binding}} - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // descriptorType = Uniform Buffer + DescriptorType::kUniformBuffer, // descriptorType = Uniform Buffer 1, // descriptorCount = 1 - {{to_vk_shader_stage_flag_bits(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} - nullptr, // pImmutableSamplers = NULL + {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} }, {% endfor %} {% for sampled_image in sampled_images %} - VkDescriptorSetLayoutBinding{ + DescriptorSetLayout{ {{sampled_image.binding}}, // binding = {{sampled_image.binding}} - VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, // descriptorType = Sampled Image + DescriptorType::kSampledImage, // descriptorType = Sampled Image 1, // descriptorCount = 1 - {{to_vk_shader_stage_flag_bits(shader_stage)}},// stageFlags = {{to_shader_stage(shader_stage)}} - nullptr, // pImmutableSamplers = NULL + {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} }, {% endfor %} }; {% endif %} -#endif }; // struct {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn index 9223f4646fb5f..460502c838a61 100644 --- a/impeller/renderer/BUILD.gn +++ b/impeller/renderer/BUILD.gn @@ -22,6 +22,7 @@ impeller_component("renderer") { "command_buffer.h", "context.cc", "context.h", + "descriptor_set_layout.h", "device_buffer.cc", "device_buffer.h", "formats.cc", diff --git a/impeller/renderer/descriptor_set_layout.h b/impeller/renderer/descriptor_set_layout.h new file mode 100644 index 0000000000000..d853f0a663086 --- /dev/null +++ b/impeller/renderer/descriptor_set_layout.h @@ -0,0 +1,27 @@ +// 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/fml/macros.h" +#include "impeller/renderer/shader_types.h" + +namespace impeller { + +enum class DescriptorType { + kSampledImage, + kUniformBuffer, +}; + +struct DescriptorSetLayout { + uint32_t binding; + DescriptorType descriptor_type; + uint32_t descriptor_count; + ShaderStage shader_stage; +}; + +} // namespace impeller diff --git a/impeller/renderer/pipeline_builder.h b/impeller/renderer/pipeline_builder.h index 44cd202997cd9..92def4e50b7ea 100644 --- a/impeller/renderer/pipeline_builder.h +++ b/impeller/renderer/pipeline_builder.h @@ -93,6 +93,13 @@ struct PipelineBuilder { << VertexShader::kLabel << "'."; return false; } + if (!vertex_descriptor->SetDescriptorSetLayouts( + VertexShader::kDescriptorSetLayouts)) { + VALIDATION_LOG << "Cound not configure vertex descriptor set layout for" + " pipeline named '" + << VertexShader::kLabel << "'."; + return false; + } desc.SetVertexDescriptor(std::move(vertex_descriptor)); } diff --git a/impeller/renderer/vertex_descriptor.cc b/impeller/renderer/vertex_descriptor.cc index a40efb31c5eb3..963a7478a1696 100644 --- a/impeller/renderer/vertex_descriptor.cc +++ b/impeller/renderer/vertex_descriptor.cc @@ -20,6 +20,16 @@ bool VertexDescriptor::SetStageInputs( return true; } +bool VertexDescriptor::SetDescriptorSetLayouts( + const DescriptorSetLayout desc_set_layout[], + size_t count) { + desc_set_layouts_.reserve(desc_set_layouts_.size() + count); + for (size_t i = 0; i < count; i++) { + desc_set_layouts_.emplace_back(desc_set_layout[i]); + } + return true; +} + // |Comparable| size_t VertexDescriptor::GetHash() const { auto seed = fml::HashCombine(); @@ -38,4 +48,9 @@ const std::vector& VertexDescriptor::GetStageInputs() const { return inputs_; } +const std::vector& +VertexDescriptor::GetDescriptorSetLayouts() const { + return desc_set_layouts_; +} + } // namespace impeller diff --git a/impeller/renderer/vertex_descriptor.h b/impeller/renderer/vertex_descriptor.h index 4bef9b86d3644..dffe6694f7caf 100644 --- a/impeller/renderer/vertex_descriptor.h +++ b/impeller/renderer/vertex_descriptor.h @@ -8,6 +8,7 @@ #include "flutter/fml/macros.h" #include "impeller/base/comparable.h" +#include "impeller/renderer/descriptor_set_layout.h" #include "impeller/renderer/shader_types.h" namespace impeller { @@ -36,11 +37,22 @@ class VertexDescriptor final : public Comparable { return SetStageInputs(inputs.data(), inputs.size()); } + template + bool SetDescriptorSetLayouts( + const std::array& inputs) { + return SetDescriptorSetLayouts(inputs.data(), inputs.size()); + } + bool SetStageInputs(const ShaderStageIOSlot* const stage_inputs[], size_t count); + bool SetDescriptorSetLayouts(const DescriptorSetLayout desc_set_layout[], + size_t count); + const std::vector& GetStageInputs() const; + const std::vector& GetDescriptorSetLayouts() const; + // |Comparable| std::size_t GetHash() const override; @@ -49,6 +61,7 @@ class VertexDescriptor final : public Comparable { private: std::vector inputs_; + std::vector desc_set_layouts_; FML_DISALLOW_COPY_AND_ASSIGN(VertexDescriptor); }; From 2b3173254281a04500b6004b137d7932af8da793 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Tue, 2 Aug 2022 11:13:04 -0700 Subject: [PATCH 049/558] Zip the dsym artifacts. (#35075) --- sky/tools/create_macos_framework.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sky/tools/create_macos_framework.py b/sky/tools/create_macos_framework.py index 42380f97aa42a..c34e20216ca1d 100755 --- a/sky/tools/create_macos_framework.py +++ b/sky/tools/create_macos_framework.py @@ -101,6 +101,11 @@ def process_framework(dst, args, fat_framework, fat_framework_binary): if args.dsym: dsym_out = os.path.splitext(fat_framework)[0] + '.dSYM' subprocess.check_call([DSYMUTIL, '-o', dsym_out, fat_framework_binary]) + subprocess.check_call([ + 'zip', '-r', + '%s/FlutterMacOS.dSYM.zip' % dst, + '%s/FlutterMacOS.dSYM/Contents' % dst + ]) if args.strip: # copy unstripped From 4e9c8699468a65673cb53584d8b84c4d3acb12eb Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 14:54:06 -0400 Subject: [PATCH 050/558] Roll Skia from df16e5713326 to 360d91b10367 (1 revision) (#35097) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 092c06e0461a7..026bf23cc410f 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': 'df16e5713326301bf47952e29fed3ff175929b30', + 'skia_revision': '360d91b103671a200eb263c2012d2b38d991080b', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 0252fac8745d0..648252f8d22a2 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: c94e796c85e69ba0fe547921f7df9858 +Signature: 04fd0ca804f277b75532089b7e405272 UNUSED LICENSES: From d10f57b5d9addaf06106ede5e2111bd8e1b5ea03 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 16:03:05 -0400 Subject: [PATCH 051/558] Roll Skia from 360d91b10367 to 22213f9acc3e (3 revisions) (#35099) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 026bf23cc410f..67d235f5bd469 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': '360d91b103671a200eb263c2012d2b38d991080b', + 'skia_revision': '22213f9acc3e0cdbd5df9c6ae571b2dd741f41fd', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 648252f8d22a2..cb4672d9812f9 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 04fd0ca804f277b75532089b7e405272 +Signature: afc2a3cbe7fcd52521b164b5b37b0665 UNUSED LICENSES: From 6724561b1cf461cee82d2b0c086184cc59cae30a Mon Sep 17 00:00:00 2001 From: godofredoc Date: Tue, 2 Aug 2022 13:21:04 -0700 Subject: [PATCH 052/558] Update the mac_host_engine configuration. (#35096) --- ci/builders/mac_host_engine.json | 35 ++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/ci/builders/mac_host_engine.json b/ci/builders/mac_host_engine.json index e0c92f24639b7..e6ee65774f537 100644 --- a/ci/builders/mac_host_engine.json +++ b/ci/builders/mac_host_engine.json @@ -172,7 +172,8 @@ "config": "mac_debug_arm64", "targets": [ "flutter/build/archives:dart_sdk_archive", - "flutter/build/archives:archive_gen_snapshot" + "flutter/build/archives:archive_gen_snapshot", + "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework" ] }, "tests": [] @@ -208,7 +209,8 @@ "ninja": { "config": "mac_profile_arm64", "targets": [ - "flutter/build/archives:archive_gen_snapshot" + "flutter/build/archives:archive_gen_snapshot", + "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework" ] }, "tests": [] @@ -244,11 +246,36 @@ "ninja": { "config": "mac_release_arm64", "targets": [ - "flutter/build/archives:archive_gen_snapshot" + "flutter/build/archives:archive_gen_snapshot", + "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework" ] }, "tests": [] } ], - "tests": [] + "tests": [], + "generators": { + "tasks": [ + { + "name": "Release-FlutterMacOS.framework", + "parameters": [ + "--dst", + "out/release", + "--arm64-out-dir", + "out/mac_release_arm64", + "--x64-out-dir", + "out/host_release", + "--dsym", + "--strip" + ], + "script": "flutter/sky/tools/create_macos_framework.py" + } + ] + }, + "archives": [ + { + "source": "out/release/FlutterMacOS.dSYM.zip", + "destination": "darwin-x64-release/FlutterMacOS.dSYM.zip" + } + ] } From 90e240eeafa194b2baa96451feb9c2af011e5a8c Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Tue, 2 Aug 2022 13:46:29 -0700 Subject: [PATCH 053/558] Remove architecture restriction from //flutter/testing:opengl. (#35098) Cf. 08416ceee0699b38874a13bb4539f97dfce6d566. Bug: https://github.com/flutter/flutter/issues/90425 Bug: https://github.com/flutter/flutter/issues/103386 --- shell/common/BUILD.gn | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 22bde213f94cb..40320c9c76c67 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -229,16 +229,13 @@ if (enable_unittests) { ":shell_unittests_gpu_configuration_config", ] - # SwiftShader only supports x86/x86_64 - if (target_cpu == "x86" || target_cpu == "x64") { - if (test_enable_gl) { - sources += [ - "shell_test_platform_view_gl.cc", - "shell_test_platform_view_gl.h", - ] - - public_deps += [ "//flutter/testing:opengl" ] - } + if (test_enable_gl) { + sources += [ + "shell_test_platform_view_gl.cc", + "shell_test_platform_view_gl.h", + ] + + public_deps += [ "//flutter/testing:opengl" ] } if (test_enable_vulkan) { From ae0513e6cae869d5550b8fa41ffa741701f63028 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Tue, 2 Aug 2022 13:52:44 -0700 Subject: [PATCH 054/558] fix noop toString() diagnostics (#35100) --- lib/web_ui/dev/create_simulator.dart | 2 +- lib/web_ui/dev/utils.dart | 2 +- lib/web_ui/test/text/line_breaker_test.dart | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/web_ui/dev/create_simulator.dart b/lib/web_ui/dev/create_simulator.dart index 85fd076c4d6ed..0ec86fd8f5455 100644 --- a/lib/web_ui/dev/create_simulator.dart +++ b/lib/web_ui/dev/create_simulator.dart @@ -27,7 +27,7 @@ class CreateSimulatorCommand extends Command with ArgUtils { lock.minorVersion, lock.device, ); - print('INFO: Simulator created ${simulator.toString()}'); + print('INFO: Simulator created $simulator'); } catch (e) { throw Exception('Error creating requested simulator. You can use Xcode ' 'to install more versions: XCode > Preferences > Components.' diff --git a/lib/web_ui/dev/utils.dart b/lib/web_ui/dev/utils.dart index 0986178e421dd..21c580e9c1ae5 100644 --- a/lib/web_ui/dev/utils.dart +++ b/lib/web_ui/dev/utils.dart @@ -276,7 +276,7 @@ Future runFlutter( if (exitCode != 0) { throw ToolExit( 'ERROR: Failed to run $executable with ' - 'arguments ${arguments.toString()}. Exited with exit code $exitCode', + 'arguments $arguments. Exited with exit code $exitCode', exitCode: exitCode, ); } diff --git a/lib/web_ui/test/text/line_breaker_test.dart b/lib/web_ui/test/text/line_breaker_test.dart index c5c6b6083875e..3b218552b829e 100644 --- a/lib/web_ui/test/text/line_breaker_test.dart +++ b/lib/web_ui/test/text/line_breaker_test.dart @@ -263,7 +263,7 @@ void testMain() { result.index, i, reason: 'Failed at test case number $t:\n' - '${testCase.toString()}\n' + '$testCase\n' '"$text"\n' '\nExpected line break at {$lastLineBreak - $i} but found line break at {$lastLineBreak - ${result.index}}.', ); @@ -283,7 +283,7 @@ void testMain() { result.index, greaterThan(i), reason: 'Failed at test case number $t:\n' - '${testCase.toString()}\n' + '$testCase\n' '"$text"\n' '\nUnexpected line break found at {$lastLineBreak - ${result.index}}.', ); From 30b65ce27c5ef148079b9ae2422354f89a662ca6 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 17:08:04 -0400 Subject: [PATCH 055/558] Roll Skia from 22213f9acc3e to cc10167ac573 (6 revisions) (#35103) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/DEPS b/DEPS index 67d235f5bd469..fcec64689f5ee 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': '22213f9acc3e0cdbd5df9c6ae571b2dd741f41fd', + 'skia_revision': 'cc10167ac5738e479e7b73a2863bb7ed38b2b6c7', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index cb4672d9812f9..11bf2e2c12d2b 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: afc2a3cbe7fcd52521b164b5b37b0665 +Signature: f5c1e8d7b1143c1dbd13f29a1fd691cb UNUSED LICENSES: @@ -2929,8 +2929,6 @@ FILE: ../../../third_party/skia/src/core/SkFontMgr.cpp FILE: ../../../third_party/skia/src/core/SkLatticeIter.cpp FILE: ../../../third_party/skia/src/core/SkLatticeIter.h FILE: ../../../third_party/skia/src/core/SkLocalMatrixImageFilter.cpp -FILE: ../../../third_party/skia/src/core/SkMiniRecorder.cpp -FILE: ../../../third_party/skia/src/core/SkMiniRecorder.h FILE: ../../../third_party/skia/src/core/SkMipmapAccessor.cpp FILE: ../../../third_party/skia/src/core/SkMipmapAccessor.h FILE: ../../../third_party/skia/src/core/SkNextID.h @@ -2938,7 +2936,6 @@ FILE: ../../../third_party/skia/src/core/SkOpts.cpp FILE: ../../../third_party/skia/src/core/SkOpts.h FILE: ../../../third_party/skia/src/core/SkPathBuilder.cpp FILE: ../../../third_party/skia/src/core/SkPathPriv.h -FILE: ../../../third_party/skia/src/core/SkPictureCommon.h FILE: ../../../third_party/skia/src/core/SkPictureImageGenerator.cpp FILE: ../../../third_party/skia/src/core/SkPixmap.cpp FILE: ../../../third_party/skia/src/core/SkPixmapPriv.h From 457a9de9f48b93bf00566279b40859b082b7d050 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 17:11:04 -0400 Subject: [PATCH 056/558] Roll Fuchsia Linux SDK from u_FbFbg2m... to ERGTYC7pf... (#35101) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index fcec64689f5ee..9f111893248d7 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'u_FbFbg2malEPTqZZDE26AOs7L68HUcRat50mggUEV4C' + 'version': 'ERGTYC7pfsifuKhgfWttuibiwb2UJRhNVg1Inlkxua4C' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index ff5b7dfed5f08..0df30332c5847 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 754f3f7f9e82cf0a98d522c9b12eee0c +Signature: 9065b2f06a72e54172d3df5edbb553d8 UNUSED LICENSES: From 73805c57ed5ae5191b262c3f4925512924d7bfc5 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 17:29:04 -0400 Subject: [PATCH 057/558] Roll Dart SDK from 9b8f6f48deb7 to b2093ad90d66 (1 revision) (#35102) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 9f111893248d7..c96f3f92c4dc4 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '9b8f6f48deb701f15a8a190953b17d6e77b1d0c7', + 'dart_revision': 'b2093ad90d6694b4b27bf6bb7362879b10a28d6f', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 59afec6019a99fbe72470b5129f872bace3953ac Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Tue, 2 Aug 2022 14:51:04 -0700 Subject: [PATCH 058/558] Delete splash screen guidance with old APIs (#35014) --- .../embedding/android/FlutterActivity.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java index 4d16a2ddab38d..13137ebf7dd7b 100644 --- a/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java +++ b/shell/platform/android/io/flutter/embedding/android/FlutterActivity.java @@ -164,12 +164,14 @@ * *

Launch Screen and Splash Screen * - *

{@code FlutterActivity} supports the display of an Android "launch screen" as well as a - * Flutter-specific "splash screen". The launch screen is displayed while the Android application - * loads. It is only applicable if {@code FlutterActivity} is the first {@code Activity} displayed - * upon loading the app. After the launch screen passes, a splash screen is optionally displayed. - * The splash screen is displayed for as long as it takes Flutter to initialize and render its first - * frame. + *

{@code FlutterActivity} supports the display of an Android "launch screen", which is displayed + * while the Android application loads. It is only applicable if {@code FlutterActivity} is the + * first {@code Activity} displayed upon loading the app. + * + *

Prior to Flutter 2.5, {@code FlutterActivity} supported the display of a Flutter-specific + * "splash screen" that would be displayed after the launch screen passes. This has since been + * deprecated. If a launch screen is specified, it will automatically persist for as long as it + * takes Flutter to initialize and render its first frame. * *

Use Android themes to display a launch screen. Create two themes: a launch theme and a normal * theme. In the launch theme, set {@code windowBackground} to the desired {@code Drawable} for the @@ -198,13 +200,6 @@ * initialization, subclass {@code FlutterActivity} and override {@link #provideSplashScreen()}. See * {@link SplashScreen} for details on implementing a splash screen. * - *

Flutter ships with a splash screen that automatically displays the exact same {@code - * windowBackground} as the launch theme discussed previously. To use that splash screen, include - * the following metadata in AndroidManifest.xml for this {@code FlutterActivity}: - * - *

{@code } - * *

Alternative Activity {@link FlutterFragmentActivity} is also available, which * is similar to {@code FlutterActivity} but it extends {@code FragmentActivity}. You should use * {@code FlutterActivity}, if possible, but if you need a {@code FragmentActivity} then you should From 4cc5ad0b7e3c1fe9d19d2621559786ceac9302b7 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 2 Aug 2022 15:07:23 -0700 Subject: [PATCH 059/558] [Impeller] Add Rect::GetPositive (#35083) --- impeller/geometry/geometry_unittests.cc | 14 ++++++++++++++ impeller/geometry/rect.h | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 31e876d9b81c4..c2b10a32d6798 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -1049,6 +1049,20 @@ TEST(GeometryTest, RectMakePointBounds) { } } +TEST(GeometryTest, RectGetPositive) { + { + Rect r{100, 200, 300, 400}; + auto actual = r.GetPositive(); + ASSERT_RECT_NEAR(r, actual); + } + { + Rect r{100, 200, -100, -100}; + auto actual = r.GetPositive(); + Rect expected(0, 100, 100, 100); + ASSERT_RECT_NEAR(expected, actual); + } +} + TEST(GeometryTest, CubicPathComponentPolylineDoesNotIncludePointOne) { CubicPathComponent component({10, 10}, {20, 35}, {35, 20}, {40, 40}); SmoothingApproximation approximation; diff --git a/impeller/geometry/rect.h b/impeller/geometry/rect.h index 3165681f898b4..8b0a169d02ff8 100644 --- a/impeller/geometry/rect.h +++ b/impeller/geometry/rect.h @@ -139,6 +139,14 @@ struct TRect { return {left, top, right, bottom}; } + /// @brief Get a version of this rectangle that has a non-negative size. + constexpr TRect GetPositive() const { + auto ltrb = GetLTRB(); + return MakeLTRB(ltrb[0], ltrb[1], ltrb[2], ltrb[3]); + } + + /// @brief Get the points that represent the 4 corners of this rectangle. The + /// order is: Top left, top right, bottom left, bottom right. constexpr std::array, 4> GetPoints() const { auto [left, top, right, bottom] = GetLTRB(); return {TPoint(left, top), TPoint(right, top), TPoint(left, bottom), From f3deaba5a3590ff68342319aa6747ffd8539795c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 18:48:03 -0400 Subject: [PATCH 060/558] Roll Skia from cc10167ac573 to ee395eb27c39 (1 revision) (#35105) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c96f3f92c4dc4..ff40d02357994 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': 'cc10167ac5738e479e7b73a2863bb7ed38b2b6c7', + 'skia_revision': 'ee395eb27c39e5219797da86786ea0ce1d0ecbce', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 11bf2e2c12d2b..79533220a4b2b 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: f5c1e8d7b1143c1dbd13f29a1fd691cb +Signature: 8fa395bf1737d4ef08ea1fa8588cfb89 UNUSED LICENSES: From ca8cd6f0a62c2f5557073fcc0400db7d1319fb77 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 2 Aug 2022 15:58:03 -0700 Subject: [PATCH 061/558] fix typos buider -> builder (#35104) --- .../display_list_builder_benchmarks.cc | 62 +++++++++---------- .../fuchsia/flutter/platform_view_unittest.cc | 2 +- .../tests/flatland_platform_view_unittest.cc | 2 +- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/display_list/display_list_builder_benchmarks.cc b/display_list/display_list_builder_benchmarks.cc index 4ebadb4521bc6..ed1d093de31e0 100644 --- a/display_list/display_list_builder_benchmarks.cc +++ b/display_list/display_list_builder_benchmarks.cc @@ -48,8 +48,8 @@ static void Complete(DisplayListBuilder& builder, } // namespace -static void BM_DisplayListBuiderDefault(benchmark::State& state, - DisplayListBuilderBenchmarkType type) { +static void BM_DisplayListBuilderDefault(benchmark::State& state, + DisplayListBuilderBenchmarkType type) { while (state.KeepRunning()) { DisplayListBuilder builder; InvokeAllRenderingOps(builder); @@ -57,7 +57,7 @@ static void BM_DisplayListBuiderDefault(benchmark::State& state, } } -static void BM_DisplayListBuiderWithScaleAndTranslate( +static void BM_DisplayListBuilderWithScaleAndTranslate( benchmark::State& state, DisplayListBuilderBenchmarkType type) { while (state.KeepRunning()) { @@ -69,7 +69,7 @@ static void BM_DisplayListBuiderWithScaleAndTranslate( } } -static void BM_DisplayListBuiderWithPerspective( +static void BM_DisplayListBuilderWithPerspective( benchmark::State& state, DisplayListBuilderBenchmarkType type) { while (state.KeepRunning()) { @@ -81,7 +81,7 @@ static void BM_DisplayListBuiderWithPerspective( } } -static void BM_DisplayListBuiderWithClipRect( +static void BM_DisplayListBuilderWithClipRect( benchmark::State& state, DisplayListBuilderBenchmarkType type) { SkRect clip_bounds = SkRect::MakeLTRB(6.5, 7.3, 90.2, 85.7); @@ -93,7 +93,7 @@ static void BM_DisplayListBuiderWithClipRect( } } -static void BM_DisplayListBuiderWithSaveLayer( +static void BM_DisplayListBuilderWithSaveLayer( benchmark::State& state, DisplayListBuilderBenchmarkType type) { while (state.KeepRunning()) { @@ -110,7 +110,7 @@ static void BM_DisplayListBuiderWithSaveLayer( } } -static void BM_DisplayListBuiderWithSaveLayerAndImageFilter( +static void BM_DisplayListBuilderWithSaveLayerAndImageFilter( benchmark::State& state, DisplayListBuilderBenchmarkType type) { DlPaint layer_paint; @@ -130,104 +130,104 @@ static void BM_DisplayListBuiderWithSaveLayerAndImageFilter( } } -BENCHMARK_CAPTURE(BM_DisplayListBuiderDefault, +BENCHMARK_CAPTURE(BM_DisplayListBuilderDefault, kDefault, DisplayListBuilderBenchmarkType::kDefault) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderDefault, +BENCHMARK_CAPTURE(BM_DisplayListBuilderDefault, kBounds, DisplayListBuilderBenchmarkType::kBounds) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderDefault, +BENCHMARK_CAPTURE(BM_DisplayListBuilderDefault, kRtree, DisplayListBuilderBenchmarkType::kRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderDefault, +BENCHMARK_CAPTURE(BM_DisplayListBuilderDefault, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithScaleAndTranslate, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithScaleAndTranslate, kDefault, DisplayListBuilderBenchmarkType::kDefault) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithScaleAndTranslate, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithScaleAndTranslate, kBounds, DisplayListBuilderBenchmarkType::kBounds) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithScaleAndTranslate, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithScaleAndTranslate, kRtree, DisplayListBuilderBenchmarkType::kRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithScaleAndTranslate, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithScaleAndTranslate, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithPerspective, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithPerspective, kDefault, DisplayListBuilderBenchmarkType::kDefault) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithPerspective, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithPerspective, kBounds, DisplayListBuilderBenchmarkType::kBounds) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithPerspective, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithPerspective, kRtree, DisplayListBuilderBenchmarkType::kRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithPerspective, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithPerspective, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithClipRect, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithClipRect, kDefault, DisplayListBuilderBenchmarkType::kDefault) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithClipRect, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithClipRect, kBounds, DisplayListBuilderBenchmarkType::kBounds) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithClipRect, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithClipRect, kRtree, DisplayListBuilderBenchmarkType::kRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithClipRect, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithClipRect, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayer, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayer, kDefault, DisplayListBuilderBenchmarkType::kDefault) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayer, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayer, kBounds, DisplayListBuilderBenchmarkType::kBounds) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayer, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayer, kRtree, DisplayListBuilderBenchmarkType::kRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayer, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayer, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayerAndImageFilter, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayerAndImageFilter, kDefault, DisplayListBuilderBenchmarkType::kDefault) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayerAndImageFilter, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayerAndImageFilter, kBounds, DisplayListBuilderBenchmarkType::kBounds) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayerAndImageFilter, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayerAndImageFilter, kRtree, DisplayListBuilderBenchmarkType::kRtree) ->Unit(benchmark::kMillisecond); -BENCHMARK_CAPTURE(BM_DisplayListBuiderWithSaveLayerAndImageFilter, +BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayerAndImageFilter, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) ->Unit(benchmark::kMillisecond); diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index 3afa8526877f3..a02ebb21f4deb 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -316,7 +316,7 @@ class PlatformViewBuilder { // Once Build is called, the instance is no longer usable. GfxPlatformView Build() { EXPECT_FALSE(std::exchange(built_, true)) - << "Build() was already called, this buider is good for one use only."; + << "Build() was already called, this builder is good for one use only."; return GfxPlatformView( delegate_, task_runners_, std::move(view_ref_pair_.view_ref), external_external_view_embedder_, std::move(ime_service_), diff --git a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc index 0e804e1f68890..674030b0fc959 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc @@ -421,7 +421,7 @@ class PlatformViewBuilder { // Once Build is called, the instance is no longer usable. FlatlandPlatformView Build() { EXPECT_FALSE(std::exchange(built_, true)) - << "Build() was already called, this buider is good for one use only."; + << "Build() was already called, this builder is good for one use only."; return FlatlandPlatformView( delegate_, task_runners_, std::move(view_ref_pair_.view_ref), external_external_view_embedder_, std::move(ime_service_), From c07e1acfaddaaa550fbb8678158633d988f25574 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 2 Aug 2022 16:24:04 -0700 Subject: [PATCH 062/558] [Impeller] Add rounded rect SDF blur (#35084) --- ci/licenses_golden/licenses_flutter | 4 + impeller/entity/BUILD.gn | 8 +- impeller/entity/contents/content_context.cc | 2 + impeller/entity/contents/content_context.h | 10 ++ .../entity/contents/rrect_shadow_contents.cc | 111 ++++++++++++++++++ .../entity/contents/rrect_shadow_contents.h | 51 ++++++++ impeller/entity/entity_unittests.cc | 57 +++++++++ impeller/entity/shaders/rrect_blur.frag | 34 ++++++ impeller/entity/shaders/rrect_blur.vert | 18 +++ 9 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 impeller/entity/contents/rrect_shadow_contents.cc create mode 100644 impeller/entity/contents/rrect_shadow_contents.h create mode 100644 impeller/entity/shaders/rrect_blur.frag create mode 100644 impeller/entity/shaders/rrect_blur.vert diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 1e5fa58c911ea..dcdaf83c6d8eb 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -570,6 +570,8 @@ FILE: ../../../flutter/impeller/entity/contents/path_contents.cc FILE: ../../../flutter/impeller/entity/contents/path_contents.h FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.h +FILE: ../../../flutter/impeller/entity/contents/rrect_shadow_contents.cc +FILE: ../../../flutter/impeller/entity/contents/rrect_shadow_contents.h FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.cc FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.h FILE: ../../../flutter/impeller/entity/contents/solid_stroke_contents.cc @@ -621,6 +623,8 @@ FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fill.vert +FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag +FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert FILE: ../../../flutter/impeller/entity/shaders/solid_fill.frag FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.frag diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 0c1dfefc6ba6e..4f51f52cbdad0 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -34,6 +34,10 @@ impeller_shaders("entity_shaders") { "shaders/glyph_atlas.vert", "shaders/gradient_fill.frag", "shaders/gradient_fill.vert", + "shaders/radial_gradient_fill.vert", + "shaders/radial_gradient_fill.frag", + "shaders/rrect_blur.vert", + "shaders/rrect_blur.frag", "shaders/solid_fill.frag", "shaders/solid_fill.vert", "shaders/solid_stroke.frag", @@ -42,8 +46,6 @@ impeller_shaders("entity_shaders") { "shaders/texture_fill.vert", "shaders/vertices.vert", "shaders/vertices.frag", - "shaders/radial_gradient_fill.vert", - "shaders/radial_gradient_fill.frag", ] } @@ -77,6 +79,8 @@ impeller_component("entity") { "contents/path_contents.h", "contents/radial_gradient_contents.cc", "contents/radial_gradient_contents.h", + "contents/rrect_shadow_contents.cc", + "contents/rrect_shadow_contents.h", "contents/solid_color_contents.cc", "contents/solid_color_contents.h", "contents/solid_stroke_contents.cc", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 60c6a062db168..bbc6efdc434d7 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -155,6 +155,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); + rrect_blur_pipelines_[{}] = + CreateDefaultPipeline(*context_); texture_blend_pipelines_[{}] = CreateDefaultPipeline(*context_); blend_color_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index fb627bad171d9..0f7c84c827513 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -40,6 +40,8 @@ #include "impeller/entity/gradient_fill.vert.h" #include "impeller/entity/radial_gradient_fill.frag.h" #include "impeller/entity/radial_gradient_fill.vert.h" +#include "impeller/entity/rrect_blur.frag.h" +#include "impeller/entity/rrect_blur.vert.h" #include "impeller/entity/solid_fill.frag.h" #include "impeller/entity/solid_fill.vert.h" #include "impeller/entity/solid_stroke.frag.h" @@ -59,6 +61,9 @@ using SolidFillPipeline = using RadialGradientFillPipeline = PipelineT; using BlendPipeline = PipelineT; +using RRectBlurPipeline = + PipelineT; +using BlendPipeline = PipelineT; using BlendColorPipeline = PipelineT; using BlendColorBurnPipeline = @@ -147,6 +152,10 @@ class ContentContext { ContentContextOptions opts) const { return GetPipeline(radial_gradient_fill_pipelines_, opts); } + std::shared_ptr GetRRectBlurPipeline( + ContentContextOptions opts) const { + return GetPipeline(rrect_blur_pipelines_, opts); + } std::shared_ptr GetSolidFillPipeline( ContentContextOptions opts) const { @@ -293,6 +302,7 @@ class ContentContext { mutable Variants gradient_fill_pipelines_; mutable Variants solid_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; + mutable Variants rrect_blur_pipelines_; mutable Variants texture_blend_pipelines_; mutable Variants texture_pipelines_; mutable Variants gaussian_blur_pipelines_; diff --git a/impeller/entity/contents/rrect_shadow_contents.cc b/impeller/entity/contents/rrect_shadow_contents.cc new file mode 100644 index 0000000000000..b6371f043e1dc --- /dev/null +++ b/impeller/entity/contents/rrect_shadow_contents.cc @@ -0,0 +1,111 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/entity/contents/rrect_shadow_contents.h" +#include + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/entity.h" +#include "impeller/geometry/path.h" +#include "impeller/geometry/path_builder.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/vertex_buffer_builder.h" +#include "impeller/tessellator/tessellator.h" + +namespace impeller { + +RRectShadowContents::RRectShadowContents() = default; + +RRectShadowContents::~RRectShadowContents() = default; + +void RRectShadowContents::SetRRect(std::optional rect, + Scalar corner_radius) { + rect_ = rect; + corner_radius_ = corner_radius; +} + +void RRectShadowContents::SetSigma(Sigma sigma) { + sigma_ = sigma; +} + +void RRectShadowContents::SetColor(Color color) { + color_ = color.Premultiply(); +} + +std::optional RRectShadowContents::GetCoverage( + const Entity& entity) const { + if (!rect_.has_value()) { + return std::nullopt; + } + + Scalar radius = Radius{sigma_}.radius; + + auto ltrb = rect_->GetLTRB(); + Rect bounds = Rect::MakeLTRB(ltrb[0] - radius, ltrb[1] - radius, + ltrb[2] + radius, ltrb[3] + radius); + return bounds.TransformBounds(entity.GetTransformation()); +}; + +bool RRectShadowContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + if (!rect_.has_value()) { + return true; + } + + using VS = RRectBlurPipeline::VertexShader; + using FS = RRectBlurPipeline::FragmentShader; + + VertexBufferBuilder vtx_builder; + + auto blur_radius = Radius{sigma_}.radius; + auto positive_rect = rect_->GetPositive(); + { + auto left = -blur_radius; + auto top = -blur_radius; + auto right = positive_rect.size.width + blur_radius; + auto bottom = positive_rect.size.height + blur_radius; + + vtx_builder.AddVertices({ + {Point(left, top)}, + {Point(right, top)}, + {Point(left, bottom)}, + {Point(left, bottom)}, + {Point(right, top)}, + {Point(right, bottom)}, + }); + } + + Command cmd; + cmd.label = "RRect Shadow"; + cmd.pipeline = + renderer.GetRRectBlurPipeline(OptionsFromPassAndEntity(pass, entity)); + cmd.stencil_reference = entity.GetStencilDepth(); + + cmd.primitive_type = PrimitiveType::kTriangle; + cmd.BindVertices(vtx_builder.CreateVertexBuffer(pass.GetTransientsBuffer())); + + VS::VertInfo vert_info; + vert_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation() * + Matrix::MakeTranslation({positive_rect.origin}); + VS::BindVertInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(vert_info)); + + FS::FragInfo frag_info; + frag_info.color = color_; + frag_info.blur_radius = blur_radius; + frag_info.rect_size = Point(positive_rect.size); + frag_info.corner_radius = + std::min(corner_radius_, std::min(positive_rect.size.width / 2.0f, + positive_rect.size.height / 2.0f)); + FS::BindFragInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frag_info)); + + if (!pass.AddCommand(std::move(cmd))) { + return false; + } + + return true; +} + +} // namespace impeller diff --git a/impeller/entity/contents/rrect_shadow_contents.h b/impeller/entity/contents/rrect_shadow_contents.h new file mode 100644 index 0000000000000..d6d46b7f5223a --- /dev/null +++ b/impeller/entity/contents/rrect_shadow_contents.h @@ -0,0 +1,51 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#include "impeller/entity/contents/contents.h" +#include "impeller/entity/contents/filters/filter_contents.h" +#include "impeller/geometry/color.h" + +namespace impeller { + +class Path; +class HostBuffer; +struct VertexBuffer; + +class RRectShadowContents final : public Contents { + public: + RRectShadowContents(); + + ~RRectShadowContents() override; + + void SetRRect(std::optional rect, Scalar corner_radius = 0); + + void SetSigma(Sigma sigma); + + void SetColor(Color color); + + // |Contents| + std::optional GetCoverage(const Entity& entity) const override; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + private: + std::optional rect_; + Scalar corner_radius_; + Sigma sigma_; + + Color color_; + + FML_DISALLOW_COPY_AND_ASSIGN(RRectShadowContents); +}; + +} // namespace impeller diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index b1f0e0b0c6ab8..37e7eef5010cd 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -10,6 +10,7 @@ #include "impeller/entity/contents/filters/blend_filter_contents.h" #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" +#include "impeller/entity/contents/rrect_shadow_contents.h" #include "impeller/entity/contents/solid_color_contents.h" #include "impeller/entity/contents/solid_stroke_contents.h" #include "impeller/entity/contents/texture_contents.h" @@ -1174,5 +1175,61 @@ TEST_P(EntityTest, ClipContentsShouldRenderIsCorrect) { } } +TEST_P(EntityTest, RRectShadowTest) { + bool first_frame = true; + auto callback = [&](ContentContext& context, RenderPass& pass) { + if (first_frame) { + first_frame = false; + ImGui::SetNextWindowPos({10, 10}); + } + + static Color color = Color::Red(); + static float corner_radius = 100; + static float blur_radius = 100; + static bool show_coverage = false; + static Color coverage_color = Color::Green().WithAlpha(0.2); + + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::SliderFloat("Corner radius", &corner_radius, 0, 300); + ImGui::SliderFloat("Blur radius", &blur_radius, 0, 300); + ImGui::ColorEdit4("Color", reinterpret_cast(&color)); + ImGui::Checkbox("Show coverage", &show_coverage); + if (show_coverage) { + ImGui::ColorEdit4("Coverage color", + reinterpret_cast(&coverage_color)); + } + ImGui::End(); + + auto [top_left, bottom_right] = IMPELLER_PLAYGROUND_LINE( + Point(200, 200), Point(600, 400), 30, Color::White(), Color::White()); + auto rect = + Rect::MakeLTRB(top_left.x, top_left.y, bottom_right.x, bottom_right.y); + + auto contents = std::make_unique(); + contents->SetRRect(rect, corner_radius); + contents->SetColor(color); + contents->SetSigma(Radius(blur_radius)); + + Entity entity; + entity.SetTransformation(Matrix::MakeScale(GetContentScale())); + entity.SetContents(std::move(contents)); + entity.Render(context, pass); + + auto coverage = entity.GetCoverage(); + if (show_coverage && coverage.has_value()) { + auto bounds_contents = std::make_unique(); + bounds_contents->SetPath( + PathBuilder{}.AddRect(entity.GetCoverage().value()).TakePath()); + bounds_contents->SetColor(coverage_color.Premultiply()); + Entity bounds_entity; + bounds_entity.SetContents(std::move(bounds_contents)); + bounds_entity.Render(context, pass); + } + + return true; + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/shaders/rrect_blur.frag b/impeller/entity/shaders/rrect_blur.frag new file mode 100644 index 0000000000000..6178b1751bca5 --- /dev/null +++ b/impeller/entity/shaders/rrect_blur.frag @@ -0,0 +1,34 @@ +// 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. + +uniform FragInfo { + vec4 color; + float blur_radius; + vec2 rect_size; + float corner_radius; +} +frag_info; + +in vec2 v_position; + +out vec4 frag_color; + +// Simple logistic sigmoid with a domain of [-1, 1] and range of [0, 1]. +float Sigmoid(float x) { + return 1.03731472073 / (1 + exp(-4 * x)) - 0.0186573603638; +} + +float RRectDistance(vec2 sample_position, vec2 rect_size, float corner_radius) { + vec2 space = abs(sample_position) - rect_size + corner_radius; + return length(max(space, 0.0)) + min(max(space.x, space.y), 0.0) - + corner_radius; +} + +void main() { + vec2 center = v_position - frag_info.rect_size / 2.0; + float dist = + RRectDistance(center, frag_info.rect_size / 2.0, frag_info.corner_radius); + float shadow_mask = Sigmoid(-dist / frag_info.blur_radius); + frag_color = frag_info.color * shadow_mask; +} diff --git a/impeller/entity/shaders/rrect_blur.vert b/impeller/entity/shaders/rrect_blur.vert new file mode 100644 index 0000000000000..36711c6ede5e0 --- /dev/null +++ b/impeller/entity/shaders/rrect_blur.vert @@ -0,0 +1,18 @@ +// 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. + +uniform VertInfo { + mat4 mvp; +} +vert_info; + +in vec2 position; + +out vec2 v_position; + +void main() { + gl_Position = vert_info.mvp * vec4(position, 0.0, 1.0); + // The fragment stage uses local coordinates to compute the blur. + v_position = position; +} From e7a37cc1cf4c3ceb3c5a947d2aba0c488a96f449 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 2 Aug 2022 16:45:04 -0700 Subject: [PATCH 063/558] [impeller] drawAtlas (#35009) --- ci/licenses_golden/licenses_flutter | 4 + impeller/aiks/canvas.cc | 36 +++++ impeller/aiks/canvas.h | 9 ++ .../display_list/display_list_dispatcher.cc | 42 +++++- impeller/entity/BUILD.gn | 4 + impeller/entity/contents/atlas_contents.cc | 137 ++++++++++++++++++ impeller/entity/contents/atlas_contents.h | 59 ++++++++ impeller/entity/contents/content_context.cc | 1 + impeller/entity/contents/content_context.h | 8 + impeller/entity/entity_unittests.cc | 89 ++++++++++++ impeller/entity/shaders/atlas_fill.frag | 28 ++++ impeller/entity/shaders/atlas_fill.vert | 21 +++ 12 files changed, 436 insertions(+), 2 deletions(-) create mode 100644 impeller/entity/contents/atlas_contents.cc create mode 100644 impeller/entity/contents/atlas_contents.h create mode 100644 impeller/entity/shaders/atlas_fill.frag create mode 100644 impeller/entity/shaders/atlas_fill.vert diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index dcdaf83c6d8eb..58281df1d52f7 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -541,6 +541,8 @@ FILE: ../../../flutter/impeller/docs/assets/xcode_frame_capture/image6.png FILE: ../../../flutter/impeller/docs/assets/xcode_frame_capture/image7.png FILE: ../../../flutter/impeller/docs/assets/xcode_frame_capture/image8.png FILE: ../../../flutter/impeller/docs/assets/xcode_frame_capture/image9.png +FILE: ../../../flutter/impeller/entity/contents/atlas_contents.cc +FILE: ../../../flutter/impeller/entity/contents/atlas_contents.h FILE: ../../../flutter/impeller/entity/contents/clip_contents.cc FILE: ../../../flutter/impeller/entity/contents/clip_contents.h FILE: ../../../flutter/impeller/entity/contents/content_context.cc @@ -593,6 +595,8 @@ FILE: ../../../flutter/impeller/entity/entity_playground.h FILE: ../../../flutter/impeller/entity/entity_unittests.cc FILE: ../../../flutter/impeller/entity/inline_pass_context.cc FILE: ../../../flutter/impeller/entity/inline_pass_context.h +FILE: ../../../flutter/impeller/entity/shaders/atlas_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/atlas_fill.vert FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.glsl FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend.vert FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_color.frag diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index dfa6371392585..e41c4647aeae5 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -8,6 +8,7 @@ #include "flutter/fml/logging.h" #include "impeller/aiks/paint_pass_delegate.h" +#include "impeller/entity/contents/atlas_contents.h" #include "impeller/entity/contents/clip_contents.h" #include "impeller/entity/contents/text_contents.h" #include "impeller/entity/contents/texture_contents.h" @@ -321,4 +322,39 @@ void Canvas::DrawVertices(Vertices vertices, GetCurrentPass().AddEntity(std::move(entity)); } +void Canvas::DrawAtlas(std::shared_ptr atlas, + std::vector transforms, + std::vector texture_coordinates, + std::vector colors, + Entity::BlendMode blend_mode, + SamplerDescriptor sampler, + std::optional cull_rect, + Paint paint) { + if (!atlas) { + return; + } + auto size = atlas->GetSize(); + + if (size.IsEmpty()) { + return; + } + + std::shared_ptr contents = std::make_shared(); + contents->SetColors(std::move(colors)); + contents->SetTransforms(std::move(transforms)); + contents->SetTextureCoordinates(std::move(texture_coordinates)); + contents->SetTexture(atlas->GetTexture()); + contents->SetSamplerDescriptor(std::move(sampler)); + contents->SetBlendMode(blend_mode); + // TODO(jonahwilliams): set cull rect. + + Entity entity; + entity.SetTransformation(GetCurrentTransformation()); + entity.SetStencilDepth(GetStencilDepth()); + entity.SetBlendMode(paint.blend_mode); + entity.SetContents(paint.WithFilters(contents, false)); + + GetCurrentPass().AddEntity(std::move(entity)); +} + } // namespace impeller diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 2e7abc61468f3..e2257a92ab468 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -97,6 +97,15 @@ class Canvas { Entity::BlendMode blend_mode, Paint paint); + void DrawAtlas(std::shared_ptr atlas, + std::vector transforms, + std::vector texture_coordinates, + std::vector colors, + Entity::BlendMode blend_mode, + SamplerDescriptor sampler, + std::optional cull_rect, + Paint paint); + Picture EndRecordingAsPicture(); private: diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index dcc4daa9220df..cdb0edf10907c 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -190,6 +190,34 @@ static Color ToColor(const SkColor& color) { }; } +static std::vector ToColors(const flutter::DlColor colors[], int count) { + auto result = std::vector(); + if (colors == nullptr) { + return result; + } + for (int i = 0; i < count; i++) { + result.push_back(ToColor(colors[i])); + } + return result; +} + +static std::vector ToRSXForms(const SkRSXform xform[], int count) { + auto result = std::vector(); + for (int i = 0; i < count; i++) { + auto form = xform[i]; + // clang-format off + auto matrix = Matrix{ + form.fSCos, form.fSSin, 0, 0, + -form.fSSin, form.fSCos, 0, 0, + 0, 0, 1, 0, + form.fTx, form.fTy, 0, 1 + }; + // clang-format on + result.push_back(matrix); + } + return result; +} + // |flutter::Dispatcher| void DisplayListDispatcher::setColorSource( const flutter::DlColorSource* source) { @@ -393,6 +421,14 @@ static std::optional ToRect(const SkRect* rect) { return Rect::MakeLTRB(rect->fLeft, rect->fTop, rect->fRight, rect->fBottom); } +static std::vector ToRects(const SkRect tex[], int count) { + auto result = std::vector(); + for (int i = 0; i < count; i++) { + result.push_back(ToRect(&tex[i]).value()); + } + return result; +} + // |flutter::Dispatcher| void DisplayListDispatcher::saveLayer(const SkRect* bounds, const flutter::SaveLayerOptions options, @@ -839,8 +875,10 @@ void DisplayListDispatcher::drawAtlas(const sk_sp atlas, flutter::DlImageSampling sampling, const SkRect* cull_rect, bool render_with_attributes) { - // Needs https://github.com/flutter/flutter/issues/95434 - UNIMPLEMENTED; + canvas_.DrawAtlas(std::make_shared(atlas->impeller_texture()), + ToRSXForms(xform, count), ToRects(tex, count), + ToColors(colors, count), ToBlendMode(mode), + ToSamplerDescriptor(sampling), ToRect(cull_rect), paint_); } // |flutter::Dispatcher| diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 4f51f52cbdad0..3ebfe3d3543dc 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -8,6 +8,8 @@ impeller_shaders("entity_shaders") { name = "entity" shaders = [ + "shaders/atlas_fill.frag", + "shaders/atlas_fill.vert", "shaders/blending/advanced_blend.vert", "shaders/blending/advanced_blend_color.frag", "shaders/blending/advanced_blend_colorburn.frag", @@ -51,6 +53,8 @@ impeller_shaders("entity_shaders") { impeller_component("entity") { sources = [ + "contents/atlas_contents.cc", + "contents/atlas_contents.h", "contents/clip_contents.cc", "contents/clip_contents.h", "contents/content_context.cc", diff --git a/impeller/entity/contents/atlas_contents.cc b/impeller/entity/contents/atlas_contents.cc new file mode 100644 index 0000000000000..963c8b6b9aaa0 --- /dev/null +++ b/impeller/entity/contents/atlas_contents.cc @@ -0,0 +1,137 @@ +// 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 "impeller/renderer/formats.h" +#include "impeller/renderer/sampler_library.h" +#include "impeller/renderer/vertex_buffer_builder.h" + +#include "impeller/entity/atlas_fill.frag.h" +#include "impeller/entity/atlas_fill.vert.h" +#include "impeller/entity/contents/atlas_contents.h" +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/entity.h" +#include "impeller/renderer/render_pass.h" + +namespace impeller { + +AtlasContents::AtlasContents() = default; + +AtlasContents::~AtlasContents() = default; + +void AtlasContents::SetTexture(std::shared_ptr texture) { + texture_ = std::move(texture); +} + +std::shared_ptr AtlasContents::GetTexture() const { + return texture_; +} + +void AtlasContents::SetTransforms(std::vector transforms) { + transforms_ = transforms; +} + +void AtlasContents::SetTextureCoordinates(std::vector texture_coords) { + texture_coords_ = texture_coords; +} + +void AtlasContents::SetColors(std::vector colors) { + colors_ = colors; +} + +void AtlasContents::SetBlendMode(Entity::BlendMode blend_mode) { + // TODO(jonahwilliams): blending of colors with texture. + blend_mode_ = blend_mode; +} + +std::optional AtlasContents::GetCoverage(const Entity& entity) const { + Rect bounding_box = {}; + for (size_t i = 0; i < texture_coords_.size(); i++) { + auto matrix = transforms_[i]; + auto sample_rect = texture_coords_[i]; + auto bounds = Rect::MakeSize(sample_rect.size).TransformBounds(matrix); + bounding_box = bounds.Union(bounding_box); + } + return bounding_box.TransformBounds(entity.GetTransformation()); +} + +void AtlasContents::SetSamplerDescriptor(SamplerDescriptor desc) { + sampler_descriptor_ = std::move(desc); +} + +const SamplerDescriptor& AtlasContents::GetSamplerDescriptor() const { + return sampler_descriptor_; +} + +bool AtlasContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + if (texture_ == nullptr) { + return true; + } + + using VS = AtlasFillVertexShader; + using FS = AtlasFillFragmentShader; + + const auto texture_size = texture_->GetSize(); + if (texture_size.IsEmpty()) { + return true; + } + + VertexBufferBuilder vertex_builder; + vertex_builder.Reserve(texture_coords_.size() * 6); + constexpr size_t indices[6] = {0, 1, 2, 1, 2, 3}; + constexpr Scalar width[6] = {0, 1, 0, 1, 0, 1}; + constexpr Scalar height[6] = {0, 0, 1, 0, 1, 1}; + for (size_t i = 0; i < texture_coords_.size(); i++) { + auto sample_rect = texture_coords_[i]; + auto matrix = transforms_[i]; + auto color = (colors_.size() > 0 ? colors_[i] : Color::Black()); + auto transformed_points = + Rect::MakeSize(sample_rect.size).GetTransformedPoints(matrix); + + for (size_t j = 0; j < 6; j++) { + VS::PerVertexData data; + data.position = transformed_points[indices[j]]; + data.texture_coords = + (sample_rect.origin + Point(sample_rect.size.width * width[j], + sample_rect.size.height * height[j])) / + texture_size; + data.color = color.Premultiply(); + vertex_builder.AppendVertex(data); + } + } + + if (!vertex_builder.HasVertices()) { + return true; + } + + auto& host_buffer = pass.GetTransientsBuffer(); + + VS::VertInfo vert_info; + vert_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + + FS::FragInfo frag_info; + frag_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); + frag_info.has_color = colors_.size() > 0 ? 1.0 : 0.0; + + Command cmd; + cmd.label = "DrawAtlas"; + cmd.pipeline = + renderer.GetAtlasPipeline(OptionsFromPassAndEntity(pass, entity)); + cmd.stencil_reference = entity.GetStencilDepth(); + cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer)); + VS::BindVertInfo(cmd, host_buffer.EmplaceUniform(vert_info)); + FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + FS::BindTextureSampler(cmd, texture_, + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + sampler_descriptor_)); + pass.AddCommand(std::move(cmd)); + + return true; +} + +} // namespace impeller diff --git a/impeller/entity/contents/atlas_contents.h b/impeller/entity/contents/atlas_contents.h new file mode 100644 index 0000000000000..d775f310915eb --- /dev/null +++ b/impeller/entity/contents/atlas_contents.h @@ -0,0 +1,59 @@ +// 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 + +#include "flutter/fml/macros.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/entity/entity.h" +#include "impeller/renderer/sampler_descriptor.h" + +namespace impeller { + +class AtlasContents final : public Contents { + public: + explicit AtlasContents(); + + ~AtlasContents() override; + + void SetTexture(std::shared_ptr texture); + + std::shared_ptr GetTexture() const; + + void SetTransforms(std::vector transforms); + + void SetBlendMode(Entity::BlendMode blend_mode); + + void SetTextureCoordinates(std::vector texture_coords); + + void SetColors(std::vector colors); + + void SetSamplerDescriptor(SamplerDescriptor desc); + + const SamplerDescriptor& GetSamplerDescriptor() const; + + // |Contents| + std::optional GetCoverage(const Entity& entity) const override; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + private: + std::shared_ptr texture_; + std::vector texture_coords_; + std::vector colors_; + std::vector transforms_; + Entity::BlendMode blend_mode_; + SamplerDescriptor sampler_descriptor_ = {}; + + FML_DISALLOW_COPY_AND_ASSIGN(AtlasContents); +}; + +} // namespace impeller diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index bbc6efdc434d7..f53bdfcf18a95 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -198,6 +198,7 @@ ContentContext::ContentContext(std::shared_ptr context) glyph_atlas_pipelines_[{}] = CreateDefaultPipeline(*context_); vertices_pipelines_[{}] = CreateDefaultPipeline(*context_); + atlas_pipelines_[{}] = CreateDefaultPipeline(*context_); // Pipelines that are variants of the base pipelines with custom descriptors. // TODO(98684): Rework this API to allow fetching the descriptor without diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 0f7c84c827513..8f2457ae3a53a 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -27,6 +27,8 @@ #include "impeller/entity/advanced_blend_saturation.frag.h" #include "impeller/entity/advanced_blend_screen.frag.h" #include "impeller/entity/advanced_blend_softlight.frag.h" +#include "impeller/entity/atlas_fill.frag.h" +#include "impeller/entity/atlas_fill.vert.h" #include "impeller/entity/blend.frag.h" #include "impeller/entity/blend.vert.h" #include "impeller/entity/border_mask_blur.frag.h" @@ -106,6 +108,7 @@ using GlyphAtlasPipeline = PipelineT; using VerticesPipeline = PipelineT; +using AtlasPipeline = PipelineT; // Instead of requiring new shaders for clips, the solid fill stages are used // to redirect writing to the stencil instead of color attachments. using ClipPipeline = PipelineT; @@ -200,6 +203,10 @@ class ContentContext { return GetPipeline(vertices_pipelines_, opts); } + std::shared_ptr GetAtlasPipeline(ContentContextOptions opts) const { + return GetPipeline(atlas_pipelines_, opts); + } + // Advanced blends. std::shared_ptr GetBlendColorPipeline( @@ -311,6 +318,7 @@ class ContentContext { mutable Variants clip_pipelines_; mutable Variants glyph_atlas_pipelines_; mutable Variants vertices_pipelines_; + mutable Variants atlas_pipelines_; // Advanced blends. mutable Variants blend_color_pipelines_; mutable Variants blend_colorburn_pipelines_; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 37e7eef5010cd..e869c612069e0 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -6,6 +6,7 @@ #include #include "flutter/testing/testing.h" +#include "impeller/entity/contents/atlas_contents.h" #include "impeller/entity/contents/clip_contents.h" #include "impeller/entity/contents/filters/blend_filter_contents.h" #include "impeller/entity/contents/filters/filter_contents.h" @@ -1090,6 +1091,94 @@ TEST_P(EntityTest, DrawVerticesSolidColorTrianglesWithIndices) { ASSERT_TRUE(OpenPlaygroundHere(e)); } +TEST_P(EntityTest, DrawAtlasNoColor) { + // Draws the image as four squares stiched together. + auto atlas = CreateTextureForFixture("bay_bridge.jpg"); + auto size = atlas->GetSize(); + // Divide image into four quadrants. + Scalar half_width = size.width / 2; + Scalar half_height = size.height / 2; + std::vector texture_coordinates = { + Rect::MakeLTRB(0, 0, half_width, half_height), + Rect::MakeLTRB(half_width, 0, size.width, half_height), + Rect::MakeLTRB(0, half_height, half_width, size.height), + Rect::MakeLTRB(half_width, half_height, size.width, size.height)}; + // Position quadrants adjacent to eachother. + std::vector transforms = { + Matrix::MakeTranslation({0, 0, 0}), + Matrix::MakeTranslation({half_width, 0, 0}), + Matrix::MakeTranslation({0, half_height, 0}), + Matrix::MakeTranslation({half_width, half_height, 0})}; + std::shared_ptr contents = std::make_shared(); + + contents->SetTransforms(std::move(transforms)); + contents->SetTextureCoordinates(std::move(texture_coordinates)); + contents->SetTexture(atlas); + contents->SetBlendMode(Entity::BlendMode::kSource); + + Entity e; + e.SetTransformation(Matrix::MakeScale(GetContentScale())); + e.SetContents(contents); + + ASSERT_TRUE(OpenPlaygroundHere(e)); +} + +TEST_P(EntityTest, DrawAtlasWithColor) { + // Draws the image as four squares stiched together. Because blend modes + // aren't implented this ends up as four solid color blocks. + auto atlas = CreateTextureForFixture("bay_bridge.jpg"); + auto size = atlas->GetSize(); + // Divide image into four quadrants. + Scalar half_width = size.width / 2; + Scalar half_height = size.height / 2; + std::vector texture_coordinates = { + Rect::MakeLTRB(0, 0, half_width, half_height), + Rect::MakeLTRB(half_width, 0, size.width, half_height), + Rect::MakeLTRB(0, half_height, half_width, size.height), + Rect::MakeLTRB(half_width, half_height, size.width, size.height)}; + // Position quadrants adjacent to eachother. + std::vector transforms = { + Matrix::MakeTranslation({0, 0, 0}), + Matrix::MakeTranslation({half_width, 0, 0}), + Matrix::MakeTranslation({0, half_height, 0}), + Matrix::MakeTranslation({half_width, half_height, 0})}; + std::vector colors = {Color::Red(), Color::Green(), Color::Blue(), + Color::Yellow()}; + std::shared_ptr contents = std::make_shared(); + + contents->SetTransforms(std::move(transforms)); + contents->SetTextureCoordinates(std::move(texture_coordinates)); + contents->SetTexture(atlas); + contents->SetColors(colors); + contents->SetBlendMode(Entity::BlendMode::kSource); + + Entity e; + e.SetTransformation(Matrix::MakeScale(GetContentScale())); + e.SetContents(contents); + + ASSERT_TRUE(OpenPlaygroundHere(e)); +} + +TEST_P(EntityTest, DrawAtlasNoColorFullSize) { + auto atlas = CreateTextureForFixture("bay_bridge.jpg"); + auto size = atlas->GetSize(); + std::vector texture_coordinates = { + Rect::MakeLTRB(0, 0, size.width, size.height)}; + std::vector transforms = {Matrix::MakeTranslation({0, 0, 0})}; + std::shared_ptr contents = std::make_shared(); + + contents->SetTransforms(std::move(transforms)); + contents->SetTextureCoordinates(std::move(texture_coordinates)); + contents->SetTexture(atlas); + contents->SetBlendMode(Entity::BlendMode::kSource); + + Entity e; + e.SetTransformation(Matrix::MakeScale(GetContentScale())); + e.SetContents(contents); + + ASSERT_TRUE(OpenPlaygroundHere(e)); +} + TEST_P(EntityTest, SolidFillCoverageIsCorrect) { // No transform { diff --git a/impeller/entity/shaders/atlas_fill.frag b/impeller/entity/shaders/atlas_fill.frag new file mode 100644 index 0000000000000..f19588e567059 --- /dev/null +++ b/impeller/entity/shaders/atlas_fill.frag @@ -0,0 +1,28 @@ +// 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 + +uniform sampler2D texture_sampler; + +uniform FragInfo { + float texture_sampler_y_coord_scale; + float has_color; +} +frag_info; + +in vec2 v_texture_coords; +in vec4 v_color; + +out vec4 frag_color; + +void main() { + vec4 sampled = IPSample(texture_sampler, v_texture_coords, + frag_info.texture_sampler_y_coord_scale); + if (frag_info.has_color == 1.0) { + frag_color = sampled.aaaa * v_color; + } else { + frag_color = sampled; + } +} diff --git a/impeller/entity/shaders/atlas_fill.vert b/impeller/entity/shaders/atlas_fill.vert new file mode 100644 index 0000000000000..29d3c0a5be6e7 --- /dev/null +++ b/impeller/entity/shaders/atlas_fill.vert @@ -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. + +uniform VertInfo { + mat4 mvp; +} +vert_info; + +in vec2 position; +in vec2 texture_coords; +in vec4 color; + +out vec2 v_texture_coords; +out vec4 v_color; + +void main() { + gl_Position = vert_info.mvp * vec4(position, 0.0, 1.0); + v_texture_coords = texture_coords; + v_color = color; +} From 1bd07deeae154fafc4249ea5b9ccc0e2147677de Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 20:02:03 -0400 Subject: [PATCH 064/558] Roll Clang Linux from 3a20597776a5 to d9e02a30b16e (#35108) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index ff40d02357994..2bfae57332063 100644 --- a/DEPS +++ b/DEPS @@ -639,7 +639,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/clang/linux-amd64', - 'version': 'git_revision:3a20597776a5d2920e511d81653b4d2b6ca0c855' + 'version': 'git_revision:d9e02a30b16ea65a7da87913c40af03e22c9571f' } ], 'condition': 'host_os == "linux" and host_cpu == "arm64"', From ccf6cee766f412f9920b8fa090b83050cebb4962 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Wed, 3 Aug 2022 01:09:48 +0100 Subject: [PATCH 065/558] [Windows] Fix incorrect public C API argument type (#35106) FlutterDesktopEngineGetTextureRegistrar is used to get the texture registrar associated with an engine object and therefore should take a FlutterDesktopEngineRef parameter. This bug was initially identified and fixed by @knopp in: https://github.com/flutter/engine/pull/27522 This patch replaces that one and adds the simplest possible unit test to get it landed. This also adds an initial unit test for the public Windows C API used to implement the C++ client wrapper. In order to fully test this API, we'll want to support test fixtures similar to what we do in the embedder API tests. See: https://github.com/flutter/flutter/issues/87299 Fixes: https://github.com/flutter/flutter/issues/86617 --- ci/licenses_golden/licenses_flutter | 1 + shell/platform/windows/BUILD.gn | 1 + .../windows/flutter_windows_unittests.cc | 25 +++++++++++++++++++ .../platform/windows/public/flutter_windows.h | 3 +-- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 shell/platform/windows/flutter_windows_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 58281df1d52f7..2cfa26d8964bb 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2401,6 +2401,7 @@ FILE: ../../../flutter/shell/platform/windows/flutter_windows_engine_unittests.c FILE: ../../../flutter/shell/platform/windows/flutter_windows_texture_registrar.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_texture_registrar.h FILE: ../../../flutter/shell/platform/windows/flutter_windows_texture_registrar_unittests.cc +FILE: ../../../flutter/shell/platform/windows/flutter_windows_unittests.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.h FILE: ../../../flutter/shell/platform/windows/flutter_windows_view_unittests.cc diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 5531f8a41310d..c83e5f2fdba99 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -173,6 +173,7 @@ executable("flutter_windows_unittests") { "flutter_window_unittests.cc", "flutter_windows_engine_unittests.cc", "flutter_windows_texture_registrar_unittests.cc", + "flutter_windows_unittests.cc", "flutter_windows_view_unittests.cc", "keyboard_key_channel_handler_unittests.cc", "keyboard_key_embedder_handler_unittests.cc", diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc new file mode 100644 index 0000000000000..e0b87dd781225 --- /dev/null +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -0,0 +1,25 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/windows/public/flutter_windows.h" + +#include + +#include "gtest/gtest.h" + +namespace flutter { + +TEST(FlutterWindowsTest, GetTextureRegistrar) { + FlutterDesktopEngineProperties properties; + memset(&properties, 0, sizeof(FlutterDesktopEngineProperties)); + properties.assets_path = L""; + properties.icu_data_path = L"icudtl.dat"; + auto engine = FlutterDesktopEngineCreate(&properties); + ASSERT_NE(engine, nullptr); + auto texture_registrar = FlutterDesktopEngineGetTextureRegistrar(engine); + EXPECT_NE(texture_registrar, nullptr); + FlutterDesktopEngineDestroy(engine); +} + +} // namespace flutter diff --git a/shell/platform/windows/public/flutter_windows.h b/shell/platform/windows/public/flutter_windows.h index ad03dd3a123f4..b5d2738778e5a 100644 --- a/shell/platform/windows/public/flutter_windows.h +++ b/shell/platform/windows/public/flutter_windows.h @@ -169,8 +169,7 @@ FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine); // Returns the texture registrar associated with the engine. FLUTTER_EXPORT FlutterDesktopTextureRegistrarRef -FlutterDesktopEngineGetTextureRegistrar( - FlutterDesktopTextureRegistrarRef texture_registrar); +FlutterDesktopEngineGetTextureRegistrar(FlutterDesktopEngineRef engine); // ========== View ========== From 27dce1225d578b11e354a8edceae0896affed9f4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 20:12:04 -0400 Subject: [PATCH 066/558] Roll Skia from ee395eb27c39 to da1c56b69334 (3 revisions) (#35110) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 2bfae57332063..476b8c321adfe 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': 'ee395eb27c39e5219797da86786ea0ce1d0ecbce', + 'skia_revision': 'da1c56b693348ac18187a7f72233ec3971319f2b', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 79533220a4b2b..1f2bcf64cdaca 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 8fa395bf1737d4ef08ea1fa8588cfb89 +Signature: d17a0b35553fbff84b9b088983ff3b0a UNUSED LICENSES: From a1e77ae885a06f14a79f684d8e421af056235962 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 20:22:04 -0400 Subject: [PATCH 067/558] Roll Clang Windows from 3a20597776a5 to d9e02a30b16e (#35109) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 476b8c321adfe..90c632e675329 100644 --- a/DEPS +++ b/DEPS @@ -650,7 +650,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/clang/windows-amd64', - 'version': 'git_revision:3a20597776a5d2920e511d81653b4d2b6ca0c855' + 'version': 'git_revision:d9e02a30b16ea65a7da87913c40af03e22c9571f' } ], 'condition': 'download_windows_deps', From bb862a2bd2a7ff0680313553de2abf5239fed27b Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 2 Aug 2022 18:14:04 -0700 Subject: [PATCH 068/558] [Impeller] Move color-only blending functions and utilities into the shader library (#35111) --- ci/licenses_golden/licenses_flutter | 2 +- .../shader_lib/impeller/blending.glsl | 193 ++++++++++++++++++ .../shaders/blending/advanced_blend.glsl | 2 +- .../blending/advanced_blend_color.frag | 5 +- .../blending/advanced_blend_colorburn.frag | 24 +-- .../blending/advanced_blend_colordodge.frag | 24 +-- .../blending/advanced_blend_darken.frag | 5 +- .../blending/advanced_blend_difference.frag | 5 +- .../blending/advanced_blend_exclusion.frag | 5 +- .../blending/advanced_blend_hardlight.frag | 5 +- .../shaders/blending/advanced_blend_hue.frag | 5 +- .../blending/advanced_blend_lighten.frag | 5 +- .../blending/advanced_blend_luminosity.frag | 5 +- .../blending/advanced_blend_multiply.frag | 5 +- .../blending/advanced_blend_overlay.frag | 6 +- .../blending/advanced_blend_saturation.frag | 5 +- .../blending/advanced_blend_screen.frag | 5 +- .../blending/advanced_blend_softlight.frag | 13 +- .../blending/advanced_blend_utils.glsl | 55 ----- 19 files changed, 230 insertions(+), 144 deletions(-) create mode 100644 impeller/compiler/shader_lib/impeller/blending.glsl delete mode 100644 impeller/entity/shaders/blending/advanced_blend_utils.glsl diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 2cfa26d8964bb..6d6fab596ba64 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -487,6 +487,7 @@ FILE: ../../../flutter/impeller/compiler/reflector.cc FILE: ../../../flutter/impeller/compiler/reflector.h FILE: ../../../flutter/impeller/compiler/runtime_stage_data.cc FILE: ../../../flutter/impeller/compiler/runtime_stage_data.h +FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/blending.glsl 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 @@ -614,7 +615,6 @@ FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_overlay.f FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_saturation.frag FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_screen.frag FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_softlight.frag -FILE: ../../../flutter/impeller/entity/shaders/blending/advanced_blend_utils.glsl FILE: ../../../flutter/impeller/entity/shaders/blending/blend.frag FILE: ../../../flutter/impeller/entity/shaders/blending/blend.vert FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.frag diff --git a/impeller/compiler/shader_lib/impeller/blending.glsl b/impeller/compiler/shader_lib/impeller/blending.glsl new file mode 100644 index 0000000000000..f92e6bc4ab9a0 --- /dev/null +++ b/impeller/compiler/shader_lib/impeller/blending.glsl @@ -0,0 +1,193 @@ +// 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 BLENDING_GLSL_ +#define BLENDING_GLSL_ + +#include +#include + +//------------------------------------------------------------------------------ +/// HSV utilities. +/// + +float IPLuminosity(vec3 color) { + return color.r * 0.3 + color.g * 0.59 + color.b * 0.11; +} + +/// Scales the color's luma by the amount necessary to place the color +/// components in a 1-0 range. +vec3 IPClipColor(vec3 color) { + float lum = IPLuminosity(color); + float mn = min(min(color.r, color.g), color.b); + float mx = max(max(color.r, color.g), color.b); + // `lum - mn` and `mx - lum` will always be >= 0 in the following conditions, + // so adding a tiny value is enough to make these divisions safe. + if (mn < 0) { + color = lum + (((color - lum) * lum) / (lum - mn + kEhCloseEnough)); + } + if (mx > 1) { + color = lum + (((color - lum) * (1 - lum)) / (mx - lum + kEhCloseEnough)); + } + return color; +} + +vec3 IPSetLuminosity(vec3 color, float luminosity) { + float relative_lum = luminosity - IPLuminosity(color); + return IPClipColor(color + relative_lum); +} + +float IPSaturation(vec3 color) { + return max(max(color.r, color.g), color.b) - + min(min(color.r, color.g), color.b); +} + +vec3 IPSetSaturation(vec3 color, float saturation) { + float mn = min(min(color.r, color.g), color.b); + float mx = max(max(color.r, color.g), color.b); + return (mn < mx) ? ((color - mn) * saturation) / (mx - mn) : vec3(0); +} + +//------------------------------------------------------------------------------ +/// Color blend functions. +/// +/// These routines take two unpremultiplied RGB colors and output a third color. +/// They can be combined with any alpha compositing operation. When these blend +/// functions are used for drawing Entities in Impeller, the output is always +/// applied to the destination using `SourceOver` alpha compositing. +/// + +vec3 IPBlendScreen(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingscreen + return dst + src - (dst * src); +} + +vec3 IPBlendHardLight(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendinghardlight + return IPVec3Choose(dst * (2 * src), IPBlendScreen(dst, 2 * src - 1), src); +} + +vec3 IPBlendOverlay(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingoverlay + // HardLight, but with reversed parameters. + return IPBlendHardLight(src, dst); +} + +vec3 IPBlendDarken(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingdarken + return min(dst, src); +} + +vec3 IPBlendLighten(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendinglighten + return max(dst, src); +} + +vec3 IPBlendColorDodge(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingcolordodge + + vec3 color = min(vec3(1), dst / (1 - src)); + + if (dst.r < kEhCloseEnough) { + color.r = 0; + } + if (dst.g < kEhCloseEnough) { + color.g = 0; + } + if (dst.b < kEhCloseEnough) { + color.b = 0; + } + + if (1 - src.r < kEhCloseEnough) { + color.r = 1; + } + if (1 - src.g < kEhCloseEnough) { + color.g = 1; + } + if (1 - src.b < kEhCloseEnough) { + color.b = 1; + } + + return color; +} + +vec3 IPBlendColorBurn(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingcolorburn + + vec3 color = 1 - min(vec3(1), (1 - dst) / src); + + if (1 - dst.r < kEhCloseEnough) { + color.r = 1; + } + if (1 - dst.g < kEhCloseEnough) { + color.g = 1; + } + if (1 - dst.b < kEhCloseEnough) { + color.b = 1; + } + + if (src.r < kEhCloseEnough) { + color.r = 0; + } + if (src.g < kEhCloseEnough) { + color.g = 0; + } + if (src.b < kEhCloseEnough) { + color.b = 0; + } + + return color; +} + +vec3 IPBlendSoftLight(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingsoftlight + + vec3 D = IPVec3ChooseCutoff(((16 * dst - 12) * dst + 4) * dst, // + sqrt(dst), // + dst, // + 0.25); + + return IPVec3Choose(dst - (1 - 2 * src) * dst * (1 - dst), // + dst + (2 * src - 1) * (D - dst), // + src); +} + +vec3 IPBlendDifference(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingdifference + return abs(dst - src); +} + +vec3 IPBlendExclusion(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingexclusion + return dst + src - 2 * dst * src; +} + +vec3 IPBlendMultiply(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingmultiply + return dst * src; +} + +vec3 IPBlendHue(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendinghue + return IPSetLuminosity(IPSetSaturation(src, IPSaturation(dst)), + IPLuminosity(dst)); +} + +vec3 IPBlendSaturation(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingsaturation + return IPSetLuminosity(IPSetSaturation(dst, IPSaturation(src)), + IPLuminosity(dst)); +} + +vec3 IPBlendColor(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingcolor + return IPSetLuminosity(src, IPLuminosity(dst)); +} + +vec3 IPBlendLuminosity(vec3 dst, vec3 src) { + // https://www.w3.org/TR/compositing-1/#blendingluminosity + return IPSetLuminosity(dst, IPLuminosity(src)); +} + +#endif diff --git a/impeller/entity/shaders/blending/advanced_blend.glsl b/impeller/entity/shaders/blending/advanced_blend.glsl index 64476c3fbdae9..57547ca5fe5f3 100644 --- a/impeller/entity/shaders/blending/advanced_blend.glsl +++ b/impeller/entity/shaders/blending/advanced_blend.glsl @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include +#include #include #include diff --git a/impeller/entity/shaders/blending/advanced_blend_color.frag b/impeller/entity/shaders/blending/advanced_blend_color.frag index 290e20adc72e5..225bd3f098122 100644 --- a/impeller/entity/shaders/blending/advanced_blend_color.frag +++ b/impeller/entity/shaders/blending/advanced_blend_color.frag @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingcolor - return SetLuminosity(src, Luminosity(dst)); + return IPBlendColor(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_colorburn.frag b/impeller/entity/shaders/blending/advanced_blend_colorburn.frag index 464728895562c..95aac01645999 100644 --- a/impeller/entity/shaders/blending/advanced_blend_colorburn.frag +++ b/impeller/entity/shaders/blending/advanced_blend_colorburn.frag @@ -2,30 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingcolorburn - vec3 color = 1 - min(vec3(1), (1 - dst) / src); - if (1 - dst.r < kEhCloseEnough) { - color.r = 1; - } - if (1 - dst.g < kEhCloseEnough) { - color.g = 1; - } - if (1 - dst.b < kEhCloseEnough) { - color.b = 1; - } - if (src.r < kEhCloseEnough) { - color.r = 0; - } - if (src.g < kEhCloseEnough) { - color.g = 0; - } - if (src.b < kEhCloseEnough) { - color.b = 0; - } - return color; + return IPBlendColorBurn(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_colordodge.frag b/impeller/entity/shaders/blending/advanced_blend_colordodge.frag index f28a4f1026359..f11fc5e68584d 100644 --- a/impeller/entity/shaders/blending/advanced_blend_colordodge.frag +++ b/impeller/entity/shaders/blending/advanced_blend_colordodge.frag @@ -2,30 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingcolordodge - vec3 color = min(vec3(1), dst / (1 - src)); - if (dst.r < kEhCloseEnough) { - color.r = 0; - } - if (dst.g < kEhCloseEnough) { - color.g = 0; - } - if (dst.b < kEhCloseEnough) { - color.b = 0; - } - if (1 - src.r < kEhCloseEnough) { - color.r = 1; - } - if (1 - src.g < kEhCloseEnough) { - color.g = 1; - } - if (1 - src.b < kEhCloseEnough) { - color.b = 1; - } - return color; + return IPBlendColorDodge(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_darken.frag b/impeller/entity/shaders/blending/advanced_blend_darken.frag index bfc8cb20e22b9..286b7ff2912e6 100644 --- a/impeller/entity/shaders/blending/advanced_blend_darken.frag +++ b/impeller/entity/shaders/blending/advanced_blend_darken.frag @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingdarken - return min(dst, src); + return IPBlendDarken(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_difference.frag b/impeller/entity/shaders/blending/advanced_blend_difference.frag index 7545bc08b55cd..9d9320fdffd78 100644 --- a/impeller/entity/shaders/blending/advanced_blend_difference.frag +++ b/impeller/entity/shaders/blending/advanced_blend_difference.frag @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingdifference - return abs(dst - src); + return IPBlendDifference(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_exclusion.frag b/impeller/entity/shaders/blending/advanced_blend_exclusion.frag index a12e47e3d043b..7c2f9f92996ca 100644 --- a/impeller/entity/shaders/blending/advanced_blend_exclusion.frag +++ b/impeller/entity/shaders/blending/advanced_blend_exclusion.frag @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingexclusion - return dst + src - 2 * dst * src; + return IPBlendExclusion(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_hardlight.frag b/impeller/entity/shaders/blending/advanced_blend_hardlight.frag index cbd109fc660fc..aa126dfdc7cc7 100644 --- a/impeller/entity/shaders/blending/advanced_blend_hardlight.frag +++ b/impeller/entity/shaders/blending/advanced_blend_hardlight.frag @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendinghardlight - return BlendHardLight(dst, src); + return IPBlendHardLight(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_hue.frag b/impeller/entity/shaders/blending/advanced_blend_hue.frag index bdcf6e2daf106..c0355b4b00d34 100644 --- a/impeller/entity/shaders/blending/advanced_blend_hue.frag +++ b/impeller/entity/shaders/blending/advanced_blend_hue.frag @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendinghue - return SetLuminosity(SetSaturation(src, Saturation(dst)), Luminosity(dst)); + return IPBlendHue(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_lighten.frag b/impeller/entity/shaders/blending/advanced_blend_lighten.frag index 1aca8cc4b7fcd..32f2df082b4f5 100644 --- a/impeller/entity/shaders/blending/advanced_blend_lighten.frag +++ b/impeller/entity/shaders/blending/advanced_blend_lighten.frag @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendinglighten - return max(dst, src); + return IPBlendLighten(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_luminosity.frag b/impeller/entity/shaders/blending/advanced_blend_luminosity.frag index 5faecd9e509aa..4ceae64493947 100644 --- a/impeller/entity/shaders/blending/advanced_blend_luminosity.frag +++ b/impeller/entity/shaders/blending/advanced_blend_luminosity.frag @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingluminosity - return SetLuminosity(dst, Luminosity(src)); + return IPBlendLuminosity(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_multiply.frag b/impeller/entity/shaders/blending/advanced_blend_multiply.frag index 92656d23fa0a7..a2fd42b6c7d2e 100644 --- a/impeller/entity/shaders/blending/advanced_blend_multiply.frag +++ b/impeller/entity/shaders/blending/advanced_blend_multiply.frag @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingmultiply - return dst * src; + return IPBlendMultiply(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_overlay.frag b/impeller/entity/shaders/blending/advanced_blend_overlay.frag index d6197f1103147..0837b91d8bfbd 100644 --- a/impeller/entity/shaders/blending/advanced_blend_overlay.frag +++ b/impeller/entity/shaders/blending/advanced_blend_overlay.frag @@ -2,12 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendinghardlight - // HardLight, but with reversed parameters. - return BlendHardLight(src, dst); + return IPBlendOverlay(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_saturation.frag b/impeller/entity/shaders/blending/advanced_blend_saturation.frag index a127446db4aad..c3fd3bebc87d7 100644 --- a/impeller/entity/shaders/blending/advanced_blend_saturation.frag +++ b/impeller/entity/shaders/blending/advanced_blend_saturation.frag @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingsaturation - return SetLuminosity(SetSaturation(dst, Saturation(src)), Luminosity(dst)); + return IPBlendSaturation(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_screen.frag b/impeller/entity/shaders/blending/advanced_blend_screen.frag index 7f059766abcf7..f65ab5db1d563 100644 --- a/impeller/entity/shaders/blending/advanced_blend_screen.frag +++ b/impeller/entity/shaders/blending/advanced_blend_screen.frag @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingscreen - return BlendScreen(dst, src); + return IPBlendScreen(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_softlight.frag b/impeller/entity/shaders/blending/advanced_blend_softlight.frag index 2d7427ae89166..3a504afbb99c6 100644 --- a/impeller/entity/shaders/blending/advanced_blend_softlight.frag +++ b/impeller/entity/shaders/blending/advanced_blend_softlight.frag @@ -2,19 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "advanced_blend_utils.glsl" +#include vec3 Blend(vec3 dst, vec3 src) { - // https://www.w3.org/TR/compositing-1/#blendingsoftlight - - vec3 D = IPVec3ChooseCutoff(((16 * dst - 12) * dst + 4) * dst, // - sqrt(dst), // - dst, // - 0.25); - - return IPVec3Choose(dst - (1 - 2 * src) * dst * (1 - dst), // - dst + (2 * src - 1) * (D - dst), // - src); + return IPBlendSoftLight(dst, src); } #include "advanced_blend.glsl" diff --git a/impeller/entity/shaders/blending/advanced_blend_utils.glsl b/impeller/entity/shaders/blending/advanced_blend_utils.glsl deleted file mode 100644 index 55645331bba8f..0000000000000 --- a/impeller/entity/shaders/blending/advanced_blend_utils.glsl +++ /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. - -#include -#include - -vec3 BlendScreen(vec3 dst, vec3 src) { - return dst + src - (dst * src); -} - -vec3 BlendHardLight(vec3 dst, vec3 src) { - return IPVec3Choose(dst * (2 * src), BlendScreen(dst, 2 * src - 1), src); -} - -//------------------------------------------------------------------------------ -// HSV utilities. -// - -float Luminosity(vec3 color) { - return color.r * 0.3 + color.g * 0.59 + color.b * 0.11; -} - -/// Scales the color's luma by the amount necessary to place the color -/// components in a 1-0 range. -vec3 ClipColor(vec3 color) { - float lum = Luminosity(color); - float mn = min(min(color.r, color.g), color.b); - float mx = max(max(color.r, color.g), color.b); - // `lum - mn` and `mx - lum` will always be >= 0 in the following conditions, - // so adding a tiny value is enough to make these divisions safe. - if (mn < 0) { - color = lum + (((color - lum) * lum) / (lum - mn + kEhCloseEnough)); - } - if (mx > 1) { - color = lum + (((color - lum) * (1 - lum)) / (mx - lum + kEhCloseEnough)); - } - return color; -} - -vec3 SetLuminosity(vec3 color, float luminosity) { - float relative_lum = luminosity - Luminosity(color); - return ClipColor(color + relative_lum); -} - -float Saturation(vec3 color) { - return max(max(color.r, color.g), color.b) - - min(min(color.r, color.g), color.b); -} - -vec3 SetSaturation(vec3 color, float saturation) { - float mn = min(min(color.r, color.g), color.b); - float mx = max(max(color.r, color.g), color.b); - return (mn < mx) ? ((color - mn) * saturation) / (mx - mn) : vec3(0); -} From c4564762773fb865d204475e10359c07de80ec60 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 2 Aug 2022 21:57:04 -0400 Subject: [PATCH 069/558] Roll Dart SDK from b2093ad90d66 to a8d90480d8ff (1 revision) (#35112) --- DEPS | 16 ++++++++-------- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/DEPS b/DEPS index 90c632e675329..790e5ffc085fe 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'b2093ad90d6694b4b27bf6bb7362879b10a28d6f', + 'dart_revision': 'a8d90480d8ff19da05c6aa82307a38ee2b294326', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -46,11 +46,11 @@ vars = { 'dart_clock_rev': '2507a228773c5e877fc9e3330080b234aad965c0', 'dart_collection_rev': '414ffa1bc8ba18bd608bbf916d95715311d89ac1', 'dart_devtools_rev': 'd131d19091f6b89ac89486bd92440a25a523e8b0', - 'dart_protobuf_rev': '9aad6aadcc0fc616051c7e0eaef78c26b3dd7b60', + 'dart_protobuf_rev': '504eefeae9892602ea50c20159db1db3768012a9', 'dart_pub_rev': '9bf4289d6fd5d6872a8929d6312bbd7098f3ea9c', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': 'e00c0ea769e32821d91c0880da8eb736839a6e6d', - 'dart_webdev_rev': '27cc5c9228ca59e721bc41fe7028e0fd6b995748', + 'dart_webdev_rev': '37bf4af1b0961f053e7cf4990a34ca5fd0ad0fd4', 'dart_webkit_inspection_protocol_rev': '57522d6b29d94903b765c757079d906555d5a171', 'dart_yaml_edit_rev': '01589b3ce447b03aed991db49f1ec6445ad5476d', 'dart_zlib_rev': '27c2f474b71d0d20764f86f60ef8b00da1a16cda', @@ -203,7 +203,7 @@ deps = { Var('dart_git') + '/dart_style.git@d7b73536a8079331c888b7da539b80e6825270ea', 'src/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@d7513b2ee0a9bad6c9526f6b0ba970b4fcca17d0', + Var('dart_git') + '/dartdoc.git@7edeeeb20a506cadec3788c273fdee6cad91e07c', 'src/third_party/dart/third_party/pkg/ffi': Var('dart_git') + '/ffi.git@18b2b549d55009ff594600b04705ff6161681e07', @@ -227,7 +227,7 @@ deps = { Var('dart_git') + '/http_multi_server.git@20bf079c8955d1250a45afb9cb096472a724a551', 'src/third_party/dart/third_party/pkg/http_parser': - Var('dart_git') + '/http_parser.git@d25b3c9e7f23e31ac388a03361737110768597f6', + Var('dart_git') + '/http_parser.git@b968f7ddde0588273a6cbd1d2eb6569f418606ac', 'src/third_party/dart/third_party/pkg/json_rpc_2': Var('dart_git') + '/json_rpc_2.git@805e6536dd961d66f6b8cd46d8f3e61774f957c9', @@ -248,7 +248,7 @@ deps = { Var('dart_git') + '/mime.git@0a75a41445eb642674a0a271eecde78cb025ee60', 'src/third_party/dart/third_party/pkg/mockito': - Var('dart_git') + '/mockito.git@d8a2ddd2054390bd03d34bf64c940884e6f7a596', + Var('dart_git') + '/mockito.git@2acf22f4d400c6e1eee0f6ca595092220fba8b34', 'src/third_party/dart/third_party/pkg/oauth2': Var('dart_git') + '/oauth2.git@199ebf15cbd5b07958438184f32e41c4447a57bf', @@ -269,7 +269,7 @@ deps = { Var('dart_git') + '/pub.git' + '@' + Var('dart_pub_rev'), 'src/third_party/dart/third_party/pkg/pub_semver': - Var('dart_git') + '/pub_semver.git@5c0b4bfd5ca57fe16f1319c581dc8c882e9b8cb2', + Var('dart_git') + '/pub_semver.git@9fd28757ba45961ac5449e0f2b0020670e921475', 'src/third_party/dart/third_party/pkg/shelf': Var('dart_git') + '/shelf.git@0371a64bd3b99044ee3158bacf8813bba735a9c7', @@ -299,7 +299,7 @@ deps = { Var('dart_git') + '/term_glyph.git@ec7cf7bb51ebb7d55760a1359f6697690dbc06ba', 'src/third_party/dart/third_party/pkg/test': - Var('dart_git') + '/test.git@b144a336776eaa1f9420f3ab38214d8c061c663e', + Var('dart_git') + '/test.git@aba7de5851ace64f1f887369ae9424582d9d4d7f', 'src/third_party/dart/third_party/pkg/test_reflective_loader': Var('dart_git') + '/test_reflective_loader.git@8d0de01bbe852fea1f8e33aba907abcba50a8a1e', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index cde3f12d8524e..2eeb58079ed3f 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 203f630cf725dd2a8c057dd8436dcb7c +Signature: 8311def9aedab010bc3f43706fd18193 UNUSED LICENSES: From 6cd744bb9706bc7435ca7d5da01abc235926106f Mon Sep 17 00:00:00 2001 From: godofredoc Date: Tue, 2 Aug 2022 19:44:04 -0700 Subject: [PATCH 070/558] Update mac artifacts to gcs. (#35113) --- ci/builders/mac_host_engine.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ci/builders/mac_host_engine.json b/ci/builders/mac_host_engine.json index e6ee65774f537..dd0bc3e9d978a 100644 --- a/ci/builders/mac_host_engine.json +++ b/ci/builders/mac_host_engine.json @@ -4,6 +4,7 @@ "archives": [ { "base_path": "out/host_debug/zip_archives/", + "type": "gcs", "include_paths": [ "out/host_debug/zip_archives/darwin-x64/FlutterMacOS.framework.zip", "out/host_debug/zip_archives/darwin-x64/gen_snapshot.zip", @@ -49,6 +50,7 @@ "archives": [ { "base_path": "out/host_profile/zip_archives/", + "type": "gcs", "include_paths": [ "out/host_profile/zip_archives/darwin-x64-profile/FlutterMacOS.framework.zip", "out/host_profile/zip_archives/darwin-x64-profile/gen_snapshot.zip", @@ -102,6 +104,7 @@ "archives": [ { "base_path": "out/host_release/zip_archives/", + "type": "gcs", "include_paths": [ "out/host_release/zip_archives/darwin-x64-release/FlutterMacOS.framework.zip", "out/host_release/zip_archives/darwin-x64-release/gen_snapshot.zip", @@ -142,6 +145,7 @@ "archives": [ { "base_path": "out/mac_debug_arm64/zip_archives/", + "type": "gcs", "include_paths": [ "out/mac_debug_arm64/zip_archives/dart-sdk-darwin-arm64.zip", "out/mac_debug_arm64/zip_archives/darwin-x64/gen_snapshot.zip" @@ -182,6 +186,7 @@ "archives": [ { "base_path": "out/mac_profile_arm64/zip_archives/", + "type": "gcs", "include_paths": [ "out/mac_profile_arm64/zip_archives/darwin-x64-profile/gen_snapshot.zip" ], @@ -219,6 +224,7 @@ "archives": [ { "base_path": "out/mac_release_arm64/zip_archives/", + "type": "gcs", "include_paths": [ "out/mac_release_arm64/zip_archives/darwin-x64-release/gen_snapshot.zip" ], From 51296a62d98c1e03e1207cedcea0ff9e0d434394 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 02:08:04 -0400 Subject: [PATCH 071/558] Roll Skia from da1c56b69334 to 149eb4561980 (1 revision) (#35116) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 790e5ffc085fe..927280878f9c4 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': 'da1c56b693348ac18187a7f72233ec3971319f2b', + 'skia_revision': '149eb4561980851be83913057d5be20c32b73e06', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 1f2bcf64cdaca..876cbaa70f5d1 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d17a0b35553fbff84b9b088983ff3b0a +Signature: b6c01ae95f21ca0bf106e7a0b75b4ab1 UNUSED LICENSES: From 05228ad454bcf468410ad9a1dbbd4263651b47f4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 02:18:06 -0400 Subject: [PATCH 072/558] Roll Dart SDK from a8d90480d8ff to ba75fe6598e3 (1 revision) (#35118) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 927280878f9c4..3d17b5e469eb8 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'a8d90480d8ff19da05c6aa82307a38ee2b294326', + 'dart_revision': 'ba75fe6598e3661e1437a3232cae6edeb3d59d81', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 2eeb58079ed3f..2c3b0e67152b9 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 8311def9aedab010bc3f43706fd18193 +Signature: 340855bc8c62a415d79b929df3688d92 UNUSED LICENSES: From 27112a024dc9742ba00ec4dd308e547d62ff68a1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 03:14:05 -0400 Subject: [PATCH 073/558] Roll Skia from 149eb4561980 to 3f99bc378abc (1 revision) (#35119) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 3d17b5e469eb8..0cc2317b2f505 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': '149eb4561980851be83913057d5be20c32b73e06', + 'skia_revision': '3f99bc378abcc53ada4c8b16bdd5be785861c4d5', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 876cbaa70f5d1..1fbd27bb7a504 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b6c01ae95f21ca0bf106e7a0b75b4ab1 +Signature: 31213fda286cee0f9881bc9d83cdaf31 UNUSED LICENSES: From fc1bc2e7cb9fcf5df85537c1e5e66d85ea436f4e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 05:14:14 -0400 Subject: [PATCH 074/558] Roll Skia from 3f99bc378abc to 88d90928a76f (1 revision) (#35121) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0cc2317b2f505..e9bbda89b3530 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': '3f99bc378abcc53ada4c8b16bdd5be785861c4d5', + 'skia_revision': '88d90928a76f91472d26cb3b2da3dd404ecf7115', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 1fbd27bb7a504..df96d2de24290 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 31213fda286cee0f9881bc9d83cdaf31 +Signature: 7d65d83b9db28c616826099695d503ec UNUSED LICENSES: From ddaa57083a82c232c839c779372255899e9b7de5 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 06:22:05 -0400 Subject: [PATCH 075/558] Roll Fuchsia Linux SDK from ERGTYC7pf... to TYBmxFHAk... (#35122) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e9bbda89b3530..82d25c5876d52 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'ERGTYC7pfsifuKhgfWttuibiwb2UJRhNVg1Inlkxua4C' + 'version': 'TYBmxFHAk2GAhAAwJyXybWL9Zqe40KaFtodBUxHDAs4C' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 0df30332c5847..753b07cfe5333 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 9065b2f06a72e54172d3df5edbb553d8 +Signature: 340b6d2063fa5af664206d3291ee0286 UNUSED LICENSES: From 2510c223e8aff116dbf5590179713808991b968b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 10:18:16 -0400 Subject: [PATCH 076/558] Roll Skia from 88d90928a76f to 044137673848 (1 revision) (#35123) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 82d25c5876d52..fa4deecb75987 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': '88d90928a76f91472d26cb3b2da3dd404ecf7115', + 'skia_revision': '0441376738480ea3bb0b94097029a46b9c653eb1', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index df96d2de24290..20d67553ac67d 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 7d65d83b9db28c616826099695d503ec +Signature: 016f5ce79a5884990946c1e54403a6d4 UNUSED LICENSES: From 2c282981d8490f44f6358a1397f6019f9f74709a Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Wed, 3 Aug 2022 07:58:03 -0700 Subject: [PATCH 077/558] Revert "Roll Dart SDK from a8d90480d8ff to ba75fe6598e3 (1 revision) (#35118)" (#35128) This reverts commit 05228ad454bcf468410ad9a1dbbd4263651b47f4. --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index fa4deecb75987..ff1a40a3be2b1 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'ba75fe6598e3661e1437a3232cae6edeb3d59d81', + 'dart_revision': 'a8d90480d8ff19da05c6aa82307a38ee2b294326', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 2c3b0e67152b9..2eeb58079ed3f 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 340855bc8c62a415d79b929df3688d92 +Signature: 8311def9aedab010bc3f43706fd18193 UNUSED LICENSES: From c5d77e3d5ff0d8bf8d60ed933d11df038343550f Mon Sep 17 00:00:00 2001 From: godofredoc Date: Wed, 3 Aug 2022 08:32:04 -0700 Subject: [PATCH 078/558] Adds mac_android_aot_engine. (#35115) --- .ci.yaml | 8 + ci/builders/mac_android_aot_engine.json | 215 ++++++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 ci/builders/mac_android_aot_engine.json diff --git a/.ci.yaml b/.ci.yaml index fd2435e6c525d..06b53651e5307 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -294,6 +294,14 @@ targets: jazzy_version: "0.14.1" timeout: 75 + - name: Mac mac_android_aot_engine + recipe: engine_v2/engine_v2 + bringup: true + timeout: 60 + properties: + config_name: mac_android_aot_engine + environment: Staging + - name: Mac mac_host_engine recipe: engine_v2/engine_v2 bringup: true diff --git a/ci/builders/mac_android_aot_engine.json b/ci/builders/mac_android_aot_engine.json new file mode 100644 index 0000000000000..6bb034cc6744d --- /dev/null +++ b/ci/builders/mac_android_aot_engine.json @@ -0,0 +1,215 @@ +{ + "builds": [ + { + "archives": [ + { + "base_path": "out/android_profile/zip_archives/", + "type": "gcs", + "include_paths": [ + "out/android_profile/zip_archives/android-arm-profile/darwin-x64.zip" + ], + "name": "android_profile" + } + ], + "drone_dimensions": [ + "device_type=none", + "os=Mac-12", + "cpu=x86" + ], + "gclient_custom_vars": { + "download_android_deps": false + }, + "gn": [ + "--runtime-mode", + "profile", + "--android" + ], + "name": "android_profile", + "ninja": { + "config": "android_profile", + "targets": [ + "flutter/lib/snapshot", + "flutter/shell/platform/android:gen_snapshot" + ] + }, + "tests": [] + }, + { + "archives": [ + { + "base_path": "out/android_profile_arm64/zip_archives/", + "type": "gcs", + "include_paths": [ + "out/android_profile_arm64/zip_archives/android-arm64-profile/darwin-x64.zip" + ], + "name": "android_profile_arm64" + } + ], + "drone_dimensions": [ + "device_type=none", + "os=Mac-12", + "cpu=x86" + ], + "gclient_custom_vars": { + "download_android_deps": false + }, + "gn": [ + "--runtime-mode", + "profile", + "--android", + "--android-cpu=arm64" + ], + "name": "android_profile_arm64", + "ninja": { + "config": "android_profile_arm64", + "targets": [ + "flutter/lib/snapshot", + "flutter/shell/platform/android:gen_snapshot" + ] + }, + "tests": [] + }, + { + "archives": [ + { + "base_path": "out/android_profile_x64/zip_archives/", + "type": "gcs", + "include_paths": [ + "out/android_profile_x64/zip_archives/android-x64-profile/darwin-x64.zip" + ], + "name": "android_profile_x64" + } + ], + "drone_dimensions": [ + "device_type=none", + "os=Mac-12", + "cpu=x86" + ], + "gclient_custom_vars": { + "download_android_deps": false + }, + "gn": [ + "--runtime-mode", + "profile", + "--android", + "--android-cpu=x64" + ], + "name": "android_profile_x64", + "ninja": { + "config": "android_profile_x64", + "targets": [ + "flutter/lib/snapshot", + "flutter/shell/platform/android:gen_snapshot" + ] + }, + "tests": [] + }, + { + "archives": [ + { + "base_path": "out/android_release/zip_archives/", + "type": "gcs", + "include_paths": [ + "out/android_release/zip_archives/android-arm-release/darwin-x64.zip" + ], + "name": "android_release" + } + ], + "drone_dimensions": [ + "device_type=none", + "os=Mac-12", + "cpu=x86" + ], + "gclient_custom_vars": { + "download_android_deps": false + }, + "gn": [ + "--runtime-mode", + "release", + "--android" + ], + "name": "android_release", + "ninja": { + "config": "android_release", + "targets": [ + "flutter/lib/snapshot", + "flutter/shell/platform/android:gen_snapshot" + ] + }, + "tests": [] + }, + { + "archives": [ + { + "base_path": "out/android_release_arm64/zip_archives/", + "type": "gcs", + "include_paths": [ + "out/android_release_arm64/zip_archives/android-arm64-release/darwin-x64.zip" + ], + "name": "android_release_arm64" + } + ], + "drone_dimensions": [ + "device_type=none", + "os=Mac-12", + "cpu=x86" + ], + "gclient_custom_vars": { + "download_android_deps": false + }, + "gn": [ + "--runtime-mode", + "release", + "--android", + "--android-cpu=arm64" + ], + "name": "android_release_arm64", + "ninja": { + "config": "android_release_arm64", + "targets": [ + "flutter/lib/snapshot", + "flutter/shell/platform/android:gen_snapshot" + ] + }, + "tests": [] + }, + { + "archives": [ + { + "base_path": "out/android_release_x64/zip_archives/", + "type": "gcs", + "include_paths": [ + "out/android_release_x64/zip_archives/android-x64-release/darwin-x64.zip" + ], + "name": "android_release_x64" + } + ], + "drone_dimensions": [ + "device_type=none", + "os=Mac-12", + "cpu=x86" + ], + "gclient_custom_vars": { + "download_android_deps": false + }, + "gn": [ + "--runtime-mode", + "release", + "--android", + "--android-cpu=x64" + ], + "name": "android_release_x64", + "ninja": { + "config": "android_release_x64", + "targets": [ + "flutter/lib/snapshot", + "flutter/shell/platform/android:gen_snapshot" + ] + }, + "tests": [] + } + ], + "tests": [], + "generators": [], + "archives": [] +} From adba70232a61ce0ef4d818ce24a0d52fda5bc4ac Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 12:21:05 -0400 Subject: [PATCH 079/558] Roll Skia from 044137673848 to 770620d9fcae (5 revisions) (#35126) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ff1a40a3be2b1..afe5082f9f7b1 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': '0441376738480ea3bb0b94097029a46b9c653eb1', + 'skia_revision': '770620d9fcae7259ee972ac4cea0cee88c51e5a1', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 20d67553ac67d..619df232e1f6e 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 016f5ce79a5884990946c1e54403a6d4 +Signature: e413cda351df999e6d3fdfb1e1715239 UNUSED LICENSES: From 058fd54b4de6a20af8c06de83611b833e16a8b9c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 14:39:04 -0400 Subject: [PATCH 080/558] Roll Skia from 770620d9fcae to 4744b2aaa20d (1 revision) (#35130) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index afe5082f9f7b1..26e42042eb2a9 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': '770620d9fcae7259ee972ac4cea0cee88c51e5a1', + 'skia_revision': '4744b2aaa20d2111118bb987dab9a7ac87b138b7', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 619df232e1f6e..bbafe7a432934 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e413cda351df999e6d3fdfb1e1715239 +Signature: dc555eec561bf2ffbcf7b205d7e3bf31 UNUSED LICENSES: From 10f4970c80b2cdff76b7e3877eb7c87dade8acda Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 3 Aug 2022 11:47:04 -0700 Subject: [PATCH 081/558] [impeller] forward paint opacity to draw atlas (#35127) --- impeller/aiks/canvas.cc | 1 + impeller/entity/contents/atlas_contents.cc | 7 ++++- impeller/entity/contents/atlas_contents.h | 3 ++ impeller/entity/entity_unittests.cc | 35 ++++++++++++++++++++++ impeller/entity/shaders/atlas_fill.frag | 9 +++--- 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index e41c4647aeae5..8aee04ec32dee 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -346,6 +346,7 @@ void Canvas::DrawAtlas(std::shared_ptr atlas, contents->SetTexture(atlas->GetTexture()); contents->SetSamplerDescriptor(std::move(sampler)); contents->SetBlendMode(blend_mode); + contents->SetAlpha(paint.color.alpha); // TODO(jonahwilliams): set cull rect. Entity entity; diff --git a/impeller/entity/contents/atlas_contents.cc b/impeller/entity/contents/atlas_contents.cc index 963c8b6b9aaa0..721fe5e7e4805 100644 --- a/impeller/entity/contents/atlas_contents.cc +++ b/impeller/entity/contents/atlas_contents.cc @@ -41,6 +41,10 @@ void AtlasContents::SetColors(std::vector colors) { colors_ = colors; } +void AtlasContents::SetAlpha(Scalar alpha) { + alpha_ = alpha; +} + void AtlasContents::SetBlendMode(Entity::BlendMode blend_mode) { // TODO(jonahwilliams): blending of colors with texture. blend_mode_ = blend_mode; @@ -116,7 +120,8 @@ bool AtlasContents::Render(const ContentContext& renderer, FS::FragInfo frag_info; frag_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); - frag_info.has_color = colors_.size() > 0 ? 1.0 : 0.0; + frag_info.has_vertex_color = colors_.size() > 0 ? 1.0 : 0.0; + frag_info.alpha = alpha_; Command cmd; cmd.label = "DrawAtlas"; diff --git a/impeller/entity/contents/atlas_contents.h b/impeller/entity/contents/atlas_contents.h index d775f310915eb..e5dd3185ba5c3 100644 --- a/impeller/entity/contents/atlas_contents.h +++ b/impeller/entity/contents/atlas_contents.h @@ -35,6 +35,8 @@ class AtlasContents final : public Contents { void SetSamplerDescriptor(SamplerDescriptor desc); + void SetAlpha(Scalar alpha); + const SamplerDescriptor& GetSamplerDescriptor() const; // |Contents| @@ -51,6 +53,7 @@ class AtlasContents final : public Contents { std::vector colors_; std::vector transforms_; Entity::BlendMode blend_mode_; + Scalar alpha_ = 1.0; SamplerDescriptor sampler_descriptor_ = {}; FML_DISALLOW_COPY_AND_ASSIGN(AtlasContents); diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index e869c612069e0..d4784161dbaf3 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -1159,6 +1159,41 @@ TEST_P(EntityTest, DrawAtlasWithColor) { ASSERT_TRUE(OpenPlaygroundHere(e)); } +TEST_P(EntityTest, DrawAtlasWithOpacity) { + // Draws the image as four squares stiched together slightly + // opaque + auto atlas = CreateTextureForFixture("bay_bridge.jpg"); + auto size = atlas->GetSize(); + // Divide image into four quadrants. + Scalar half_width = size.width / 2; + Scalar half_height = size.height / 2; + std::vector texture_coordinates = { + Rect::MakeLTRB(0, 0, half_width, half_height), + Rect::MakeLTRB(half_width, 0, size.width, half_height), + Rect::MakeLTRB(0, half_height, half_width, size.height), + Rect::MakeLTRB(half_width, half_height, size.width, size.height)}; + // Position quadrants adjacent to eachother. + std::vector transforms = { + Matrix::MakeTranslation({0, 0, 0}), + Matrix::MakeTranslation({half_width, 0, 0}), + Matrix::MakeTranslation({0, half_height, 0}), + Matrix::MakeTranslation({half_width, half_height, 0})}; + + std::shared_ptr contents = std::make_shared(); + + contents->SetTransforms(std::move(transforms)); + contents->SetTextureCoordinates(std::move(texture_coordinates)); + contents->SetTexture(atlas); + contents->SetAlpha(0.5); + contents->SetBlendMode(Entity::BlendMode::kSource); + + Entity e; + e.SetTransformation(Matrix::MakeScale(GetContentScale())); + e.SetContents(contents); + + ASSERT_TRUE(OpenPlaygroundHere(e)); +} + TEST_P(EntityTest, DrawAtlasNoColorFullSize) { auto atlas = CreateTextureForFixture("bay_bridge.jpg"); auto size = atlas->GetSize(); diff --git a/impeller/entity/shaders/atlas_fill.frag b/impeller/entity/shaders/atlas_fill.frag index f19588e567059..e211971ca1bb9 100644 --- a/impeller/entity/shaders/atlas_fill.frag +++ b/impeller/entity/shaders/atlas_fill.frag @@ -8,7 +8,8 @@ uniform sampler2D texture_sampler; uniform FragInfo { float texture_sampler_y_coord_scale; - float has_color; + float has_vertex_color; + float alpha; } frag_info; @@ -20,9 +21,9 @@ out vec4 frag_color; void main() { vec4 sampled = IPSample(texture_sampler, v_texture_coords, frag_info.texture_sampler_y_coord_scale); - if (frag_info.has_color == 1.0) { - frag_color = sampled.aaaa * v_color; + if (frag_info.has_vertex_color == 1.0) { + frag_color = sampled.aaaa * v_color * frag_info.alpha; } else { - frag_color = sampled; + frag_color = sampled * frag_info.alpha; } } From 88daade06304ad18c96a13cf8b5f1039689da33f Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Wed, 3 Aug 2022 20:26:44 +0100 Subject: [PATCH 082/558] [Windows] Add missing testing namespace (#35131) flutter_windows_unittests.cc had its tests inside the flutter namespace rather than the flutter:testing namespace. This adds the missing namespace and makes one namespace-related cleanup in one of the key event unit tests as well. This is a post-landing cleanup for PR: https://github.com/flutter/engine/pull/35106 Issue: https://github.com/flutter/flutter/issues/86617 --- shell/platform/windows/flutter_windows_unittests.cc | 2 ++ .../windows/keyboard_key_embedder_handler_unittests.cc | 9 +++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index e0b87dd781225..52676d3fd7fd2 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -9,6 +9,7 @@ #include "gtest/gtest.h" namespace flutter { +namespace testing { TEST(FlutterWindowsTest, GetTextureRegistrar) { FlutterDesktopEngineProperties properties; @@ -22,4 +23,5 @@ TEST(FlutterWindowsTest, GetTextureRegistrar) { FlutterDesktopEngineDestroy(engine); } +} // namespace testing } // namespace flutter diff --git a/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc b/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc index aee316a4e16d6..3c526d9ba6558 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc +++ b/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc @@ -14,6 +14,7 @@ #include "gtest/gtest.h" namespace flutter { +namespace testing { namespace { @@ -71,11 +72,6 @@ UINT DefaultMapVkToScan(UINT virtual_key, bool extended) { extended ? MAPVK_VK_TO_VSC_EX : MAPVK_VK_TO_VSC); } -} // namespace - -namespace testing { - -namespace { constexpr uint64_t kScanCodeKeyA = 0x1e; constexpr uint64_t kScanCodeAltLeft = 0x38; constexpr uint64_t kScanCodeNumpad1 = 0x4f; @@ -86,9 +82,10 @@ constexpr uint64_t kScanCodeShiftRight = 0x36; constexpr uint64_t kVirtualKeyA = 0x41; -using namespace ::flutter::testing::keycodes; } // namespace +using namespace ::flutter::testing::keycodes; + TEST(KeyboardKeyEmbedderHandlerTest, ConvertChar32ToUtf8) { std::string result; From 1188a808e1e06139b7f83f3e9611fee66e947ee2 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 3 Aug 2022 13:27:04 -0700 Subject: [PATCH 083/558] [impeller] use cullRect for drawAtlas coverage (#35133) --- impeller/aiks/canvas.cc | 2 +- impeller/entity/contents/atlas_contents.cc | 8 +++++ impeller/entity/contents/atlas_contents.h | 3 ++ impeller/entity/entity_unittests.cc | 40 +++++++++++++++++++++- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 8aee04ec32dee..8b48264cf8527 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -346,8 +346,8 @@ void Canvas::DrawAtlas(std::shared_ptr atlas, contents->SetTexture(atlas->GetTexture()); contents->SetSamplerDescriptor(std::move(sampler)); contents->SetBlendMode(blend_mode); + contents->SetCullRect(cull_rect); contents->SetAlpha(paint.color.alpha); - // TODO(jonahwilliams): set cull rect. Entity entity; entity.SetTransformation(GetCurrentTransformation()); diff --git a/impeller/entity/contents/atlas_contents.cc b/impeller/entity/contents/atlas_contents.cc index 721fe5e7e4805..8e82a568c1fcd 100644 --- a/impeller/entity/contents/atlas_contents.cc +++ b/impeller/entity/contents/atlas_contents.cc @@ -50,7 +50,15 @@ void AtlasContents::SetBlendMode(Entity::BlendMode blend_mode) { blend_mode_ = blend_mode; } +void AtlasContents::SetCullRect(std::optional cull_rect) { + cull_rect_ = cull_rect; +} + std::optional AtlasContents::GetCoverage(const Entity& entity) const { + if (cull_rect_.has_value()) { + return cull_rect_.value().TransformBounds(entity.GetTransformation()); + } + Rect bounding_box = {}; for (size_t i = 0; i < texture_coords_.size(); i++) { auto matrix = transforms_[i]; diff --git a/impeller/entity/contents/atlas_contents.h b/impeller/entity/contents/atlas_contents.h index e5dd3185ba5c3..2ff284c1a5143 100644 --- a/impeller/entity/contents/atlas_contents.h +++ b/impeller/entity/contents/atlas_contents.h @@ -33,6 +33,8 @@ class AtlasContents final : public Contents { void SetColors(std::vector colors); + void SetCullRect(std::optional cull_rect); + void SetSamplerDescriptor(SamplerDescriptor desc); void SetAlpha(Scalar alpha); @@ -53,6 +55,7 @@ class AtlasContents final : public Contents { std::vector colors_; std::vector transforms_; Entity::BlendMode blend_mode_; + std::optional cull_rect_; Scalar alpha_ = 1.0; SamplerDescriptor sampler_descriptor_ = {}; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index d4784161dbaf3..a38b6bb9744b9 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -1159,6 +1159,44 @@ TEST_P(EntityTest, DrawAtlasWithColor) { ASSERT_TRUE(OpenPlaygroundHere(e)); } +TEST_P(EntityTest, DrawAtlasUsesProvidedCullRectForCoverage) { + auto atlas = CreateTextureForFixture("bay_bridge.jpg"); + auto size = atlas->GetSize(); + + Scalar half_width = size.width / 2; + Scalar half_height = size.height / 2; + std::vector texture_coordinates = { + Rect::MakeLTRB(0, 0, half_width, half_height), + Rect::MakeLTRB(half_width, 0, size.width, half_height), + Rect::MakeLTRB(0, half_height, half_width, size.height), + Rect::MakeLTRB(half_width, half_height, size.width, size.height)}; + std::vector transforms = { + Matrix::MakeTranslation({0, 0, 0}), + Matrix::MakeTranslation({half_width, 0, 0}), + Matrix::MakeTranslation({0, half_height, 0}), + Matrix::MakeTranslation({half_width, half_height, 0})}; + + std::shared_ptr contents = std::make_shared(); + + contents->SetTransforms(std::move(transforms)); + contents->SetTextureCoordinates(std::move(texture_coordinates)); + contents->SetTexture(atlas); + contents->SetBlendMode(Entity::BlendMode::kSource); + + auto transform = Matrix::MakeScale(GetContentScale()); + Entity e; + e.SetTransformation(transform); + e.SetContents(contents); + + ASSERT_EQ(contents->GetCoverage(e).value(), + Rect::MakeSize(size).TransformBounds(transform)); + + contents->SetCullRect(Rect::MakeLTRB(0, 0, 10, 10)); + + ASSERT_EQ(contents->GetCoverage(e).value(), + Rect::MakeLTRB(0, 0, 10, 10).TransformBounds(transform)); +} + TEST_P(EntityTest, DrawAtlasWithOpacity) { // Draws the image as four squares stiched together slightly // opaque @@ -1184,8 +1222,8 @@ TEST_P(EntityTest, DrawAtlasWithOpacity) { contents->SetTransforms(std::move(transforms)); contents->SetTextureCoordinates(std::move(texture_coordinates)); contents->SetTexture(atlas); - contents->SetAlpha(0.5); contents->SetBlendMode(Entity::BlendMode::kSource); + contents->SetAlpha(0.5); Entity e; e.SetTransformation(Matrix::MakeScale(GetContentScale())); From 1743d1db1ddace8e63c0b530ff080fdc07eccc7e Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Wed, 3 Aug 2022 17:12:04 -0400 Subject: [PATCH 084/558] =?UTF-8?q?Revert=20"[Impeller]=20[Vulkan]=20Gener?= =?UTF-8?q?ate=20descriptor=20set=20layouts=20in=20backen=E2=80=A6=20(#351?= =?UTF-8?q?36)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ci/licenses_golden/licenses_flutter | 1 - impeller/compiler/code_gen_template.h | 30 ++++++++++++----------- impeller/renderer/BUILD.gn | 1 - impeller/renderer/descriptor_set_layout.h | 27 -------------------- impeller/renderer/pipeline_builder.h | 7 ------ impeller/renderer/vertex_descriptor.cc | 15 ------------ impeller/renderer/vertex_descriptor.h | 13 ---------- 7 files changed, 16 insertions(+), 78 deletions(-) delete mode 100644 impeller/renderer/descriptor_set_layout.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 6d6fab596ba64..659ee197fee08 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -808,7 +808,6 @@ FILE: ../../../flutter/impeller/renderer/command_buffer.cc FILE: ../../../flutter/impeller/renderer/command_buffer.h FILE: ../../../flutter/impeller/renderer/context.cc FILE: ../../../flutter/impeller/renderer/context.h -FILE: ../../../flutter/impeller/renderer/descriptor_set_layout.h FILE: ../../../flutter/impeller/renderer/device_buffer.cc FILE: ../../../flutter/impeller/renderer/device_buffer.h FILE: ../../../flutter/impeller/renderer/device_buffer_unittests.cc diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index 7769f02779524..4a061fcadb5ad 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -16,17 +16,15 @@ constexpr std::string_view kReflectionHeaderTemplate = {# Note: The nogncheck decorations are only to make GN not mad at the template#} {# this file is generated from. There are no GN rule violations in the generated#} {# file itself and the no-check declarations will be stripped in generated files.#} -#include "impeller/renderer/buffer_view.h" {# // nogncheck #} +#include "impeller/renderer/buffer_view.h" {# // nogncheck #} -#include "impeller/renderer/command.h" {# // nogncheck #} +#include "impeller/renderer/command.h" {# // nogncheck #} -#include "impeller/renderer/descriptor_set_layout.h" {# // nogncheck #} +#include "impeller/renderer/sampler.h" {# // nogncheck #} -#include "impeller/renderer/sampler.h" {# // nogncheck #} +#include "impeller/renderer/shader_types.h" {# // nogncheck #} -#include "impeller/renderer/shader_types.h" {# // nogncheck #} - -#include "impeller/renderer/texture.h" {# // nogncheck #} +#include "impeller/renderer/texture.h" {# // nogncheck #} namespace impeller { @@ -152,26 +150,30 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} // =========================================================================== // Metadata for Vulkan ======================================================= // =========================================================================== +#ifdef IMPELLER_ENABLE_VULKAN_REFLECTION {% if length(buffers)+length(sampled_images) > 0 %} - static constexpr std::array kDescriptorSetLayouts{ + static constexpr std::array kDescriptorSetLayouts{ {% for buffer in buffers %} - DescriptorSetLayout{ + VkDescriptorSetLayoutBinding{ {{buffer.binding}}, // binding = {{buffer.binding}} - DescriptorType::kUniformBuffer, // descriptorType = Uniform Buffer + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // descriptorType = Uniform Buffer 1, // descriptorCount = 1 - {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} + {{to_vk_shader_stage_flag_bits(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} + nullptr, // pImmutableSamplers = NULL }, {% endfor %} {% for sampled_image in sampled_images %} - DescriptorSetLayout{ + VkDescriptorSetLayoutBinding{ {{sampled_image.binding}}, // binding = {{sampled_image.binding}} - DescriptorType::kSampledImage, // descriptorType = Sampled Image + VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, // descriptorType = Sampled Image 1, // descriptorCount = 1 - {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} + {{to_vk_shader_stage_flag_bits(shader_stage)}},// stageFlags = {{to_shader_stage(shader_stage)}} + nullptr, // pImmutableSamplers = NULL }, {% endfor %} }; {% endif %} +#endif }; // struct {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn index 460502c838a61..9223f4646fb5f 100644 --- a/impeller/renderer/BUILD.gn +++ b/impeller/renderer/BUILD.gn @@ -22,7 +22,6 @@ impeller_component("renderer") { "command_buffer.h", "context.cc", "context.h", - "descriptor_set_layout.h", "device_buffer.cc", "device_buffer.h", "formats.cc", diff --git a/impeller/renderer/descriptor_set_layout.h b/impeller/renderer/descriptor_set_layout.h deleted file mode 100644 index d853f0a663086..0000000000000 --- a/impeller/renderer/descriptor_set_layout.h +++ /dev/null @@ -1,27 +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 "flutter/fml/macros.h" -#include "impeller/renderer/shader_types.h" - -namespace impeller { - -enum class DescriptorType { - kSampledImage, - kUniformBuffer, -}; - -struct DescriptorSetLayout { - uint32_t binding; - DescriptorType descriptor_type; - uint32_t descriptor_count; - ShaderStage shader_stage; -}; - -} // namespace impeller diff --git a/impeller/renderer/pipeline_builder.h b/impeller/renderer/pipeline_builder.h index 92def4e50b7ea..44cd202997cd9 100644 --- a/impeller/renderer/pipeline_builder.h +++ b/impeller/renderer/pipeline_builder.h @@ -93,13 +93,6 @@ struct PipelineBuilder { << VertexShader::kLabel << "'."; return false; } - if (!vertex_descriptor->SetDescriptorSetLayouts( - VertexShader::kDescriptorSetLayouts)) { - VALIDATION_LOG << "Cound not configure vertex descriptor set layout for" - " pipeline named '" - << VertexShader::kLabel << "'."; - return false; - } desc.SetVertexDescriptor(std::move(vertex_descriptor)); } diff --git a/impeller/renderer/vertex_descriptor.cc b/impeller/renderer/vertex_descriptor.cc index 963a7478a1696..a40efb31c5eb3 100644 --- a/impeller/renderer/vertex_descriptor.cc +++ b/impeller/renderer/vertex_descriptor.cc @@ -20,16 +20,6 @@ bool VertexDescriptor::SetStageInputs( return true; } -bool VertexDescriptor::SetDescriptorSetLayouts( - const DescriptorSetLayout desc_set_layout[], - size_t count) { - desc_set_layouts_.reserve(desc_set_layouts_.size() + count); - for (size_t i = 0; i < count; i++) { - desc_set_layouts_.emplace_back(desc_set_layout[i]); - } - return true; -} - // |Comparable| size_t VertexDescriptor::GetHash() const { auto seed = fml::HashCombine(); @@ -48,9 +38,4 @@ const std::vector& VertexDescriptor::GetStageInputs() const { return inputs_; } -const std::vector& -VertexDescriptor::GetDescriptorSetLayouts() const { - return desc_set_layouts_; -} - } // namespace impeller diff --git a/impeller/renderer/vertex_descriptor.h b/impeller/renderer/vertex_descriptor.h index dffe6694f7caf..4bef9b86d3644 100644 --- a/impeller/renderer/vertex_descriptor.h +++ b/impeller/renderer/vertex_descriptor.h @@ -8,7 +8,6 @@ #include "flutter/fml/macros.h" #include "impeller/base/comparable.h" -#include "impeller/renderer/descriptor_set_layout.h" #include "impeller/renderer/shader_types.h" namespace impeller { @@ -37,22 +36,11 @@ class VertexDescriptor final : public Comparable { return SetStageInputs(inputs.data(), inputs.size()); } - template - bool SetDescriptorSetLayouts( - const std::array& inputs) { - return SetDescriptorSetLayouts(inputs.data(), inputs.size()); - } - bool SetStageInputs(const ShaderStageIOSlot* const stage_inputs[], size_t count); - bool SetDescriptorSetLayouts(const DescriptorSetLayout desc_set_layout[], - size_t count); - const std::vector& GetStageInputs() const; - const std::vector& GetDescriptorSetLayouts() const; - // |Comparable| std::size_t GetHash() const override; @@ -61,7 +49,6 @@ class VertexDescriptor final : public Comparable { private: std::vector inputs_; - std::vector desc_set_layouts_; FML_DISALLOW_COPY_AND_ASSIGN(VertexDescriptor); }; From 633a2c868ac9547605164e3bd6976f2632c1e4da Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 19:34:05 -0400 Subject: [PATCH 085/558] Roll Fuchsia Linux SDK from TYBmxFHAk... to OsNl2rRU2... (#35144) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 26e42042eb2a9..df3e05bddd14e 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'TYBmxFHAk2GAhAAwJyXybWL9Zqe40KaFtodBUxHDAs4C' + 'version': 'OsNl2rRU2Ke1LGMaUiXwlLoCjQWJKyTR6NIFLJRaOasC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 753b07cfe5333..55edc85609001 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 340b6d2063fa5af664206d3291ee0286 +Signature: 09915b728e09affac80eb39f8f03a5a2 UNUSED LICENSES: From 2944653f476c516209ed15b9535651037171219a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 19:58:04 -0400 Subject: [PATCH 086/558] Roll Dart SDK from a8d90480d8ff to 1835098e9ae8 (3 revisions) (#35145) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index df3e05bddd14e..472ac94b1d212 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'a8d90480d8ff19da05c6aa82307a38ee2b294326', + 'dart_revision': '1835098e9ae82d5625b8dea4497d71f163ce8724', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 2eeb58079ed3f..0279daaec37b2 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 8311def9aedab010bc3f43706fd18193 +Signature: b84fd634f252e43672b79e2d014c3e59 UNUSED LICENSES: From 86d862da243e4b317b96e9d8fa3fd17cee5a625b Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 3 Aug 2022 18:56:04 -0700 Subject: [PATCH 087/558] [Impeller] Enable SDF approximation when drawing mask blurred solid Rects and RRects (#35151) --- impeller/aiks/canvas.cc | 43 +++++++++++++++++++ impeller/aiks/canvas.h | 6 +++ impeller/aiks/paint.cc | 15 +++++-- impeller/aiks/paint.h | 10 ++++- .../display_list/display_list_dispatcher.cc | 23 +++++----- 5 files changed, 80 insertions(+), 17 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 8b48264cf8527..6fd63ee662e06 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -5,11 +5,13 @@ #include "impeller/aiks/canvas.h" #include +#include #include "flutter/fml/logging.h" #include "impeller/aiks/paint_pass_delegate.h" #include "impeller/entity/contents/atlas_contents.h" #include "impeller/entity/contents/clip_contents.h" +#include "impeller/entity/contents/rrect_shadow_contents.h" #include "impeller/entity/contents/text_contents.h" #include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/contents/vertices_contents.h" @@ -146,10 +148,51 @@ void Canvas::DrawPaint(Paint paint) { GetCurrentPass().AddEntity(std::move(entity)); } +bool Canvas::AttemptDrawBlurredRRect(const Rect& rect, + Scalar corner_radius, + Paint& paint) { + if (!paint.mask_blur_descriptor.has_value() || + paint.mask_blur_descriptor->style != FilterContents::BlurStyle::kNormal || + paint.style != Paint::Style::kFill) { + return false; + } + + // For symmetrically mask blurred solid RRects, absorb the mask blur and use + // a faster SDF approximation. + + auto contents = std::make_shared(); + contents->SetColor(paint.color); + contents->SetSigma(paint.mask_blur_descriptor->sigma); + contents->SetRRect(rect, corner_radius); + + paint.mask_blur_descriptor = std::nullopt; + + Entity entity; + entity.SetTransformation(GetCurrentTransformation()); + entity.SetStencilDepth(GetStencilDepth()); + entity.SetBlendMode(paint.blend_mode); + entity.SetContents(paint.WithFilters(std::move(contents))); + + GetCurrentPass().AddEntity(std::move(entity)); + + return true; +} + void Canvas::DrawRect(Rect rect, Paint paint) { + if (AttemptDrawBlurredRRect(rect, 0, paint)) { + return; + } DrawPath(PathBuilder{}.AddRect(rect).TakePath(), std::move(paint)); } +void Canvas::DrawRRect(Rect rect, Scalar corner_radius, Paint paint) { + if (AttemptDrawBlurredRRect(rect, corner_radius, paint)) { + return; + } + DrawPath(PathBuilder{}.AddRoundedRect(rect, corner_radius).TakePath(), + std::move(paint)); +} + void Canvas::DrawCircle(Point center, Scalar radius, Paint paint) { DrawPath(PathBuilder{}.AddCircle(center, radius).TakePath(), std::move(paint)); diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index e2257a92ab468..78f6fa9a0f627 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -70,6 +70,8 @@ class Canvas { void DrawRect(Rect rect, Paint paint); + void DrawRRect(Rect rect, Scalar corner_radius, Paint paint); + void DrawCircle(Point center, Scalar radius, Paint paint); void DrawImage(std::shared_ptr image, @@ -126,6 +128,10 @@ class Canvas { void RestoreClip(); + bool AttemptDrawBlurredRRect(const Rect& rect, + Scalar corner_radius, + Paint& paint); + FML_DISALLOW_COPY_AND_ASSIGN(Canvas); }; diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 6a71dc46d7379..e32b556a07fca 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -43,9 +43,9 @@ std::shared_ptr Paint::WithFilters( std::optional is_solid_color) const { bool is_solid_color_val = is_solid_color.value_or(!contents); - if (mask_filter.has_value()) { - const MaskFilterProc& filter = mask_filter.value(); - input = filter(FilterInput::Make(input), is_solid_color_val); + if (mask_blur_descriptor.has_value()) { + input = mask_blur_descriptor->CreateMaskBlur(FilterInput::Make(input), + is_solid_color_val); } if (image_filter.has_value()) { @@ -61,4 +61,13 @@ std::shared_ptr Paint::WithFilters( return input; } +std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( + FilterInput::Ref input, + bool is_solid_color) const { + if (is_solid_color) { + return FilterContents::MakeGaussianBlur(input, sigma, sigma, style); + } + return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style); +} + } // namespace impeller diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index edf9b197668c4..2a9f831bd06db 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -30,6 +30,14 @@ struct Paint { kStroke, }; + struct MaskBlurDescriptor { + FilterContents::BlurStyle style; + Sigma sigma; + + std::shared_ptr CreateMaskBlur(FilterInput::Ref input, + bool is_solid_color) const; + }; + Color color = Color::Black(); std::shared_ptr contents; @@ -42,7 +50,7 @@ struct Paint { std::optional image_filter; std::optional color_filter; - std::optional mask_filter; + std::optional mask_blur_descriptor; /// @brief Wrap this paint's configured filters to the given contents. /// @param[in] input The contents to wrap with paint's filters. diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index cdb0edf10907c..b78cffd2aa4e2 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -345,22 +345,16 @@ static FilterContents::BlurStyle ToBlurStyle(SkBlurStyle blur_style) { void DisplayListDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) { // Needs https://github.com/flutter/flutter/issues/95434 if (filter == nullptr) { - paint_.mask_filter = std::nullopt; + paint_.mask_blur_descriptor = std::nullopt; return; } switch (filter->type()) { case flutter::DlMaskFilterType::kBlur: { auto blur = filter->asBlur(); - auto style = ToBlurStyle(blur->style()); - auto sigma = Sigma(blur->sigma()); - - paint_.mask_filter = [style, sigma](FilterInput::Ref input, - bool is_solid_color) { - if (is_solid_color) { - return FilterContents::MakeGaussianBlur(input, sigma, sigma, style); - } - return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style); + paint_.mask_blur_descriptor = { + .style = ToBlurStyle(blur->style()), + .sigma = Sigma(blur->sigma()), }; break; } @@ -709,8 +703,7 @@ void DisplayListDispatcher::drawLine(const SkPoint& p0, const SkPoint& p1) { // |flutter::Dispatcher| void DisplayListDispatcher::drawRect(const SkRect& rect) { - auto path = PathBuilder{}.AddRect(ToRect(rect)).TakePath(); - canvas_.DrawPath(std::move(path), paint_); + canvas_.DrawRect(ToRect(rect), paint_); } // |flutter::Dispatcher| @@ -727,7 +720,11 @@ void DisplayListDispatcher::drawCircle(const SkPoint& center, SkScalar radius) { // |flutter::Dispatcher| void DisplayListDispatcher::drawRRect(const SkRRect& rrect) { - canvas_.DrawPath(ToPath(rrect), paint_); + if (rrect.isSimple()) { + canvas_.DrawRRect(ToRect(rrect.rect()), rrect.getSimpleRadii().fX, paint_); + } else { + canvas_.DrawPath(ToPath(rrect), paint_); + } } // |flutter::Dispatcher| From 7b6911a843c4f8db3e9e4d289f79d03370e9e491 Mon Sep 17 00:00:00 2001 From: Nayuta403 <40540394+Nayuta403@users.noreply.github.com> Date: Thu, 4 Aug 2022 11:43:04 +0800 Subject: [PATCH 088/558] Make FlutterEngineGroup support more params (#107394) (#34663) --- .../embedding/engine/FlutterEngine.java | 11 +- .../embedding/engine/FlutterEngineGroup.java | 100 ++++++++++- .../FlutterEngineGroupComponentTest.java | 155 +++++++++++++++--- 3 files changed, 236 insertions(+), 30 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java index 708e3f4a8c241..8fb3bf2a6a37c 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngine.java @@ -393,7 +393,10 @@ private boolean isAttachedToJni() { @NonNull Context context, @NonNull DartEntrypoint dartEntrypoint, @Nullable String initialRoute, - @Nullable List dartEntrypointArgs) { + @Nullable List dartEntrypointArgs, + @Nullable PlatformViewsController platformViewsController, + boolean automaticallyRegisterPlugins, + boolean waitForRestorationData) { if (!isAttachedToJni()) { throw new IllegalStateException( "Spawn can only be called on a fully constructed FlutterEngine"); @@ -409,7 +412,11 @@ private boolean isAttachedToJni() { context, // Context. null, // FlutterLoader. A null value passed here causes the constructor to get it from the // FlutterInjector. - newFlutterJNI); // FlutterJNI. + newFlutterJNI, // FlutterJNI. + platformViewsController, // PlatformViewsController. + null, // String[]. The Dart VM has already started, this arguments will have no effect. + automaticallyRegisterPlugins, // boolean. + waitForRestorationData); // boolean } /** diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngineGroup.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngineGroup.java index bb1a9ba2995cf..fc9a95c2dd7bf 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngineGroup.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngineGroup.java @@ -11,6 +11,7 @@ import io.flutter.FlutterInjector; import io.flutter.embedding.engine.dart.DartExecutor.DartEntrypoint; import io.flutter.embedding.engine.loader.FlutterLoader; +import io.flutter.plugin.platform.PlatformViewsController; import java.util.ArrayList; import java.util.List; @@ -142,20 +143,39 @@ public FlutterEngine createAndRunEngine(@NonNull Options options) { DartEntrypoint dartEntrypoint = options.getDartEntrypoint(); String initialRoute = options.getInitialRoute(); List dartEntrypointArgs = options.getDartEntrypointArgs(); + PlatformViewsController platformViewsController = options.getPlatformViewsController(); + platformViewsController = + platformViewsController != null ? platformViewsController : new PlatformViewsController(); + boolean automaticallyRegisterPlugins = options.getAutomaticallyRegisterPlugins(); + boolean waitForRestorationData = options.getWaitForRestorationData(); if (dartEntrypoint == null) { dartEntrypoint = DartEntrypoint.createDefault(); } if (activeEngines.size() == 0) { - engine = createEngine(context); + engine = + createEngine( + context, + platformViewsController, + automaticallyRegisterPlugins, + waitForRestorationData); if (initialRoute != null) { engine.getNavigationChannel().setInitialRoute(initialRoute); } engine.getDartExecutor().executeDartEntrypoint(dartEntrypoint, dartEntrypointArgs); } else { engine = - activeEngines.get(0).spawn(context, dartEntrypoint, initialRoute, dartEntrypointArgs); + activeEngines + .get(0) + .spawn( + context, + dartEntrypoint, + initialRoute, + dartEntrypointArgs, + platformViewsController, + automaticallyRegisterPlugins, + waitForRestorationData); } activeEngines.add(engine); @@ -178,8 +198,19 @@ public void onEngineWillDestroy() { } @VisibleForTesting - /* package */ FlutterEngine createEngine(Context context) { - return new FlutterEngine(context); + /* package */ FlutterEngine createEngine( + Context context, + @NonNull PlatformViewsController platformViewsController, + boolean automaticallyRegisterPlugins, + boolean waitForRestorationData) { + return new FlutterEngine( + context, // Context. + null, // FlutterLoader. + null, // FlutterJNI. + platformViewsController, // PlatformViewsController. + null, // String[]. The Dart VM has already started, this arguments will have no effect. + automaticallyRegisterPlugins, // boolean. + waitForRestorationData); // boolean. } /** Options that control how a FlutterEngine should be created. */ @@ -188,6 +219,9 @@ public static class Options { @Nullable private DartEntrypoint dartEntrypoint; @Nullable private String initialRoute; @Nullable private List dartEntrypointArgs; + @NonNull private PlatformViewsController platformViewsController; + private boolean automaticallyRegisterPlugins = true; + private boolean waitForRestorationData = false; public Options(@NonNull Context context) { this.context = context; @@ -219,6 +253,28 @@ public List getDartEntrypointArgs() { return dartEntrypointArgs; } + /** Manages platform views. */ + public PlatformViewsController getPlatformViewsController() { + return platformViewsController; + } + + /** + * If plugins are automatically registered, then they are registered during the {@link + * io.flutter.embedding.engine.FlutterEngine}'s constructor. + */ + public boolean getAutomaticallyRegisterPlugins() { + return automaticallyRegisterPlugins; + } + + /** + * The waitForRestorationData flag controls whether the engine delays responding to requests + * from the framework for restoration data until that data has been provided to the engine via + * {@code RestorationChannel.setRestorationData(byte[] data)}. + */ + public boolean getWaitForRestorationData() { + return waitForRestorationData; + } + /** * Setter for `dartEntrypoint` property. * @@ -251,5 +307,41 @@ public Options setDartEntrypointArgs(List dartEntrypointArgs) { this.dartEntrypointArgs = dartEntrypointArgs; return this; } + + /** + * Setter for `platformViewsController` property. + * + * @param platformViewsController Manages platform views. + */ + public Options setPlatformViewsController( + @NonNull PlatformViewsController platformViewsController) { + this.platformViewsController = platformViewsController; + return this; + } + + /** + * Setter for `automaticallyRegisterPlugins` property. + * + * @param automaticallyRegisterPlugins If plugins are automatically registered, then they are + * registered during the execution of {@link io.flutter.embedding.engine.FlutterEngine}'s + * constructor. + */ + public Options setAutomaticallyRegisterPlugins(boolean automaticallyRegisterPlugins) { + this.automaticallyRegisterPlugins = automaticallyRegisterPlugins; + return this; + } + + /** + * Setter for `waitForRestorationData` property. + * + * @param waitForRestorationData The waitForRestorationData flag controls whether the engine + * delays responding to requests from the framework for restoration data until that data has + * been provided to the engine via {@code RestorationChannel.setRestorationData(byte[] + * data)}. + */ + public Options setWaitForRestorationData(boolean waitForRestorationData) { + this.waitForRestorationData = waitForRestorationData; + return this; + } } } diff --git a/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineGroupComponentTest.java b/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineGroupComponentTest.java index 223ec86f3d342..4e91e7788ca64 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineGroupComponentTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineGroupComponentTest.java @@ -5,6 +5,7 @@ package io.flutter.embedding.engine; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; @@ -25,6 +26,7 @@ import io.flutter.embedding.engine.dart.DartExecutor.DartEntrypoint; import io.flutter.embedding.engine.loader.FlutterLoader; import io.flutter.embedding.engine.systemchannels.NavigationChannel; +import io.flutter.plugin.platform.PlatformViewsController; import io.flutter.plugins.GeneratedPluginRegistrant; import java.util.ArrayList; import java.util.List; @@ -42,7 +44,7 @@ @RunWith(AndroidJUnit4.class) public class FlutterEngineGroupComponentTest { private final Context ctx = ApplicationProvider.getApplicationContext(); - @Mock FlutterJNI mockflutterJNI; + @Mock FlutterJNI mockFlutterJNI; @Mock FlutterLoader mockFlutterLoader; FlutterEngineGroup engineGroupUnderTest; FlutterEngine firstEngineUnderTest; @@ -54,26 +56,46 @@ public void setUp() { MockitoAnnotations.openMocks(this); jniAttached = false; - when(mockflutterJNI.isAttached()).thenAnswer(invocation -> jniAttached); - doAnswer(invocation -> jniAttached = true).when(mockflutterJNI).attachToNative(); + when(mockFlutterJNI.isAttached()).thenAnswer(invocation -> jniAttached); + doAnswer(invocation -> jniAttached = true).when(mockFlutterJNI).attachToNative(); GeneratedPluginRegistrant.clearRegisteredEngines(); when(mockFlutterLoader.findAppBundlePath()).thenReturn("some/path/to/flutter_assets"); + + FlutterJNI.Factory jniFactory = + new FlutterJNI.Factory() { + @Override + public FlutterJNI provideFlutterJNI() { + // The default implementation is that `new FlutterJNI()` will report errors when + // creating the engine later, + // Change mockFlutterJNI to the default so that we can create the engine directly in + // later tests + return mockFlutterJNI; + } + }; + FlutterInjector.setInstance( - new FlutterInjector.Builder().setFlutterLoader(mockFlutterLoader).build()); + new FlutterInjector.Builder() + .setFlutterLoader(mockFlutterLoader) + .setFlutterJNIFactory(jniFactory) + .build()); firstEngineUnderTest = spy( new FlutterEngine( ctx, mock(FlutterLoader.class), - mockflutterJNI, + mockFlutterJNI, /*dartVmArgs=*/ new String[] {}, /*automaticallyRegisterPlugins=*/ false)); engineGroupUnderTest = new FlutterEngineGroup(ctx) { @Override - FlutterEngine createEngine(Context context) { + FlutterEngine createEngine( + Context context, + PlatformViewsController platformViewsController, + boolean automaticallyRegisterPlugins, + boolean waitForRestorationData) { return firstEngineUnderTest; } }; @@ -124,7 +146,10 @@ public void canSpawnMoreEngines() { any(Context.class), any(DartEntrypoint.class), nullable(String.class), - nullable(List.class)); + nullable(List.class), + any(PlatformViewsController.class), + any(Boolean.class), + any(Boolean.class)); FlutterEngine secondEngine = engineGroupUnderTest.createAndRunEngine(ctx, mock(DartEntrypoint.class)); @@ -139,7 +164,10 @@ public void canSpawnMoreEngines() { any(Context.class), any(DartEntrypoint.class), nullable(String.class), - nullable(List.class))) + nullable(List.class), + any(PlatformViewsController.class), + any(Boolean.class), + any(Boolean.class))) .thenReturn(mock(FlutterEngine.class)); FlutterEngine thirdEngine = @@ -156,7 +184,7 @@ public void canCreateAndRunCustomEntrypoints() { FlutterInjector.instance().flutterLoader().findAppBundlePath(), "other entrypoint")); assertEquals(1, engineGroupUnderTest.activeEngines.size()); - verify(mockflutterJNI, times(1)) + verify(mockFlutterJNI, times(1)) .runBundleAndSnapshotFromLibrary( eq("some/path/to/flutter_assets"), eq("other entrypoint"), @@ -174,13 +202,13 @@ public void canCreateAndRunWithCustomInitialRoute() { assertEquals(1, engineGroupUnderTest.activeEngines.size()); verify(firstEngine.getNavigationChannel(), times(1)).setInitialRoute("/foo"); - when(mockflutterJNI.isAttached()).thenReturn(true); + when(mockFlutterJNI.isAttached()).thenReturn(true); jniAttached = false; - FlutterJNI secondMockflutterJNI = mock(FlutterJNI.class); - when(secondMockflutterJNI.isAttached()).thenAnswer(invocation -> jniAttached); - doAnswer(invocation -> jniAttached = true).when(secondMockflutterJNI).attachToNative(); - doReturn(secondMockflutterJNI) - .when(mockflutterJNI) + FlutterJNI secondMockFlutterJNI = mock(FlutterJNI.class); + when(secondMockFlutterJNI.isAttached()).thenAnswer(invocation -> jniAttached); + doAnswer(invocation -> jniAttached = true).when(secondMockFlutterJNI).attachToNative(); + doReturn(secondMockFlutterJNI) + .when(mockFlutterJNI) .spawn( nullable(String.class), nullable(String.class), @@ -191,7 +219,7 @@ public void canCreateAndRunWithCustomInitialRoute() { engineGroupUnderTest.createAndRunEngine(ctx, mock(DartEntrypoint.class), "/bar"); assertEquals(2, engineGroupUnderTest.activeEngines.size()); - verify(mockflutterJNI, times(1)) + verify(mockFlutterJNI, times(1)) .spawn(nullable(String.class), nullable(String.class), eq("/bar"), nullable(List.class)); } @@ -204,7 +232,7 @@ public void canCreateAndRunWithCustomEntrypointArgs() { .setDartEntrypoint(mock(DartEntrypoint.class)) .setDartEntrypointArgs(firstDartEntrypointArgs)); assertEquals(1, engineGroupUnderTest.activeEngines.size()); - verify(mockflutterJNI, times(1)) + verify(mockFlutterJNI, times(1)) .runBundleAndSnapshotFromLibrary( nullable(String.class), nullable(String.class), @@ -212,13 +240,13 @@ public void canCreateAndRunWithCustomEntrypointArgs() { any(AssetManager.class), eq(firstDartEntrypointArgs)); - when(mockflutterJNI.isAttached()).thenReturn(true); + when(mockFlutterJNI.isAttached()).thenReturn(true); jniAttached = false; - FlutterJNI secondMockflutterJNI = mock(FlutterJNI.class); - when(secondMockflutterJNI.isAttached()).thenAnswer(invocation -> jniAttached); - doAnswer(invocation -> jniAttached = true).when(secondMockflutterJNI).attachToNative(); - doReturn(secondMockflutterJNI) - .when(mockflutterJNI) + FlutterJNI secondMockFlutterJNI = mock(FlutterJNI.class); + when(secondMockFlutterJNI.isAttached()).thenAnswer(invocation -> jniAttached); + doAnswer(invocation -> jniAttached = true).when(secondMockFlutterJNI).attachToNative(); + doReturn(secondMockFlutterJNI) + .when(mockFlutterJNI) .spawn( nullable(String.class), nullable(String.class), @@ -232,11 +260,90 @@ public void canCreateAndRunWithCustomEntrypointArgs() { .setDartEntrypointArgs(secondDartEntrypointArgs)); assertEquals(2, engineGroupUnderTest.activeEngines.size()); - verify(mockflutterJNI, times(1)) + verify(mockFlutterJNI, times(1)) .spawn( nullable(String.class), nullable(String.class), nullable(String.class), eq(secondDartEntrypointArgs)); } + + @Test + public void createEngineSupportMoreParams() { + // Create a new FlutterEngineGroup because the first engine created in engineGroupUnderTest was + // changed to firstEngineUnderTest in `setUp()`, so can't use it to validate params. + FlutterEngineGroup engineGroup = new FlutterEngineGroup(ctx); + + PlatformViewsController controller = new PlatformViewsController(); + boolean waitForRestorationData = true; + boolean automaticallyRegisterPlugins = true; + + when(FlutterInjector.instance().flutterLoader().automaticallyRegisterPlugins()) + .thenReturn(true); + assertTrue(FlutterInjector.instance().flutterLoader().automaticallyRegisterPlugins()); + assertEquals(0, GeneratedPluginRegistrant.getRegisteredEngines().size()); + + FlutterEngine firstEngine = + engineGroup.createAndRunEngine( + new FlutterEngineGroup.Options(ctx) + .setDartEntrypoint(mock(DartEntrypoint.class)) + .setPlatformViewsController(controller) + .setWaitForRestorationData(waitForRestorationData) + .setAutomaticallyRegisterPlugins(automaticallyRegisterPlugins)); + + assertEquals(1, GeneratedPluginRegistrant.getRegisteredEngines().size()); + assertEquals(controller, firstEngine.getPlatformViewsController()); + assertEquals( + waitForRestorationData, firstEngine.getRestorationChannel().waitForRestorationData); + } + + @Test + public void spawnEngineSupportMoreParams() { + FlutterEngine firstEngine = + engineGroupUnderTest.createAndRunEngine( + new FlutterEngineGroup.Options(ctx).setDartEntrypoint(mock(DartEntrypoint.class))); + assertEquals(1, engineGroupUnderTest.activeEngines.size()); + verify(mockFlutterJNI, times(1)) + .runBundleAndSnapshotFromLibrary( + nullable(String.class), + nullable(String.class), + isNull(), + any(AssetManager.class), + nullable(List.class)); + + when(mockFlutterJNI.isAttached()).thenReturn(true); + jniAttached = false; + FlutterJNI secondMockFlutterJNI = mock(FlutterJNI.class); + when(secondMockFlutterJNI.isAttached()).thenAnswer(invocation -> jniAttached); + doAnswer(invocation -> jniAttached = true).when(secondMockFlutterJNI).attachToNative(); + doReturn(secondMockFlutterJNI) + .when(mockFlutterJNI) + .spawn( + nullable(String.class), + nullable(String.class), + nullable(String.class), + nullable(List.class)); + + PlatformViewsController controller = new PlatformViewsController(); + boolean waitForRestorationData = false; + boolean automaticallyRegisterPlugins = false; + + when(FlutterInjector.instance().flutterLoader().automaticallyRegisterPlugins()) + .thenReturn(true); + assertTrue(FlutterInjector.instance().flutterLoader().automaticallyRegisterPlugins()); + assertEquals(0, GeneratedPluginRegistrant.getRegisteredEngines().size()); + + FlutterEngine secondEngine = + engineGroupUnderTest.createAndRunEngine( + new FlutterEngineGroup.Options(ctx) + .setDartEntrypoint(mock(DartEntrypoint.class)) + .setWaitForRestorationData(waitForRestorationData) + .setPlatformViewsController(controller) + .setAutomaticallyRegisterPlugins(automaticallyRegisterPlugins)); + + assertEquals( + waitForRestorationData, secondEngine.getRestorationChannel().waitForRestorationData); + assertEquals(controller, secondEngine.getPlatformViewsController()); + assertEquals(0, GeneratedPluginRegistrant.getRegisteredEngines().size()); + } } From e32e0d217b96ff985699e1b41a18da3c8e485c2b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 3 Aug 2022 23:54:05 -0400 Subject: [PATCH 089/558] Roll Dart SDK from 1835098e9ae8 to 2a422d5af6c8 (1 revision) (#35152) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 472ac94b1d212..6e2fc21f179ad 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '1835098e9ae82d5625b8dea4497d71f163ce8724', + 'dart_revision': '2a422d5af6c8e7e9c6a3c37dcf41f905378a3218', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 87874adcfb0c2210446ef558d3f38043f1b1de42 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Wed, 3 Aug 2022 21:36:03 -0700 Subject: [PATCH 090/558] Don't redefine SkSL builtin 'saturate' (#35154) --- impeller/fixtures/ink_sparkle.frag | 10 +++------- .../shaders/general_shaders/uniforms_sorted.frag | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/impeller/fixtures/ink_sparkle.frag b/impeller/fixtures/ink_sparkle.frag index adc410c776c1b..1b3a43ca45d35 100644 --- a/impeller/fixtures/ink_sparkle.frag +++ b/impeller/fixtures/ink_sparkle.frag @@ -32,10 +32,6 @@ const float PI_ROTATE_LEFT = PI * -0.0078125; const float ONE_THIRD = 1./3.; const vec2 TURBULENCE_SCALE = vec2(0.8); -float saturate(float x) { - return clamp(x, 0.0, 1.0); -} - float triangle_noise(highp vec2 n) { n = fract(n * vec2(5.3987, 5.4421)); n += dot(n.yx, n.xy + vec2(21.5351, 14.3137)); @@ -60,7 +56,7 @@ float soft_circle(vec2 uv, vec2 xy, float radius, float blur) { float soft_ring(vec2 uv, vec2 xy, float radius, float thickness, float blur) { float circle_outer = soft_circle(uv, xy, radius + thickness, blur); float circle_inner = soft_circle(uv, xy, max(radius - thickness, 0.0), blur); - return saturate(circle_outer - circle_inner); + return clamp(circle_outer - circle_inner, 0.0, 1.0); } float circle_grid(vec2 resolution, vec2 p, vec2 xy, vec2 rotation, float cell_diameter) { @@ -77,7 +73,7 @@ float sparkle(vec2 uv, float t) { s += threshold(n + sin(PI * (t + 0.35)), 0.1, 0.15); s += threshold(n + sin(PI * (t + 0.7)), 0.2, 0.25); s += threshold(n + sin(PI * (t + 1.05)), 0.3, 0.35); - return saturate(s) * 0.55; + return clamp(s, 0.0, 1.0) * 0.55; } float turbulence(vec2 uv) { @@ -86,7 +82,7 @@ float turbulence(vec2 uv) { 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 saturate(0.45 + 0.8 * v); + return clamp(0.45 + 0.8 * v, 0.0, 1.0); } void main() { diff --git a/lib/ui/fixtures/shaders/general_shaders/uniforms_sorted.frag b/lib/ui/fixtures/shaders/general_shaders/uniforms_sorted.frag index e7e191fe49e96..3c97433f004ba 100644 --- a/lib/ui/fixtures/shaders/general_shaders/uniforms_sorted.frag +++ b/lib/ui/fixtures/shaders/general_shaders/uniforms_sorted.frag @@ -37,10 +37,6 @@ const float PI_ROTATE_LEFT = PI * -0.0078125; const float ONE_THIRD = 1./3.; const vec2 TURBULENCE_SCALE = vec2(0.8); -float saturate(float x) { - return clamp(x, 0.0, 1.0); -} - float triangle_noise(highp vec2 n) { n = fract(n * vec2(5.3987, 5.4421)); n += dot(n.yx, n.xy + vec2(21.5351, 14.3137)); @@ -65,7 +61,7 @@ float soft_circle(vec2 uv, vec2 xy, float radius, float blur) { float soft_ring(vec2 uv, vec2 xy, float radius, float thickness, float blur) { float circle_outer = soft_circle(uv, xy, radius + thickness, blur); float circle_inner = soft_circle(uv, xy, max(radius - thickness, 0.0), blur); - return saturate(circle_outer - circle_inner); + return clamp(circle_outer - circle_inner, 0.0, 1.0); } float circle_grid(vec2 resolution, vec2 p, vec2 xy, vec2 rotation, float cell_diameter) { @@ -82,7 +78,7 @@ float sparkle(vec2 uv, float t) { s += threshold(n + sin(PI * (t + 0.35)), 0.1, 0.15); s += threshold(n + sin(PI * (t + 0.7)), 0.2, 0.25); s += threshold(n + sin(PI * (t + 1.05)), 0.3, 0.35); - return saturate(s) * 0.55; + return clamp(s, 0.0, 1.0) * 0.55; } float turbulence(vec2 uv) { @@ -91,7 +87,7 @@ float turbulence(vec2 uv) { 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 saturate(0.45 + 0.8 * v); + return clamp(0.45 + 0.8 * v, 0.0, 1.0); } void main() { From 9752a2014e5eecafe0709ac688a1a9bdea88d81a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 4 Aug 2022 03:01:06 -0400 Subject: [PATCH 091/558] Roll Skia from 4744b2aaa20d to 1617a4027d3b (9 revisions) (#35156) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6e2fc21f179ad..b522c52dcbf16 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': '4744b2aaa20d2111118bb987dab9a7ac87b138b7', + 'skia_revision': '1617a4027d3b802b034d718cdd8ace2c520f483f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index bbafe7a432934..3cb97a94ed5da 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: dc555eec561bf2ffbcf7b205d7e3bf31 +Signature: 44880828aa8f200231751c14894fb1f7 UNUSED LICENSES: From c4b86c9154fe7caa2519e8bf00bb1255ff28ae80 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 4 Aug 2022 04:52:04 -0400 Subject: [PATCH 092/558] Roll Dart SDK from 2a422d5af6c8 to 05131e03aa5e (1 revision) (#35158) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index b522c52dcbf16..71ec7d59a3ca5 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '2a422d5af6c8e7e9c6a3c37dcf41f905378a3218', + 'dart_revision': '05131e03aa5e1a8af8e7a6c0f1f9583f583f9623', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -203,7 +203,7 @@ deps = { Var('dart_git') + '/dart_style.git@d7b73536a8079331c888b7da539b80e6825270ea', 'src/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@7edeeeb20a506cadec3788c273fdee6cad91e07c', + Var('dart_git') + '/dartdoc.git@bd57c0e7b7562abda6d556ce5a386b67fb4ff4c7', 'src/third_party/dart/third_party/pkg/ffi': Var('dart_git') + '/ffi.git@18b2b549d55009ff594600b04705ff6161681e07', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 0279daaec37b2..36063f715ed80 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: b84fd634f252e43672b79e2d014c3e59 +Signature: 73196eb1d0cecd56c98d3465d14bfefb UNUSED LICENSES: From 02c1ca78b8779c79ece401a01c7fb9aab9696e70 Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Thu, 4 Aug 2022 17:21:09 +0800 Subject: [PATCH 093/558] [Impeller] Implement tile mode for linear gradient and radial gradient (#35087) --- impeller/aiks/aiks_unittests.cc | 51 +++++++++++++++---- .../compiler/shader_lib/impeller/texture.glsl | 24 +++++++++ .../display_list/display_list_dispatcher.cc | 3 ++ .../contents/linear_gradient_contents.cc | 5 ++ .../contents/linear_gradient_contents.h | 4 ++ .../contents/radial_gradient_contents.cc | 5 ++ .../contents/radial_gradient_contents.h | 4 ++ impeller/entity/entity.h | 22 ++++++++ impeller/entity/shaders/gradient_fill.frag | 13 ++++- .../entity/shaders/radial_gradient_fill.frag | 11 +++- 10 files changed, 130 insertions(+), 12 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 4d0e29b4782d8..55e5a9f1e6dd3 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -203,18 +203,51 @@ TEST_P(AiksTest, CanSaveLayerStandalone) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -TEST_P(AiksTest, CanRenderRadialGradient) { +TEST_P(AiksTest, CanRenderLinearGradient) { Canvas canvas; + Paint paint; + std::vector offsets = { + {0, 0, 0}, {0, 300, 0}, {300, 0, 0}, {300, 300, 0}}; + std::vector tile_modes = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + for (int i = 0; i < 4; i++) { + canvas.Save(); + canvas.Translate(offsets[i]); + auto contents = std::make_shared(); + contents->SetEndPoints({0, 0}, {100, 100}); + std::vector colors = {Color{0.9019, 0.3921, 0.3960, 1.0}, + Color{0.5686, 0.5960, 0.8980, 1.0}}; + contents->SetColors(std::move(colors)); + contents->SetTileMode(tile_modes[i]); + paint.contents = contents; + canvas.DrawRect({0, 0, 200, 200}, paint); + canvas.Restore(); + } + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} +TEST_P(AiksTest, CanRenderRadialGradient) { + Canvas canvas; Paint paint; - auto contents = std::make_shared(); - contents->SetCenterAndRadius({125, 125}, 100); - std::vector colors = {Color{0.9019, 0.3921, 0.3960, 1.0}, - Color{0.5686, 0.5960, 0.8980, 1.0}}; - contents->SetColors(std::move(colors)); - paint.contents = contents; - - canvas.DrawRect({25, 25, 200, 200}, paint); + std::vector offsets = { + {0, 0, 0}, {0, 300, 0}, {300, 0, 0}, {300, 300, 0}}; + std::vector tile_modes = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + for (int i = 0; i < 4; i++) { + canvas.Save(); + canvas.Translate(offsets[i]); + auto contents = std::make_shared(); + contents->SetCenterAndRadius({50, 50}, 50); + std::vector colors = {Color{0.9019, 0.3921, 0.3960, 1.0}, + Color{0.5686, 0.5960, 0.8980, 1.0}}; + contents->SetColors(std::move(colors)); + contents->SetTileMode(tile_modes[i]); + paint.contents = contents; + canvas.DrawRect({0, 0, 200, 200}, paint); + canvas.Restore(); + } ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } diff --git a/impeller/compiler/shader_lib/impeller/texture.glsl b/impeller/compiler/shader_lib/impeller/texture.glsl index 5d2498377147c..9ef001303be88 100644 --- a/impeller/compiler/shader_lib/impeller/texture.glsl +++ b/impeller/compiler/shader_lib/impeller/texture.glsl @@ -28,4 +28,28 @@ vec4 IPSampleClampToBorder(sampler2D tex, vec2 uv) { return texture(tex, uv) * within_bounds; } + +// These values must correspond to the order of the items in the +// 'Entity::TileMode' enum class. +const float kTileModeClamp = 0; +const float kTileModeRepeat = 1; +const float kTileModeMirror = 2; +const float kTileModeDecal = 3; + +/// Compute an interpolant value "t". +/// +/// The domain appears to be any value and the range is [0 to 1]. +float IPTileTextureCoords(float t, float tile_mode) { + if (tile_mode == kTileModeClamp) { + t = clamp(t, 0.0, 1.0); + } else if (tile_mode == kTileModeRepeat) { + t = fract(t); + } else if (tile_mode == kTileModeMirror) { + float t1 = t - 1; + float t2 = t1 - 2 * floor(t1 * 0.5) - 1; + t = abs(t2); + } + return t; +} + #endif diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index b78cffd2aa4e2..550e9d4816212 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -246,6 +246,7 @@ void DisplayListDispatcher::setColorSource( colors.emplace_back(ToColor(linear->colors()[i])); } contents->SetColors(std::move(colors)); + contents->SetTileMode(static_cast(linear->tile_mode())); paint_.contents = std::move(contents); return; } @@ -261,6 +262,8 @@ void DisplayListDispatcher::setColorSource( colors.emplace_back(ToColor(radialGradient->colors()[i])); } contents->SetColors(std::move(colors)); + contents->SetTileMode( + static_cast(radialGradient->tile_mode())); paint_.contents = std::move(contents); return; } diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index d4188efbecad4..374e990d4e5a0 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -35,6 +35,10 @@ void LinearGradientContents::SetColors(std::vector colors) { } } +void LinearGradientContents::SetTileMode(Entity::TileMode tile_mode) { + tile_mode_ = tile_mode; +} + const std::vector& LinearGradientContents::GetColors() const { return colors_; } @@ -77,6 +81,7 @@ bool LinearGradientContents::Render(const ContentContext& renderer, gradient_info.end_point = end_point_; gradient_info.start_color = colors_[0].Premultiply(); gradient_info.end_color = colors_[1].Premultiply(); + gradient_info.tile_mode = static_cast(tile_mode_); Command cmd; cmd.label = "LinearGradientFill"; diff --git a/impeller/entity/contents/linear_gradient_contents.h b/impeller/entity/contents/linear_gradient_contents.h index e534a9423e39c..71605fdd0fd43 100644 --- a/impeller/entity/contents/linear_gradient_contents.h +++ b/impeller/entity/contents/linear_gradient_contents.h @@ -10,6 +10,7 @@ #include "flutter/fml/macros.h" #include "impeller/entity/contents/path_contents.h" +#include "impeller/entity/entity.h" #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" @@ -36,6 +37,8 @@ class LinearGradientContents final : public PathContents { void SetColors(std::vector colors); + void SetTileMode(Entity::TileMode tile_mode); + const std::vector& GetColors() const; private: @@ -43,6 +46,7 @@ class LinearGradientContents final : public PathContents { Point start_point_; Point end_point_; std::vector colors_; + Entity::TileMode tile_mode_; FML_DISALLOW_COPY_AND_ASSIGN(LinearGradientContents); }; diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index f94fca51164f5..4ea50e0a1dd6d 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -35,6 +35,10 @@ void RadialGradientContents::SetColors(std::vector colors) { } } +void RadialGradientContents::SetTileMode(Entity::TileMode tile_mode) { + tile_mode_ = tile_mode; +} + const std::vector& RadialGradientContents::GetColors() const { return colors_; } @@ -77,6 +81,7 @@ bool RadialGradientContents::Render(const ContentContext& renderer, gradient_info.radius = radius_; gradient_info.center_color = colors_[0].Premultiply(); gradient_info.edge_color = colors_[1].Premultiply(); + gradient_info.tile_mode = static_cast(tile_mode_); Command cmd; cmd.label = "RadialGradientFill"; diff --git a/impeller/entity/contents/radial_gradient_contents.h b/impeller/entity/contents/radial_gradient_contents.h index 83e096841dddd..3e936ae383fba 100644 --- a/impeller/entity/contents/radial_gradient_contents.h +++ b/impeller/entity/contents/radial_gradient_contents.h @@ -10,6 +10,7 @@ #include "flutter/fml/macros.h" #include "impeller/entity/contents/path_contents.h" +#include "impeller/entity/entity.h" #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" #include "impeller/geometry/point.h" @@ -36,6 +37,8 @@ class RadialGradientContents final : public PathContents { void SetColors(std::vector colors); + void SetTileMode(Entity::TileMode tile_mode); + const std::vector& GetColors() const; private: @@ -43,6 +46,7 @@ class RadialGradientContents final : public PathContents { Point center_; Scalar radius_; std::vector colors_; + Entity::TileMode tile_mode_; FML_DISALLOW_COPY_AND_ASSIGN(RadialGradientContents); }; diff --git a/impeller/entity/entity.h b/impeller/entity/entity.h index 7c83f0f2da726..b79ce60699260 100644 --- a/impeller/entity/entity.h +++ b/impeller/entity/entity.h @@ -62,6 +62,28 @@ class Entity { kLastAdvancedBlendMode = kLuminosity, }; + /// An enum to define how to repeat, fold, or omit colors outside of the + /// typically defined range of the source of the colors (such as the + /// bounds of an image or the defining geometry of a gradient). + enum class TileMode { + /// Replicate the edge color if the shader draws outside of its original + /// bounds. + kClamp, + + /// Repeat the shader's image horizontally and vertically (or both along and + /// perpendicular to a gradient's geometry). + kRepeat, + + /// Repeat the shader's image horizontally and vertically, seamlessly + /// alternating mirrored images. + kMirror, + + /// Render the shader's image pixels only within its original bounds. If the + /// shader draws outside of its original bounds, transparent black is drawn + /// instead. + kDecal, + }; + enum class ClipOperation { kDifference, kIntersect, diff --git a/impeller/entity/shaders/gradient_fill.frag b/impeller/entity/shaders/gradient_fill.frag index b70cc6b879254..858c56b83b8e8 100644 --- a/impeller/entity/shaders/gradient_fill.frag +++ b/impeller/entity/shaders/gradient_fill.frag @@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform GradientInfo { vec2 start_point; vec2 end_point; vec4 start_color; vec4 end_color; + float tile_mode; } gradient_info; in vec2 interpolated_vertices; @@ -19,6 +22,12 @@ void main() { interpolated_vertices - gradient_info.start_point, gradient_info.end_point - gradient_info.start_point ); - float interp = dot / (len * len); - frag_color = mix(gradient_info.start_color, gradient_info.end_color, interp); + float t = dot / (len * len); + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + + t = IPTileTextureCoords(t, gradient_info.tile_mode); + frag_color = mix(gradient_info.start_color, gradient_info.end_color, t); } diff --git a/impeller/entity/shaders/radial_gradient_fill.frag b/impeller/entity/shaders/radial_gradient_fill.frag index 5e1dcc7380d39..1e6f46dace8fd 100644 --- a/impeller/entity/shaders/radial_gradient_fill.frag +++ b/impeller/entity/shaders/radial_gradient_fill.frag @@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include + uniform GradientInfo { vec2 center; float radius; vec4 center_color; vec4 edge_color; + float tile_mode; } gradient_info; in vec2 interpolated_vertices; @@ -15,6 +18,12 @@ out vec4 frag_color; void main() { float len = length(interpolated_vertices - gradient_info.center); - float t = smoothstep(0.0, gradient_info.radius, len); + float t = len / gradient_info.radius; + if ((t < 0.0 || t > 1.0) && gradient_info.tile_mode == kTileModeDecal) { + frag_color = vec4(0); + return; + } + + t = IPTileTextureCoords(t, gradient_info.tile_mode); frag_color = mix(gradient_info.center_color, gradient_info.edge_color, t); } From f17a4e40ffdbbfdb2c42d89f94e3a565718800f4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 4 Aug 2022 07:08:05 -0400 Subject: [PATCH 094/558] Roll Skia from 1617a4027d3b to fbd9c4d05842 (1 revision) (#35159) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 71ec7d59a3ca5..27e1ca0982a54 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': '1617a4027d3b802b034d718cdd8ace2c520f483f', + 'skia_revision': 'fbd9c4d0584285fa5bbb033f291b65c7b73ef1ae', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 3cb97a94ed5da..4d7389967b77b 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 44880828aa8f200231751c14894fb1f7 +Signature: eb4de80edd9a408b3f245a79e661e0a3 UNUSED LICENSES: From 7ab49583a927b67036dd5dc65ed59cc144c960fd Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 4 Aug 2022 08:45:06 -0400 Subject: [PATCH 095/558] Roll Fuchsia Linux SDK from OsNl2rRU2... to AH3k3SvM2... (#35160) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 27e1ca0982a54..0708a790ba510 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'OsNl2rRU2Ke1LGMaUiXwlLoCjQWJKyTR6NIFLJRaOasC' + 'version': 'AH3k3SvM2pVCNAkuLe3yKL-KYMupq7Bgoftkx-D0unkC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 55edc85609001..b600580966c50 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 09915b728e09affac80eb39f8f03a5a2 +Signature: edb9709b9184c2694501c4e65aa4566a UNUSED LICENSES: From 10c48e332c0b921db0d6d5747d6a3b9b25971264 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 4 Aug 2022 09:54:05 -0400 Subject: [PATCH 096/558] Roll Dart SDK from 05131e03aa5e to 68137ce3d59a (1 revision) (#35161) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0708a790ba510..7dd3fbed521bc 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '05131e03aa5e1a8af8e7a6c0f1f9583f583f9623', + 'dart_revision': '68137ce3d59a5d81472e432f666f23e91dee7691', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 36063f715ed80..98d430828b6c9 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 73196eb1d0cecd56c98d3465d14bfefb +Signature: b4b527484f4cf788e7f1d393b0ea161f UNUSED LICENSES: From ec1be5b9c3c4b51c4d81cb4170563f8078fd01a7 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 4 Aug 2022 10:37:25 -0400 Subject: [PATCH 097/558] Roll Skia from fbd9c4d05842 to 098c234c05f7 (1 revision) (#35162) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 7dd3fbed521bc..97087956d55e4 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': 'fbd9c4d0584285fa5bbb033f291b65c7b73ef1ae', + 'skia_revision': '098c234c05f7680999f9a27ef98c6e116e21d2df', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 4d7389967b77b..80f19bff6b496 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: eb4de80edd9a408b3f245a79e661e0a3 +Signature: ec7e163e434e5dee311adfcd1fcd2d19 UNUSED LICENSES: From 9ec11a055056434cbcb2cf375b26c8700525593d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marchand?= Date: Thu, 4 Aug 2022 12:53:20 -0400 Subject: [PATCH 098/558] [Fuchsia] Specify the target API level in pm_tool.gni (#35132) Bug: fxb/105705 --- tools/fuchsia/gn-sdk/pm_tool.gni | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/fuchsia/gn-sdk/pm_tool.gni b/tools/fuchsia/gn-sdk/pm_tool.gni index 5323a3d4f1c3f..73dabf0d6be02 100644 --- a/tools/fuchsia/gn-sdk/pm_tool.gni +++ b/tools/fuchsia/gn-sdk/pm_tool.gni @@ -84,7 +84,10 @@ template("fuchsia_pm_tool") { package_name, ] if (command == "build") { + assert(fuchsia_target_api_level != -1, + "Must set a target api level when creating an archive") args += [ + "--api-level=${fuchsia_target_api_level}", command, "-output-package-manifest", rebase_path(_pkg_output_manifest, root_build_dir), From 8a82422e5d18edfd020be49b30dffabecb498f6c Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Thu, 4 Aug 2022 13:59:59 -0400 Subject: [PATCH 099/558] Revert "[impeller] Set binding base for fragment shaders (#35052)" (#35167) This reverts commit e771729efdde3cdbdf0404973c3e72dc15933ad0. --- impeller/compiler/compiler.cc | 15 --------------- impeller/compiler/compiler.h | 2 -- impeller/compiler/compiler_test.cc | 12 ------------ impeller/compiler/compiler_test.h | 3 --- impeller/compiler/compiler_unittests.cc | 23 ----------------------- impeller/fixtures/BUILD.gn | 1 - impeller/fixtures/sample.frag | 14 -------------- 7 files changed, 70 deletions(-) delete mode 100644 impeller/fixtures/sample.frag diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index e38aa14714555..e5b2018fd267f 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -13,15 +13,10 @@ #include "impeller/compiler/compiler_backend.h" #include "impeller/compiler/includer.h" #include "impeller/compiler/logger.h" -#include "impeller/compiler/types.h" namespace impeller { namespace compiler { -const uint32_t kFragBindingBase = 128; -const size_t kNumUniformKinds = - int(shaderc_uniform_kind::shaderc_uniform_kind_buffer) + 1; - static CompilerBackend CreateMSLCompiler(const spirv_cross::ParsedIR& ir, const SourceOptions& source_options) { auto sl_compiler = std::make_shared(ir); @@ -109,15 +104,6 @@ static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir, return compiler; } -void Compiler::SetBindingBase(shaderc::CompileOptions& compiler_opts) const { - for (size_t uniform_kind = 0; uniform_kind < kNumUniformKinds; - uniform_kind++) { - compiler_opts.SetBindingBaseForStage( - ToShaderCShaderKind(SourceType::kFragmentShader), - static_cast(uniform_kind), kFragBindingBase); - } -} - Compiler::Compiler(const fml::Mapping& source_mapping, SourceOptions source_options, Reflector::Options reflector_options) @@ -226,7 +212,6 @@ Compiler::Compiler(const fml::Mapping& source_mapping, } spirv_options.SetAutoBindUniforms(true); - SetBindingBase(spirv_options); spirv_options.SetAutoMapLocations(true); std::vector included_file_names; diff --git a/impeller/compiler/compiler.h b/impeller/compiler/compiler.h index 379f610fd2286..9dd3d901c3dde 100644 --- a/impeller/compiler/compiler.h +++ b/impeller/compiler/compiler.h @@ -57,8 +57,6 @@ class Compiler { std::string GetDependencyNames(std::string separator) const; - void SetBindingBase(shaderc::CompileOptions& compiler_opts) const; - FML_DISALLOW_COPY_AND_ASSIGN(Compiler); }; diff --git a/impeller/compiler/compiler_test.cc b/impeller/compiler/compiler_test.cc index 402d05fe7346f..85b3abaa5f9c5 100644 --- a/impeller/compiler/compiler_test.cc +++ b/impeller/compiler/compiler_test.cc @@ -6,11 +6,6 @@ #include -#include "flutter/fml/file.h" -#include "flutter/fml/logging.h" -#include "flutter/fml/mapping.h" -#include "flutter/fml/unique_fd.h" - namespace impeller { namespace compiler { namespace testing { @@ -63,13 +58,6 @@ static std::string SLFileName(const char* fixture_name, return stream.str(); } -std::unique_ptr CompilerTest::GetReflectionJson( - const char* fixture_name) const { - auto filename = ReflectionJSONName(fixture_name); - auto fd = fml::OpenFileReadOnly(intermediates_directory_, filename.c_str()); - return fml::FileMapping::CreateReadOnly(fd); -} - bool CompilerTest::CanCompileAndReflect(const char* fixture_name, SourceType source_type) const { auto fixture = flutter::testing::OpenFixtureAsMapping(fixture_name); diff --git a/impeller/compiler/compiler_test.h b/impeller/compiler/compiler_test.h index 0e4fd94fd3929..a7be1c688b198 100644 --- a/impeller/compiler/compiler_test.h +++ b/impeller/compiler/compiler_test.h @@ -25,9 +25,6 @@ class CompilerTest : public ::testing::TestWithParam { const char* fixture_name, SourceType source_type = SourceType::kUnknown) const; - std::unique_ptr GetReflectionJson( - const char* fixture_name) const; - private: fml::UniqueFD intermediates_directory_; diff --git a/impeller/compiler/compiler_unittests.cc b/impeller/compiler/compiler_unittests.cc index f46b745c81703..d19d9f00c98c0 100644 --- a/impeller/compiler/compiler_unittests.cc +++ b/impeller/compiler/compiler_unittests.cc @@ -9,8 +9,6 @@ #include "impeller/compiler/source_options.h" #include "impeller/compiler/types.h" -#include "nlohmann/json.hpp" - namespace impeller { namespace compiler { namespace testing { @@ -52,27 +50,6 @@ TEST_P(CompilerTest, CanCompileComputeShader) { ASSERT_TRUE(CanCompileAndReflect("sample.comp", SourceType::kComputeShader)); } -TEST_P(CompilerTest, BindingBaseForFragShader) { - if (GetParam() == TargetPlatform::kFlutterSPIRV) { - // This is a failure of reflection which this target doesn't perform. - GTEST_SKIP(); - } - - ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader)); - ASSERT_TRUE(CanCompileAndReflect("sample.frag", SourceType::kFragmentShader)); - - auto get_binding = [&](const char* fixture) -> uint32_t { - auto json_fd = GetReflectionJson(fixture); - nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping()); - return shader_json["buffers"][0]["binding"].get(); - }; - - auto vert_uniform_binding = get_binding("sample.vert"); - auto frag_uniform_binding = get_binding("sample.frag"); - - ASSERT_GT(frag_uniform_binding, vert_uniform_binding); -} - TEST_P(CompilerTest, MustFailDueToMultipleLocationPerStructMember) { if (GetParam() == TargetPlatform::kFlutterSPIRV) { // This is a failure of reflection which this target doesn't perform. diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index 635125cc1ecc9..d955a90bfa9df 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -43,7 +43,6 @@ test_fixtures("file_fixtures") { "embarcadero.jpg", "kalimba.jpg", "sample.comp", - "sample.frag", "sample.tesc", "sample.tese", "sample.vert", diff --git a/impeller/fixtures/sample.frag b/impeller/fixtures/sample.frag deleted file mode 100644 index 5d9c83604dd68..0000000000000 --- a/impeller/fixtures/sample.frag +++ /dev/null @@ -1,14 +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. - -uniform FragInfo { - vec4 color; -} -frag_info; - -out vec4 frag_color; - -void main() { - frag_color = frag_info.color; -} From b74af4c5a46da08ff32071d49780a2fa486e1877 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Thu, 4 Aug 2022 11:29:03 -0700 Subject: [PATCH 100/558] remove outdated ignores (#35143) --- lib/ui/hash_codes.dart | 2 +- lib/ui/hooks.dart | 1 - lib/ui/painting.dart | 12 +-- lib/ui/ui.dart | 4 +- lib/web_ui/lib/geometry.dart | 47 +++++----- lib/web_ui/lib/painting.dart | 23 +++-- lib/web_ui/lib/path.dart | 5 +- lib/web_ui/lib/path_metrics.dart | 4 +- lib/web_ui/lib/platform_dispatcher.dart | 4 +- lib/web_ui/lib/pointer.dart | 2 +- lib/web_ui/lib/semantics.dart | 4 +- .../lib/src/engine/canvaskit/canvas.dart | 1 - .../src/engine/canvaskit/canvaskit_api.dart | 2 - .../engine/canvaskit/canvaskit_canvas.dart | 86 ++++++++----------- .../lib/src/engine/canvaskit/image.dart | 1 - .../src/engine/canvaskit/image_filter.dart | 2 +- .../lib/src/engine/canvaskit/layer.dart | 2 +- .../engine/canvaskit/layer_scene_builder.dart | 4 +- lib/web_ui/lib/src/engine/canvaskit/path.dart | 2 +- .../lib/src/engine/canvaskit/shader.dart | 12 +-- .../lib/src/engine/canvaskit/vertices.dart | 8 +- lib/web_ui/lib/src/engine/engine_canvas.dart | 1 - .../lib/src/engine/html/bitmap_canvas.dart | 8 +- lib/web_ui/lib/src/engine/html/canvas.dart | 83 ++++++++---------- lib/web_ui/lib/src/engine/html/painting.dart | 2 +- lib/web_ui/lib/src/engine/html/picture.dart | 4 +- .../lib/src/engine/html/render_vertices.dart | 25 +++--- .../lib/src/engine/html/scene_builder.dart | 10 +-- .../src/engine/html/shaders/image_shader.dart | 6 +- .../lib/src/engine/html/shaders/shader.dart | 12 +-- lib/web_ui/lib/src/engine/html/surface.dart | 6 +- .../lib/src/engine/html/surface_stats.dart | 2 +- lib/web_ui/lib/src/engine/initialization.dart | 1 - .../lib/src/engine/navigation/history.dart | 4 +- .../lib/src/engine/pointer_binding.dart | 12 +-- .../lib/src/engine/pointer_converter.dart | 2 +- .../lib/src/engine/semantics/semantics.dart | 12 ++- .../lib/src/engine/services/buffers.dart | 4 +- .../src/engine/services/message_codec.dart | 3 +- .../src/engine/services/message_codecs.dart | 2 +- .../src/engine/services/serialization.dart | 2 +- lib/web_ui/lib/src/engine/text/paragraph.dart | 4 +- .../src/engine/text_editing/text_editing.dart | 2 +- lib/web_ui/lib/src/engine/validators.dart | 10 +-- lib/web_ui/lib/text.dart | 12 +-- lib/web_ui/lib/window.dart | 2 +- lib/web_ui/test/canvaskit/surface_test.dart | 2 - .../engine/semantics/text_field_test.dart | 4 +- lib/web_ui/test/hash_codes_test.dart | 2 - lib/web_ui/test/text/font_loading_test.dart | 2 +- lib/web_ui/test/window_test.dart | 12 --- testing/dart/channel_buffers_test.dart | 1 - testing/litetest/lib/litetest.dart | 4 - 53 files changed, 215 insertions(+), 271 deletions(-) diff --git a/lib/ui/hash_codes.dart b/lib/ui/hash_codes.dart index 94afd258d3568..19cf712ad6c5c 100644 --- a/lib/ui/hash_codes.dart +++ b/lib/ui/hash_codes.dart @@ -43,7 +43,7 @@ class _Jenkins { /// For example: /// /// ```dart -/// int get hashCode => hashValues(foo, bar, hashList(quux), baz); // ignore: deprecated_member_use +/// int get hashCode => hashValues(foo, bar, hashList(quux), baz); /// ``` /// /// ## Deprecation diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart index 5a14b4e3f8035..1cdbf90baeebf 100644 --- a/lib/ui/hooks.dart +++ b/lib/ui/hooks.dart @@ -5,7 +5,6 @@ part of dart.ui; @pragma('vm:entry-point') -// ignore: unused_element void _updateWindowMetrics( Object id, double devicePixelRatio, diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 5b52122e15726..913000ba4d5fb 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -3579,7 +3579,7 @@ class _ImageFilter extends NativeFieldWrapperClass1 { /// Creates an image filter that applies a Gaussian blur. _ImageFilter.blur(_GaussianBlurImageFilter filter) : assert(filter != null), - creator = filter { // ignore: prefer_initializing_formals + creator = filter { _constructor(); _initBlur(filter.sigmaX, filter.sigmaY, filter.tileMode.index); } @@ -3588,7 +3588,7 @@ class _ImageFilter extends NativeFieldWrapperClass1 { /// to the max value within the given radii along the x and y axes. _ImageFilter.dilate(_DilateImageFilter filter) : assert(filter != null), - creator = filter { // ignore: prefer_initializing_formals + creator = filter { _constructor(); _initDilate(filter.radiusX, filter.radiusY); } @@ -3597,7 +3597,7 @@ class _ImageFilter extends NativeFieldWrapperClass1 { /// to the minimum channel value within the given radii along the x and y axes. _ImageFilter.erode(_ErodeImageFilter filter) : assert(filter != null), - creator = filter { // ignore: prefer_initializing_formals + creator = filter { _constructor(); _initErode(filter.radiusX, filter.radiusY); } @@ -3608,7 +3608,7 @@ class _ImageFilter extends NativeFieldWrapperClass1 { /// when used with [BackdropFilter] would magnify the background image. _ImageFilter.matrix(_MatrixImageFilter filter) : assert(filter != null), - creator = filter { // ignore: prefer_initializing_formals + creator = filter { if (filter.data.length != 16) { throw ArgumentError('"matrix4" must have 16 entries.'); } @@ -3619,7 +3619,7 @@ class _ImageFilter extends NativeFieldWrapperClass1 { /// Converts a color filter to an image filter. _ImageFilter.fromColorFilter(ColorFilter filter) : assert(filter != null), - creator = filter { // ignore: prefer_initializing_formals + creator = filter { _constructor(); final _ColorFilter? nativeFilter = filter._toNativeColorFilter(); _initColorFilter(nativeFilter); @@ -3628,7 +3628,7 @@ class _ImageFilter extends NativeFieldWrapperClass1 { /// Composes `_innerFilter` with `_outerFilter`. _ImageFilter.composed(_ComposeImageFilter filter) : assert(filter != null), - creator = filter { // ignore: prefer_initializing_formals + creator = filter { _constructor(); final _ImageFilter nativeFilterInner = filter.innerFilter._toNativeImageFilter(); final _ImageFilter nativeFilterOuter = filter.outerFilter._toNativeImageFilter(); diff --git a/lib/ui/ui.dart b/lib/ui/ui.dart index b61743c7c5087..2695a80916ee4 100644 --- a/lib/ui/ui.dart +++ b/lib/ui/ui.dart @@ -16,10 +16,10 @@ import 'dart:collection' as collection; import 'dart:convert'; import 'dart:developer' as developer; import 'dart:ffi'; -import 'dart:io'; // ignore: unused_import +import 'dart:io'; import 'dart:isolate' show SendPort; import 'dart:math' as math; -import 'dart:nativewrappers'; // ignore: unused_import +import 'dart:nativewrappers'; import 'dart:typed_data'; part 'annotations.dart'; diff --git a/lib/web_ui/lib/geometry.dart b/lib/web_ui/lib/geometry.dart index 3e3fb4bc47431..3d60b13e92601 100644 --- a/lib/web_ui/lib/geometry.dart +++ b/lib/web_ui/lib/geometry.dart @@ -4,13 +4,12 @@ // See https://github.com/flutter/engine/blob/main/lib/ui/geometry.dart for // documentation of APIs. -// ignore_for_file: public_member_api_docs part of ui; abstract class OffsetBase { const OffsetBase(this._dx, this._dy) - : assert(_dx != null), // ignore: unnecessary_null_comparison - assert(_dy != null); // ignore: unnecessary_null_comparison + : assert(_dx != null), + assert(_dy != null); final double _dx; final double _dy; @@ -58,7 +57,7 @@ class Offset extends OffsetBase { Offset operator %(double operand) => Offset(dx % operand, dy % operand); Rect operator &(Size other) => Rect.fromLTWH(dx, dy, other.width, other.height); static Offset? lerp(Offset? a, Offset? b, double t) { - assert(t != null); // ignore: unnecessary_null_comparison + assert(t != null); if (b == null) { if (a == null) { return null; @@ -149,7 +148,7 @@ class Size extends OffsetBase { Size get flipped => Size(height, width); static Size? lerp(Size? a, Size? b, double t) { - assert(t != null); // ignore: unnecessary_null_comparison + assert(t != null); if (b == null) { if (a == null) { return null; @@ -182,10 +181,10 @@ class Size extends OffsetBase { class Rect { const Rect.fromLTRB(this.left, this.top, this.right, this.bottom) - : assert(left != null), // ignore: unnecessary_null_comparison - assert(top != null), // ignore: unnecessary_null_comparison - assert(right != null), // ignore: unnecessary_null_comparison - assert(bottom != null); // ignore: unnecessary_null_comparison + : assert(left != null), + assert(top != null), + assert(right != null), + assert(bottom != null); const Rect.fromLTWH(double left, double top, double width, double height) : this.fromLTRB(left, top, left + width, top + height); @@ -292,7 +291,7 @@ class Rect { } static Rect? lerp(Rect? a, Rect? b, double t) { - assert(t != null); // ignore: unnecessary_null_comparison + assert(t != null); if (b == null) { if (a == null) { return null; @@ -350,7 +349,7 @@ class Radius { Radius operator ~/(double operand) => Radius.elliptical((x ~/ operand).toDouble(), (y ~/ operand).toDouble()); Radius operator %(double operand) => Radius.elliptical(x % operand, y % operand); static Radius? lerp(Radius? a, Radius? b, double t) { - assert(t != null); // ignore: unnecessary_null_comparison + assert(t != null); if (b == null) { if (a == null) { return null; @@ -548,18 +547,18 @@ class RRect { this.blRadiusX = 0.0, this.blRadiusY = 0.0, bool uniformRadii = false, - }) : assert(left != null), // ignore: unnecessary_null_comparison - assert(top != null), // ignore: unnecessary_null_comparison - assert(right != null), // ignore: unnecessary_null_comparison - assert(bottom != null), // ignore: unnecessary_null_comparison - assert(tlRadiusX != null), // ignore: unnecessary_null_comparison - assert(tlRadiusY != null), // ignore: unnecessary_null_comparison - assert(trRadiusX != null), // ignore: unnecessary_null_comparison - assert(trRadiusY != null), // ignore: unnecessary_null_comparison - assert(brRadiusX != null), // ignore: unnecessary_null_comparison - assert(brRadiusY != null), // ignore: unnecessary_null_comparison - assert(blRadiusX != null), // ignore: unnecessary_null_comparison - assert(blRadiusY != null), // ignore: unnecessary_null_comparison + }) : assert(left != null), + assert(top != null), + assert(right != null), + assert(bottom != null), + assert(tlRadiusX != null), + assert(tlRadiusY != null), + assert(trRadiusX != null), + assert(trRadiusY != null), + assert(brRadiusX != null), + assert(brRadiusY != null), + assert(blRadiusX != null), + assert(blRadiusY != null), webOnlyUniformRadii = uniformRadii; final double left; @@ -806,7 +805,7 @@ class RRect { } static RRect? lerp(RRect? a, RRect? b, double t) { - assert(t != null); // ignore: unnecessary_null_comparison + assert(t != null); if (b == null) { if (a == null) { return null; diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index c5873c1dd4a11..40bc7fb65e31c 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -3,19 +3,18 @@ // found in the LICENSE file. // For documentation see https://github.com/flutter/engine/blob/main/lib/ui/painting.dart -// ignore_for_file: public_member_api_docs part of ui; // ignore: unused_element, Used in Shader assert. bool _offsetIsValid(Offset offset) { - assert(offset != null, 'Offset argument was null.'); // ignore: unnecessary_null_comparison + assert(offset != null, 'Offset argument was null.'); assert(!offset.dx.isNaN && !offset.dy.isNaN, 'Offset argument contained a NaN value.'); return true; } // ignore: unused_element, Used in Shader assert. bool _matrix4IsValid(Float32List matrix4) { - assert(matrix4 != null, 'Matrix4 argument was null.'); // ignore: unnecessary_null_comparison + assert(matrix4 != null, 'Matrix4 argument was null.'); assert(matrix4.length == 16, 'Matrix4 must have 16 entries.'); return true; } @@ -37,7 +36,7 @@ Color _scaleAlpha(Color a, double factor) { } class Color { - const Color(int value) : this.value = value & 0xFFFFFFFF;// ignore: unnecessary_this + const Color(int value) : value = value & 0xFFFFFFFF; const Color.fromARGB(int a, int r, int g, int b) : value = (((a & 0xff) << 24) | ((r & 0xff) << 16) | @@ -94,7 +93,7 @@ class Color { } static Color? lerp(Color? a, Color? b, double t) { - assert(t != null); // ignore: unnecessary_null_comparison + assert(t != null); if (b == null) { if (a == null) { return null; @@ -146,7 +145,7 @@ class Color { } static int getAlphaFromOpacity(double opacity) { - assert(opacity != null); // ignore: unnecessary_null_comparison + assert(opacity != null); return (opacity.clamp(0.0, 1.0) * 255).round(); } @@ -369,8 +368,8 @@ class MaskFilter { const MaskFilter.blur( this._style, this._sigma, - ) : assert(_style != null), // ignore: unnecessary_null_comparison - assert(_sigma != null); // ignore: unnecessary_null_comparison + ) : assert(_style != null), + assert(_sigma != null); final BlurStyle _style; final double _sigma; @@ -656,8 +655,8 @@ class Shadow { this.color = const Color(_kColorDefault), this.offset = Offset.zero, this.blurRadius = 0.0, - }) : assert(color != null, 'Text shadow color was null.'), // ignore: unnecessary_null_comparison - assert(offset != null, 'Text shadow offset was null.'), // ignore: unnecessary_null_comparison + }) : assert(color != null, 'Text shadow color was null.'), + assert(offset != null, 'Text shadow offset was null.'), assert(blurRadius >= 0.0, 'Text shadow blur radius should be non-negative.'); static const int _kColorDefault = 0xFF000000; @@ -686,7 +685,7 @@ class Shadow { } static Shadow? lerp(Shadow? a, Shadow? b, double t) { - assert(t != null); // ignore: unnecessary_null_comparison + assert(t != null); if (b == null) { if (a == null) { return null; @@ -707,7 +706,7 @@ class Shadow { } static List? lerpList(List? a, List? b, double t) { - assert(t != null); // ignore: unnecessary_null_comparison + assert(t != null); if (a == null && b == null) { return null; } diff --git a/lib/web_ui/lib/path.dart b/lib/web_ui/lib/path.dart index 49cd141798048..c609b82d109ba 100644 --- a/lib/web_ui/lib/path.dart +++ b/lib/web_ui/lib/path.dart @@ -5,7 +5,6 @@ part of ui; // For documentation see https://github.com/flutter/engine/blob/main/lib/ui/painting.dart -// ignore_for_file: public_member_api_docs abstract class Path { factory Path() { @@ -64,8 +63,8 @@ abstract class Path { // see https://skia.org/user/api/SkPath_Reference#SkPath_getBounds Rect getBounds(); static Path combine(PathOperation operation, Path path1, Path path2) { - assert(path1 != null); // ignore: unnecessary_null_comparison - assert(path2 != null); // ignore: unnecessary_null_comparison + assert(path1 != null); + assert(path2 != null); if (engine.useCanvasKit) { return engine.CkPath.combine(operation, path1, path2); } diff --git a/lib/web_ui/lib/path_metrics.dart b/lib/web_ui/lib/path_metrics.dart index d4324f1d4a476..5cf8df9552641 100644 --- a/lib/web_ui/lib/path_metrics.dart +++ b/lib/web_ui/lib/path_metrics.dart @@ -27,8 +27,8 @@ abstract class PathMetric { class Tangent { const Tangent(this.position, this.vector) - : assert(position != null), // ignore: unnecessary_null_comparison - assert(vector != null); // ignore: unnecessary_null_comparison + : assert(position != null), + assert(vector != null); factory Tangent.fromAngle(Offset position, double angle) { return Tangent(position, Offset(math.cos(angle), math.sin(angle))); } diff --git a/lib/web_ui/lib/platform_dispatcher.dart b/lib/web_ui/lib/platform_dispatcher.dart index 9c5bbb749d5ac..defcc6df15cdd 100644 --- a/lib/web_ui/lib/platform_dispatcher.dart +++ b/lib/web_ui/lib/platform_dispatcher.dart @@ -396,7 +396,7 @@ class Locale { const Locale( this._languageCode, [ this._countryCode, - ]) : assert(_languageCode != null), // ignore: unnecessary_null_comparison + ]) : assert(_languageCode != null), assert(_languageCode != ''), scriptCode = null; @@ -404,7 +404,7 @@ class Locale { String languageCode = 'und', this.scriptCode, String? countryCode, - }) : assert(languageCode != null), // ignore: unnecessary_null_comparison + }) : assert(languageCode != null), assert(languageCode != ''), _languageCode = languageCode, assert(scriptCode != ''), diff --git a/lib/web_ui/lib/pointer.dart b/lib/web_ui/lib/pointer.dart index 9ae2377904301..3106f903d34cd 100644 --- a/lib/web_ui/lib/pointer.dart +++ b/lib/web_ui/lib/pointer.dart @@ -151,6 +151,6 @@ class PointerData { class PointerDataPacket { const PointerDataPacket({this.data = const []}) - : assert(data != null); // ignore: unnecessary_null_comparison + : assert(data != null); final List data; } diff --git a/lib/web_ui/lib/semantics.dart b/lib/web_ui/lib/semantics.dart index 9a4ce2ccf91e8..10db1cfcc76c4 100644 --- a/lib/web_ui/lib/semantics.dart +++ b/lib/web_ui/lib/semantics.dart @@ -5,7 +5,7 @@ part of ui; class SemanticsAction { - const SemanticsAction._(this.index) : assert(index != null); // ignore: unnecessary_null_comparison + const SemanticsAction._(this.index) : assert(index != null); static const int _kTapIndex = 1 << 0; static const int _kLongPressIndex = 1 << 1; @@ -134,7 +134,7 @@ class SemanticsAction { } class SemanticsFlag { - const SemanticsFlag._(this.index) : assert(index != null); // ignore: unnecessary_null_comparison + const SemanticsFlag._(this.index) : assert(index != null); final int index; diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvas.dart b/lib/web_ui/lib/src/engine/canvaskit/canvas.dart index 2c26d0b7ddbc8..b499f95abe3a6 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvas.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvas.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: public_member_api_docs import 'dart:math' as math; import 'dart:typed_data'; 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 1652d51047ea2..3ef9ed6de0b28 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -7,8 +7,6 @@ /// Prefer keeping the original CanvasKit names so it is easier to locate /// the API behind these bindings in the Skia source code. // ignore_for_file: non_constant_identifier_names - -// ignore_for_file: public_member_api_docs @JS() library canvaskit_api; diff --git a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart index a1c8c85473b2f..87c94858dd2c7 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart @@ -22,7 +22,7 @@ import 'vertices.dart'; /// An implementation of [ui.Canvas] that is backed by a CanvasKit canvas. class CanvasKitCanvas implements ui.Canvas { factory CanvasKitCanvas(ui.PictureRecorder recorder, [ui.Rect? cullRect]) { - assert(recorder != null); // ignore: unnecessary_null_comparison + assert(recorder != null); if (recorder.isRecording) { throw ArgumentError( '"recorder" must not already be associated with another Canvas.'); @@ -43,7 +43,7 @@ class CanvasKitCanvas implements ui.Canvas { @override void saveLayer(ui.Rect? bounds, ui.Paint paint) { - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); if (bounds == null) { _saveLayerWithoutBounds(paint); } else { @@ -94,7 +94,7 @@ class CanvasKitCanvas implements ui.Canvas { @override void transform(Float64List matrix4) { - assert(matrix4 != null); // ignore: unnecessary_null_comparison + assert(matrix4 != null); if (matrix4.length != 16) { throw ArgumentError('"matrix4" must have 16 entries.'); } @@ -114,8 +114,8 @@ class CanvasKitCanvas implements ui.Canvas { void clipRect(ui.Rect rect, {ui.ClipOp clipOp = ui.ClipOp.intersect, bool doAntiAlias = true}) { assert(rectIsValid(rect)); - assert(clipOp != null); // ignore: unnecessary_null_comparison - assert(doAntiAlias != null); // ignore: unnecessary_null_comparison + assert(clipOp != null); + assert(doAntiAlias != null); _clipRect(rect, clipOp, doAntiAlias); } @@ -126,7 +126,7 @@ class CanvasKitCanvas implements ui.Canvas { @override void clipRRect(ui.RRect rrect, {bool doAntiAlias = true}) { assert(rrectIsValid(rrect)); - assert(doAntiAlias != null); // ignore: unnecessary_null_comparison + assert(doAntiAlias != null); _clipRRect(rrect, doAntiAlias); } @@ -136,9 +136,8 @@ class CanvasKitCanvas implements ui.Canvas { @override void clipPath(ui.Path path, {bool doAntiAlias = true}) { - // ignore: unnecessary_null_comparison assert(path != null); // path is checked on the engine side - assert(doAntiAlias != null); // ignore: unnecessary_null_comparison + assert(doAntiAlias != null); _canvas.clipPath(path as CkPath, doAntiAlias); } @@ -159,8 +158,8 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawColor(ui.Color color, ui.BlendMode blendMode) { - assert(color != null); // ignore: unnecessary_null_comparison - assert(blendMode != null); // ignore: unnecessary_null_comparison + assert(color != null); + assert(blendMode != null); _drawColor(color, blendMode); } @@ -172,7 +171,7 @@ class CanvasKitCanvas implements ui.Canvas { void drawLine(ui.Offset p1, ui.Offset p2, ui.Paint paint) { assert(offsetIsValid(p1)); assert(offsetIsValid(p2)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawLine(p1, p2, paint); } @@ -182,7 +181,7 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawPaint(ui.Paint paint) { - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawPaint(paint); } @@ -193,7 +192,7 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawRect(ui.Rect rect, ui.Paint paint) { assert(rectIsValid(rect)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawRect(rect, paint); } @@ -204,7 +203,7 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawRRect(ui.RRect rrect, ui.Paint paint) { assert(rrectIsValid(rrect)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawRRect(rrect, paint); } @@ -216,7 +215,7 @@ class CanvasKitCanvas implements ui.Canvas { void drawDRRect(ui.RRect outer, ui.RRect inner, ui.Paint paint) { assert(rrectIsValid(outer)); assert(rrectIsValid(inner)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawDRRect(outer, inner, paint); } @@ -227,7 +226,7 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawOval(ui.Rect rect, ui.Paint paint) { assert(rectIsValid(rect)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawOval(rect, paint); } @@ -238,7 +237,7 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawCircle(ui.Offset c, double radius, ui.Paint paint) { assert(offsetIsValid(c)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawCircle(c, radius, paint); } @@ -250,7 +249,7 @@ class CanvasKitCanvas implements ui.Canvas { void drawArc(ui.Rect rect, double startAngle, double sweepAngle, bool useCenter, ui.Paint paint) { assert(rectIsValid(rect)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawArc(rect, startAngle, sweepAngle, useCenter, paint); } @@ -261,52 +260,47 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawPath(ui.Path path, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(path != null); // path is checked on the engine side - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _canvas.drawPath(path as CkPath, paint as CkPaint); } @override void drawImage(ui.Image image, ui.Offset p, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(image != null); // image is checked on the engine side assert(offsetIsValid(p)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _canvas.drawImage(image as CkImage, p, paint as CkPaint); } @override void drawImageRect(ui.Image image, ui.Rect src, ui.Rect dst, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(image != null); // image is checked on the engine side assert(rectIsValid(src)); assert(rectIsValid(dst)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _canvas.drawImageRect(image as CkImage, src, dst, paint as CkPaint); } @override void drawImageNine( ui.Image image, ui.Rect center, ui.Rect dst, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(image != null); // image is checked on the engine side assert(rectIsValid(center)); assert(rectIsValid(dst)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _canvas.drawImageNine(image as CkImage, center, dst, paint as CkPaint); } @override void drawPicture(ui.Picture picture) { - // ignore: unnecessary_null_comparison assert(picture != null); // picture is checked on the engine side _canvas.drawPicture(picture as CkPicture); } @override void drawParagraph(ui.Paragraph paragraph, ui.Offset offset) { - assert(paragraph != null); // ignore: unnecessary_null_comparison + assert(paragraph != null); assert(offsetIsValid(offset)); _drawParagraph(paragraph, offset); } @@ -318,9 +312,9 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawPoints( ui.PointMode pointMode, List points, ui.Paint paint) { - assert(pointMode != null); // ignore: unnecessary_null_comparison - assert(points != null); // ignore: unnecessary_null_comparison - assert(paint != null); // ignore: unnecessary_null_comparison + assert(pointMode != null); + assert(points != null); + assert(paint != null); final SkFloat32List skPoints = toMallocedSkPoints(points); _canvas.drawPoints( paint as CkPaint, @@ -333,9 +327,9 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawRawPoints( ui.PointMode pointMode, Float32List points, ui.Paint paint) { - assert(pointMode != null); // ignore: unnecessary_null_comparison - assert(points != null); // ignore: unnecessary_null_comparison - assert(paint != null); // ignore: unnecessary_null_comparison + assert(pointMode != null); + assert(points != null); + assert(paint != null); if (points.length % 2 != 0) { throw ArgumentError('"points" must have an even number of values.'); } @@ -349,10 +343,9 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawVertices( ui.Vertices vertices, ui.BlendMode blendMode, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(vertices != null); // vertices is checked on the engine side - assert(paint != null); // ignore: unnecessary_null_comparison - assert(blendMode != null); // ignore: unnecessary_null_comparison + assert(paint != null); + assert(blendMode != null); _canvas.drawVertices(vertices as CkVertices, blendMode, paint as CkPaint); } @@ -365,12 +358,11 @@ class CanvasKitCanvas implements ui.Canvas { ui.BlendMode? blendMode, ui.Rect? cullRect, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(atlas != null); // atlas is checked on the engine side - assert(transforms != null); // ignore: unnecessary_null_comparison - assert(rects != null); // ignore: unnecessary_null_comparison + assert(transforms != null); + assert(rects != null); assert(colors == null || colors.isEmpty || blendMode != null); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); final int rectCount = rects.length; if (transforms.length != rectCount) { @@ -418,12 +410,11 @@ class CanvasKitCanvas implements ui.Canvas { ui.BlendMode? blendMode, ui.Rect? cullRect, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(atlas != null); // atlas is checked on the engine side - assert(rstTransforms != null); // ignore: unnecessary_null_comparison - assert(rects != null); // ignore: unnecessary_null_comparison + assert(rstTransforms != null); + assert(rects != null); assert(colors == null || blendMode != null); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); final int rectCount = rects.length; if (rstTransforms.length != rectCount) { @@ -464,10 +455,9 @@ class CanvasKitCanvas implements ui.Canvas { @override void drawShadow(ui.Path path, ui.Color color, double elevation, bool transparentOccluder) { - // ignore: unnecessary_null_comparison assert(path != null); // path is checked on the engine side - assert(color != null); // ignore: unnecessary_null_comparison - assert(transparentOccluder != null); // ignore: unnecessary_null_comparison + assert(color != null); + assert(transparentOccluder != null); _drawShadow(path, color, elevation, transparentOccluder); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/image.dart b/lib/web_ui/lib/src/engine/canvaskit/image.dart index f3f84e2c4400b..921d5fe024f48 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -83,7 +83,6 @@ class ImageCodecException implements Exception { const String _kNetworkImageMessage = 'Failed to load network image.'; typedef HttpRequestFactory = DomXMLHttpRequest Function(); -// ignore: prefer_function_declarations_over_variables HttpRequestFactory httpRequestFactory = () => createDomXMLHttpRequest(); void debugRestoreHttpRequestFactory() { httpRequestFactory = () => createDomXMLHttpRequest(); diff --git a/lib/web_ui/lib/src/engine/canvaskit/image_filter.dart b/lib/web_ui/lib/src/engine/canvaskit/image_filter.dart index faf3fb992d0cd..231e89f900d9c 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/image_filter.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/image_filter.dart @@ -135,7 +135,7 @@ class _CkBlurImageFilter extends CkImageFilter { class _CkMatrixImageFilter extends CkImageFilter { _CkMatrixImageFilter( {required Float64List matrix, required this.filterQuality}) - : this.matrix = Float64List.fromList(matrix), // ignore: unnecessary_this + : matrix = Float64List.fromList(matrix), super._(); final Float64List matrix; diff --git a/lib/web_ui/lib/src/engine/canvaskit/layer.dart b/lib/web_ui/lib/src/engine/canvaskit/layer.dart index 79e6ac36b8079..c74b547ee3654 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/layer.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/layer.dart @@ -468,7 +468,7 @@ class PictureLayer extends Layer { @override void paint(PaintContext paintContext) { - assert(picture != null); // ignore: unnecessary_null_comparison + assert(picture != null); assert(needsPainting); paintContext.leafNodesCanvas!.save(); 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 153cd17c1cab9..bca671f68026b 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 @@ -147,7 +147,7 @@ class LayerSceneBuilder implements ui.SceneBuilder { ui.ColorFilter filter, { ui.ColorFilterEngineLayer? oldLayer, }) { - assert(filter != null); // ignore: unnecessary_null_comparison + assert(filter != null); return pushLayer(ColorFilterEngineLayer(filter)); } @@ -156,7 +156,7 @@ class LayerSceneBuilder implements ui.SceneBuilder { ui.ImageFilter filter, { ui.ImageFilterEngineLayer? oldLayer, }) { - assert(filter != null); // ignore: unnecessary_null_comparison + assert(filter != null); return pushLayer(ImageFilterEngineLayer(filter)); } diff --git a/lib/web_ui/lib/src/engine/canvaskit/path.dart b/lib/web_ui/lib/src/engine/canvaskit/path.dart index 96217e010f972..3bbf4f90cb8b4 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/path.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/path.dart @@ -86,7 +86,7 @@ class CkPath extends ManagedSkiaObject implements ui.Path { @override void addPolygon(List points, bool close) { - assert(points != null); // ignore: unnecessary_null_comparison + assert(points != null); final SkFloat32List encodedPoints = toMallocedSkPoints(points); skiaObject.addPoly(encodedPoints.toTypedArray(), close); freeFloat32List(encodedPoints); diff --git a/lib/web_ui/lib/src/engine/canvaskit/shader.dart b/lib/web_ui/lib/src/engine/canvaskit/shader.dart index f8c25d4827cca..94ac8f22122af 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/shader.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/shader.dart @@ -28,10 +28,10 @@ class CkGradientSweep extends CkShader implements ui.Gradient { CkGradientSweep(this.center, this.colors, this.colorStops, this.tileMode, this.startAngle, this.endAngle, this.matrix4) : assert(offsetIsValid(center)), - assert(colors != null), // ignore: unnecessary_null_comparison - assert(tileMode != null), // ignore: unnecessary_null_comparison - assert(startAngle != null), // ignore: unnecessary_null_comparison - assert(endAngle != null), // ignore: unnecessary_null_comparison + assert(colors != null), + assert(tileMode != null), + assert(startAngle != null), + assert(endAngle != null), assert(startAngle < endAngle), assert(matrix4 == null || matrix4IsValid(matrix4)) { validateColorStops(colors, colorStops); @@ -77,8 +77,8 @@ class CkGradientLinear extends CkShader implements ui.Gradient { Float32List? matrix, ) : assert(offsetIsValid(from)), assert(offsetIsValid(to)), - assert(colors != null), // ignore: unnecessary_null_comparison - assert(tileMode != null), // ignore: unnecessary_null_comparison + assert(colors != null), + assert(tileMode != null), matrix4 = matrix { if (assertionsEnabled) { assert(matrix4 == null || matrix4IsValid(matrix4!)); diff --git a/lib/web_ui/lib/src/engine/canvaskit/vertices.dart b/lib/web_ui/lib/src/engine/canvaskit/vertices.dart index 2125a969c9284..22cfbebda12ed 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/vertices.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/vertices.dart @@ -17,8 +17,8 @@ class CkVertices extends ManagedSkiaObject implements ui.Vertices { List? colors, List? indices, }) { - assert(mode != null); // ignore: unnecessary_null_comparison - assert(positions != null); // ignore: unnecessary_null_comparison + assert(mode != null); + assert(positions != null); if (textureCoordinates != null && textureCoordinates.length != positions.length) { throw ArgumentError( @@ -49,8 +49,8 @@ class CkVertices extends ManagedSkiaObject implements ui.Vertices { Int32List? colors, Uint16List? indices, }) { - assert(mode != null); // ignore: unnecessary_null_comparison - assert(positions != null); // ignore: unnecessary_null_comparison + assert(mode != null); + assert(positions != null); if (textureCoordinates != null && textureCoordinates.length != positions.length) { throw ArgumentError( diff --git a/lib/web_ui/lib/src/engine/engine_canvas.dart b/lib/web_ui/lib/src/engine/engine_canvas.dart index 14a952dfc471c..ba956254ce40f 100644 --- a/lib/web_ui/lib/src/engine/engine_canvas.dart +++ b/lib/web_ui/lib/src/engine/engine_canvas.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. // For member documentation see https://api.flutter.dev/flutter/dart-ui/Canvas-class.html -// ignore_for_file: public_member_api_docs import 'dart:typed_data'; diff --git a/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart b/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart index 0bc8528595c1d..3bebbd94b53a1 100644 --- a/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart @@ -39,7 +39,7 @@ class BitmapCanvas extends EngineCanvas { /// initialize this canvas. BitmapCanvas(this._bounds, RenderStrategy renderStrategy, {double density = 1.0}) - : assert(_bounds != null), // ignore: unnecessary_null_comparison + : assert(_bounds != null), _density = density, _renderStrategy = renderStrategy, widthInBitmapPixels = widthToPhysical(_bounds.width), @@ -70,7 +70,7 @@ class BitmapCanvas extends EngineCanvas { /// Painting outside these bounds will result in cropping. ui.Rect get bounds => _bounds; set bounds(ui.Rect newValue) { - assert(newValue != null); // ignore: unnecessary_null_comparison + assert(newValue != null); _bounds = newValue; final int newCanvasPositionX = _bounds.left.floor() - kPaddingPixels; final int newCanvasPositionY = _bounds.top.floor() - kPaddingPixels; @@ -218,7 +218,7 @@ class BitmapCanvas extends EngineCanvas { // Used by picture to assess if canvas is large enough to reuse as is. bool doesFitBounds(ui.Rect newBounds, double newDensity) { - assert(newBounds != null); // ignore: unnecessary_null_comparison + assert(newBounds != null); return widthInBitmapPixels >= widthToPhysical(newBounds.width) && heightInBitmapPixels >= heightToPhysical(newBounds.height) && _density == newDensity; @@ -1343,7 +1343,7 @@ String? stringForStrokeCap(ui.StrokeCap? strokeCap) { } String stringForStrokeJoin(ui.StrokeJoin strokeJoin) { - assert(strokeJoin != null); // ignore: unnecessary_null_comparison + assert(strokeJoin != null); switch (strokeJoin) { case ui.StrokeJoin.round: return 'round'; diff --git a/lib/web_ui/lib/src/engine/html/canvas.dart b/lib/web_ui/lib/src/engine/html/canvas.dart index 867504f7b9e4c..8f310f3865207 100644 --- a/lib/web_ui/lib/src/engine/html/canvas.dart +++ b/lib/web_ui/lib/src/engine/html/canvas.dart @@ -36,7 +36,7 @@ class SurfaceCanvas implements ui.Canvas { @override void saveLayer(ui.Rect? bounds, ui.Paint paint) { - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); if (bounds == null) { _saveLayerWithoutBounds(paint); } else { @@ -85,7 +85,7 @@ class SurfaceCanvas implements ui.Canvas { @override void transform(Float64List matrix4) { - assert(matrix4 != null); // ignore: unnecessary_null_comparison + assert(matrix4 != null); if (matrix4.length != 16) { throw ArgumentError('"matrix4" must have 16 entries.'); } @@ -105,8 +105,8 @@ class SurfaceCanvas implements ui.Canvas { void clipRect(ui.Rect rect, {ui.ClipOp clipOp = ui.ClipOp.intersect, bool doAntiAlias = true}) { assert(rectIsValid(rect)); - assert(clipOp != null); // ignore: unnecessary_null_comparison - assert(doAntiAlias != null); // ignore: unnecessary_null_comparison + assert(clipOp != null); + assert(doAntiAlias != null); _clipRect(rect, clipOp, doAntiAlias); } @@ -117,7 +117,7 @@ class SurfaceCanvas implements ui.Canvas { @override void clipRRect(ui.RRect rrect, {bool doAntiAlias = true}) { assert(rrectIsValid(rrect)); - assert(doAntiAlias != null); // ignore: unnecessary_null_comparison + assert(doAntiAlias != null); _clipRRect(rrect, doAntiAlias); } @@ -127,9 +127,8 @@ class SurfaceCanvas implements ui.Canvas { @override void clipPath(ui.Path path, {bool doAntiAlias = true}) { - // ignore: unnecessary_null_comparison assert(path != null); // path is checked on the engine side - assert(doAntiAlias != null); // ignore: unnecessary_null_comparison + assert(doAntiAlias != null); _clipPath(path, doAntiAlias); } @@ -167,8 +166,8 @@ class SurfaceCanvas implements ui.Canvas { @override void drawColor(ui.Color color, ui.BlendMode blendMode) { - assert(color != null); // ignore: unnecessary_null_comparison - assert(blendMode != null); // ignore: unnecessary_null_comparison + assert(color != null); + assert(blendMode != null); _drawColor(color, blendMode); } @@ -180,7 +179,7 @@ class SurfaceCanvas implements ui.Canvas { void drawLine(ui.Offset p1, ui.Offset p2, ui.Paint paint) { assert(offsetIsValid(p1)); assert(offsetIsValid(p2)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawLine(p1, p2, paint); } @@ -190,7 +189,7 @@ class SurfaceCanvas implements ui.Canvas { @override void drawPaint(ui.Paint paint) { - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawPaint(paint); } @@ -201,7 +200,7 @@ class SurfaceCanvas implements ui.Canvas { @override void drawRect(ui.Rect rect, ui.Paint paint) { assert(rectIsValid(rect)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawRect(rect, paint); } @@ -212,7 +211,7 @@ class SurfaceCanvas implements ui.Canvas { @override void drawRRect(ui.RRect rrect, ui.Paint paint) { assert(rrectIsValid(rrect)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawRRect(rrect, paint); } @@ -224,7 +223,7 @@ class SurfaceCanvas implements ui.Canvas { void drawDRRect(ui.RRect outer, ui.RRect inner, ui.Paint paint) { assert(rrectIsValid(outer)); assert(rrectIsValid(inner)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawDRRect(outer, inner, paint); } @@ -235,7 +234,7 @@ class SurfaceCanvas implements ui.Canvas { @override void drawOval(ui.Rect rect, ui.Paint paint) { assert(rectIsValid(rect)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawOval(rect, paint); } @@ -246,7 +245,7 @@ class SurfaceCanvas implements ui.Canvas { @override void drawCircle(ui.Offset c, double radius, ui.Paint paint) { assert(offsetIsValid(c)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawCircle(c, radius, paint); } @@ -258,7 +257,7 @@ class SurfaceCanvas implements ui.Canvas { void drawArc(ui.Rect rect, double startAngle, double sweepAngle, bool useCenter, ui.Paint paint) { assert(rectIsValid(rect)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); const double pi = math.pi; const double pi2 = 2.0 * pi; @@ -293,9 +292,8 @@ class SurfaceCanvas implements ui.Canvas { @override void drawPath(ui.Path path, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(path != null); // path is checked on the engine side - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawPath(path, paint); } @@ -305,10 +303,9 @@ class SurfaceCanvas implements ui.Canvas { @override void drawImage(ui.Image image, ui.Offset offset, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(image != null); // image is checked on the engine side assert(offsetIsValid(offset)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawImage(image, offset, paint); } @@ -318,11 +315,10 @@ class SurfaceCanvas implements ui.Canvas { @override void drawImageRect(ui.Image image, ui.Rect src, ui.Rect dst, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(image != null); // image is checked on the engine side assert(rectIsValid(src)); assert(rectIsValid(dst)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); _drawImageRect(image, src, dst, paint); } @@ -375,11 +371,10 @@ class SurfaceCanvas implements ui.Canvas { @override void drawImageNine( ui.Image image, ui.Rect center, ui.Rect dst, ui.Paint paint) { - // ignore: unnecessary_null_comparison assert(image != null); // image is checked on the engine side assert(rectIsValid(center)); assert(rectIsValid(dst)); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); if (dst.isEmpty) { return; @@ -424,14 +419,13 @@ class SurfaceCanvas implements ui.Canvas { @override void drawPicture(ui.Picture picture) { - // ignore: unnecessary_null_comparison assert(picture != null); // picture is checked on the engine side _canvas.drawPicture(picture); } @override void drawParagraph(ui.Paragraph paragraph, ui.Offset offset) { - assert(paragraph != null); // ignore: unnecessary_null_comparison + assert(paragraph != null); assert(offsetIsValid(offset)); _drawParagraph(paragraph, offset); } @@ -443,9 +437,9 @@ class SurfaceCanvas implements ui.Canvas { @override void drawPoints( ui.PointMode pointMode, List points, ui.Paint paint) { - assert(pointMode != null); // ignore: unnecessary_null_comparison - assert(points != null); // ignore: unnecessary_null_comparison - assert(paint != null); // ignore: unnecessary_null_comparison + assert(pointMode != null); + assert(points != null); + assert(paint != null); final Float32List pointList = offsetListToFloat32List(points); drawRawPoints(pointMode, pointList, paint); } @@ -453,9 +447,9 @@ class SurfaceCanvas implements ui.Canvas { @override void drawRawPoints( ui.PointMode pointMode, Float32List points, ui.Paint paint) { - assert(pointMode != null); // ignore: unnecessary_null_comparison - assert(points != null); // ignore: unnecessary_null_comparison - assert(paint != null); // ignore: unnecessary_null_comparison + assert(pointMode != null); + assert(points != null); + assert(paint != null); if (points.length % 2 != 0) { throw ArgumentError('"points" must have an even number of values.'); } @@ -466,8 +460,8 @@ class SurfaceCanvas implements ui.Canvas { void drawVertices( ui.Vertices vertices, ui.BlendMode blendMode, ui.Paint paint) { //assert(vertices != null); // vertices is checked on the engine side - assert(paint != null); // ignore: unnecessary_null_comparison - assert(blendMode != null); // ignore: unnecessary_null_comparison + assert(paint != null); + assert(blendMode != null); _canvas.drawVertices( vertices as SurfaceVertices, blendMode, paint as SurfacePaint); } @@ -482,12 +476,11 @@ class SurfaceCanvas implements ui.Canvas { ui.Rect? cullRect, ui.Paint paint, ) { - // ignore: unnecessary_null_comparison assert(atlas != null); // atlas is checked on the engine side - assert(transforms != null); // ignore: unnecessary_null_comparison - assert(rects != null); // ignore: unnecessary_null_comparison + assert(transforms != null); + assert(rects != null); assert(colors == null || colors.isEmpty || blendMode != null); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); final int rectCount = rects.length; if (transforms.length != rectCount) { @@ -512,12 +505,11 @@ class SurfaceCanvas implements ui.Canvas { ui.Rect? cullRect, ui.Paint paint, ) { - // ignore: unnecessary_null_comparison assert(atlas != null); // atlas is checked on the engine side - assert(rstTransforms != null); // ignore: unnecessary_null_comparison - assert(rects != null); // ignore: unnecessary_null_comparison + assert(rstTransforms != null); + assert(rects != null); assert(colors == null || blendMode != null); - assert(paint != null); // ignore: unnecessary_null_comparison + assert(paint != null); final int rectCount = rects.length; if (rstTransforms.length != rectCount) { @@ -543,10 +535,9 @@ class SurfaceCanvas implements ui.Canvas { double elevation, bool transparentOccluder, ) { - // ignore: unnecessary_null_comparison assert(path != null); // path is checked on the engine side - assert(color != null); // ignore: unnecessary_null_comparison - assert(transparentOccluder != null); // ignore: unnecessary_null_comparison + assert(color != null); + assert(transparentOccluder != null); _canvas.drawShadow(path, color, elevation, transparentOccluder); } } diff --git a/lib/web_ui/lib/src/engine/html/painting.dart b/lib/web_ui/lib/src/engine/html/painting.dart index 0616b7ca6d749..beb9f25354291 100644 --- a/lib/web_ui/lib/src/engine/html/painting.dart +++ b/lib/web_ui/lib/src/engine/html/painting.dart @@ -161,7 +161,7 @@ class SurfacePaint implements ui.Paint { @override set strokeMiterLimit(double value) { - assert(value != null); // ignore: unnecessary_null_comparison + assert(value != null); } @override diff --git a/lib/web_ui/lib/src/engine/html/picture.dart b/lib/web_ui/lib/src/engine/html/picture.dart index 05487a4f57708..da6f988ba8df7 100644 --- a/lib/web_ui/lib/src/engine/html/picture.dart +++ b/lib/web_ui/lib/src/engine/html/picture.dart @@ -54,8 +54,8 @@ class PaintRequest { PaintRequest({ required this.canvasSize, required this.paintCallback, - }) : assert(canvasSize != null), // ignore: unnecessary_null_comparison - assert(paintCallback != null); // ignore: unnecessary_null_comparison + }) : assert(canvasSize != null), + assert(paintCallback != null); final ui.Size canvasSize; final ui.VoidCallback paintCallback; diff --git a/lib/web_ui/lib/src/engine/html/render_vertices.dart b/lib/web_ui/lib/src/engine/html/render_vertices.dart index 1c05b349f84ab..4c8305b2660bc 100644 --- a/lib/web_ui/lib/src/engine/html/render_vertices.dart +++ b/lib/web_ui/lib/src/engine/html/render_vertices.dart @@ -26,14 +26,11 @@ class SurfaceVertices implements ui.Vertices { List positions, { List? colors, List? indices, - }) : assert(mode != null), // ignore: unnecessary_null_comparison - assert(positions != null), // ignore: unnecessary_null_comparison - // ignore: unnecessary_this - this.colors = colors != null ? _int32ListFromColors(colors) : null, - // ignore: unnecessary_this - this.indices = indices != null ? Uint16List.fromList(indices) : null, - // ignore: unnecessary_this - this.positions = offsetListToFloat32List(positions) { + }) : assert(mode != null), + assert(positions != null), + colors = colors != null ? _int32ListFromColors(colors) : null, + indices = indices != null ? Uint16List.fromList(indices) : null, + positions = offsetListToFloat32List(positions) { initWebGl(); } @@ -42,15 +39,15 @@ class SurfaceVertices implements ui.Vertices { this.positions, { this.colors, this.indices, - }) : assert(mode != null), // ignore: unnecessary_null_comparison - assert(positions != null) { // ignore: unnecessary_null_comparison + }) : assert(mode != null), + assert(positions != null) { initWebGl(); } final ui.VertexMode mode; final Float32List positions; final Int32List? colors; - final Uint16List? indices; // ignore: unused_field + final Uint16List? indices; static Int32List _int32ListFromColors(List colors) { final Int32List list = Int32List(colors.length); @@ -180,7 +177,7 @@ class _WebGlRenderer implements GlRenderer { // // Create buffer for vertex coordinates. final Object positionsBuffer = gl.createBuffer()!; - assert(positionsBuffer != null); // ignore: unnecessary_null_comparison + assert(positionsBuffer != null); Object? vao; if (imageShader != null) { @@ -372,7 +369,7 @@ class _WebGlRenderer implements GlRenderer { // Setup geometry. final Object positionsBuffer = gl.createBuffer()!; - assert(positionsBuffer != null); // ignore: unnecessary_null_comparison + assert(positionsBuffer != null); gl.bindArrayBuffer(positionsBuffer); gl.bufferData(vertices, gl.kStaticDraw); // Point an attribute to the currently bound vertex buffer object. @@ -447,7 +444,7 @@ class _WebGlRenderer implements GlRenderer { @override void drawHairline( DomCanvasRenderingContext2D? ctx, Float32List positions) { - assert(positions != null); // ignore: unnecessary_null_comparison + assert(positions != null); final int pointCount = positions.length ~/ 2; ctx!.lineWidth = 1.0; ctx.beginPath(); 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 d7fa62552fd4f..22ad25f5a9f89 100644 --- a/lib/web_ui/lib/src/engine/html/scene_builder.dart +++ b/lib/web_ui/lib/src/engine/html/scene_builder.dart @@ -137,7 +137,7 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { ui.Clip clipBehavior = ui.Clip.antiAlias, ui.ClipRectEngineLayer? oldLayer, }) { - assert(clipBehavior != null); // ignore: unnecessary_null_comparison + assert(clipBehavior != null); return _pushSurface( PersistedClipRect(oldLayer as PersistedClipRect?, rect, clipBehavior)); } @@ -168,7 +168,7 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { ui.Clip clipBehavior = ui.Clip.antiAlias, ui.ClipPathEngineLayer? oldLayer, }) { - assert(clipBehavior != null); // ignore: unnecessary_null_comparison + assert(clipBehavior != null); return _pushSurface( PersistedClipPath(oldLayer as PersistedClipPath?, path, clipBehavior)); } @@ -206,7 +206,7 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { ui.ColorFilter filter, { ui.ColorFilterEngineLayer? oldLayer, }) { - assert(filter != null); // ignore: unnecessary_null_comparison + assert(filter != null); return _pushSurface( PersistedColorFilter(oldLayer as PersistedColorFilter?, filter)); } @@ -226,7 +226,7 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { ui.ImageFilter filter, { ui.ImageFilterEngineLayer? oldLayer, }) { - assert(filter != null); // ignore: unnecessary_null_comparison + assert(filter != null); return _pushSurface( PersistedImageFilter(oldLayer as PersistedImageFilter?, filter)); } @@ -264,7 +264,7 @@ class SurfaceSceneBuilder implements ui.SceneBuilder { ui.ShaderMaskEngineLayer? oldLayer, ui.FilterQuality filterQuality = ui.FilterQuality.low, }) { - assert(blendMode != null); // ignore: unnecessary_null_comparison + assert(blendMode != null); return _pushSurface(PersistedShaderMask( oldLayer as PersistedShaderMask?, shader, maskRect, blendMode, filterQuality)); diff --git a/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart b/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart index b8c900739c8be..63573eff49ec6 100644 --- a/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart +++ b/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart @@ -17,8 +17,8 @@ import 'vertex_shaders.dart'; class EngineImageShader implements ui.ImageShader { EngineImageShader(ui.Image image, this.tileModeX, this.tileModeY, Float64List matrix4, this.filterQuality) - : this.image = image as HtmlImage, // ignore: unnecessary_this - this.matrix4 = Float32List.fromList(matrix4); // ignore: unnecessary_this + : image = image as HtmlImage, + matrix4 = Float32List.fromList(matrix4); final ui.TileMode tileModeX; final ui.TileMode tileModeY; @@ -187,7 +187,7 @@ class EngineImageShader implements ui.ImageShader { /// /// Create buffer for vertex coordinates. final Object positionsBuffer = gl.createBuffer()!; - assert(positionsBuffer != null); // ignore: unnecessary_null_comparison + assert(positionsBuffer != null); Object? vao; if (isWebGl2) { diff --git a/lib/web_ui/lib/src/engine/html/shaders/shader.dart b/lib/web_ui/lib/src/engine/html/shaders/shader.dart index d77ab513175e3..a12da953df576 100644 --- a/lib/web_ui/lib/src/engine/html/shaders/shader.dart +++ b/lib/web_ui/lib/src/engine/html/shaders/shader.dart @@ -60,10 +60,10 @@ class GradientSweep extends EngineGradient { GradientSweep(this.center, this.colors, this.colorStops, this.tileMode, this.startAngle, this.endAngle, this.matrix4) : assert(offsetIsValid(center)), - assert(colors != null), // ignore: unnecessary_null_comparison - assert(tileMode != null), // ignore: unnecessary_null_comparison - assert(startAngle != null), // ignore: unnecessary_null_comparison - assert(endAngle != null), // ignore: unnecessary_null_comparison + assert(colors != null), + assert(tileMode != null), + assert(startAngle != null), + assert(endAngle != null), assert(startAngle < endAngle), super._() { validateColorStops(colors, colorStops); @@ -180,8 +180,8 @@ class GradientLinear extends EngineGradient { Float32List? matrix, ) : assert(offsetIsValid(from)), assert(offsetIsValid(to)), - assert(colors != null), // ignore: unnecessary_null_comparison - assert(tileMode != null), // ignore: unnecessary_null_comparison + assert(colors != null), + assert(tileMode != null), matrix4 = matrix == null ? null : FastMatrix32(matrix), super._() { if (assertionsEnabled) { diff --git a/lib/web_ui/lib/src/engine/html/surface.dart b/lib/web_ui/lib/src/engine/html/surface.dart index 21b2a2378e211..15cc063c14597 100644 --- a/lib/web_ui/lib/src/engine/html/surface.dart +++ b/lib/web_ui/lib/src/engine/html/surface.dart @@ -223,7 +223,7 @@ abstract class PersistedSurface implements ui.EngineLayer { /// surface. PersistedSurfaceState get state => _state; set state(PersistedSurfaceState newState) { - assert(newState != null); // ignore: unnecessary_null_comparison + assert(newState != null); assert(newState != _state, 'Attempted to set state that the surface is already in. This likely indicates a bug in the compositor.'); assert(_debugValidateStateTransition(newState)); @@ -414,7 +414,7 @@ abstract class PersistedSurface implements ui.EngineLayer { /// creates a new element by calling [build]. @mustCallSuper void update(covariant PersistedSurface oldSurface) { - assert(oldSurface != null); // ignore: unnecessary_null_comparison + assert(oldSurface != null); assert(!identical(oldSurface, this)); assert(debugAssertSurfaceState(this, PersistedSurfaceState.created)); assert(debugAssertSurfaceState(oldSurface, PersistedSurfaceState.active, @@ -1049,7 +1049,7 @@ abstract class PersistedContainerSurface extends PersistedSurface { final PersistedSurface child = _children[i]; final DomHTMLElement childElement = child.rootElement! as DomHTMLElement; - assert(childElement != null); // ignore: unnecessary_null_comparison + assert(childElement != null); if (!isStationary) { if (refNode == null) { containerElement!.append(childElement); 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 06f7f321d0bfb..339bf85ec2d05 100644 --- a/lib/web_ui/lib/src/engine/html/surface_stats.dart +++ b/lib/web_ui/lib/src/engine/html/surface_stats.dart @@ -237,7 +237,7 @@ void debugPrintSurfaceStats(PersistedScene scene, int frameNumber) { void countReusesRecursively(PersistedSurface surface) { final DebugSurfaceStats stats = surfaceStatsFor(surface); - assert(stats != null); // ignore: unnecessary_null_comparison + assert(stats != null); surfaceRetainCount += stats.retainSurfaceCount; elementReuseCount += stats.reuseElementCount; diff --git a/lib/web_ui/lib/src/engine/initialization.dart b/lib/web_ui/lib/src/engine/initialization.dart index eb20b9626f5b3..1257c677f8ab9 100644 --- a/lib/web_ui/lib/src/engine/initialization.dart +++ b/lib/web_ui/lib/src/engine/initialization.dart @@ -266,7 +266,6 @@ FontCollection get fontCollection => _fontCollection!; FontCollection? _fontCollection; Future _setAssetManager(AssetManager assetManager) async { - // ignore: unnecessary_null_comparison assert(assetManager != null, 'Cannot set assetManager to null'); if (assetManager == _assetManager) { return; diff --git a/lib/web_ui/lib/src/engine/navigation/history.dart b/lib/web_ui/lib/src/engine/navigation/history.dart index 3110e2deef049..bbee4c807bb58 100644 --- a/lib/web_ui/lib/src/engine/navigation/history.dart +++ b/lib/web_ui/lib/src/engine/navigation/history.dart @@ -359,7 +359,7 @@ class SingleEntryBrowserHistory extends BrowserHistory { /// replaces the state of the entry so that we can recognize it later using /// [_isOriginEntry] inside [_popStateListener]. void _setupOriginEntry(UrlStrategy strategy) { - assert(strategy != null); // ignore: unnecessary_null_comparison + assert(strategy != null); strategy.replaceState(_wrapOriginState(currentState), 'origin', ''); } @@ -370,7 +370,7 @@ class SingleEntryBrowserHistory extends BrowserHistory { bool replace = false, String? path, }) { - assert(strategy != null); // ignore: unnecessary_null_comparison + assert(strategy != null); path ??= currentPath; if (replace) { strategy.replaceState(_flutterState, 'flutter', path); diff --git a/lib/web_ui/lib/src/engine/pointer_binding.dart b/lib/web_ui/lib/src/engine/pointer_binding.dart index 9fbea7793eae5..a41b550c5fd8a 100644 --- a/lib/web_ui/lib/src/engine/pointer_binding.dart +++ b/lib/web_ui/lib/src/engine/pointer_binding.dart @@ -687,9 +687,9 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin { required DomPointerEvent event, required _SanitizedDetails details, }) { - assert(data != null); // ignore: unnecessary_null_comparison - assert(event != null); // ignore: unnecessary_null_comparison - assert(details != null); // ignore: unnecessary_null_comparison + assert(data != null); + assert(event != null); + assert(details != null); final ui.PointerDeviceKind kind = _pointerTypeToDeviceKind(event.pointerType!); final double tilt = _computeHighestTilt(event); final Duration timeStamp = _BaseAdapter._eventTimeStampToDuration(event.timeStamp!); @@ -979,9 +979,9 @@ class _MouseAdapter extends _BaseAdapter with _WheelEventListenerMixin { required DomMouseEvent event, required _SanitizedDetails details, }) { - assert(data != null); // ignore: unnecessary_null_comparison - assert(event != null); // ignore: unnecessary_null_comparison - assert(details != null); // ignore: unnecessary_null_comparison + assert(data != null); + assert(event != null); + assert(details != null); _pointerDataConverter.convert( data, change: details.change, diff --git a/lib/web_ui/lib/src/engine/pointer_converter.dart b/lib/web_ui/lib/src/engine/pointer_converter.dart index 5b9974d039d51..4f94cd49b8bfa 100644 --- a/lib/web_ui/lib/src/engine/pointer_converter.dart +++ b/lib/web_ui/lib/src/engine/pointer_converter.dart @@ -240,7 +240,7 @@ class PointerDataConverter { print('>> device=$device change=$change buttons=$buttons'); } final bool isDown = buttons != 0; - assert(change != null); // ignore: unnecessary_null_comparison + assert(change != null); if (signalKind == null || signalKind == ui.PointerSignalKind.none) { switch (change) { diff --git a/lib/web_ui/lib/src/engine/semantics/semantics.dart b/lib/web_ui/lib/src/engine/semantics/semantics.dart index de91d2a6fa86c..3f5448b53a3c5 100644 --- a/lib/web_ui/lib/src/engine/semantics/semantics.dart +++ b/lib/web_ui/lib/src/engine/semantics/semantics.dart @@ -382,7 +382,7 @@ abstract class RoleManager { /// /// A single role object manages exactly one [SemanticsObject]. RoleManager(this.role, this.semanticsObject) - : assert(semanticsObject != null); // ignore: unnecessary_null_comparison + : assert(semanticsObject != null); /// Role identifier. final Role role; @@ -869,7 +869,7 @@ class SemanticsObject { void updateSelf(SemanticsNodeUpdate update) { // Update all field values and their corresponding dirty flags before // applying the updates to the DOM. - assert(update.flags != null); // ignore: unnecessary_null_comparison + assert(update.flags != null); if (_flags != update.flags) { _flags = update.flags; _markFlagsDirty(); @@ -1473,8 +1473,8 @@ class EngineSemanticsOwner { /// allows the same node to be detached from one parent in the tree and /// reattached to another parent. void _attachObject({required SemanticsObject parent, required SemanticsObject child}) { - assert(child != null); // ignore: unnecessary_null_comparison - assert(parent != null); // ignore: unnecessary_null_comparison + assert(child != null); + assert(parent != null); child._parent = parent; _attachments[child.id] = parent; } @@ -1549,8 +1549,6 @@ class EngineSemanticsOwner { /// The top-level DOM element of the semantics DOM element tree. DomElement? _rootSemanticsElement; - - // ignore: prefer_function_declarations_over_variables TimestampFunction _now = () => DateTime.now(); void debugOverrideTimestampFunction(TimestampFunction value) { @@ -1615,7 +1613,7 @@ class EngineSemanticsOwner { /// The default mode is [AccessibilityMode.unknown]. AccessibilityMode get mode => _mode; set mode(AccessibilityMode value) { - assert(value != null); // ignore: unnecessary_null_comparison + assert(value != null); _mode = value; } diff --git a/lib/web_ui/lib/src/engine/services/buffers.dart b/lib/web_ui/lib/src/engine/services/buffers.dart index 725ad2a12772f..7800966635ce1 100644 --- a/lib/web_ui/lib/src/engine/services/buffers.dart +++ b/lib/web_ui/lib/src/engine/services/buffers.dart @@ -212,8 +212,8 @@ abstract class _TypedDataBuffer extends ListBase { /// Like [insertAll], but with a guaranteed non-`null` [start] and [end]. void _insertKnownLength(int index, Iterable values, int start, int end) { - assert(values != null); // ignore: unnecessary_null_comparison - assert(end != null); // ignore: unnecessary_null_comparison + assert(values != null); + assert(end != null); if (start > values.length || end > values.length) { throw StateError('Too few elements'); } diff --git a/lib/web_ui/lib/src/engine/services/message_codec.dart b/lib/web_ui/lib/src/engine/services/message_codec.dart index 0a4285cdaa97d..cb8c26b74647b 100644 --- a/lib/web_ui/lib/src/engine/services/message_codec.dart +++ b/lib/web_ui/lib/src/engine/services/message_codec.dart @@ -32,7 +32,6 @@ abstract class MessageCodec { class MethodCall { /// Creates a [MethodCall] representing the invocation of [method] with the /// specified [arguments]. - // ignore: unnecessary_null_comparison const MethodCall(this.method, [this.arguments]) : assert(method != null); /// The name of the method to be called. @@ -102,7 +101,7 @@ class PlatformException implements Exception { required this.code, this.message, this.details, - }) : assert(code != null); // ignore: unnecessary_null_comparison + }) : assert(code != null); /// An error code. final String code; diff --git a/lib/web_ui/lib/src/engine/services/message_codecs.dart b/lib/web_ui/lib/src/engine/services/message_codecs.dart index dc6a221119efd..d084c9730cf25 100644 --- a/lib/web_ui/lib/src/engine/services/message_codecs.dart +++ b/lib/web_ui/lib/src/engine/services/message_codecs.dart @@ -160,7 +160,7 @@ class JSONMethodCodec implements MethodCodec { @override ByteData? encodeErrorEnvelope( {required String code, String? message, dynamic details}) { - assert(code != null); // ignore: unnecessary_null_comparison + assert(code != null); return const JSONMessageCodec() .encodeMessage([code, message, details]); } diff --git a/lib/web_ui/lib/src/engine/services/serialization.dart b/lib/web_ui/lib/src/engine/services/serialization.dart index c5e2ee53ccf33..1188abcb4e18a 100644 --- a/lib/web_ui/lib/src/engine/services/serialization.dart +++ b/lib/web_ui/lib/src/engine/services/serialization.dart @@ -122,7 +122,7 @@ class WriteBuffer { /// The byte order used is [Endian.host] throughout. class ReadBuffer { /// Creates a [ReadBuffer] for reading from the specified [data]. - ReadBuffer(this.data) : assert(data != null); // ignore: unnecessary_null_comparison + ReadBuffer(this.data) : assert(data != null); /// The underlying data being read. final ByteData data; diff --git a/lib/web_ui/lib/src/engine/text/paragraph.dart b/lib/web_ui/lib/src/engine/text/paragraph.dart index 84e315c3240fa..7011038f71054 100644 --- a/lib/web_ui/lib/src/engine/text/paragraph.dart +++ b/lib/web_ui/lib/src/engine/text/paragraph.dart @@ -726,8 +726,8 @@ void applyTextStyleToElement({ required EngineTextStyle style, bool isSpan = false, }) { - assert(element != null); // ignore: unnecessary_null_comparison - assert(style != null); // ignore: unnecessary_null_comparison + assert(element != null); + assert(style != null); bool updateDecoration = false; final DomCSSStyleDeclaration cssStyle = element.style; 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 4b4b227eada63..f9ec958f18b79 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 @@ -355,7 +355,7 @@ class AutofillInfo { factory AutofillInfo.fromFrameworkMessage(Map autofill, {TextCapitalizationConfig textCapitalization = const TextCapitalizationConfig.defaultCapitalization()}) { - assert(autofill != null); // ignore: unnecessary_null_comparison + assert(autofill != null); final String uniqueIdentifier = autofill.readString('uniqueIdentifier'); final List? hintsList = autofill.tryList('hints'); final String? firstHint = (hintsList == null || hintsList.isEmpty) ? null : hintsList.first as String; diff --git a/lib/web_ui/lib/src/engine/validators.dart b/lib/web_ui/lib/src/engine/validators.dart index 43a108c161f4b..64c3dd5a2ed95 100644 --- a/lib/web_ui/lib/src/engine/validators.dart +++ b/lib/web_ui/lib/src/engine/validators.dart @@ -7,7 +7,7 @@ import 'dart:typed_data'; import 'package:ui/ui.dart' as ui; bool rectIsValid(ui.Rect rect) { - assert(rect != null, 'Rect argument was null.'); // ignore: unnecessary_null_comparison + assert(rect != null, 'Rect argument was null.'); assert( !(rect.left.isNaN || rect.right.isNaN || @@ -18,7 +18,7 @@ bool rectIsValid(ui.Rect rect) { } bool rrectIsValid(ui.RRect rrect) { - assert(rrect != null, 'RRect argument was null.'); // ignore: unnecessary_null_comparison + assert(rrect != null, 'RRect argument was null.'); assert( !(rrect.left.isNaN || rrect.right.isNaN || @@ -29,20 +29,20 @@ bool rrectIsValid(ui.RRect rrect) { } bool offsetIsValid(ui.Offset offset) { - assert(offset != null, 'Offset argument was null.'); // ignore: unnecessary_null_comparison + assert(offset != null, 'Offset argument was null.'); assert(!offset.dx.isNaN && !offset.dy.isNaN, 'Offset argument contained a NaN value.'); return true; } bool matrix4IsValid(Float32List matrix4) { - assert(matrix4 != null, 'Matrix4 argument was null.'); // ignore: unnecessary_null_comparison + assert(matrix4 != null, 'Matrix4 argument was null.'); assert(matrix4.length == 16, 'Matrix4 must have 16 entries.'); return true; } bool radiusIsValid(ui.Radius radius) { - assert(radius != null, 'Radius argument was null.'); // ignore: unnecessary_null_comparison + assert(radius != null, 'Radius argument was null.'); assert(!radius.x.isNaN && !radius.y.isNaN, 'Radius argument contained a NaN value.'); return true; diff --git a/lib/web_ui/lib/text.dart b/lib/web_ui/lib/text.dart index ef45267cca23e..e1c2a56fd1eb2 100644 --- a/lib/web_ui/lib/text.dart +++ b/lib/web_ui/lib/text.dart @@ -44,7 +44,7 @@ class FontWeight { w900 ]; static FontWeight? lerp(FontWeight? a, FontWeight? b, double t) { - assert(t != null); // ignore: unnecessary_null_comparison + assert(t != null); if (a == null && b == null) { return null; } @@ -74,10 +74,10 @@ class FontWeight { class FontFeature { const FontFeature(this.feature, [this.value = 1]) - : assert(feature != null), // ignore: unnecessary_null_comparison + : assert(feature != null), assert(feature.length == 4, 'Feature tag must be exactly four characters long.'), - assert(value != null), // ignore: unnecessary_null_comparison + assert(value != null), assert(value >= 0, 'Feature value must be zero or a positive integer.'); const FontFeature.enable(String feature) : this(feature, 1); const FontFeature.disable(String feature) : this(feature, 0); @@ -579,8 +579,8 @@ class TextPosition { const TextPosition({ required this.offset, this.affinity = TextAffinity.downstream, - }) : assert(offset != null), // ignore: unnecessary_null_comparison - assert(affinity != null); // ignore: unnecessary_null_comparison + }) : assert(offset != null), + assert(affinity != null); final int offset; final TextAffinity affinity; @@ -655,7 +655,7 @@ class TextRange { class ParagraphConstraints { const ParagraphConstraints({ required this.width, - }) : assert(width != null); // ignore: unnecessary_null_comparison + }) : assert(width != null); final double width; @override diff --git a/lib/web_ui/lib/window.dart b/lib/web_ui/lib/window.dart index 9ef1677a84dc5..bbb033b42e395 100644 --- a/lib/web_ui/lib/window.dart +++ b/lib/web_ui/lib/window.dart @@ -167,7 +167,7 @@ enum Brightness { // TODO(dit): see https://github.com/flutter/flutter/issues/33614. class CallbackHandle { CallbackHandle.fromRawHandle(this._handle) - : assert(_handle != null, "'_handle' must not be null."); // ignore: unnecessary_null_comparison + : assert(_handle != null, "'_handle' must not be null."); final int _handle; diff --git a/lib/web_ui/test/canvaskit/surface_test.dart b/lib/web_ui/test/canvaskit/surface_test.dart index 1eb2721bf41ee..123fff01514f3 100644 --- a/lib/web_ui/test/canvaskit/surface_test.dart +++ b/lib/web_ui/test/canvaskit/surface_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: avoid_dynamic_calls - import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/src/engine.dart'; 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 d57763df97ba4..0f2c2bd713e63 100644 --- a/lib/web_ui/test/engine/semantics/text_field_test.dart +++ b/lib/web_ui/test/engine/semantics/text_field_test.dart @@ -122,7 +122,7 @@ void testMain() { expect(domDocument.activeElement, flutterViewEmbedder.glassPaneElement); expect(appHostNode.activeElement, strategy.domElement); expect(textField.editableElement, strategy.domElement); - expect((textField.editableElement as dynamic).value, 'hello'); // ignore: avoid_dynamic_calls + expect((textField.editableElement as dynamic).value, 'hello'); expect(textField.editableElement.getAttribute('aria-label'), 'greeting'); expect(textField.editableElement.style.width, '10px'); expect(textField.editableElement.style.height, '15px'); @@ -137,7 +137,7 @@ void testMain() { expect(domDocument.activeElement, domDocument.body); expect(appHostNode.activeElement, null); expect(strategy.domElement, null); - expect((textField.editableElement as dynamic).value, 'bye'); // ignore: avoid_dynamic_calls + expect((textField.editableElement as dynamic).value, 'bye'); expect(textField.editableElement.getAttribute('aria-label'), 'farewell'); expect(textField.editableElement.style.width, '12px'); expect(textField.editableElement.style.height, '17px'); diff --git a/lib/web_ui/test/hash_codes_test.dart b/lib/web_ui/test/hash_codes_test.dart index 9d4f24786de4f..7f56a727b6811 100644 --- a/lib/web_ui/test/hash_codes_test.dart +++ b/lib/web_ui/test/hash_codes_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: deprecated_member_use_from_same_package - import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; import 'package:ui/ui.dart'; diff --git a/lib/web_ui/test/text/font_loading_test.dart b/lib/web_ui/test/text/font_loading_test.dart index f0d9b97d3dfee..07dc6d933db0d 100644 --- a/lib/web_ui/test/text/font_loading_test.dart +++ b/lib/web_ui/test/text/font_loading_test.dart @@ -97,7 +97,7 @@ Future testMain() async { fontFamily: 'Blehm'); final Completer completer = Completer(); domWindow.requestAnimationFrame(allowInterop((_) { completer.complete();}) ); - await (completer.future); // ignore: unnecessary_parenthesis + await completer.future; window.onPlatformMessage = oldHandler; expect(actualName, 'flutter/system'); expect(message, '{"type":"fontsChange"}'); diff --git a/lib/web_ui/test/window_test.dart b/lib/web_ui/test/window_test.dart index f8f8748abfcea..c310f0f9ef125 100644 --- a/lib/web_ui/test/window_test.dart +++ b/lib/web_ui/test/window_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: avoid_dynamic_calls - import 'dart:async'; import 'dart:js_util' as js_util; @@ -189,7 +187,6 @@ void testMain() { await window.handleNavigationMessage( const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeInformationUpdated', - // ignore: prefer_const_literals_to_create_immutables { 'location': '/baz', 'state': null, @@ -220,7 +217,6 @@ void testMain() { 'flutter/navigation', const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeUpdated', - // ignore: prefer_const_literals_to_create_immutables {'routeName': '/bar'}, )), (_) { callback.complete(); }, @@ -235,7 +231,6 @@ void testMain() { 'flutter/navigation', const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeInformationUpdated', - // ignore: prefer_const_literals_to_create_immutables { 'location': '/baz', 'state': null, @@ -251,7 +246,6 @@ void testMain() { await window.handleNavigationMessage( const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeUpdated', - // ignore: prefer_const_literals_to_create_immutables {'routeName': '/foo'}, )) ); @@ -273,7 +267,6 @@ void testMain() { 'flutter/navigation', const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeInformationUpdated', - // ignore: prefer_const_literals_to_create_immutables { 'location': '/baz', 'state': { @@ -313,7 +306,6 @@ void testMain() { 'flutter/navigation', const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeInformationUpdated', - // ignore: prefer_const_literals_to_create_immutables { 'location': '/baz', 'state': '/state', @@ -330,7 +322,6 @@ void testMain() { 'flutter/navigation', const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeInformationUpdated', - // ignore: prefer_const_literals_to_create_immutables { 'location': '/baz', 'state': '/state1', @@ -348,7 +339,6 @@ void testMain() { 'flutter/navigation', const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeInformationUpdated', - // ignore: prefer_const_literals_to_create_immutables { 'location': '/foo', 'state': '/foostate1', @@ -378,7 +368,6 @@ void testMain() { 'flutter/navigation', const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeUpdated', - // ignore: prefer_const_literals_to_create_immutables {'routeName': '/bar'}, )), (_) { callback.complete(); }, @@ -404,7 +393,6 @@ void testMain() { 'flutter/navigation', const JSONMethodCodec().encodeMethodCall(const MethodCall( 'routeInformationUpdated', - // ignore: prefer_const_literals_to_create_immutables { 'location': '/baz', 'state': null, diff --git a/testing/dart/channel_buffers_test.dart b/testing/dart/channel_buffers_test.dart index 8781d0d29cede..4683a62254d77 100644 --- a/testing/dart/channel_buffers_test.dart +++ b/testing/dart/channel_buffers_test.dart @@ -52,7 +52,6 @@ void main() { // Ignoring the returned future because the completion of the drain is // communicated using the `completer`. - // ignore: unawaited_futures buffers.drain(channel, (ByteData? drainedData, ui.PlatformMessageResponseCallback drainedCallback) async { log.add('callback'); completer.complete(); diff --git a/testing/litetest/lib/litetest.dart b/testing/litetest/lib/litetest.dart index efc627d13c63f..a4d9873d58bb7 100644 --- a/testing/litetest/lib/litetest.dart +++ b/testing/litetest/lib/litetest.dart @@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:async_helper/async_minitest.dart'; // ignore: unused_import -import 'package:expect/expect.dart'; // ignore: unused_import - -import 'src/matchers.dart'; // ignore: unused_import import 'src/test_suite.dart'; export 'package:async_helper/async_minitest.dart' hide test; From 0f4afe8c5ae77e53aa381dea73a3d6c0cd98226c Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Thu, 4 Aug 2022 14:33:04 -0400 Subject: [PATCH 101/558] =?UTF-8?q?Reland=20"[Impeller]=20[Vulkan]=20Gener?= =?UTF-8?q?ate=20descriptor=20set=20layouts=20in=20backen=E2=80=A6=20(#351?= =?UTF-8?q?66)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ci/licenses_golden/licenses_flutter | 1 + impeller/compiler/code_gen_template.h | 30 +++++++++++------------ impeller/renderer/BUILD.gn | 1 + impeller/renderer/descriptor_set_layout.h | 27 ++++++++++++++++++++ impeller/renderer/pipeline_builder.h | 7 ++++++ impeller/renderer/vertex_descriptor.cc | 15 ++++++++++++ impeller/renderer/vertex_descriptor.h | 13 ++++++++++ 7 files changed, 78 insertions(+), 16 deletions(-) create mode 100644 impeller/renderer/descriptor_set_layout.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 659ee197fee08..6d6fab596ba64 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -808,6 +808,7 @@ FILE: ../../../flutter/impeller/renderer/command_buffer.cc FILE: ../../../flutter/impeller/renderer/command_buffer.h FILE: ../../../flutter/impeller/renderer/context.cc FILE: ../../../flutter/impeller/renderer/context.h +FILE: ../../../flutter/impeller/renderer/descriptor_set_layout.h FILE: ../../../flutter/impeller/renderer/device_buffer.cc FILE: ../../../flutter/impeller/renderer/device_buffer.h FILE: ../../../flutter/impeller/renderer/device_buffer_unittests.cc diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index 4a061fcadb5ad..7769f02779524 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -16,15 +16,17 @@ constexpr std::string_view kReflectionHeaderTemplate = {# Note: The nogncheck decorations are only to make GN not mad at the template#} {# this file is generated from. There are no GN rule violations in the generated#} {# file itself and the no-check declarations will be stripped in generated files.#} -#include "impeller/renderer/buffer_view.h" {# // nogncheck #} +#include "impeller/renderer/buffer_view.h" {# // nogncheck #} -#include "impeller/renderer/command.h" {# // nogncheck #} +#include "impeller/renderer/command.h" {# // nogncheck #} -#include "impeller/renderer/sampler.h" {# // nogncheck #} +#include "impeller/renderer/descriptor_set_layout.h" {# // nogncheck #} -#include "impeller/renderer/shader_types.h" {# // nogncheck #} +#include "impeller/renderer/sampler.h" {# // nogncheck #} -#include "impeller/renderer/texture.h" {# // nogncheck #} +#include "impeller/renderer/shader_types.h" {# // nogncheck #} + +#include "impeller/renderer/texture.h" {# // nogncheck #} namespace impeller { @@ -150,30 +152,26 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} // =========================================================================== // Metadata for Vulkan ======================================================= // =========================================================================== -#ifdef IMPELLER_ENABLE_VULKAN_REFLECTION {% if length(buffers)+length(sampled_images) > 0 %} - static constexpr std::array kDescriptorSetLayouts{ + static constexpr std::array kDescriptorSetLayouts{ {% for buffer in buffers %} - VkDescriptorSetLayoutBinding{ + DescriptorSetLayout{ {{buffer.binding}}, // binding = {{buffer.binding}} - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // descriptorType = Uniform Buffer + DescriptorType::kUniformBuffer, // descriptorType = Uniform Buffer 1, // descriptorCount = 1 - {{to_vk_shader_stage_flag_bits(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} - nullptr, // pImmutableSamplers = NULL + {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} }, {% endfor %} {% for sampled_image in sampled_images %} - VkDescriptorSetLayoutBinding{ + DescriptorSetLayout{ {{sampled_image.binding}}, // binding = {{sampled_image.binding}} - VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, // descriptorType = Sampled Image + DescriptorType::kSampledImage, // descriptorType = Sampled Image 1, // descriptorCount = 1 - {{to_vk_shader_stage_flag_bits(shader_stage)}},// stageFlags = {{to_shader_stage(shader_stage)}} - nullptr, // pImmutableSamplers = NULL + {{to_shader_stage(shader_stage)}}, // stageFlags = {{to_shader_stage(shader_stage)}} }, {% endfor %} }; {% endif %} -#endif }; // struct {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn index 9223f4646fb5f..460502c838a61 100644 --- a/impeller/renderer/BUILD.gn +++ b/impeller/renderer/BUILD.gn @@ -22,6 +22,7 @@ impeller_component("renderer") { "command_buffer.h", "context.cc", "context.h", + "descriptor_set_layout.h", "device_buffer.cc", "device_buffer.h", "formats.cc", diff --git a/impeller/renderer/descriptor_set_layout.h b/impeller/renderer/descriptor_set_layout.h new file mode 100644 index 0000000000000..d853f0a663086 --- /dev/null +++ b/impeller/renderer/descriptor_set_layout.h @@ -0,0 +1,27 @@ +// 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/fml/macros.h" +#include "impeller/renderer/shader_types.h" + +namespace impeller { + +enum class DescriptorType { + kSampledImage, + kUniformBuffer, +}; + +struct DescriptorSetLayout { + uint32_t binding; + DescriptorType descriptor_type; + uint32_t descriptor_count; + ShaderStage shader_stage; +}; + +} // namespace impeller diff --git a/impeller/renderer/pipeline_builder.h b/impeller/renderer/pipeline_builder.h index 44cd202997cd9..92def4e50b7ea 100644 --- a/impeller/renderer/pipeline_builder.h +++ b/impeller/renderer/pipeline_builder.h @@ -93,6 +93,13 @@ struct PipelineBuilder { << VertexShader::kLabel << "'."; return false; } + if (!vertex_descriptor->SetDescriptorSetLayouts( + VertexShader::kDescriptorSetLayouts)) { + VALIDATION_LOG << "Cound not configure vertex descriptor set layout for" + " pipeline named '" + << VertexShader::kLabel << "'."; + return false; + } desc.SetVertexDescriptor(std::move(vertex_descriptor)); } diff --git a/impeller/renderer/vertex_descriptor.cc b/impeller/renderer/vertex_descriptor.cc index a40efb31c5eb3..963a7478a1696 100644 --- a/impeller/renderer/vertex_descriptor.cc +++ b/impeller/renderer/vertex_descriptor.cc @@ -20,6 +20,16 @@ bool VertexDescriptor::SetStageInputs( return true; } +bool VertexDescriptor::SetDescriptorSetLayouts( + const DescriptorSetLayout desc_set_layout[], + size_t count) { + desc_set_layouts_.reserve(desc_set_layouts_.size() + count); + for (size_t i = 0; i < count; i++) { + desc_set_layouts_.emplace_back(desc_set_layout[i]); + } + return true; +} + // |Comparable| size_t VertexDescriptor::GetHash() const { auto seed = fml::HashCombine(); @@ -38,4 +48,9 @@ const std::vector& VertexDescriptor::GetStageInputs() const { return inputs_; } +const std::vector& +VertexDescriptor::GetDescriptorSetLayouts() const { + return desc_set_layouts_; +} + } // namespace impeller diff --git a/impeller/renderer/vertex_descriptor.h b/impeller/renderer/vertex_descriptor.h index 4bef9b86d3644..dffe6694f7caf 100644 --- a/impeller/renderer/vertex_descriptor.h +++ b/impeller/renderer/vertex_descriptor.h @@ -8,6 +8,7 @@ #include "flutter/fml/macros.h" #include "impeller/base/comparable.h" +#include "impeller/renderer/descriptor_set_layout.h" #include "impeller/renderer/shader_types.h" namespace impeller { @@ -36,11 +37,22 @@ class VertexDescriptor final : public Comparable { return SetStageInputs(inputs.data(), inputs.size()); } + template + bool SetDescriptorSetLayouts( + const std::array& inputs) { + return SetDescriptorSetLayouts(inputs.data(), inputs.size()); + } + bool SetStageInputs(const ShaderStageIOSlot* const stage_inputs[], size_t count); + bool SetDescriptorSetLayouts(const DescriptorSetLayout desc_set_layout[], + size_t count); + const std::vector& GetStageInputs() const; + const std::vector& GetDescriptorSetLayouts() const; + // |Comparable| std::size_t GetHash() const override; @@ -49,6 +61,7 @@ class VertexDescriptor final : public Comparable { private: std::vector inputs_; + std::vector desc_set_layouts_; FML_DISALLOW_COPY_AND_ASSIGN(VertexDescriptor); }; From e179256ebd822bd0bf548885e55cc4ecd512c1d1 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 4 Aug 2022 21:33:55 +0300 Subject: [PATCH 102/558] [Linux] remove AtkText stub implementation (#34839) When Orca has "Speak object under mouse" enabled, it tries to get the text range extents for any object that implements the AtkText interface and gets a bit confused by our AtkText stub implementation that merely returns null for `get_text`. Removing the stub implementation helps to avoid the issue that Orca would try to call `atk_text_get_range_extents()` with `start_offset=0` and `end_offset=0`: > Atk-CRITICAL **: atk_text_get_range_extents: assertion 'start_offset >= 0 && start_offset < end_offset' failed --- shell/platform/linux/fl_accessible_node.cc | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/shell/platform/linux/fl_accessible_node.cc b/shell/platform/linux/fl_accessible_node.cc index 0ecbf9b50af14..d0681de80e761 100644 --- a/shell/platform/linux/fl_accessible_node.cc +++ b/shell/platform/linux/fl_accessible_node.cc @@ -89,7 +89,6 @@ enum { kProp0, kPropEngine, kPropId, kPropLast }; static void fl_accessible_node_component_interface_init( AtkComponentIface* iface); static void fl_accessible_node_action_interface_init(AtkActionIface* iface); -static void fl_accessible_node_text_interface_init(AtkTextIface* iface); G_DEFINE_TYPE_WITH_CODE( FlAccessibleNode, @@ -99,9 +98,7 @@ G_DEFINE_TYPE_WITH_CODE( G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT, fl_accessible_node_component_interface_init) G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, - fl_accessible_node_action_interface_init) - G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT, - fl_accessible_node_text_interface_init)) + fl_accessible_node_action_interface_init)) // Returns TRUE if [flag] has changed between [old_flags] and [flags]. static gboolean flag_is_changed(FlutterSemanticsFlag old_flags, @@ -338,13 +335,6 @@ static const gchar* fl_accessible_node_get_name(AtkAction* action, gint i) { return data->name; } -// Implements AtkText::get_text. -static gchar* fl_accessible_node_get_text(AtkText* text, - gint start_offset, - gint end_offset) { - return nullptr; -} - // Implements FlAccessibleNode::set_name. static void fl_accessible_node_set_name_impl(FlAccessibleNode* self, const gchar* name) { @@ -475,10 +465,6 @@ static void fl_accessible_node_action_interface_init(AtkActionIface* iface) { iface->get_name = fl_accessible_node_get_name; } -static void fl_accessible_node_text_interface_init(AtkTextIface* iface) { - iface->get_text = fl_accessible_node_get_text; -} - static void fl_accessible_node_init(FlAccessibleNode* self) { FlAccessibleNodePrivate* priv = FL_ACCESSIBLE_NODE_GET_PRIVATE(self); priv->actions = g_ptr_array_new(); From 5eac0584b9b17ec8e15dbd636044ff9ffe5143a3 Mon Sep 17 00:00:00 2001 From: Phil Quitslund Date: Thu, 4 Aug 2022 11:37:07 -0700 Subject: [PATCH 103/558] [testing/scenario_app] fix no-op interpolated toStrings() (#35165) --- testing/scenario_app/bin/android_integration_tests.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/scenario_app/bin/android_integration_tests.dart b/testing/scenario_app/bin/android_integration_tests.dart index f9e99976f1a55..02fbdfa265290 100644 --- a/testing/scenario_app/bin/android_integration_tests.dart +++ b/testing/scenario_app/bin/android_integration_tests.dart @@ -71,7 +71,7 @@ void main(List args) async { try { goldenFile = File(join(screenshotPath, fileName))..writeAsBytesSync(fileContent, flush: true); } on FileSystemException catch (err) { - panic(['failed to create screenshot $fileName: ${err.toString()}']); + panic(['failed to create screenshot $fileName: $err']); } log('wrote ${goldenFile.absolute.path}'); if (isSkiaGoldClientAvailable) { @@ -79,13 +79,13 @@ void main(List args) async { .addImg(fileName, goldenFile, screenshotSize: screenshot.pixelCount) .catchError((dynamic err) { - panic(['skia gold comparison failed: ${err.toString()}']); + panic(['skia gold comparison failed: $err']); }); pendingComparisons.add(comparison); } }, onError: (dynamic err) { - panic(['error while receiving bytes: ${err.toString()}']); + panic(['error while receiving bytes: $err']); }, cancelOnError: true); }); From 9d75cd463b8ceca76a9d1bbc166a8ec60b66e6d6 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Thu, 4 Aug 2022 12:10:38 -0700 Subject: [PATCH 104/558] [impellerc] Namespace user functions (#35155) --- impeller/compiler/spirv_sksl.cc | 26 +++++++++++++ impeller/compiler/spirv_sksl.h | 2 + .../fixtures/shaders/general_shaders/BUILD.gn | 1 + .../no_builtin_redefinition.frag | 38 +++++++++++++++++++ testing/dart/fragment_shader_test.dart | 10 +++++ 5 files changed, 77 insertions(+) create mode 100644 lib/ui/fixtures/shaders/general_shaders/no_builtin_redefinition.frag diff --git a/impeller/compiler/spirv_sksl.cc b/impeller/compiler/spirv_sksl.cc index 977f593ccbd64..42fbeeb4a5e18 100644 --- a/impeller/compiler/spirv_sksl.cc +++ b/impeller/compiler/spirv_sksl.cc @@ -38,6 +38,8 @@ std::string CompilerSkSL::compile() { backend.use_array_constructor = true; backend.workgroup_size_is_hidden = true; + fixup_user_functions(); + fixup_anonymous_struct_names(); fixup_type_alias(); reorder_type_alias(); @@ -72,6 +74,30 @@ std::string CompilerSkSL::compile() { return buffer.str(); } +void CompilerSkSL::fixup_user_functions() { + const std::string prefix = "__flutter_local_"; + ir.for_each_typed_id([&](uint32_t, const SPIRFunction& func) { + const auto& original_name = get_name(func.self); + // Just in case. Don't add the prefix a second time. + if (original_name.rfind(prefix, 0) == 0) { + return; + } + std::string new_name = prefix + original_name; + set_name(func.self, new_name); + }); + + ir.for_each_typed_id( + [&](uint32_t, const SPIRFunctionPrototype& func) { + const auto& original_name = get_name(func.self); + // Just in case. Don't add the prefix a second time. + if (original_name.rfind(prefix, 0) == 0) { + return; + } + std::string new_name = prefix + original_name; + set_name(func.self, new_name); + }); +} + void CompilerSkSL::emit_header() { statement("// This SkSL shader is autogenerated by spirv-cross."); statement(""); diff --git a/impeller/compiler/spirv_sksl.h b/impeller/compiler/spirv_sksl.h index 3fbe4cc1fdcae..7469ba37df4c2 100644 --- a/impeller/compiler/spirv_sksl.h +++ b/impeller/compiler/spirv_sksl.h @@ -38,6 +38,8 @@ class CompilerSkSL : public spirv_cross::CompilerGLSL { void emit_uniform(const spirv_cross::SPIRVariable& var) override; + void fixup_user_functions(); + void detect_unsupported_resources(); bool emit_constant_resources(); bool emit_struct_resources(); diff --git a/lib/ui/fixtures/shaders/general_shaders/BUILD.gn b/lib/ui/fixtures/shaders/general_shaders/BUILD.gn index 548b3b0499df5..c99d06320baa4 100644 --- a/lib/ui/fixtures/shaders/general_shaders/BUILD.gn +++ b/lib/ui/fixtures/shaders/general_shaders/BUILD.gn @@ -11,6 +11,7 @@ if (enable_unittests) { "blue_green_sampler.frag", "children_and_uniforms.frag", "functions.frag", + "no_builtin_redefinition.frag", "no_uniforms.frag", "simple.frag", "uniforms.frag", diff --git a/lib/ui/fixtures/shaders/general_shaders/no_builtin_redefinition.frag b/lib/ui/fixtures/shaders/general_shaders/no_builtin_redefinition.frag new file mode 100644 index 0000000000000..4e74fe27b86b2 --- /dev/null +++ b/lib/ui/fixtures/shaders/general_shaders/no_builtin_redefinition.frag @@ -0,0 +1,38 @@ +#version 320 es + +// 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. + +precision highp float; + +layout ( location = 0 ) out vec4 oColor; + +layout ( location = 0 ) uniform float a; // should be 1.0 + +float saturate(float x) { + return clamp(x, 0.0, 1.0); +} + +float addA(float x) { + return x + a; +} + +vec2 pairWithA(float x) { + return vec2(x, a); +} + +vec3 composedFunction(float x) { + return vec3(addA(x), pairWithA(x)); +} + +float multiParam(float x, float y, float z) { + return x * y * z * a; +} + +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); +} diff --git a/testing/dart/fragment_shader_test.dart b/testing/dart/fragment_shader_test.dart index d77e7b6835913..d19a59c0173b7 100644 --- a/testing/dart/fragment_shader_test.dart +++ b/testing/dart/fragment_shader_test.dart @@ -118,6 +118,16 @@ void main() async { expect(throws, equals(true)); }); + test('user defined functions do not redefine builtins', () async { + final FragmentProgram program = await FragmentProgram.fromAsset( + 'no_builtin_redefinition.frag.iplr', + ); + final Shader shader = program.shader( + floatUniforms: Float32List.fromList([1.0]), + ); + await _expectShaderRendersGreen(shader); + }); + test('fromAsset accepts a shader with no uniforms', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'no_uniforms.frag.iplr', From 708349373697c5fa603789ea8aa08a0275b2e7f1 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 4 Aug 2022 13:11:05 -0700 Subject: [PATCH 105/558] We decided not to support bare ellipsis in the API docs. (#35146) --- lib/ui/painting.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 913000ba4d5fb..3783920590bd9 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4760,7 +4760,7 @@ class Canvas extends NativeFieldWrapperClass1 { /// canvas.clipPath(Path() /// ..addRect(const Rect.fromLTRB(80, 10, 100, 20)) /// ..addRect(const Rect.fromLTRB(10, 80, 20, 100))); - /// ... + /// // ... /// } /// ``` /// @@ -5243,7 +5243,7 @@ class Canvas extends NativeFieldWrapperClass1 { /// ], null, null, null, paint); /// } /// - /// ... + /// // ... /// } /// ``` /// @@ -5289,7 +5289,7 @@ class Canvas extends NativeFieldWrapperClass1 { /// ], BlendMode.srcIn, null, paint); /// } /// - /// ... + /// // ... /// } /// ``` /// @@ -5427,7 +5427,7 @@ class Canvas extends NativeFieldWrapperClass1 { /// canvas.drawRawAtlas(spriteAtlas, transformList, rectList, null, null, null, paint); /// } /// - /// ... + /// // ... /// } /// ``` /// @@ -5496,7 +5496,7 @@ class Canvas extends NativeFieldWrapperClass1 { /// canvas.drawRawAtlas(spriteAtlas, transformList, rectList, colorList, BlendMode.srcIn, null, paint); /// } /// - /// ... + /// // ... /// } /// ``` /// From 19fd9dd9877b0b7287eb110688e9fdfc86200222 Mon Sep 17 00:00:00 2001 From: JKris95 Date: Thu, 4 Aug 2022 22:52:05 +0200 Subject: [PATCH 106/558] Adds documentation for PathMetric.length (#34923) --- lib/ui/painting.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 3783920590bd9..8be9426168858 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -2895,6 +2895,10 @@ class PathMetric { contourIndex = _measure.currentContourIndex; /// Return the total length of the current contour. + /// + /// The length may be calculated from an approximation of the geometry + /// originally added. For this reason, it is not recommended to rely on + /// this property for mathematically correct lengths of common shapes. final double length; /// Whether the contour is closed. From 81f540020ad0a0e129f4b8d026ceeff45dcb4fd0 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 4 Aug 2022 16:57:04 -0400 Subject: [PATCH 107/558] Roll Fuchsia Mac SDK from YeMyxhFzo... to CUZLMQ1lB... (#35171) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 97087956d55e4..a26dc7aee9c10 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'YeMyxhFzoCNrwt0GrUkvlLgP9N_gYEy8dQ6B0Stvp5YC' + 'version': 'CUZLMQ1lB9tR2iKDOs94gUVL5mnO_aC5kckqcyH1Z6MC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 6f47e3755ade051460163168360840d7e6075f53 Mon Sep 17 00:00:00 2001 From: Xilai Zhang Date: Thu, 4 Aug 2022 14:38:05 -0700 Subject: [PATCH 108/558] [gn] mac entitlement config when dart sdk is non prebuilt (#35016) --- build/archives/BUILD.gn | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/build/archives/BUILD.gn b/build/archives/BUILD.gn index 2282c2d457d02..658ee2ce09308 100644 --- a/build/archives/BUILD.gn +++ b/build/archives/BUILD.gn @@ -172,17 +172,22 @@ if (build_engine_artifacts && !flutter_prebuilt_dart_sdk) { zip_bundle_from_file("dart_sdk_archive") { deps = [ "//third_party/dart:create_sdk" ] output = "dart-sdk-$full_target_platform_name.zip" - if (is_mac) { - # Mac artifacts sometimes use mac and sometimes darwin. Standardizing the - # names will require changes in the list of artifacts the tool is downloading. - output = "dart-sdk-darwin-$target_cpu.zip" - } files = [ { source = rebase_path("$root_build_dir/dart-sdk") destination = "dart-sdk" }, ] + if (is_mac) { + output = "dart-sdk-darwin-$target_cpu.zip" + deps += [ ":dart_sdk_entitlement_config" ] + files += [ + { + source = "$target_gen_dir/dart_sdk_entitlements.txt" + destination = "entitlements.txt" + }, + ] + } } } From 96388119cf3f516f2a344a545bc195cfe6d7054b Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 4 Aug 2022 15:23:04 -0700 Subject: [PATCH 109/558] Embedders use DisplayListBuilder for compositing (#35170) --- flow/embedded_views.cc | 63 +++++++++++++++ flow/embedded_views.h | 79 ++++++++++++++++++- flow/layers/layer.h | 6 ++ flow/layers/layer_tree.cc | 1 + flow/layers/layer_tree_unittests.cc | 2 +- flow/layers/platform_view_layer.cc | 9 ++- flow/testing/mock_embedder.cc | 4 +- flow/testing/mock_embedder.h | 2 +- shell/common/rasterizer_unittests.cc | 2 +- .../shell_test_external_view_embedder.cc | 5 +- .../shell_test_external_view_embedder.h | 2 +- .../external_view_embedder.cc | 67 ++++++++++------ .../external_view_embedder.h | 16 ++-- .../external_view_embedder_unittests.cc | 30 +++---- .../framework/Source/FlutterPlatformViews.mm | 54 ++++++++----- .../Source/FlutterPlatformViews_Internal.h | 16 ++-- .../darwin/ios/ios_external_view_embedder.h | 2 +- .../darwin/ios/ios_external_view_embedder.mm | 2 +- .../embedder_external_view_embedder.cc | 7 +- .../embedder_external_view_embedder.h | 2 +- .../flatland_external_view_embedder.cc | 5 +- .../flutter/flatland_external_view_embedder.h | 2 +- .../flutter/gfx_external_view_embedder.cc | 5 +- .../flutter/gfx_external_view_embedder.h | 2 +- .../fuchsia/flutter/platform_view_unittest.cc | 4 +- ...atland_external_view_embedder_unittests.cc | 2 +- .../tests/flatland_platform_view_unittest.cc | 4 +- .../gfx_external_view_embedder_unittests.cc | 2 +- shell/testing/tester_main.cc | 4 +- 29 files changed, 291 insertions(+), 110 deletions(-) diff --git a/flow/embedded_views.cc b/flow/embedded_views.cc index 1fb1d244b0e1b..959986dada16f 100644 --- a/flow/embedded_views.cc +++ b/flow/embedded_views.cc @@ -6,6 +6,69 @@ namespace flutter { +SkPictureEmbedderViewSlice::SkPictureEmbedderViewSlice(SkRect view_bounds) { + auto rtree_factory = RTreeFactory(); + rtree_ = rtree_factory.getInstance(); + + recorder_ = std::make_unique(); + recorder_->beginRecording(view_bounds, &rtree_factory); +} + +SkCanvas* SkPictureEmbedderViewSlice::canvas() { + return recorder_->getRecordingCanvas(); +} + +DisplayListBuilder* SkPictureEmbedderViewSlice::builder() { + return nullptr; +} + +void SkPictureEmbedderViewSlice::end_recording() { + picture_ = recorder_->finishRecordingAsPicture(); +} + +std::list SkPictureEmbedderViewSlice::searchNonOverlappingDrawnRects( + const SkRect& query) const { + return rtree_->searchNonOverlappingDrawnRects(query); +} + +void SkPictureEmbedderViewSlice::render_into(SkCanvas* canvas) { + canvas->drawPicture(picture_); +} + +void SkPictureEmbedderViewSlice::render_into(DisplayListBuilder* builder) { + builder->drawPicture(picture_, nullptr, false); +} + +DisplayListEmbedderViewSlice::DisplayListEmbedderViewSlice(SkRect view_bounds) { + recorder_ = std::make_unique(view_bounds); +} + +SkCanvas* DisplayListEmbedderViewSlice::canvas() { + return recorder_ ? recorder_.get() : nullptr; +} + +DisplayListBuilder* DisplayListEmbedderViewSlice::builder() { + return recorder_ ? recorder_->builder().get() : nullptr; +} + +void DisplayListEmbedderViewSlice::end_recording() { + display_list_ = recorder_->Build(); + recorder_ = nullptr; +} + +std::list DisplayListEmbedderViewSlice::searchNonOverlappingDrawnRects( + const SkRect& query) const { + return display_list_->rtree()->searchNonOverlappingDrawnRects(query); +} + +void DisplayListEmbedderViewSlice::render_into(SkCanvas* canvas) { + display_list_->RenderTo(canvas); +} + +void DisplayListEmbedderViewSlice::render_into(DisplayListBuilder* builder) { + builder->drawDisplayList(display_list_); +} + void ExternalViewEmbedder::SubmitFrame(GrDirectContext* context, std::unique_ptr frame) { frame->Submit(); diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 394fa9d829a92..011c20ff3dd87 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -7,11 +7,13 @@ #include +#include "flutter/flow/rtree.h" #include "flutter/flow/surface_frame.h" #include "flutter/fml/memory/ref_counted.h" #include "flutter/fml/raster_thread_merger.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" #include "third_party/skia/include/core/SkPoint.h" #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkRect.h" @@ -218,10 +220,12 @@ class EmbeddedViewParams { EmbeddedViewParams(SkMatrix matrix, SkSize size_points, - MutatorsStack mutators_stack) + MutatorsStack mutators_stack, + bool display_list_enabled = false) : matrix_(matrix), size_points_(size_points), - mutators_stack_(mutators_stack) { + mutators_stack_(mutators_stack), + display_list_enabled_(display_list_enabled) { SkPath path; SkRect starting_rect = SkRect::MakeSize(size_points); path.addRect(starting_rect); @@ -243,6 +247,10 @@ class EmbeddedViewParams { // Clippings are ignored. const SkRect& finalBoundingRect() const { return final_bounding_rect_; } + // Whether the embedder should construct DisplayList objects to hold the + // rendering commands for each between-view slice of the layer tree. + bool display_list_enabled() const { return display_list_enabled_; } + bool operator==(const EmbeddedViewParams& other) const { return size_points_ == other.size_points_ && mutators_stack_ == other.mutators_stack_ && @@ -255,6 +263,7 @@ class EmbeddedViewParams { SkSize size_points_; MutatorsStack mutators_stack_; SkRect final_bounding_rect_; + bool display_list_enabled_; }; enum class PostPrerollResult { @@ -269,6 +278,70 @@ enum class PostPrerollResult { kSkipAndRetryFrame }; +// The |PlatformViewLayer| calls |CompositeEmbeddedView| in its |Paint| +// method to replace the leaf_nodes_canvas and leaf_nodes_builder in its +// |PaintContext| for subsequent layers in the frame to render into. +// The builder value will only be supplied if the associated ScopedFrame +// is being rendered to DisplayLists. The |EmbedderPaintContext| struct +// allows the method to return both values. +struct EmbedderPaintContext { + SkCanvas* canvas; + DisplayListBuilder* builder; +}; + +// The |EmbedderViewSlice| represents the details of recording all of +// the layer tree rendering operations that appear between before, after +// and between the embedded views. The Slice may be recorded into an +// SkPicture or a DisplayListBuilder depending on the ScopedFrame. +class EmbedderViewSlice { + public: + virtual ~EmbedderViewSlice() = default; + virtual SkCanvas* canvas() = 0; + virtual DisplayListBuilder* builder() = 0; + virtual void end_recording() = 0; + virtual std::list searchNonOverlappingDrawnRects( + const SkRect& query) const = 0; + virtual void render_into(SkCanvas* canvas) = 0; + virtual void render_into(DisplayListBuilder* builder) = 0; +}; + +class SkPictureEmbedderViewSlice : public EmbedderViewSlice { + public: + SkPictureEmbedderViewSlice(SkRect view_bounds); + ~SkPictureEmbedderViewSlice() override = default; + + SkCanvas* canvas() override; + DisplayListBuilder* builder() override; + void end_recording() override; + std::list searchNonOverlappingDrawnRects( + const SkRect& query) const override; + void render_into(SkCanvas* canvas) override; + void render_into(DisplayListBuilder* builder) override; + + private: + std::unique_ptr recorder_; + sk_sp rtree_; + sk_sp picture_; +}; + +class DisplayListEmbedderViewSlice : public EmbedderViewSlice { + public: + DisplayListEmbedderViewSlice(SkRect view_bounds); + ~DisplayListEmbedderViewSlice() override = default; + + SkCanvas* canvas() override; + DisplayListBuilder* builder() override; + void end_recording() override; + std::list searchNonOverlappingDrawnRects( + const SkRect& query) const override; + void render_into(SkCanvas* canvas) override; + void render_into(DisplayListBuilder* builder) override; + + private: + std::unique_ptr recorder_; + sk_sp display_list_; +}; + // Facilitates embedding of platform views within the flow layer tree. // // Used on iOS, Android (hybrid composite mode), and on embedded platforms @@ -317,7 +390,7 @@ class ExternalViewEmbedder { virtual std::vector GetCurrentCanvases() = 0; // Must be called on the UI thread. - virtual SkCanvas* CompositeEmbeddedView(int view_id) = 0; + virtual EmbedderPaintContext CompositeEmbeddedView(int view_id) = 0; // Implementers must submit the frame by calling frame.Submit(). // diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 63d30c3bb5ebe..ef66af244e073 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -106,6 +106,12 @@ struct PrerollContext { bool subtree_can_inherit_opacity = false; std::vector* raster_cached_entries; + + // This flag will be set to true iff the frame will be constructing + // a DisplayList for the layer tree. This flag is mostly of note to + // the embedders that must decide between creating SkPicture or + // DisplayList objects for the inter-view slices of the layer tree. + bool display_list_enabled = false; }; struct PaintContext { diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index f481a05c65bcb..53748a42832b7 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -64,6 +64,7 @@ bool LayerTree::Preroll(CompositorContext::ScopedFrame& frame, .checkerboard_offscreen_layers = checkerboard_offscreen_layers_, .frame_device_pixel_ratio = device_pixel_ratio_, .raster_cached_entries = &raster_cache_items_, + .display_list_enabled = frame.display_list_builder() != nullptr, // clang-format on }; diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc index fa3bb00b455eb..63de819e15808 100644 --- a/flow/layers/layer_tree_unittests.cc +++ b/flow/layers/layer_tree_unittests.cc @@ -199,7 +199,7 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { // PrerollContext that this test must be revisited and updated. // If any fields get removed or replaced, then the expect_defaults closure // will fail to compile, again bringing attention to updating this test. - EXPECT_EQ(sizeof(PrerollContext), size_t(112)); + EXPECT_EQ(sizeof(PrerollContext), size_t(120)); MutatorsStack mock_mutators; FixedRefreshRateStopwatch mock_raster_time; diff --git a/flow/layers/platform_view_layer.cc b/flow/layers/platform_view_layer.cc index 285db390cc91d..8a46cbbce127c 100644 --- a/flow/layers/platform_view_layer.cc +++ b/flow/layers/platform_view_layer.cc @@ -25,7 +25,8 @@ void PlatformViewLayer::Preroll(PrerollContext* context, set_subtree_has_platform_view(true); std::unique_ptr params = std::make_unique(matrix, size_, - context->mutators_stack); + context->mutators_stack, + context->display_list_enabled); context->view_embedder->PrerollCompositeEmbeddedView(view_id_, std::move(params)); } @@ -36,8 +37,10 @@ void PlatformViewLayer::Paint(PaintContext& context) const { "does not support embedding"; return; } - SkCanvas* canvas = context.view_embedder->CompositeEmbeddedView(view_id_); - context.leaf_nodes_canvas = canvas; + EmbedderPaintContext embedder_context = + context.view_embedder->CompositeEmbeddedView(view_id_); + context.leaf_nodes_canvas = embedder_context.canvas; + context.leaf_nodes_builder = embedder_context.builder; } } // namespace flutter diff --git a/flow/testing/mock_embedder.cc b/flow/testing/mock_embedder.cc index 11d34ee80beda..6c3c7bf0a59a7 100644 --- a/flow/testing/mock_embedder.cc +++ b/flow/testing/mock_embedder.cc @@ -37,8 +37,8 @@ std::vector MockViewEmbedder::GetCurrentCanvases() { } // |ExternalViewEmbedder| -SkCanvas* MockViewEmbedder::CompositeEmbeddedView(int view_id) { - return nullptr; +EmbedderPaintContext MockViewEmbedder::CompositeEmbeddedView(int view_id) { + return {nullptr, nullptr}; } } // namespace testing diff --git a/flow/testing/mock_embedder.h b/flow/testing/mock_embedder.h index 2de6ddb51c7b7..ea6a1e09c771d 100644 --- a/flow/testing/mock_embedder.h +++ b/flow/testing/mock_embedder.h @@ -38,7 +38,7 @@ class MockViewEmbedder : public ExternalViewEmbedder { std::vector GetCurrentCanvases() override; // |ExternalViewEmbedder| - SkCanvas* CompositeEmbeddedView(int view_id) override; + EmbedderPaintContext CompositeEmbeddedView(int view_id) override; }; } // namespace testing diff --git a/shell/common/rasterizer_unittests.cc b/shell/common/rasterizer_unittests.cc index 4ae9beb937396..35693c8de848c 100644 --- a/shell/common/rasterizer_unittests.cc +++ b/shell/common/rasterizer_unittests.cc @@ -66,7 +66,7 @@ class MockExternalViewEmbedder : public ExternalViewEmbedder { PostPrerollResult( fml::RefPtr raster_thread_merger)); MOCK_METHOD0(GetCurrentCanvases, std::vector()); - MOCK_METHOD1(CompositeEmbeddedView, SkCanvas*(int view_id)); + MOCK_METHOD1(CompositeEmbeddedView, EmbedderPaintContext(int view_id)); MOCK_METHOD2(SubmitFrame, void(GrDirectContext* context, std::unique_ptr frame)); diff --git a/shell/common/shell_test_external_view_embedder.cc b/shell/common/shell_test_external_view_embedder.cc index 015709d96f686..b0f28ff1f08b9 100644 --- a/shell/common/shell_test_external_view_embedder.cc +++ b/shell/common/shell_test_external_view_embedder.cc @@ -56,8 +56,9 @@ std::vector ShellTestExternalViewEmbedder::GetCurrentCanvases() { } // |ExternalViewEmbedder| -SkCanvas* ShellTestExternalViewEmbedder::CompositeEmbeddedView(int view_id) { - return nullptr; +EmbedderPaintContext ShellTestExternalViewEmbedder::CompositeEmbeddedView( + int view_id) { + return {nullptr, nullptr}; } // |ExternalViewEmbedder| diff --git a/shell/common/shell_test_external_view_embedder.h b/shell/common/shell_test_external_view_embedder.h index 72c101ed1f4bc..f958f6199e694 100644 --- a/shell/common/shell_test_external_view_embedder.h +++ b/shell/common/shell_test_external_view_embedder.h @@ -59,7 +59,7 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { std::vector GetCurrentCanvases() override; // |ExternalViewEmbedder| - SkCanvas* CompositeEmbeddedView(int view_id) override; + EmbedderPaintContext CompositeEmbeddedView(int view_id) override; // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.cc b/shell/platform/android/external_view_embedder/external_view_embedder.cc index a9417ebb16211..8bbb1682b2ba6 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -30,13 +30,15 @@ void AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView( TRACE_EVENT0("flutter", "AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView"); - auto rtree_factory = RTreeFactory(); - view_rtrees_.insert_or_assign(view_id, rtree_factory.getInstance()); - - auto picture_recorder = std::make_unique(); - picture_recorder->beginRecording(SkRect::Make(frame_size_), &rtree_factory); + SkRect view_bounds = SkRect::Make(frame_size_); + std::unique_ptr view; + if (params->display_list_enabled()) { + view = std::make_unique(view_bounds); + } else { + view = std::make_unique(view_bounds); + } + slices_.insert_or_assign(view_id, std::move(view)); - picture_recorders_.insert_or_assign(view_id, std::move(picture_recorder)); composition_order_.push_back(view_id); // Update params only if they changed. if (view_params_.count(view_id) == 1 && @@ -47,11 +49,12 @@ void AndroidExternalViewEmbedder::PrerollCompositeEmbeddedView( } // |ExternalViewEmbedder| -SkCanvas* AndroidExternalViewEmbedder::CompositeEmbeddedView(int view_id) { - if (picture_recorders_.count(view_id) == 1) { - return picture_recorders_.at(view_id)->getRecordingCanvas(); +EmbedderPaintContext AndroidExternalViewEmbedder::CompositeEmbeddedView( + int view_id) { + if (slices_.count(view_id) == 1) { + return {slices_.at(view_id)->canvas(), slices_.at(view_id)->builder()}; } - return nullptr; + return {nullptr, nullptr}; } // |ExternalViewEmbedder| @@ -59,7 +62,9 @@ std::vector AndroidExternalViewEmbedder::GetCurrentCanvases() { std::vector canvases; for (size_t i = 0; i < composition_order_.size(); i++) { int64_t view_id = composition_order_[i]; - canvases.push_back(picture_recorders_.at(view_id)->getRecordingCanvas()); + if (slices_.count(view_id) == 1) { + canvases.push_back(slices_.at(view_id)->canvas()); + } } return canvases; } @@ -90,6 +95,7 @@ void AndroidExternalViewEmbedder::SubmitFrame( std::unordered_map overlay_layers; std::unordered_map> pictures; SkCanvas* background_canvas = frame->SkiaCanvas(); + DisplayListBuilder* background_builder = frame->GetDisplayListBuilder().get(); auto current_frame_view_count = composition_order_.size(); // Restore the clip context after exiting this method since it's changed @@ -98,16 +104,13 @@ void AndroidExternalViewEmbedder::SubmitFrame( for (size_t i = 0; i < current_frame_view_count; i++) { int64_t view_id = composition_order_[i]; - if (picture_recorders_.at(view_id)->getRecordingCanvas() == nullptr) { + EmbedderViewSlice* slice = slices_.at(view_id).get(); + if (slice->canvas() == nullptr) { continue; } - sk_sp picture = - picture_recorders_.at(view_id)->finishRecordingAsPicture(); - FML_CHECK(picture); - pictures.insert({view_id, picture}); + slice->end_recording(); - sk_sp rtree = view_rtrees_.at(view_id); SkRect joined_rect = SkRect::MakeEmpty(); // Determinate if Flutter UI intersects with any of the previous @@ -121,7 +124,7 @@ void AndroidExternalViewEmbedder::SubmitFrame( SkRect current_view_rect = GetViewRect(current_view_id); // Each rect corresponds to a native view that renders Flutter UI. std::list intersection_rects = - rtree->searchNonOverlappingDrawnRects(current_view_rect); + slice->searchNonOverlappingDrawnRects(current_view_rect); // Limit the number of native views, so it doesn't grow forever. // @@ -144,8 +147,16 @@ void AndroidExternalViewEmbedder::SubmitFrame( // drawn on the overlay layer. background_canvas->clipRect(joined_rect, SkClipOp::kDifference); } - background_canvas->drawPicture(pictures.at(view_id)); + if (background_builder) { + slice->render_into(background_builder); + } else { + slice->render_into(background_canvas); + } } + + // Manually trigger the SkAutoCanvasRestore before we submit the frame + save.restore(); + // Submit the background canvas frame before switching the GL context to // the overlay surfaces. // @@ -177,10 +188,10 @@ void AndroidExternalViewEmbedder::SubmitFrame( continue; } std::unique_ptr frame = - CreateSurfaceIfNeeded(context, // - view_id, // - pictures.at(view_id), // - overlay->second // + CreateSurfaceIfNeeded(context, // + view_id, // + slices_.at(view_id).get(), // + overlay->second // ); if (should_submit_current_frame) { frame->Submit(); @@ -192,7 +203,7 @@ void AndroidExternalViewEmbedder::SubmitFrame( std::unique_ptr AndroidExternalViewEmbedder::CreateSurfaceIfNeeded(GrDirectContext* context, int64_t view_id, - sk_sp picture, + EmbedderViewSlice* slice, const SkRect& rect) { std::shared_ptr layer = surface_pool_->GetLayer( context, android_context_, jni_facade_, surface_factory_); @@ -212,7 +223,11 @@ AndroidExternalViewEmbedder::CreateSurfaceIfNeeded(GrDirectContext* context, // Offset the picture since its absolute position on the scene is determined // by the position of the overlay view. overlay_canvas->translate(-rect.x(), -rect.y()); - overlay_canvas->drawPicture(picture); + if (frame->GetDisplayListBuilder()) { + slice->render_into(frame->GetDisplayListBuilder().get()); + } else { + slice->render_into(overlay_canvas); + } return frame; } @@ -258,7 +273,7 @@ void AndroidExternalViewEmbedder::Reset() { previous_frame_view_count_ = composition_order_.size(); composition_order_.clear(); - picture_recorders_.clear(); + slices_.clear(); } // |ExternalViewEmbedder| diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.h b/shell/platform/android/external_view_embedder/external_view_embedder.h index 2ec13297bb9ad..aa6e0729b22b6 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.h +++ b/shell/platform/android/external_view_embedder/external_view_embedder.h @@ -42,7 +42,7 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { std::unique_ptr params) override; // |ExternalViewEmbedder| - SkCanvas* CompositeEmbeddedView(int view_id) override; + EmbedderPaintContext CompositeEmbeddedView(int view_id) override; // |ExternalViewEmbedder| std::vector GetCurrentCanvases() override; @@ -115,19 +115,15 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { // view. std::vector composition_order_; - // The platform view's picture recorder keyed off the platform view id, which - // contains any subsequent operation until the next platform view or the end - // of the last leaf node in the layer tree. - std::unordered_map> - picture_recorders_; + // The |EmbedderViewSlice| implementation keyed off the platform view id, + // which contains any subsequent operations until the next platform view or + // the end of the last leaf node in the layer tree. + std::unordered_map> slices_; // The params for a platform view, which contains the size, position and // mutation stack. std::unordered_map view_params_; - // The r-tree that captures the operations for the picture recorders. - std::unordered_map> view_rtrees_; - // The number of platform views in the previous frame. int64_t previous_frame_view_count_; @@ -146,7 +142,7 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { // Finally, draws the picture on the frame's canvas. std::unique_ptr CreateSurfaceIfNeeded(GrDirectContext* context, int64_t view_id, - sk_sp picture, + EmbedderViewSlice* slice, const SkRect& rect); }; diff --git a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc index 7ff2a86592455..df21dae22820b 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc @@ -147,8 +147,8 @@ TEST(AndroidExternalViewEmbedder, GetCurrentCanvasesCompositeOrder) { auto canvases = embedder->GetCurrentCanvases(); ASSERT_EQ(2UL, canvases.size()); - ASSERT_EQ(embedder->CompositeEmbeddedView(0), canvases[0]); - ASSERT_EQ(embedder->CompositeEmbeddedView(1), canvases[1]); + ASSERT_EQ(embedder->CompositeEmbeddedView(0).canvas, canvases[0]); + ASSERT_EQ(embedder->CompositeEmbeddedView(1).canvas, canvases[1]); } TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) { @@ -156,15 +156,15 @@ TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) { auto embedder = std::make_unique( android_context, nullptr, nullptr, GetTaskRunnersForFixture()); - ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(0)); + ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(0).canvas); embedder->PrerollCompositeEmbeddedView( 0, std::make_unique()); - ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(0)); + ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(0).canvas); - ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(1)); + ASSERT_EQ(nullptr, embedder->CompositeEmbeddedView(1).canvas); embedder->PrerollCompositeEmbeddedView( 1, std::make_unique()); - ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(1)); + ASSERT_NE(nullptr, embedder->CompositeEmbeddedView(1).canvas); } TEST(AndroidExternalViewEmbedder, CancelFrame) { @@ -391,7 +391,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) { embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1)); // This is the recording canvas flow writes to. - auto canvas_1 = embedder->CompositeEmbeddedView(0); + auto canvas_1 = embedder->CompositeEmbeddedView(0).canvas; auto rect_paint = SkPaint(); rect_paint.setColor(SkColors::kCyan); @@ -458,7 +458,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrame) { embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1)); // This is the recording canvas flow writes to. - auto canvas_1 = embedder->CompositeEmbeddedView(0); + auto canvas_1 = embedder->CompositeEmbeddedView(0).canvas; auto rect_paint = SkPaint(); rect_paint.setColor(SkColors::kCyan); @@ -560,7 +560,7 @@ TEST(AndroidExternalViewEmbedder, SubmitFrameOverlayComposition) { rect_paint.setStyle(SkPaint::Style::kFill_Style); // This simulates Flutter UI that intersects with the first Android view. - embedder->CompositeEmbeddedView(0)->drawRect( + embedder->CompositeEmbeddedView(0).canvas->drawRect( SkRect::MakeXYWH(25, 25, 80, 150), rect_paint); { @@ -577,10 +577,10 @@ TEST(AndroidExternalViewEmbedder, SubmitFrameOverlayComposition) { } // This simulates Flutter UI that intersects with the first and second Android // views. - embedder->CompositeEmbeddedView(1)->drawRect(SkRect::MakeXYWH(25, 25, 80, 50), - rect_paint); + embedder->CompositeEmbeddedView(1).canvas->drawRect( + SkRect::MakeXYWH(25, 25, 80, 50), rect_paint); - embedder->CompositeEmbeddedView(1)->drawRect( + embedder->CompositeEmbeddedView(1).canvas->drawRect( SkRect::MakeXYWH(75, 75, 30, 100), rect_paint); EXPECT_CALL(*jni_mock, FlutterViewCreateOverlaySurface()) @@ -745,7 +745,7 @@ TEST(AndroidExternalViewEmbedder, DestroyOverlayLayersOnSizeChange) { embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1)); // This simulates Flutter UI that intersects with the Android view. - embedder->CompositeEmbeddedView(0)->drawRect( + embedder->CompositeEmbeddedView(0).canvas->drawRect( SkRect::MakeXYWH(50, 50, 200, 200), SkPaint()); // Create a new overlay surface. @@ -832,7 +832,7 @@ TEST(AndroidExternalViewEmbedder, DoesNotDestroyOverlayLayersOnSizeChange) { embedder->PrerollCompositeEmbeddedView(0, std::move(view_params_1)); // This simulates Flutter UI that intersects with the Android view. - embedder->CompositeEmbeddedView(0)->drawRect( + embedder->CompositeEmbeddedView(0).canvas->drawRect( SkRect::MakeXYWH(50, 50, 200, 200), SkPaint()); // Create a new overlay surface. @@ -948,7 +948,7 @@ TEST(AndroidExternalViewEmbedder, Teardown) { embedder->PrerollCompositeEmbeddedView(0, std::move(view_params)); // This simulates Flutter UI that intersects with the Android view. - embedder->CompositeEmbeddedView(0)->drawRect( + embedder->CompositeEmbeddedView(0).canvas->drawRect( SkRect::MakeXYWH(50, 50, 200, 200), SkPaint()); // Create a new overlay surface. diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index e7cca9c817e5d..d37d1edd5e1c7 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -324,11 +324,15 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { // All the CATransactions should be committed by the end of the last frame, // so catransaction_added_ must be false. FML_DCHECK(!catransaction_added_); - picture_recorders_[view_id] = std::make_unique(); - auto rtree_factory = RTreeFactory(); - platform_view_rtrees_[view_id] = rtree_factory.getInstance(); - picture_recorders_[view_id]->beginRecording(SkRect::Make(frame_size_), &rtree_factory); + SkRect view_bounds = SkRect::Make(frame_size_); + std::unique_ptr view; + if (params->display_list_enabled()) { + view = std::make_unique(view_bounds); + } else { + view = std::make_unique(view_bounds); + } + slices_.insert_or_assign(view_id, std::move(view)); composition_order_.push_back(view_id); @@ -361,7 +365,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { std::vector canvases; for (size_t i = 0; i < composition_order_.size(); i++) { int64_t view_id = composition_order_[i]; - canvases.push_back(picture_recorders_[view_id]->getRecordingCanvas()); + canvases.push_back(slices_[view_id]->canvas()); } return canvases; } @@ -459,16 +463,16 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { ApplyMutators(mutatorStack, touchInterceptor); } -SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(int view_id) { +EmbedderPaintContext FlutterPlatformViewsController::CompositeEmbeddedView(int view_id) { // Any UIKit related code has to run on main thread. FML_DCHECK([[NSThread currentThread] isMainThread]); // Do nothing if the view doesn't need to be composited. if (views_to_recomposite_.count(view_id) == 0) { - return picture_recorders_[view_id]->getRecordingCanvas(); + return {slices_[view_id]->canvas(), slices_[view_id]->builder()}; } CompositeWithParams(view_id, current_composition_params_[view_id]); views_to_recomposite_.erase(view_id); - return picture_recorders_[view_id]->getRecordingCanvas(); + return {slices_[view_id]->canvas(), slices_[view_id]->builder()}; } void FlutterPlatformViewsController::Reset() { @@ -481,8 +485,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { views_.clear(); composition_order_.clear(); active_composition_order_.clear(); - picture_recorders_.clear(); - platform_view_rtrees_.clear(); + slices_.clear(); current_composition_params_.clear(); clip_count_.clear(); views_to_recomposite_.clear(); @@ -513,12 +516,15 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { DisposeViews(); SkCanvas* background_canvas = frame->SkiaCanvas(); + DisplayListBuilder* background_builder = frame->GetDisplayListBuilder().get(); // Resolve all pending GPU operations before allocating a new surface. background_canvas->flush(); + // Clipping the background canvas before drawing the picture recorders requires to // save and restore the clip context. SkAutoCanvasRestore save(background_canvas, /*doSave=*/true); + // Maps a platform view id to a vector of `FlutterPlatformViewLayer`. LayersMap platform_view_layers; @@ -527,8 +533,8 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { for (size_t i = 0; i < num_platform_views; i++) { int64_t platform_view_id = composition_order_[i]; - sk_sp rtree = platform_view_rtrees_[platform_view_id]; - sk_sp picture = picture_recorders_[platform_view_id]->finishRecordingAsPicture(); + EmbedderViewSlice* slice = slices_[platform_view_id].get(); + slice->end_recording(); // Check if the current picture contains overlays that intersect with the // current platform view or any of the previous platform views. @@ -536,7 +542,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { int64_t current_platform_view_id = composition_order_[j - 1]; SkRect platform_view_rect = GetPlatformViewRect(current_platform_view_id); std::list intersection_rects = - rtree->searchNonOverlappingDrawnRects(platform_view_rect); + slice->searchNonOverlappingDrawnRects(platform_view_rect); auto allocation_size = intersection_rects.size(); // For testing purposes, the overlay id is used to find the overlay view. @@ -573,7 +579,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { // Get a new host layer. std::shared_ptr layer = GetLayer(gr_context, // ios_context, // - picture, // + slice, // joined_rect, // current_platform_view_id, // overlay_id // @@ -583,8 +589,16 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { overlay_id++; } } - background_canvas->drawPicture(picture); + if (background_builder) { + slice->render_into(background_builder); + } else { + slice->render_into(background_canvas); + } } + + // Manually trigger the SkAutoCanvasRestore before we submit the frame + save.restore(); + // If a layer was allocated in the previous frame, but it's not used in the current frame, // then it can be removed from the scene. RemoveUnusedLayers(); @@ -636,7 +650,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { std::shared_ptr FlutterPlatformViewsController::GetLayer( GrDirectContext* gr_context, std::shared_ptr ios_context, - sk_sp picture, + EmbedderViewSlice* slice, SkRect rect, int64_t view_id, int64_t overlay_id) { @@ -669,7 +683,11 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { } SkCanvas* overlay_canvas = frame->SkiaCanvas(); overlay_canvas->clear(SK_ColorTRANSPARENT); - overlay_canvas->drawPicture(picture); + if (frame->GetDisplayListBuilder()) { + slice->render_into(frame->GetDisplayListBuilder().get()); + } else { + slice->render_into(overlay_canvas); + } layer->did_submit_last_frame = frame->Submit(); return layer; @@ -730,7 +748,7 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { } void FlutterPlatformViewsController::ResetFrameState() { - picture_recorders_.clear(); + slices_.clear(); composition_order_.clear(); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index fde21d23e2e20..3c7a252ada303 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -165,7 +165,7 @@ class FlutterPlatformViewsController { std::vector GetCurrentCanvases(); - SkCanvas* CompositeEmbeddedView(int view_id); + EmbedderPaintContext CompositeEmbeddedView(int view_id); // The rect of the platform view at index view_id. This rect has been translated into the // host view coordinate system. Units are device screen pixels. @@ -227,7 +227,7 @@ class FlutterPlatformViewsController { // the picture on the layer's canvas. std::shared_ptr GetLayer(GrDirectContext* gr_context, std::shared_ptr ios_context, - sk_sp picture, + EmbedderViewSlice* slice, SkRect rect, int64_t view_id, int64_t overlay_id); @@ -251,15 +251,11 @@ class FlutterPlatformViewsController { // The pool of reusable view layers. The pool allows to recycle layer in each frame. std::unique_ptr layer_pool_; - // The platform view's R-tree keyed off the view id, which contains any subsequent - // draw operation until the next platform view or the last leaf node in the layer tree. - // - // The R-trees are deleted by the FlutterPlatformViewsController.reset(). - std::map> platform_view_rtrees_; - - // The platform view's picture recorder keyed off the view id, which contains any subsequent + // The platform view's |EmbedderViewSlice| keyed off the view id, which contains any subsequent // operation until the next platform view or the end of the last leaf node in the layer tree. - std::map> picture_recorders_; + // + // The Slices are deleted by the FlutterPlatformViewsController.reset(). + std::map> slices_; fml::scoped_nsobject channel_; fml::scoped_nsobject flutter_view_; diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.h b/shell/platform/darwin/ios/ios_external_view_embedder.h index 6c023d1b793e1..54170d5a1c5b8 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.h +++ b/shell/platform/darwin/ios/ios_external_view_embedder.h @@ -50,7 +50,7 @@ class IOSExternalViewEmbedder : public ExternalViewEmbedder { std::vector GetCurrentCanvases() override; // |ExternalViewEmbedder| - SkCanvas* CompositeEmbeddedView(int view_id) override; + EmbedderPaintContext CompositeEmbeddedView(int view_id) override; // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.mm b/shell/platform/darwin/ios/ios_external_view_embedder.mm index 1323fa4c2f487..f82a98f91d429 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -65,7 +65,7 @@ } // |ExternalViewEmbedder| -SkCanvas* IOSExternalViewEmbedder::CompositeEmbeddedView(int view_id) { +EmbedderPaintContext IOSExternalViewEmbedder::CompositeEmbeddedView(int view_id) { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::CompositeEmbeddedView"); FML_CHECK(platform_views_controller_); return platform_views_controller_->CompositeEmbeddedView(view_id); diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index 14927f4833be5..56580e3f5e89d 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -111,15 +111,16 @@ std::vector EmbedderExternalViewEmbedder::GetCurrentCanvases() { } // |ExternalViewEmbedder| -SkCanvas* EmbedderExternalViewEmbedder::CompositeEmbeddedView(int view_id) { +EmbedderPaintContext EmbedderExternalViewEmbedder::CompositeEmbeddedView( + int view_id) { auto vid = EmbedderExternalView::ViewIdentifier(view_id); auto found = pending_views_.find(vid); if (found == pending_views_.end()) { FML_DCHECK(false) << "Attempted to composite a view that was not " "pre-rolled."; - return nullptr; + return {nullptr, nullptr}; } - return found->second->GetCanvas(); + return {found->second->GetCanvas(), nullptr}; } static FlutterBackingStoreConfig MakeBackingStoreConfig( diff --git a/shell/platform/embedder/embedder_external_view_embedder.h b/shell/platform/embedder/embedder_external_view_embedder.h index 98fe8b2a56639..94bbf6712a46c 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.h +++ b/shell/platform/embedder/embedder_external_view_embedder.h @@ -94,7 +94,7 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder { std::vector GetCurrentCanvases() override; // |ExternalViewEmbedder| - SkCanvas* CompositeEmbeddedView(int view_id) override; + EmbedderPaintContext CompositeEmbeddedView(int view_id) override; // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc index 8eca3629343d5..7b9ac92512996 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc @@ -67,12 +67,13 @@ void FlatlandExternalViewEmbedder::PrerollCompositeEmbeddedView( frame_composition_order_.push_back(handle); } -SkCanvas* FlatlandExternalViewEmbedder::CompositeEmbeddedView(int view_id) { +flutter::EmbedderPaintContext +FlatlandExternalViewEmbedder::CompositeEmbeddedView(int view_id) { zx_handle_t handle = static_cast(view_id); auto found = frame_layers_.find(handle); FML_CHECK(found != frame_layers_.end()); - return found->second.canvas_spy->GetSpyingCanvas(); + return {found->second.canvas_spy->GetSpyingCanvas(), nullptr}; } flutter::PostPrerollResult FlatlandExternalViewEmbedder::PostPrerollAction( diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h index a47cd42055965..1c07f8393aac6 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h @@ -70,7 +70,7 @@ class FlatlandExternalViewEmbedder final std::unique_ptr params) override; // |ExternalViewEmbedder| - SkCanvas* CompositeEmbeddedView(int view_id) override; + flutter::EmbedderPaintContext CompositeEmbeddedView(int view_id) override; // |ExternalViewEmbedder| flutter::PostPrerollResult PostPrerollAction( diff --git a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.cc b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.cc index 388671808f001..1501e8fbd8268 100644 --- a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.cc @@ -176,12 +176,13 @@ void GfxExternalViewEmbedder::PrerollCompositeEmbeddedView( frame_composition_order_.push_back(handle); } -SkCanvas* GfxExternalViewEmbedder::CompositeEmbeddedView(int view_id) { +flutter::EmbedderPaintContext GfxExternalViewEmbedder::CompositeEmbeddedView( + int view_id) { zx_handle_t handle = static_cast(view_id); auto found = frame_layers_.find(handle); FML_CHECK(found != frame_layers_.end()); - return found->second.canvas_spy->GetSpyingCanvas(); + return {found->second.canvas_spy->GetSpyingCanvas(), nullptr}; } flutter::PostPrerollResult GfxExternalViewEmbedder::PostPrerollAction( diff --git a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h index 81b061776973b..09be1bf769b21 100644 --- a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h @@ -93,7 +93,7 @@ class GfxExternalViewEmbedder final : public flutter::ExternalViewEmbedder { std::unique_ptr params) override; // |ExternalViewEmbedder| - SkCanvas* CompositeEmbeddedView(int view_id) override; + flutter::EmbedderPaintContext CompositeEmbeddedView(int view_id) override; // |ExternalViewEmbedder| flutter::PostPrerollResult PostPrerollAction( diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index a02ebb21f4deb..4f6a9cc2149c4 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -63,7 +63,9 @@ class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder { void PrerollCompositeEmbeddedView( int view_id, std::unique_ptr params) override {} - SkCanvas* CompositeEmbeddedView(int view_id) override { return nullptr; } + flutter::EmbedderPaintContext CompositeEmbeddedView(int view_id) override { + return {nullptr, nullptr}; + } }; class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { 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 0c88990e41e07..5ac7705ada835 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 @@ -306,7 +306,7 @@ void DrawFrameWithView(FlatlandExternalViewEmbedder& external_view_embedder, external_view_embedder.PostPrerollAction(nullptr); background_draw_callback(root_canvas); SkCanvas* overlay_canvas = - external_view_embedder.CompositeEmbeddedView(view_id); + external_view_embedder.CompositeEmbeddedView(view_id).canvas; overlay_draw_callback(overlay_canvas); } external_view_embedder.EndFrame(false, nullptr); diff --git a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc index 674030b0fc959..beaf150684a7e 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc @@ -62,7 +62,9 @@ class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder { void PrerollCompositeEmbeddedView( int view_id, std::unique_ptr params) override {} - SkCanvas* CompositeEmbeddedView(int view_id) override { return nullptr; } + flutter::EmbedderPaintContext CompositeEmbeddedView(int view_id) override { + return {nullptr, nullptr}; + } }; class MockPlatformViewDelegate : public flutter::PlatformView::Delegate { diff --git a/shell/platform/fuchsia/flutter/tests/gfx_external_view_embedder_unittests.cc b/shell/platform/fuchsia/flutter/tests/gfx_external_view_embedder_unittests.cc index f99c54fb1904a..adbcc643e1af1 100644 --- a/shell/platform/fuchsia/flutter/tests/gfx_external_view_embedder_unittests.cc +++ b/shell/platform/fuchsia/flutter/tests/gfx_external_view_embedder_unittests.cc @@ -480,7 +480,7 @@ void DrawFrameWithView(GfxExternalViewEmbedder& external_view_embedder, external_view_embedder.PostPrerollAction(nullptr); background_draw_callback(root_canvas); SkCanvas* overlay_canvas = - external_view_embedder.CompositeEmbeddedView(view_id); + external_view_embedder.CompositeEmbeddedView(view_id).canvas; overlay_draw_callback(overlay_canvas); } external_view_embedder.EndFrame(false, nullptr); diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc index 155e2f071d6d6..ecab46ac1a7f1 100644 --- a/shell/testing/tester_main.cc +++ b/shell/testing/tester_main.cc @@ -60,7 +60,9 @@ class TesterExternalViewEmbedder : public ExternalViewEmbedder { std::vector GetCurrentCanvases() override { return {&canvas_}; } // |ExternalViewEmbedder| - SkCanvas* CompositeEmbeddedView(int view_id) override { return &canvas_; } + EmbedderPaintContext CompositeEmbeddedView(int view_id) override { + return {&canvas_, nullptr}; + } private: SkCanvas canvas_; From 7d1abfe094e8cd6e34e839512b26a6260cdf5d70 Mon Sep 17 00:00:00 2001 From: Yegor Date: Thu, 4 Aug 2022 16:03:03 -0700 Subject: [PATCH 110/558] [web] remove dependency on web_installers and transitively all code that used it (#32852) --- lib/web_ui/README.md | 21 -- lib/web_ui/dev/browser_lock.dart | 23 +- lib/web_ui/dev/browser_lock.yaml | 27 --- lib/web_ui/dev/chrome_installer.dart | 3 +- lib/web_ui/dev/common.dart | 5 - lib/web_ui/dev/create_simulator.dart | 38 ---- lib/web_ui/dev/environment.dart | 7 - lib/web_ui/dev/felt.dart | 2 - lib/web_ui/dev/safari_installation.dart | 90 -------- lib/web_ui/dev/safari_ios.dart | 209 ------------------ lib/web_ui/dev/test_platform.dart | 2 +- .../lib/src/engine/browser_detection.dart | 10 +- lib/web_ui/pubspec.yaml | 5 - .../backdrop_filter_golden_test.dart | 1 - .../test/canvaskit/canvas_golden_test.dart | 1 - lib/web_ui/test/canvaskit/canvas_test.dart | 4 +- .../test/canvaskit/canvaskit_api_test.dart | 3 +- .../canvaskit/color_filter_golden_test.dart | 1 - .../test/canvaskit/embedded_views_test.dart | 3 +- .../canvaskit/fallback_fonts_golden_test.dart | 3 - lib/web_ui/test/canvaskit/filter_test.dart | 11 +- .../flutter_tester_emulation_golden_test.dart | 1 - .../test/canvaskit/frame_timings_test.dart | 3 +- .../test/canvaskit/hot_restart_test.dart | 4 +- .../test/canvaskit/image_golden_test.dart | 1 - .../initialization_services_vs_ui_test.dart | 4 +- .../test/canvaskit/initialization_test.dart | 3 +- lib/web_ui/test/canvaskit/layer_test.dart | 4 +- .../linear_gradient_golden_test.dart | 1 - lib/web_ui/test/canvaskit/path_test.dart | 4 +- lib/web_ui/test/canvaskit/picture_test.dart | 3 +- .../canvaskit/platform_dispatcher_test.dart | 3 +- lib/web_ui/test/canvaskit/scene_test.dart | 3 +- lib/web_ui/test/canvaskit/semantics_test.dart | 4 +- .../canvaskit/shader_mask_golden_test.dart | 1 - lib/web_ui/test/canvaskit/shader_test.dart | 3 +- .../canvaskit/skia_font_collection_test.dart | 3 +- .../canvaskit/skia_objects_cache_test.dart | 3 +- .../test/canvaskit/surface_factory_test.dart | 3 +- lib/web_ui/test/canvaskit/surface_test.dart | 4 +- .../canvaskit/sweep_gradient_golden_test.dart | 1 - lib/web_ui/test/canvaskit/text_test.dart | 4 +- lib/web_ui/test/canvaskit/vertices_test.dart | 5 +- .../test/engine/pointer_binding_test.dart | 10 +- .../test/engine/semantics/semantics_test.dart | 6 +- 45 files changed, 44 insertions(+), 506 deletions(-) delete mode 100644 lib/web_ui/dev/create_simulator.dart delete mode 100644 lib/web_ui/dev/safari_installation.dart delete mode 100644 lib/web_ui/dev/safari_ios.dart diff --git a/lib/web_ui/README.md b/lib/web_ui/README.md index 4284463585a3c..d13e1ee6b145d 100644 --- a/lib/web_ui/README.md +++ b/lib/web_ui/README.md @@ -108,27 +108,6 @@ Changing parameters in the browser lock is effective immediately when running tests locally. To make changes effective on LUCI follow instructions in [Rolling Browsers][#rolling-browsers]. -#### Local testing in Safari using the iOS Simulator - -1. If you haven't already, install Xcode. -2. The iOS version and device type used by web engine tests are specified in - the [browser_lock.yaml][2] file. Install the iOS Simulator version using: - Xcode > Preferences > Components -3. Run `xcrun simctl list devices`. If the simulator you want is not installed - use step 4. -4. Use felt to create a simulator: - -``` -felt create_simulator -``` - -To run tests on ios-safari use the one of the following commands: - -``` -felt test --browser=ios-safari -felt test --browser=ios-safari test/alarm_clock_test.dart -``` - ### Rolling browsers When running tests on LUCI using Chromium, LUCI uses the version of Chromium diff --git a/lib/web_ui/dev/browser_lock.dart b/lib/web_ui/dev/browser_lock.dart index 08b7a62eba5e6..5439ab648ee60 100644 --- a/lib/web_ui/dev/browser_lock.dart +++ b/lib/web_ui/dev/browser_lock.dart @@ -27,13 +27,11 @@ class BrowserLock { BrowserLock._fromYaml(YamlMap yaml) : chromeLock = ChromeLock._fromYaml(yaml['chrome'] as YamlMap), firefoxLock = FirefoxLock._fromYaml(yaml['firefox'] as YamlMap), - edgeLock = EdgeLock._fromYaml(yaml['edge'] as YamlMap), - safariIosLock = SafariIosLock._fromYaml(yaml['safari_ios'] as YamlMap); + edgeLock = EdgeLock._fromYaml(yaml['edge'] as YamlMap); final ChromeLock chromeLock; final FirefoxLock firefoxLock; final EdgeLock edgeLock; - final SafariIosLock safariIosLock; } class ChromeLock { @@ -68,22 +66,3 @@ class EdgeLock { final String launcherVersion; } - -class SafariIosLock { - SafariIosLock._fromYaml(YamlMap yaml) : - majorVersion = yaml['major_version'] as int, - minorVersion = yaml['minor_version'] as int, - device = yaml['device'] as String, - heightOfHeader = yaml['height_of_header'] as int, - heightOfFooter = yaml['height_of_footer'] as int, - scaleFactor = yaml['scale_factor'] as double; - - final int majorVersion; - final int minorVersion; - final String device; - final int heightOfHeader; - final int heightOfFooter; - final double scaleFactor; - - String get simulatorDescription => '$device with iOS $majorVersion.$minorVersion'; -} diff --git a/lib/web_ui/dev/browser_lock.yaml b/lib/web_ui/dev/browser_lock.yaml index d6f26f21ab262..f816d27932093 100644 --- a/lib/web_ui/dev/browser_lock.yaml +++ b/lib/web_ui/dev/browser_lock.yaml @@ -25,30 +25,3 @@ firefox: edge: launcher_version: '1.2.0.0' - -safari_ios: - # Make sure this version is the same version supported by LUCI macOS bots. - # XCode on these bots will be updated once a year, do not forget to update - # `heightOfHeader` during this time. - major_version: 13 - minor_version: 0 - device: 'iPhone 11' - # `xcrun simctl` command is used to take screenshots. It takes the screenshot - # of the entire simulator. Therefore we need to crop all the parts other than - # the browsers' content. This file must be in sync with the local and LUCI - # versions of macOS, iOS Simulator, and Xcode. - # `heightOfHeader` is the number of pixels taken by the phone's header menu - # and the browsers address bar. - # TODO: https://github.com/flutter/flutter/issues/65672 - height_of_header: 189 - # `heightOfFooter` is the number of pixels taken by the phone's navigation - # menu. - height_of_footer: 250 - # Most of the time tests use a portion of the screen to compare goldens - # instead of the entire screen. This area is reprented by a rectangle - # when taking screenshots. However the rectangle dimensions are in logical - # coordinates. In order to convert these coordinates to coordinates on the - # phone screeen we enlarge or shrink the area by applying a linear - # transformation by a scale_factor (a.k.a. we perform isotropic scaling). - # This value will be differ depending on the phone. - scale_factor: 3.00 diff --git a/lib/web_ui/dev/chrome_installer.dart b/lib/web_ui/dev/chrome_installer.dart index e5ed8c889fd76..dd3cafec47aed 100644 --- a/lib/web_ui/dev/chrome_installer.dart +++ b/lib/web_ui/dev/chrome_installer.dart @@ -196,7 +196,8 @@ class ChromeInstaller { stopwatch.stop(); print( - 'INFO: The unzip took ${stopwatch.elapsedMilliseconds ~/ 1000} seconds.'); + 'The unzip took ${stopwatch.elapsedMilliseconds ~/ 1000} seconds.' + ); } else { // We have to unzip into a temporary directory and then copy the files // out because our tests expect the files to be direct children of the diff --git a/lib/web_ui/dev/common.dart b/lib/web_ui/dev/common.dart index addbc68445eda..b73dc7908ceca 100644 --- a/lib/web_ui/dev/common.dart +++ b/lib/web_ui/dev/common.dart @@ -11,7 +11,6 @@ import 'browser_lock.dart'; import 'chrome.dart'; import 'edge.dart'; import 'firefox.dart'; -import 'safari_ios.dart'; import 'safari_macos.dart'; /// The port number for debugging. @@ -231,14 +230,12 @@ const String kChrome = 'chrome'; const String kEdge = 'edge'; const String kFirefox = 'firefox'; const String kSafari = 'safari'; -const String kSafariIos = 'ios-safari'; const List kAllBrowserNames = [ kChrome, kEdge, kFirefox, kSafari, - kSafariIos, ]; /// Creates an environment for a browser. @@ -254,8 +251,6 @@ BrowserEnvironment getBrowserEnvironment(String browserName) { return FirefoxEnvironment(); case kSafari: return SafariMacOsEnvironment(); - case kSafariIos: - return SafariIosEnvironment(); } throw UnsupportedError('Browser $browserName is not supported.'); } diff --git a/lib/web_ui/dev/create_simulator.dart b/lib/web_ui/dev/create_simulator.dart deleted file mode 100644 index 0ec86fd8f5455..0000000000000 --- a/lib/web_ui/dev/create_simulator.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; - -import 'package:args/command_runner.dart'; -import 'package:simulators/simulator_manager.dart'; - -import 'browser_lock.dart'; -import 'utils.dart'; - -class CreateSimulatorCommand extends Command with ArgUtils { - @override - String get name => 'create_simulator'; - - @override - String get description => 'Creates mobile simulators.'; - - @override - FutureOr run() async { - final IosSimulatorManager iosSimulatorManager = IosSimulatorManager(); - try { - final SafariIosLock lock = browserLock.safariIosLock; - final IosSimulator simulator = await iosSimulatorManager.createSimulator( - lock.majorVersion, - lock.minorVersion, - lock.device, - ); - print('INFO: Simulator created $simulator'); - } catch (e) { - throw Exception('Error creating requested simulator. You can use Xcode ' - 'to install more versions: XCode > Preferences > Components.' - ' Exception: $e'); - } - return true; - } -} diff --git a/lib/web_ui/dev/environment.dart b/lib/web_ui/dev/environment.dart index 7fe5f90834b06..1c5530ba2a0d0 100644 --- a/lib/web_ui/dev/environment.dart +++ b/lib/web_ui/dev/environment.dart @@ -169,13 +169,6 @@ class Environment { 'test_results', )); - /// Path to the screenshots taken by iOS simulator. - io.Directory get webUiSimulatorScreenshotsDirectory => - io.Directory(pathlib.join( - webUiDartToolDir.path, - 'ios_screenshots', - )); - /// Path to the script that clones the Flutter repo. io.File get cloneFlutterScript => io.File(pathlib.join( engineToolsDir.path, diff --git a/lib/web_ui/dev/felt.dart b/lib/web_ui/dev/felt.dart index 6088acbc0ebed..1048c8bdcf3a6 100644 --- a/lib/web_ui/dev/felt.dart +++ b/lib/web_ui/dev/felt.dart @@ -8,7 +8,6 @@ import 'package:args/command_runner.dart'; import 'build.dart'; import 'clean.dart'; -import 'create_simulator.dart'; import 'exceptions.dart'; import 'licenses.dart'; import 'run.dart'; @@ -21,7 +20,6 @@ CommandRunner runner = CommandRunner( ) ..addCommand(BuildCommand()) ..addCommand(CleanCommand()) - ..addCommand(CreateSimulatorCommand()) ..addCommand(LicensesCommand()) ..addCommand(RunCommand()) ..addCommand(TestCommand()); diff --git a/lib/web_ui/dev/safari_installation.dart b/lib/web_ui/dev/safari_installation.dart deleted file mode 100644 index 497ae06dc7f86..0000000000000 --- a/lib/web_ui/dev/safari_installation.dart +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; -import 'dart:io' as io; - -import 'package:simulators/simulator_manager.dart'; - -import 'browser_lock.dart'; -import 'common.dart'; -import 'utils.dart'; - -/// Returns [IosSimulator] if the [Platform] is `macOS` and simulator -/// is started. -/// -/// Throws an [StateError] if these two conditions are not met. -IosSimulator get iosSimulator { - if (!io.Platform.isMacOS) { - throw StateError('iOS Simulator is only available on macOS machines.'); - } - if (_iosSimulator == null) { - throw StateError( - 'iOS Simulator not started. Please first call initIOSSimulator method', - ); - } - return _iosSimulator!; -} -IosSimulator? _iosSimulator; - -/// Inializes and boots an [IosSimulator] using the [iosMajorVersion], -/// [iosMinorVersion] and [iosDevice] arguments. -Future initIosSimulator() async { - if (_iosSimulator != null) { - throw StateError('_iosSimulator can only be initialized once'); - } - final IosSimulatorManager iosSimulatorManager = IosSimulatorManager(); - final IosSimulator simulator; - final SafariIosLock lock = browserLock.safariIosLock; - try { - simulator = await iosSimulatorManager.getSimulator( - lock.majorVersion, - lock.minorVersion, - lock.device, - ); - _iosSimulator = simulator; - } catch (e) { - io.stderr.writeln( - 'Error getting iOS Simulator for ${lock.simulatorDescription}.\n' - 'Try running `felt create` command before running tests.', - ); - rethrow; - } - - if (!simulator.booted) { - await simulator.boot(); - print('INFO: Simulator ${simulator.id} booted.'); - cleanupCallbacks.add(() async { - await simulator.shutdown(); - print('INFO: Simulator ${simulator.id} shutdown.'); - }); - } -} - -/// Returns the installation of Safari. -/// -/// Currently uses the Safari version installed on the operating system. -/// -/// Latest Safari version for Catalina, Mojave, High Siera is 13. -/// -/// Latest Safari version for Sierra is 12. -Future getOrInstallSafari({ - StringSink? infoLog, -}) async { - // These tests are aimed to run only on macOS machines local or on LUCI. - if (!io.Platform.isMacOS) { - throw UnimplementedError('Safari on ${io.Platform.operatingSystem} is' - ' not supported. Safari is only supported on macOS.'); - } - - infoLog ??= io.stdout; - - // Since Safari is included in macOS, always assume there will be one on the - // system. - infoLog.writeln('Using the system version that is already installed.'); - return BrowserInstallation( - version: 'system', - executable: PlatformBinding.instance.getMacApplicationLauncher(), - ); -} diff --git a/lib/web_ui/dev/safari_ios.dart b/lib/web_ui/dev/safari_ios.dart deleted file mode 100644 index c180e3832d218..0000000000000 --- a/lib/web_ui/dev/safari_ios.dart +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; -import 'dart:io' as io; -import 'dart:math' as math; - -import 'package:image/image.dart'; -import 'package:path/path.dart' as path; -import 'package:test_api/src/backend/runtime.dart'; -import 'package:uuid/uuid.dart'; - -import 'browser.dart'; -import 'browser_lock.dart'; -import 'browser_process.dart'; -import 'environment.dart'; -import 'safari_installation.dart'; -import 'utils.dart'; - -/// Info about the screen layout for the current version of iOS Safari. -/// -/// This is used to properly take screenshots of the browser. -class SafariScreenInfo { - SafariScreenInfo(this.heightOfHeader, this.heightOfFooter, this.scaleFactor); - - final int heightOfHeader; - final int heightOfFooter; - final double scaleFactor; -} - -/// Provides an environment for the mobile variant of Safari running in an iOS -/// simulator. -class SafariIosEnvironment implements BrowserEnvironment { - late final SafariScreenInfo _screenInfo; - - @override - final String name = 'Safari iOS'; - - @override - Future launchBrowserInstance(Uri url, {bool debug = false}) async { - return SafariIos(url, _screenInfo); - } - - @override - Runtime get packageTestRuntime => Runtime.safari; - - @override - Future prepare() async { - final SafariIosLock lock = browserLock.safariIosLock; - _screenInfo = SafariScreenInfo( - lock.heightOfHeader, lock.heightOfFooter, lock.scaleFactor); - - /// Create the directory to use for taking screenshots, if it does not - /// exists. - if (!environment.webUiSimulatorScreenshotsDirectory.existsSync()) { - environment.webUiSimulatorScreenshotsDirectory.createSync(); - } - // Temporary directories are deleted in the clenaup phase of after `felt` - // runs the tests. - temporaryDirectories.add(environment.webUiSimulatorScreenshotsDirectory); - - await initIosSimulator(); - } - - @override - Future cleanup() async {} - - @override - String get packageTestConfigurationYamlFile => 'dart_test_safari.yaml'; -} - -/// Runs an instance of Safari for iOS (i.e. mobile Safari). -/// -/// Most of the communication with the browser is expected to happen via HTTP, -/// so this exposes a bare-bones API. The browser starts as soon as the class is -/// constructed, and is killed when [close] is called. -/// -/// Any errors starting or running the process are reported through [onExit]. -class SafariIos extends Browser { - - /// Starts a new instance of Safari open to the given [url], which may be a - /// [Uri]. - factory SafariIos(Uri url, SafariScreenInfo screenInfo) { - return SafariIos._(BrowserProcess(() async { - // iOS-Safari - // Uses `xcrun simctl`. It is a command line utility to control the - // Simulator. For more details on interacting with the simulator: - // https://developer.apple.com/library/archive/documentation/IDEs/Conceptual/iOS_Simulator_Guide/InteractingwiththeiOSSimulator/InteractingwiththeiOSSimulator.html - final io.Process process = await io.Process.start('xcrun', [ - 'simctl', - 'openurl', // Opens the url on Safari installed on the simulator. - 'booted', // The simulator is already booted. - url.toString(), - ]); - - return process; - }), screenInfo); - } - - SafariIos._(this._process, this._screenInfo); - final BrowserProcess _process; - final SafariScreenInfo _screenInfo; - - @override - Future get onExit => _process.onExit; - - @override - Future close() => _process.close(); - - @override - bool get supportsScreenshots => true; - - @override - - /// Capture a screenshot of entire simulator. - /// - /// Example screenshot with dimensions: W x H. - /// - /// <---------- W -------------> - /// _____________________________ - /// | Phone Top bar (clock etc.) | Ʌ - /// |_____________________________| | - /// | Broswer search bar | | - /// |_____________________________| | - /// | Web page content | | - /// | | | - /// | | - /// | | H - /// | | - /// | | | - /// | | | - /// | | | - /// | | | - /// |_____________________________| | - /// | Phone footer bar | | - /// |_____________________________| V - /// - /// After taking the screenshot, the image is cropped as heigh as - /// [_heightOfHeader] and [_heightOfFooter] from the top and bottom parts - /// consecutively. Hence web content has the dimensions: - /// - /// W x (H - [_heightOfHeader] - [_heightOfFooter]) - /// - /// [region] is used to decide which part of the web content will be used in - /// test image. It includes starting coordinate x,y as well as height and - /// width of the area to capture. - /// - /// Uses simulator tool `xcrun simctl`'s 'screenshot' command. - @override - Future captureScreenshot(math.Rectangle? region) async { - final String screenshotTag = const Uuid().v4(); - - final String filename = 'screenshot$screenshotTag.png'; - - await iosSimulator.takeScreenshot( - filename, - environment.webUiSimulatorScreenshotsDirectory, - ); - - final io.File file = io.File(path.join( - environment.webUiSimulatorScreenshotsDirectory.path, filename)); - List imageBytes; - if (!file.existsSync()) { - throw Exception('Failed to read the screenshot $filename.'); - } - imageBytes = await file.readAsBytes(); - file.deleteSync(); - - final Image screenshot = decodePng(imageBytes)!; - // Create an image with no footer and header. The _heightOfHeader, - // _heightOfFooter values are already in real coordinates therefore - // they don't need to be scaled. - final Image content = copyCrop( - screenshot, - 0, - _screenInfo.heightOfHeader, - screenshot.width, - screenshot.height - - _screenInfo.heightOfFooter - - _screenInfo.heightOfHeader, - ); - - if (region == null) { - return content; - } else { - final math.Rectangle scaledRegion = _scaleScreenshotRegion(region); - return copyCrop( - content, - scaledRegion.left.toInt(), - scaledRegion.top.toInt(), - scaledRegion.width.toInt(), - scaledRegion.height.toInt(), - ); - } - } - - /// Perform a linear transform on the screenshot region to convert its - /// dimensions from linear coordinated to coordinated on the phone screen. - /// This uniform/isotropic scaling is done using [_scaleFactor]. - math.Rectangle _scaleScreenshotRegion(math.Rectangle region) { - return math.Rectangle( - region.left * _screenInfo.scaleFactor, - region.top * _screenInfo.scaleFactor, - region.width * _screenInfo.scaleFactor, - region.height * _screenInfo.scaleFactor, - ); - } -} diff --git a/lib/web_ui/dev/test_platform.dart b/lib/web_ui/dev/test_platform.dart index 2c33c2e2d2180..2a80684c7b4f5 100644 --- a/lib/web_ui/dev/test_platform.dart +++ b/lib/web_ui/dev/test_platform.dart @@ -323,7 +323,7 @@ class BrowserPlatform extends PlatformPlugin { if (!(await browserManager).supportsScreenshots) { print( - 'INFO: Skipping screenshot check for $filename. Current browser/OS ' + 'Skipping screenshot check for $filename. Current browser/OS ' 'combination does not support screenshots.', ); return shelf.Response.ok(json.encode('OK')); diff --git a/lib/web_ui/lib/src/engine/browser_detection.dart b/lib/web_ui/lib/src/engine/browser_detection.dart index 24ab65bcfebd1..6e263e2ac5593 100644 --- a/lib/web_ui/lib/src/engine/browser_detection.dart +++ b/lib/web_ui/lib/src/engine/browser_detection.dart @@ -236,8 +236,16 @@ bool get isIOS15 { domWindow.navigator.userAgent.contains('OS 15_'); } +/// If set to true pretends that the current browser is iOS Safari. +/// +/// Useful for tests. Do not use in production code. +@visibleForTesting +bool debugEmulateIosSafari = false; + /// Returns true if the browser is iOS Safari, false otherwise. -bool get isIosSafari => +bool get isIosSafari => debugEmulateIosSafari || _isActualIosSafari; + +bool get _isActualIosSafari => browserEngine == BrowserEngine.webkit && operatingSystem == OperatingSystem.iOs; diff --git a/lib/web_ui/pubspec.yaml b/lib/web_ui/pubspec.yaml index e623366630820..8ccf08592378d 100644 --- a/lib/web_ui/pubspec.yaml +++ b/lib/web_ui/pubspec.yaml @@ -41,10 +41,5 @@ dev_dependencies: path: ../../web_sdk/web_test_utils web_engine_tester: path: ../../web_sdk/web_engine_tester - simulators: - git: - url: https://github.com/flutter/web_installers.git - path: packages/simulators/ - ref: 9afed28b771da1c4e82a3382c4a2b31344c04522 skia_gold_client: path: ../../testing/skia_gold_client diff --git a/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart b/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart index a8d445b50fcf5..67d4b003a5b1c 100644 --- a/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart +++ b/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart @@ -54,7 +54,6 @@ void testMain() { await matchGoldenFile('canvaskit_backdropfilter_blur_edges.png', region: region); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); } diff --git a/lib/web_ui/test/canvaskit/canvas_golden_test.dart b/lib/web_ui/test/canvaskit/canvas_golden_test.dart index 8b1fc7b8d92ac..77a3a57eb7fc5 100644 --- a/lib/web_ui/test/canvaskit/canvas_golden_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_golden_test.dart @@ -814,7 +814,6 @@ void testMain() { await matchGoldenFile('canvaskit_empty_scene.png', region: const ui.Rect.fromLTRB(0, 0, 100, 100)); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); } diff --git a/lib/web_ui/test/canvaskit/canvas_test.dart b/lib/web_ui/test/canvaskit/canvas_test.dart index d8cbb1f0a6d15..cacb5ed4c6c3f 100644 --- a/lib/web_ui/test/canvaskit/canvas_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_test.dart @@ -8,7 +8,6 @@ import 'dart:async'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/src/engine/browser_detection.dart'; import '../engine/canvas_test.dart'; import 'common.dart'; @@ -25,6 +24,5 @@ Future testMain() async { setUpCanvasKitTest(); runCanvasTests(deviceClipRoundsOut: true); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart index a320f2d8bea85..8418965a164da 100644 --- a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart +++ b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart @@ -59,8 +59,7 @@ void testMain() { group('SkParagraph', () { _textStyleTests(); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } void _blendModeTests() { diff --git a/lib/web_ui/test/canvaskit/color_filter_golden_test.dart b/lib/web_ui/test/canvaskit/color_filter_golden_test.dart index 475f8fc63148f..9833ee1fd577c 100644 --- a/lib/web_ui/test/canvaskit/color_filter_golden_test.dart +++ b/lib/web_ui/test/canvaskit/color_filter_golden_test.dart @@ -136,7 +136,6 @@ void testMain() { await matchSceneGolden('canvaskit_inverse_colormatrix.png', builder.build(), write: true); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); } diff --git a/lib/web_ui/test/canvaskit/embedded_views_test.dart b/lib/web_ui/test/canvaskit/embedded_views_test.dart index 1e459785a4500..61ce23a724830 100644 --- a/lib/web_ui/test/canvaskit/embedded_views_test.dart +++ b/lib/web_ui/test/canvaskit/embedded_views_test.dart @@ -1060,8 +1060,7 @@ void testMain() { _overlay, ]); }); - // TODO(dit): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } // Used to test that the platform views and overlays are in the correct order in diff --git a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart index c0b731620672d..ed1293b813e23 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -91,7 +91,6 @@ void testMain() { recorder.endRecording(), region: kDefaultRegion, ); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); @@ -201,7 +200,6 @@ void testMain() { recorder.endRecording(), region: kDefaultRegion, ); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); @@ -356,7 +354,6 @@ void testMain() { } } }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 }, skip: isSafari); } diff --git a/lib/web_ui/test/canvaskit/filter_test.dart b/lib/web_ui/test/canvaskit/filter_test.dart index c21684f18d04a..0c3d6b46dcd57 100644 --- a/lib/web_ui/test/canvaskit/filter_test.dart +++ b/lib/web_ui/test/canvaskit/filter_test.dart @@ -46,10 +46,7 @@ void testMain() { ]; } - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - if (!isIosSafari) { - setUpCanvasKitTest(); - } + setUpCanvasKitTest(); group('ImageFilters', () { test('can be constructed', () { @@ -92,8 +89,7 @@ void testMain() { expect((paint.imageFilter! as ManagedSkiaObject).skiaObject, same(skiaFilter)); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); group('MaskFilter', () { test('with 0 sigma can be set on a Paint', () { @@ -103,6 +99,5 @@ void testMain() { expect(() => paint.maskFilter = filter, isNot(throwsException)); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart b/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart index 455af77659743..add30b29ca95d 100644 --- a/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart +++ b/lib/web_ui/test/canvaskit/flutter_tester_emulation_golden_test.dart @@ -112,7 +112,6 @@ void testMain() { region: kDefaultRegion, ); }); - // TODO(yjbanov): https://github.com/flutter/flutter/issues/60040 // TODO(yjbanov): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); } diff --git a/lib/web_ui/test/canvaskit/frame_timings_test.dart b/lib/web_ui/test/canvaskit/frame_timings_test.dart index ca0ee4df79917..7cab6bc8f0247 100644 --- a/lib/web_ui/test/canvaskit/frame_timings_test.dart +++ b/lib/web_ui/test/canvaskit/frame_timings_test.dart @@ -4,7 +4,6 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/src/engine/browser_detection.dart'; import '../frame_timings_common.dart'; import 'common.dart'; @@ -20,5 +19,5 @@ void testMain() { test('collects frame timings', () async { await runFrameTimingsTest(); }); - }, skip: isIosSafari); // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 + }); } diff --git a/lib/web_ui/test/canvaskit/hot_restart_test.dart b/lib/web_ui/test/canvaskit/hot_restart_test.dart index c99bc57e6963a..4923c3b6e8951 100644 --- a/lib/web_ui/test/canvaskit/hot_restart_test.dart +++ b/lib/web_ui/test/canvaskit/hot_restart_test.dart @@ -26,7 +26,5 @@ void testMain() { // Should find the existing instance and reuse it. expect(firstCanvasKitInstance, windowFlutterCanvasKit); - - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/image_golden_test.dart b/lib/web_ui/test/canvaskit/image_golden_test.dart index e7bda2e34465d..afcd198e7e714 100644 --- a/lib/web_ui/test/canvaskit/image_golden_test.dart +++ b/lib/web_ui/test/canvaskit/image_golden_test.dart @@ -54,7 +54,6 @@ void testMain() { isTrue, ); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 }, skip: isSafari); } diff --git a/lib/web_ui/test/canvaskit/initialization_services_vs_ui_test.dart b/lib/web_ui/test/canvaskit/initialization_services_vs_ui_test.dart index 1268aa12a6b9a..31820129fb49b 100644 --- a/lib/web_ui/test/canvaskit/initialization_services_vs_ui_test.dart +++ b/lib/web_ui/test/canvaskit/initialization_services_vs_ui_test.dart @@ -39,9 +39,7 @@ void testMain() { expect(MouseCursor.instance, isNotNull); expect(KeyboardBinding.instance, isNotNull); expect(PointerBinding.instance, isNotNull); - - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } DomElement? findGlassPane() { diff --git a/lib/web_ui/test/canvaskit/initialization_test.dart b/lib/web_ui/test/canvaskit/initialization_test.dart index 202983939e49f..53f3dd34674ec 100644 --- a/lib/web_ui/test/canvaskit/initialization_test.dart +++ b/lib/web_ui/test/canvaskit/initialization_test.dart @@ -22,6 +22,5 @@ void testMain() { 'canvaskit (requested explicitly)'); expect(domDocument.body!.getAttribute('flt-build-mode'), 'debug'); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/layer_test.dart b/lib/web_ui/test/canvaskit/layer_test.dart index dfc4f7ea73349..8a1fdcaaf8c52 100644 --- a/lib/web_ui/test/canvaskit/layer_test.dart +++ b/lib/web_ui/test/canvaskit/layer_test.dart @@ -55,7 +55,5 @@ void testMain() { recorder.beginRecording(ui.Rect.zero); LayerSceneBuilder().addPicture(ui.Offset.zero, recorder.endRecording()); }); - - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/linear_gradient_golden_test.dart b/lib/web_ui/test/canvaskit/linear_gradient_golden_test.dart index 465e4030493c8..9cca66b39db3f 100644 --- a/lib/web_ui/test/canvaskit/linear_gradient_golden_test.dart +++ b/lib/web_ui/test/canvaskit/linear_gradient_golden_test.dart @@ -101,7 +101,6 @@ void testMain() { recorder.endRecording(), ); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); } diff --git a/lib/web_ui/test/canvaskit/path_test.dart b/lib/web_ui/test/canvaskit/path_test.dart index 5ef031f9aa9f0..febfbf89b63ff 100644 --- a/lib/web_ui/test/canvaskit/path_test.dart +++ b/lib/web_ui/test/canvaskit/path_test.dart @@ -190,7 +190,5 @@ void testMain() { expect(original.getBounds(), rect1); expect(copy.getBounds(), rect1.expandToInclude(rect2)); }); - }, - skip: - isIosSafari); // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 + }); } diff --git a/lib/web_ui/test/canvaskit/picture_test.dart b/lib/web_ui/test/canvaskit/picture_test.dart index b082d13d6e260..5ed13acc1edcf 100644 --- a/lib/web_ui/test/canvaskit/picture_test.dart +++ b/lib/web_ui/test/canvaskit/picture_test.dart @@ -102,6 +102,5 @@ void testMain() { expect(data!.lengthInBytes, 10 * 15 * 4); expect(data.buffer.asUint32List().first, color.value); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/platform_dispatcher_test.dart b/lib/web_ui/test/canvaskit/platform_dispatcher_test.dart index e13eff9584f92..85421d24f70ab 100644 --- a/lib/web_ui/test/canvaskit/platform_dispatcher_test.dart +++ b/lib/web_ui/test/canvaskit/platform_dispatcher_test.dart @@ -40,6 +40,5 @@ void testMain() { [true], ); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/scene_test.dart b/lib/web_ui/test/canvaskit/scene_test.dart index 2dd134a2ca5ec..9395c067bb3d7 100644 --- a/lib/web_ui/test/canvaskit/scene_test.dart +++ b/lib/web_ui/test/canvaskit/scene_test.dart @@ -57,6 +57,5 @@ void testMain() { final ui.Scene scene = builder.build(); expect(scene, isNotNull); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/semantics_test.dart b/lib/web_ui/test/canvaskit/semantics_test.dart index 7053c3d7958b2..7df21aeeaac19 100644 --- a/lib/web_ui/test/canvaskit/semantics_test.dart +++ b/lib/web_ui/test/canvaskit/semantics_test.dart @@ -8,7 +8,6 @@ import 'dart:async'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/src/engine/browser_detection.dart'; import '../engine/semantics/semantics_test.dart'; import 'common.dart'; @@ -25,6 +24,5 @@ Future testMain() async { setUpCanvasKitTest(); runSemanticsTests(); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/shader_mask_golden_test.dart b/lib/web_ui/test/canvaskit/shader_mask_golden_test.dart index eb53ed554bc5a..3b7481496242a 100644 --- a/lib/web_ui/test/canvaskit/shader_mask_golden_test.dart +++ b/lib/web_ui/test/canvaskit/shader_mask_golden_test.dart @@ -158,7 +158,6 @@ void testMain() { await matchSceneGolden('canvaskit_shadermask_linear_translated.png', builder.build()); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); } diff --git a/lib/web_ui/test/canvaskit/shader_test.dart b/lib/web_ui/test/canvaskit/shader_test.dart index 2f44ed7e7a837..0c0dcda41845c 100644 --- a/lib/web_ui/test/canvaskit/shader_test.dart +++ b/lib/web_ui/test/canvaskit/shader_test.dart @@ -71,8 +71,7 @@ void testMain() { ) as CkImageShader; expect(imageShader, isA()); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } const List testColors = [ui.Color(0xFFFFFF00), ui.Color(0xFFFFFFFF)]; diff --git a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart index 76a0f56b24f27..8d667d8af12ec 100644 --- a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart +++ b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart @@ -124,6 +124,5 @@ void testMain() { // what's specified in the manifest, and the manifest takes precedence. expect(ahem.bytes.length, ahemData.lengthInBytes); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart b/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart index 4602cc279987f..68e2e92458b7b 100644 --- a/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart +++ b/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart @@ -21,8 +21,7 @@ void main() { void testMain() { group('skia_objects_cache', () { _tests(); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } void _tests() { diff --git a/lib/web_ui/test/canvaskit/surface_factory_test.dart b/lib/web_ui/test/canvaskit/surface_factory_test.dart index bdefb5a9214fb..9fa98d64f0ba7 100644 --- a/lib/web_ui/test/canvaskit/surface_factory_test.dart +++ b/lib/web_ui/test/canvaskit/surface_factory_test.dart @@ -99,6 +99,5 @@ void testMain() { overlays.forEach(expectDisposed); expect(originalFactory.debugSurfaceCount, 1); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/surface_test.dart b/lib/web_ui/test/canvaskit/surface_test.dart index 123fff01514f3..74038d52a4591 100644 --- a/lib/web_ui/test/canvaskit/surface_test.dart +++ b/lib/web_ui/test/canvaskit/surface_test.dart @@ -97,7 +97,7 @@ void testMain() { // which cannot be a different size from the canvas. // TODO(hterkelsen): See if we can give a custom size for software // surfaces. - }, skip: isFirefox || isIosSafari); + }, skip: isFirefox); test( 'Surface creates new context when WebGL context is restored', @@ -186,5 +186,5 @@ void testMain() { expect(surface.htmlCanvas!.style.width, '5px'); expect(surface.htmlCanvas!.style.height, '8px'); }); - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/sweep_gradient_golden_test.dart b/lib/web_ui/test/canvaskit/sweep_gradient_golden_test.dart index 53af0dbc8505e..ee90f20da1b4d 100644 --- a/lib/web_ui/test/canvaskit/sweep_gradient_golden_test.dart +++ b/lib/web_ui/test/canvaskit/sweep_gradient_golden_test.dart @@ -68,7 +68,6 @@ void testMain() { recorder.endRecording(), ); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); } diff --git a/lib/web_ui/test/canvaskit/text_test.dart b/lib/web_ui/test/canvaskit/text_test.dart index 4b6bb478bac32..ec5621731a14a 100644 --- a/lib/web_ui/test/canvaskit/text_test.dart +++ b/lib/web_ui/test/canvaskit/text_test.dart @@ -4,7 +4,6 @@ import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/src/engine/browser_detection.dart'; import 'package:ui/ui.dart' as ui; import 'common.dart'; @@ -66,6 +65,5 @@ void testMain() { // because the directionality of the 'h' is LTR. expect(boxes.single.direction, equals(ui.TextDirection.ltr)); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); } diff --git a/lib/web_ui/test/canvaskit/vertices_test.dart b/lib/web_ui/test/canvaskit/vertices_test.dart index 0db4f8f31fd7b..5b871ff1b89b2 100644 --- a/lib/web_ui/test/canvaskit/vertices_test.dart +++ b/lib/web_ui/test/canvaskit/vertices_test.dart @@ -36,8 +36,7 @@ void testMain() { ); vertices.delete(); }); - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 - }, skip: isIosSafari); + }); test('Vertices are not anti-aliased by default', () async { const ui.Rect region = ui.Rect.fromLTRB(0, 0, 500, 500); @@ -63,8 +62,6 @@ void testMain() { EnginePlatformDispatcher.instance.rasterizer! .draw(builder.build().layerTree); await matchGoldenFile('canvaskit_vertices_antialiased.png', region: region); - - // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 }, skip: isSafari); } diff --git a/lib/web_ui/test/engine/pointer_binding_test.dart b/lib/web_ui/test/engine/pointer_binding_test.dart index 6d843e6d0449b..44ff17a0017e9 100644 --- a/lib/web_ui/test/engine/pointer_binding_test.dart +++ b/lib/web_ui/test/engine/pointer_binding_test.dart @@ -36,9 +36,6 @@ void _testEach( } } -/// Some methods in this class are skipped for iOS-Safari. -// TODO(mdebbar): https://github.com/flutter/flutter/issues/60033 - void main() { internalBootstrapBrowserTest(() => testMain); } @@ -54,13 +51,18 @@ void testMain() { }); test('ios workaround', () { + debugEmulateIosSafari = true; + addTearDown(() { + debugEmulateIosSafari = false; + }); + final MockSafariPointerEventWorkaround mockSafariPointer = MockSafariPointerEventWorkaround(); SafariPointerEventWorkaround.instance = mockSafariPointer; final PointerBinding instance = PointerBinding(createDomHTMLDivElement()); expect(mockSafariPointer.workAroundInvoked, isIosSafari); instance.dispose(); - }, skip: !isIosSafari); + }, skip: !isSafari); test('_PointerEventContext generates expected events', () { if (!_PointerEventContext().isSupported) { diff --git a/lib/web_ui/test/engine/semantics/semantics_test.dart b/lib/web_ui/test/engine/semantics/semantics_test.dart index 907d365a03d7a..84051cc5dd787 100644 --- a/lib/web_ui/test/engine/semantics/semantics_test.dart +++ b/lib/web_ui/test/engine/semantics/semantics_test.dart @@ -1927,11 +1927,7 @@ void _testPlatformView() { expect(shadowRoot.elementFromPoint(10, 50), child3); semantics().semanticsEnabled = false; - // TODO(yjbanov): unable to debug this test on iOS Safari as hacking on a - // Linux machine. iOS Safari returns getBoundingClientRect - // values that are half of desktop browsers, possibly due to - // devicePixelRatio but need to confirm. - }, skip: isIosSafari); + }); } /// A facade in front of [ui.SemanticsUpdateBuilder.updateNode] that From 1ff8b17ead382d4904e681dc145c8f505d09c17c Mon Sep 17 00:00:00 2001 From: Ricardo Amador <32242716+ricardoamador@users.noreply.github.com> Date: Thu, 4 Aug 2022 16:52:29 -0700 Subject: [PATCH 111/558] Move firebase test lab logs to a staging bucket (#35149) * Updated the bucket for firebase testing to the staging project. * updated the project. * Adding environment variables for gcp project and storage bucket. * Updated to exit if environment variables were not provided. --- ci/firebase_testlab.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ci/firebase_testlab.py b/ci/firebase_testlab.py index 36b5d419b6471..92069a7c1f584 100755 --- a/ci/firebase_testlab.py +++ b/ci/firebase_testlab.py @@ -11,7 +11,16 @@ import subprocess import sys -BUCKET = 'gs://flutter_firebase_testlab' +if 'STORAGE_BUCKET' not in os.environ: + print('The GCP storage bucket must be provided as an environment variable.') + sys.exit(1) +BUCKET = os.environ['STORAGE_BUCKET'] + +if 'GCP_PROJECT' not in os.environ: + print('The GCP project must be provided as an environment variable.') + sys.exit(1) +PROJECT = os.environ['GCP_PROJECT'] + script_dir = os.path.dirname(os.path.realpath(__file__)) buildroot_dir = os.path.abspath(os.path.join(script_dir, '..', '..')) out_dir = os.path.join(buildroot_dir, 'out') @@ -28,7 +37,7 @@ def run_firebase_test(apk, results_dir): [ 'gcloud', '--project', - 'flutter-infra', + PROJECT, 'firebase', 'test', 'android', From e4f93b853de0cdab5c197f8fb63aa675f76004a7 Mon Sep 17 00:00:00 2001 From: Dwayne Slater Date: Thu, 4 Aug 2022 17:12:04 -0700 Subject: [PATCH 112/558] Fix handling of external texture transforms on Android (#24888) --- .ci.yaml | 2 +- .../android/android_external_texture_gl.cc | 39 ++++++++++++---- .../android/platform_view_android_jni_impl.cc | 44 ++++++++++++------- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 06b53651e5307..1d894ed4deb55 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -118,7 +118,7 @@ targets: - DEPS - .ci.yaml - testing/** - - shell/platforms/android/** + - shell/platform/android/** - name: Linux Benchmarks enabled_branches: diff --git a/shell/platform/android/android_external_texture_gl.cc b/shell/platform/android/android_external_texture_gl.cc index f24e7068563aa..599d6190b3306 100644 --- a/shell/platform/android/android_external_texture_gl.cc +++ b/shell/platform/android/android_external_texture_gl.cc @@ -64,23 +64,44 @@ void AndroidExternalTextureGL::Paint(SkCanvas& canvas, kPremul_SkAlphaType, nullptr); if (image) { SkAutoCanvasRestore autoRestore(&canvas, true); - canvas.translate(bounds.x(), bounds.y()); - canvas.scale(bounds.width(), bounds.height()); - if (!transform.isIdentity()) { - SkMatrix transformAroundCenter(transform); - transformAroundCenter.preTranslate(-0.5, -0.5); - transformAroundCenter.postScale(1, -1); - transformAroundCenter.postTranslate(0.5, 0.5); - canvas.concat(transformAroundCenter); + // The incoming texture is vertically flipped, so we flip it + // back. OpenGL's coordinate system has Positive Y equivalent to up, while + // Skia's coordinate system has Negative Y equvalent to up. + canvas.translate(bounds.x(), bounds.y() + bounds.height()); + canvas.scale(bounds.width(), -bounds.height()); + + if (!transform.isIdentity()) { + sk_sp shader = image->makeShader( + SkTileMode::kRepeat, SkTileMode::kRepeat, sampling, transform); + + SkPaint paintWithShader; + if (paint) { + paintWithShader = *paint; + } + paintWithShader.setShader(shader); + canvas.drawRect(SkRect::MakeWH(1, 1), paintWithShader); + } else { + canvas.drawImage(image, 0, 0, sampling, paint); } - canvas.drawImage(image, 0, 0, sampling, paint); } } void AndroidExternalTextureGL::UpdateTransform() { jni_facade_->SurfaceTextureGetTransformMatrix( fml::jni::ScopedJavaLocalRef(surface_texture_), transform); + + // Android's SurfaceTexture transform matrix works on texture coordinate + // lookups in the range 0.0-1.0, while Skia's Shader transform matrix works on + // the image itself, as if it were inscribed inside a clip rect. + // An Android transform that scales lookup by 0.5 (displaying 50% of the + // texture) is the same as a Skia transform by 2.0 (scaling 50% of the image + // outside of the virtual "clip rect"), so we invert the incoming matrix. + SkMatrix inverted; + if (!transform.invert(&inverted)) { + FML_LOG(FATAL) << "Invalid SurfaceTexture transformation matrix"; + } + transform = inverted; } void AndroidExternalTextureGL::OnGrContextDestroyed() { diff --git a/shell/platform/android/platform_view_android_jni_impl.cc b/shell/platform/android/platform_view_android_jni_impl.cc index 92070dc0f52e6..2d02fcbfd3fb2 100644 --- a/shell/platform/android/platform_view_android_jni_impl.cc +++ b/shell/platform/android/platform_view_android_jni_impl.cc @@ -1319,18 +1319,6 @@ void PlatformViewAndroidJNIImpl::SurfaceTextureUpdateTexImage( FML_CHECK(fml::jni::CheckException(env)); } -// The bounds we set for the canvas are post composition. -// To fill the canvas we need to ensure that the transformation matrix -// on the `SurfaceTexture` will be scaled to fill. We rescale and preseve -// the scaled aspect ratio. -SkSize ScaleToFill(float scaleX, float scaleY) { - const double epsilon = std::numeric_limits::epsilon(); - // scaleY is negative. - const double minScale = fmin(scaleX, fabs(scaleY)); - const double rescale = 1.0f / (minScale + epsilon); - return SkSize::Make(scaleX * rescale, scaleY * rescale); -} - void PlatformViewAndroidJNIImpl::SurfaceTextureGetTransformMatrix( JavaLocalRef surface_texture, SkMatrix& transform) { @@ -1355,12 +1343,34 @@ void PlatformViewAndroidJNIImpl::SurfaceTextureGetTransformMatrix( FML_CHECK(fml::jni::CheckException(env)); float* m = env->GetFloatArrayElements(transformMatrix.obj(), nullptr); - float scaleX = m[0], scaleY = m[5]; - const SkSize scaled = ScaleToFill(scaleX, scaleY); + + // SurfaceTexture 4x4 Column Major -> Skia 3x3 Row Major + + // SurfaceTexture 4x4 (Column Major): + // | m[0] m[4] m[ 8] m[12] | + // | m[1] m[5] m[ 9] m[13] | + // | m[2] m[6] m[10] m[14] | + // | m[3] m[7] m[11] m[15] | + + // According to Android documentation, the 4x4 matrix returned should be used + // with texture coordinates in the form (s, t, 0, 1). Since the z component is + // always 0.0, we are free to ignore any element that multiplies with the z + // component. Converting this to a 3x3 matrix is easy: + + // SurfaceTexture 3x3 (Column Major): + // | m[0] m[4] m[12] | + // | m[1] m[5] m[13] | + // | m[3] m[7] m[15] | + + // Skia (Row Major): + // | m[0] m[1] m[2] | + // | m[3] m[4] m[5] | + // | m[6] m[7] m[8] | + SkScalar matrix3[] = { - scaled.fWidth, m[1], m[2], // - m[4], scaled.fHeight, m[6], // - m[8], m[9], m[10], // + m[0], m[4], m[12], // + m[1], m[5], m[13], // + m[3], m[7], m[15], // }; env->ReleaseFloatArrayElements(transformMatrix.obj(), m, JNI_ABORT); transform.set9(matrix3); From a4780451769d5385aafd810bc7fe4ac61b7355bf Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 4 Aug 2022 17:59:04 -0700 Subject: [PATCH 113/558] [impeller] Convert drawImageNine into drawImageRect (#35173) --- ci/licenses_golden/licenses_flutter | 2 + impeller/display_list/BUILD.gn | 2 + .../display_list/display_list_dispatcher.cc | 31 +++++- .../display_list/display_list_unittests.cc | 76 +++++++++++++++ impeller/display_list/nine_patch_converter.cc | 94 +++++++++++++++++++ impeller/display_list/nine_patch_converter.h | 47 ++++++++++ 6 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 impeller/display_list/nine_patch_converter.cc create mode 100644 impeller/display_list/nine_patch_converter.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 6d6fab596ba64..5343b8072b205 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -510,6 +510,8 @@ 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/nine_patch_converter.cc +FILE: ../../../flutter/impeller/display_list/nine_patch_converter.h FILE: ../../../flutter/impeller/docs/assets/read_frame_captures/image1.png FILE: ../../../flutter/impeller/docs/assets/read_frame_captures/image10.png FILE: ../../../flutter/impeller/docs/assets/read_frame_captures/image11.png diff --git a/impeller/display_list/BUILD.gn b/impeller/display_list/BUILD.gn index a7a51ae9b393f..d68ae5b9ddc7b 100644 --- a/impeller/display_list/BUILD.gn +++ b/impeller/display_list/BUILD.gn @@ -10,6 +10,8 @@ impeller_component("display_list") { "display_list_dispatcher.h", "display_list_image_impeller.cc", "display_list_image_impeller.h", + "nine_patch_converter.cc", + "nine_patch_converter.h", ] public_deps = [ diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 550e9d4816212..77b935c1daa85 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -13,6 +13,7 @@ #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "impeller/display_list/display_list_image_impeller.h" +#include "impeller/display_list/nine_patch_converter.h" #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/linear_gradient_contents.h" #include "impeller/entity/contents/radial_gradient_contents.h" @@ -827,6 +828,24 @@ static impeller::SamplerDescriptor ToSamplerDescriptor( return desc; } +static impeller::SamplerDescriptor ToSamplerDescriptor( + const flutter::DlFilterMode options) { + impeller::SamplerDescriptor desc; + switch (options) { + case flutter::DlFilterMode::kNearest: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kNearest; + desc.label = "Nearest Sampler"; + break; + case flutter::DlFilterMode::kLinear: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; + desc.label = "Linear Sampler"; + break; + default: + break; + } + return desc; +} + // |flutter::Dispatcher| void DisplayListDispatcher::drawImageRect( const sk_sp image, @@ -837,7 +856,7 @@ void DisplayListDispatcher::drawImageRect( SkCanvas::SrcRectConstraint constraint) { canvas_.DrawImageRect( std::make_shared(image->impeller_texture()), // image - ToRect(src), // source rect + ToRect(src), // source rect ToRect(dst), // destination rect paint_, // paint ToSamplerDescriptor(sampling) // sampling @@ -850,8 +869,11 @@ void DisplayListDispatcher::drawImageNine(const sk_sp image, const SkRect& dst, flutter::DlFilterMode filter, bool render_with_attributes) { - // Needs https://github.com/flutter/flutter/issues/95434 - UNIMPLEMENTED; + NinePatchConverter converter = {}; + converter.DrawNinePatch( + std::make_shared(image->impeller_texture()), + Rect::MakeLTRB(center.fLeft, center.fTop, center.fRight, center.fBottom), + ToRect(dst), ToSamplerDescriptor(filter), &canvas_, &paint_); } // |flutter::Dispatcher| @@ -862,6 +884,9 @@ void DisplayListDispatcher::drawImageLattice( flutter::DlFilterMode filter, bool render_with_attributes) { // Needs https://github.com/flutter/flutter/issues/95434 + // Don't implement this one since it is not exposed by flutter, + // Skia internally converts calls to drawImageNine into this method, + // which is then converted back to drawImageNine by display list. UNIMPLEMENTED; } diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index 65207ec24eea5..6cfbec35cfac0 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -357,5 +357,81 @@ TEST_P(DisplayListTest, CanDrawBackdropFilter) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(DisplayListTest, CanDrawNinePatchImage) { + // Image is drawn with corners to scale and center pieces stretched to fit. + auto texture = CreateTextureForFixture("embarcadero.jpg"); + flutter::DisplayListBuilder builder; + auto size = texture->GetSize(); + builder.drawImageNine( + DlImageImpeller::Make(texture), + SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4, + size.height * 3 / 4), + SkRect::MakeLTRB(0, 0, size.width * 2, size.height * 2), + flutter::DlFilterMode::kNearest, true); + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(DisplayListTest, CanDrawNinePatchImageCenterWidthBiggerThanDest) { + // Edge case, the width of the corners does not leave any room for the + // center slice. The center (across the vertical axis) is folded out of the + // resulting image. + auto texture = CreateTextureForFixture("embarcadero.jpg"); + flutter::DisplayListBuilder builder; + auto size = texture->GetSize(); + builder.drawImageNine( + DlImageImpeller::Make(texture), + SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4, + size.height * 3 / 4), + SkRect::MakeLTRB(0, 0, size.width / 2, size.height), + flutter::DlFilterMode::kNearest, true); + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(DisplayListTest, CanDrawNinePatchImageCenterHeightBiggerThanDest) { + // Edge case, the height of the corners does not leave any room for the + // center slice. The center (across the horizontal axis) is folded out of the + // resulting image. + auto texture = CreateTextureForFixture("embarcadero.jpg"); + flutter::DisplayListBuilder builder; + auto size = texture->GetSize(); + builder.drawImageNine( + DlImageImpeller::Make(texture), + SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4, + size.height * 3 / 4), + SkRect::MakeLTRB(0, 0, size.width, size.height / 2), + flutter::DlFilterMode::kNearest, true); + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(DisplayListTest, CanDrawNinePatchImageCenterBiggerThanDest) { + // Edge case, the width and height of the corners does not leave any + // room for the center slices. Only the corners are displayed. + auto texture = CreateTextureForFixture("embarcadero.jpg"); + flutter::DisplayListBuilder builder; + auto size = texture->GetSize(); + builder.drawImageNine( + DlImageImpeller::Make(texture), + SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4, + size.height * 3 / 4), + SkRect::MakeLTRB(0, 0, size.width / 2, size.height / 2), + flutter::DlFilterMode::kNearest, true); + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + +TEST_P(DisplayListTest, CanDrawNinePatchImageCornersScaledDown) { + // Edge case, there is not enough room for the corners to be drawn + // without scaling them down. + auto texture = CreateTextureForFixture("embarcadero.jpg"); + flutter::DisplayListBuilder builder; + auto size = texture->GetSize(); + builder.drawImageNine( + DlImageImpeller::Make(texture), + SkIRect::MakeLTRB(size.width / 4, size.height / 4, size.width * 3 / 4, + size.height * 3 / 4), + SkRect::MakeLTRB(0, 0, size.width / 4, size.height / 4), + flutter::DlFilterMode::kNearest, true); + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/display_list/nine_patch_converter.cc b/impeller/display_list/nine_patch_converter.cc new file mode 100644 index 0000000000000..2a9872e0ea8a3 --- /dev/null +++ b/impeller/display_list/nine_patch_converter.cc @@ -0,0 +1,94 @@ +// 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 "impeller/display_list/nine_patch_converter.h" + +namespace impeller { + +NinePatchConverter::NinePatchConverter() = default; + +NinePatchConverter::~NinePatchConverter() = default; + +std::vector NinePatchConverter::InitSlices(double img0, + double imgC0, + double imgC1, + double img1, + double dst0, + double dst1) { + auto imageDim = img1 - img0; + auto destDim = dst1 - dst0; + + if (imageDim == destDim) { + // If the src and dest are the same size then we do not need scaling + // We return 4 values for a single slice + return {img0, dst0, img1, dst1}; + } + + auto edge0Dim = imgC0 - img0; + auto edge1Dim = img1 - imgC1; + auto edgesDim = edge0Dim + edge1Dim; + + if (edgesDim >= destDim) { + // the center portion has disappeared, leaving only the edges to scale to a + // common center position in the destination this produces only 2 slices + // which is 8 values + auto dstC = dst0 + destDim * edge0Dim / edgesDim; + // clang-format off + return { + img0, dst0, imgC0, dstC, + imgC1, dstC, img1, dst1, + }; + // clang-format on + } + + // center portion is nonEmpty and only that part is scaled + // we need 3 slices which is 12 values + auto dstC0 = dst0 + edge0Dim; + auto dstC1 = dst1 - edge1Dim; + // clang-format off + return { + img0, dst0, imgC0, dstC0, + imgC0, dstC0, imgC1, dstC1, + imgC1, dstC1, img1, dst1, + }; + // clang-format on +} + +void NinePatchConverter::DrawNinePatch(std::shared_ptr image, + Rect center, + Rect dst, + SamplerDescriptor sampler, + Canvas* canvas, + Paint* paint) { + if (dst.IsEmpty()) { + return; + } + auto image_size = image->GetSize(); + auto hSlices = InitSlices(0, center.GetLeft(), center.GetRight(), + image_size.width, dst.GetLeft(), dst.GetRight()); + auto vSlices = InitSlices(0, center.GetTop(), center.GetBottom(), + image_size.height, dst.GetTop(), dst.GetBottom()); + + for (size_t yi = 0; yi < vSlices.size(); yi += 4) { + auto srcY0 = vSlices[yi]; + auto dstY0 = vSlices[yi + 1]; + auto srcY1 = vSlices[yi + 2]; + auto dstY1 = vSlices[yi + 3]; + for (size_t xi = 0; xi < hSlices.size(); xi += 4) { + auto srcX0 = hSlices[xi]; + auto dstX0 = hSlices[xi + 1]; + auto srcX1 = hSlices[xi + 2]; + auto dstX1 = hSlices[xi + 3]; + // TODO(jonahwilliams): consider converting this into a single call to + // DrawImageAtlas. + canvas->DrawImageRect(image, Rect::MakeLTRB(srcX0, srcY0, srcX1, srcY1), + Rect::MakeLTRB(dstX0, dstY0, dstX1, dstY1), *paint, + sampler); + } + } +} + +} // namespace impeller diff --git a/impeller/display_list/nine_patch_converter.h b/impeller/display_list/nine_patch_converter.h new file mode 100644 index 0000000000000..a9250099d4250 --- /dev/null +++ b/impeller/display_list/nine_patch_converter.h @@ -0,0 +1,47 @@ +// 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 "flutter/fml/macros.h" +#include "impeller/aiks/canvas.h" +#include "impeller/aiks/image.h" +#include "impeller/aiks/paint.h" +#include "impeller/geometry/path.h" +#include "impeller/renderer/sampler_descriptor.h" + +namespace impeller { + +// Converts a call to draw a nine patch image into a draw atlas call. +class NinePatchConverter { + public: + NinePatchConverter(); + + ~NinePatchConverter(); + + void DrawNinePatch(std::shared_ptr image, + Rect center, + Rect dst, + SamplerDescriptor sampler, + Canvas* canvas, + Paint* paint); + + private: + // Return a list of slice coordinates based on the size of the nine-slice + // parameters in one dimension. Each set of slice coordinates contains a + // begin/end pair for each of the source (image) and dest (screen) in the + // order (src0, dst0, src1, dst1). The area from src0 => src1 of the image is + // painted on the screen from dst0 => dst1 The slices for each dimension are + // generated independently. + std::vector InitSlices(double img0, + double imgC0, + double imgC1, + double img1, + double dst0, + double dst1); +}; + +} // namespace impeller From 76cd7b0edf4cf1566d26adc16c9e9b0f252f702d Mon Sep 17 00:00:00 2001 From: godofredoc Date: Thu, 4 Aug 2022 18:48:04 -0700 Subject: [PATCH 114/558] Adds a script the generates and bundle the ios artifacts. (#35168) --- sky/tools/create_full_ios_framework.py | 214 +++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 sky/tools/create_full_ios_framework.py diff --git a/sky/tools/create_full_ios_framework.py b/sky/tools/create_full_ios_framework.py new file mode 100644 index 0000000000000..115f369a6bab9 --- /dev/null +++ b/sky/tools/create_full_ios_framework.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python3 +# +# 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. + +# Generates and zip the ios flutter framework including the architecture +# dependent snapshot. + +import argparse +import os +import shutil +import subprocess +import sys + +from create_xcframework import create_xcframework + +DSYMUTIL = os.path.join( + os.path.dirname(__file__), '..', '..', '..', 'buildtools', 'mac-x64', + 'clang', 'bin', 'dsymutil' +) + +buildroot_dir = os.path.abspath( + os.path.join(os.path.realpath(__file__), '..', '..', '..', '..') +) + + +def main(): + parser = argparse.ArgumentParser( + description=( + 'Creates Flutter.framework, Flutter.xcframework and ' + 'copies architecture-dependent gen_snapshot binaries to output dir' + ) + ) + + parser.add_argument('--dst', type=str, required=True) + parser.add_argument('--clang-dir', type=str, default='clang_x64') + parser.add_argument('--x64-out-dir', type=str) + parser.add_argument('--arm64-out-dir', type=str, required=True) + parser.add_argument('--simulator-x64-out-dir', type=str, required=True) + parser.add_argument('--simulator-arm64-out-dir', type=str, required=False) + parser.add_argument('--strip', action="store_true", default=False) + parser.add_argument('--dsym', action="store_true", default=False) + parser.add_argument( + '--strip-bitcode', + dest='strip_bitcode', + action="store_true", + default=False + ) + + args = parser.parse_args() + + dst = ( + args.dst + if os.path.isabs(args.dst) else os.path.join(buildroot_dir, args.dst) + ) + + arm64_out_dir = ( + args.arm64_out_dir if os.path.isabs(args.arm64_out_dir) else + os.path.join(buildroot_dir, args.arm64_out_dir) + ) + + x64_out_dir = None + if args.x64_out_dir: + x64_out_dir = ( + args.x64_out_dir if os.path.isabs(args.x64_out_dir) else + os.path.join(buildroot_dir, args.x64_out_dir) + ) + + simulator_x64_out_dir = None + if args.simulator_x64_out_dir: + simulator_x64_out_dir = ( + args.simulator_x64_out_dir if os.path.isabs(args.simulator_x64_out_dir) + else os.path.join(buildroot_dir, args.simulator_x64_out_dir) + ) + + framework = os.path.join(dst, 'Flutter.framework') + simulator_framework = os.path.join(dst, 'sim', 'Flutter.framework') + arm64_framework = os.path.join(arm64_out_dir, 'Flutter.framework') + simulator_x64_framework = os.path.join( + simulator_x64_out_dir, 'Flutter.framework' + ) + + simulator_arm64_out_dir = None + if args.simulator_arm64_out_dir: + simulator_arm64_out_dir = ( + args.simulator_arm64_out_dir if os.path.isabs( + args.simulator_arm64_out_dir + ) else os.path.join(buildroot_dir, args.simulator_arm64_out_dir) + ) + + if args.simulator_arm64_out_dir is not None: + simulator_arm64_framework = os.path.join( + simulator_arm64_out_dir, 'Flutter.framework' + ) + + if not os.path.isdir(arm64_framework): + print('Cannot find iOS arm64 Framework at %s' % arm64_framework) + return 1 + + if not os.path.isdir(simulator_x64_framework): + print('Cannot find iOS x64 simulator Framework at %s' % simulator_framework) + return 1 + + if not os.path.isfile(DSYMUTIL): + print('Cannot find dsymutil at %s' % DSYMUTIL) + return 1 + + create_framework( + args, dst, framework, arm64_framework, simulator_framework, + simulator_x64_framework, simulator_arm64_framework + ) + framework_binary = os.path.join(framework, 'Flutter') + process_framework(args, framework, framework_binary) + generate_gen_snapshot(args, dst, x64_out_dir, arm64_out_dir) + zip_archive(dst) + + +def create_framework( + args, dst, framework, arm64_framework, simulator_framework, + simulator_x64_framework, simulator_arm64_framework +): + arm64_dylib = os.path.join(arm64_framework, 'Flutter') + simulator_x64_dylib = os.path.join(simulator_x64_framework, 'Flutter') + simulator_arm64_dylib = os.path.join(simulator_arm64_framework, 'Flutter') + if not os.path.isfile(arm64_dylib): + print('Cannot find iOS arm64 dylib at %s' % arm64_dylib) + return 1 + + if not os.path.isfile(simulator_x64_dylib): + print('Cannot find iOS simulator dylib at %s' % simulator_dylib) + return 1 + + shutil.rmtree(framework, True) + shutil.copytree(arm64_framework, framework) + framework_binary = os.path.join(framework, 'Flutter') + + if args.simulator_arm64_out_dir is not None: + shutil.rmtree(simulator_framework, True) + shutil.copytree(simulator_arm64_framework, simulator_framework) + + simulator_framework_binary = os.path.join(simulator_framework, 'Flutter') + + # Create the arm64/x64 simulator fat framework. + subprocess.check_call([ + 'lipo', simulator_x64_dylib, simulator_arm64_dylib, '-create', + '-output', simulator_framework_binary + ]) + process_framework(args, simulator_framework, simulator_framework_binary) + simulator_framework = simulator_framework + else: + simulator_framework = simulator_x64_framework + + # Create XCFramework from the arm-only fat framework and the arm64/x64 simulator frameworks, or just the + # x64 simulator framework if only that one exists. + xcframeworks = [simulator_framework, framework] + create_xcframework(location=dst, name='Flutter', frameworks=xcframeworks) + + # Add the x64 simulator into the fat framework + subprocess.check_call([ + 'lipo', arm64_dylib, simulator_x64_dylib, '-create', '-output', + framework_binary + ]) + + +def zip_archive(dst): + subprocess.check_call([ + 'zip', '-r', 'artifacts.zip', 'gen_snapshot_arm64', 'Flutter.xcframework' + ], + cwd=dst) + + +def process_framework(args, framework, framework_binary): + if args.strip_bitcode: + subprocess.check_call([ + 'xcrun', 'bitcode_strip', '-r', framework_binary, '-o', framework_binary + ]) + + if args.dsym: + dsym_out = os.path.splitext(framework)[0] + '.dSYM' + subprocess.check_call([DSYMUTIL, '-o', dsym_out, framework_binary]) + + if args.strip: + # copy unstripped + unstripped_out = os.path.join(dst, 'Flutter.unstripped') + shutil.copyfile(framework_binary, unstripped_out) + + subprocess.check_call(["strip", "-x", "-S", framework_binary]) + + +def generate_gen_snapshot(args, dst, x64_out_dir, arm64_out_dir): + if x64_out_dir: + _generate_gen_snapshot(x64_out_dir, os.path.join(dst, 'gen_snapshot_x64')) + + if arm64_out_dir: + _generate_gen_snapshot( + os.path.join(arm64_out_dir, args.clang_dir), + os.path.join(dst, 'gen_snapshot_arm64') + ) + + +def _generate_gen_snapshot(directory, destination): + gen_snapshot_dir = os.path.join(directory, 'gen_snapshot') + if not os.path.isfile(gen_snapshot_dir): + print('Cannot find gen_snapshot at %s' % gen_snapshot_dir) + sys.exit(1) + + subprocess.check_call([ + 'xcrun', 'bitcode_strip', '-r', gen_snapshot_dir, '-o', destination + ]) + + +if __name__ == '__main__': + sys.exit(main()) From 8e05bbe6b83856082d8a52796ebc471e67ea53b7 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 4 Aug 2022 21:58:04 -0400 Subject: [PATCH 115/558] Roll Fuchsia Linux SDK from AH3k3SvM2... to BRTz21cLl... (#35175) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index a26dc7aee9c10..cac2c2c8f5cdb 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'AH3k3SvM2pVCNAkuLe3yKL-KYMupq7Bgoftkx-D0unkC' + 'version': 'BRTz21cLlhH2ZqgzoilIhU18cYA9axzlNywByomqJVgC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index b600580966c50..d8538082a3fa6 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: edb9709b9184c2694501c4e65aa4566a +Signature: a96ad7fa96a0d9334534d6e0b8fa0cec UNUSED LICENSES: From 25bad51f09d6fcdcb59abf09f63f1db37339a519 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 4 Aug 2022 22:41:05 -0400 Subject: [PATCH 116/558] Roll Dart SDK from 68137ce3d59a to 0ab07c889f74 (2 revisions) (#35176) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index cac2c2c8f5cdb..bce690a95beee 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '68137ce3d59a5d81472e432f666f23e91dee7691', + 'dart_revision': '0ab07c889f7410eca414af8f079f7408ae014184', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -47,7 +47,7 @@ vars = { 'dart_collection_rev': '414ffa1bc8ba18bd608bbf916d95715311d89ac1', 'dart_devtools_rev': 'd131d19091f6b89ac89486bd92440a25a523e8b0', 'dart_protobuf_rev': '504eefeae9892602ea50c20159db1db3768012a9', - 'dart_pub_rev': '9bf4289d6fd5d6872a8929d6312bbd7098f3ea9c', + 'dart_pub_rev': 'ac7db6c07318efa4a8712110275eaf70f96a6d00', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': 'e00c0ea769e32821d91c0880da8eb736839a6e6d', 'dart_webdev_rev': '37bf4af1b0961f053e7cf4990a34ca5fd0ad0fd4', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 98d430828b6c9..c046e35202b92 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: b4b527484f4cf788e7f1d393b0ea161f +Signature: 42fee749e6a564c97acc48f2e05cd339 UNUSED LICENSES: From 7a536ee025fa42170f5e312ec43c3ed2ed9a63cb Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 02:38:07 -0400 Subject: [PATCH 117/558] Roll Dart SDK from 0ab07c889f74 to 16cbbc9d5e4b (1 revision) (#35177) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index bce690a95beee..4259c072b05d1 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '0ab07c889f7410eca414af8f079f7408ae014184', + 'dart_revision': '16cbbc9d5e4ba2ecc25826c9e8426ef8bf09e87a', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From e1e4a283f943d7dac686583351c8d245a4d82f67 Mon Sep 17 00:00:00 2001 From: magicianA Date: Fri, 5 Aug 2022 15:54:05 +0800 Subject: [PATCH 118/558] [Impeller] Enforce shader resource limits in impellerc (#35120) --- impeller/compiler/compiler.cc | 121 ++++++++++++++++++++++++ impeller/compiler/compiler_unittests.cc | 6 ++ impeller/fixtures/BUILD.gn | 1 + impeller/fixtures/resources_limit.vert | 9 ++ 4 files changed, 137 insertions(+) create mode 100644 impeller/fixtures/resources_limit.vert diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index e5b2018fd267f..0d7af022cc36f 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -4,6 +4,7 @@ #include "impeller/compiler/compiler.h" +#include #include #include #include @@ -104,6 +105,124 @@ static CompilerBackend CreateCompiler(const spirv_cross::ParsedIR& ir, return compiler; } +static void SetLimitations(shaderc::CompileOptions& compiler_opts) { + using Limit = std::pair; + static constexpr std::array limits = { + Limit{shaderc_limit::shaderc_limit_max_lights, 8}, + Limit{shaderc_limit::shaderc_limit_max_clip_planes, 6}, + Limit{shaderc_limit::shaderc_limit_max_texture_units, 2}, + Limit{shaderc_limit::shaderc_limit_max_texture_coords, 8}, + Limit{shaderc_limit::shaderc_limit_max_vertex_attribs, 16}, + Limit{shaderc_limit::shaderc_limit_max_vertex_uniform_components, 4096}, + Limit{shaderc_limit::shaderc_limit_max_varying_floats, 60}, + Limit{shaderc_limit::shaderc_limit_max_vertex_texture_image_units, 16}, + Limit{shaderc_limit::shaderc_limit_max_combined_texture_image_units, 80}, + Limit{shaderc_limit::shaderc_limit_max_texture_image_units, 16}, + Limit{shaderc_limit::shaderc_limit_max_fragment_uniform_components, 1024}, + Limit{shaderc_limit::shaderc_limit_max_draw_buffers, 8}, + Limit{shaderc_limit::shaderc_limit_max_vertex_uniform_vectors, 256}, + Limit{shaderc_limit::shaderc_limit_max_varying_vectors, 15}, + Limit{shaderc_limit::shaderc_limit_max_fragment_uniform_vectors, 256}, + Limit{shaderc_limit::shaderc_limit_max_vertex_output_vectors, 16}, + Limit{shaderc_limit::shaderc_limit_max_fragment_input_vectors, 15}, + Limit{shaderc_limit::shaderc_limit_min_program_texel_offset, -8}, + Limit{shaderc_limit::shaderc_limit_max_program_texel_offset, 7}, + Limit{shaderc_limit::shaderc_limit_max_clip_distances, 8}, + Limit{shaderc_limit::shaderc_limit_max_compute_work_group_count_x, 65535}, + Limit{shaderc_limit::shaderc_limit_max_compute_work_group_count_y, 65535}, + Limit{shaderc_limit::shaderc_limit_max_compute_work_group_count_z, 65535}, + Limit{shaderc_limit::shaderc_limit_max_compute_work_group_size_x, 1024}, + Limit{shaderc_limit::shaderc_limit_max_compute_work_group_size_y, 1024}, + Limit{shaderc_limit::shaderc_limit_max_compute_work_group_size_z, 64}, + Limit{shaderc_limit::shaderc_limit_max_compute_uniform_components, 512}, + Limit{shaderc_limit::shaderc_limit_max_compute_texture_image_units, 16}, + Limit{shaderc_limit::shaderc_limit_max_compute_image_uniforms, 8}, + Limit{shaderc_limit::shaderc_limit_max_compute_atomic_counters, 8}, + Limit{shaderc_limit::shaderc_limit_max_compute_atomic_counter_buffers, 1}, + Limit{shaderc_limit::shaderc_limit_max_varying_components, 60}, + Limit{shaderc_limit::shaderc_limit_max_vertex_output_components, 64}, + Limit{shaderc_limit::shaderc_limit_max_geometry_input_components, 64}, + Limit{shaderc_limit::shaderc_limit_max_geometry_output_components, 128}, + Limit{shaderc_limit::shaderc_limit_max_fragment_input_components, 128}, + Limit{shaderc_limit::shaderc_limit_max_image_units, 8}, + Limit{shaderc_limit:: + shaderc_limit_max_combined_image_units_and_fragment_outputs, + 8}, + Limit{shaderc_limit::shaderc_limit_max_combined_shader_output_resources, + 8}, + Limit{shaderc_limit::shaderc_limit_max_image_samples, 0}, + Limit{shaderc_limit::shaderc_limit_max_vertex_image_uniforms, 0}, + Limit{shaderc_limit::shaderc_limit_max_tess_control_image_uniforms, 0}, + Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_image_uniforms, 0}, + Limit{shaderc_limit::shaderc_limit_max_geometry_image_uniforms, 0}, + Limit{shaderc_limit::shaderc_limit_max_fragment_image_uniforms, 8}, + Limit{shaderc_limit::shaderc_limit_max_combined_image_uniforms, 8}, + Limit{shaderc_limit::shaderc_limit_max_geometry_texture_image_units, 16}, + Limit{shaderc_limit::shaderc_limit_max_geometry_output_vertices, 256}, + Limit{shaderc_limit::shaderc_limit_max_geometry_total_output_components, + 1024}, + Limit{shaderc_limit::shaderc_limit_max_geometry_uniform_components, 512}, + Limit{shaderc_limit::shaderc_limit_max_geometry_varying_components, 60}, + Limit{shaderc_limit::shaderc_limit_max_tess_control_input_components, + 128}, + Limit{shaderc_limit::shaderc_limit_max_tess_control_output_components, + 128}, + Limit{shaderc_limit::shaderc_limit_max_tess_control_texture_image_units, + 16}, + Limit{shaderc_limit::shaderc_limit_max_tess_control_uniform_components, + 1024}, + Limit{ + shaderc_limit::shaderc_limit_max_tess_control_total_output_components, + 4096}, + Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_input_components, + 128}, + Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_output_components, + 128}, + Limit{ + shaderc_limit::shaderc_limit_max_tess_evaluation_texture_image_units, + 16}, + Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_uniform_components, + 1024}, + Limit{shaderc_limit::shaderc_limit_max_tess_patch_components, 120}, + Limit{shaderc_limit::shaderc_limit_max_patch_vertices, 32}, + Limit{shaderc_limit::shaderc_limit_max_tess_gen_level, 64}, + Limit{shaderc_limit::shaderc_limit_max_viewports, 16}, + Limit{shaderc_limit::shaderc_limit_max_vertex_atomic_counters, 0}, + Limit{shaderc_limit::shaderc_limit_max_tess_control_atomic_counters, 0}, + Limit{shaderc_limit::shaderc_limit_max_tess_evaluation_atomic_counters, + 0}, + Limit{shaderc_limit::shaderc_limit_max_geometry_atomic_counters, 0}, + Limit{shaderc_limit::shaderc_limit_max_fragment_atomic_counters, 8}, + Limit{shaderc_limit::shaderc_limit_max_combined_atomic_counters, 8}, + Limit{shaderc_limit::shaderc_limit_max_atomic_counter_bindings, 1}, + Limit{shaderc_limit::shaderc_limit_max_vertex_atomic_counter_buffers, 0}, + Limit{ + shaderc_limit::shaderc_limit_max_tess_control_atomic_counter_buffers, + 0}, + Limit{shaderc_limit:: + shaderc_limit_max_tess_evaluation_atomic_counter_buffers, + 0}, + Limit{shaderc_limit::shaderc_limit_max_geometry_atomic_counter_buffers, + 0}, + Limit{shaderc_limit::shaderc_limit_max_fragment_atomic_counter_buffers, + 0}, + Limit{shaderc_limit::shaderc_limit_max_combined_atomic_counter_buffers, + 1}, + Limit{shaderc_limit::shaderc_limit_max_atomic_counter_buffer_size, 32}, + Limit{shaderc_limit::shaderc_limit_max_transform_feedback_buffers, 4}, + Limit{shaderc_limit:: + shaderc_limit_max_transform_feedback_interleaved_components, + 64}, + Limit{shaderc_limit::shaderc_limit_max_cull_distances, 8}, + Limit{shaderc_limit::shaderc_limit_max_combined_clip_and_cull_distances, + 8}, + Limit{shaderc_limit::shaderc_limit_max_samples, 4}, + }; + for (auto& [limit, value] : limits) { + compiler_opts.SetLimit(limit, value); + } +} + Compiler::Compiler(const fml::Mapping& source_mapping, SourceOptions source_options, Reflector::Options reflector_options) @@ -139,6 +258,8 @@ Compiler::Compiler(const fml::Mapping& source_mapping, shaderc_source_language::shaderc_source_language_glsl); spirv_options.SetForcedVersionProfile(460, shaderc_profile::shaderc_profile_core); + SetLimitations(spirv_options); + switch (source_options.target_platform) { case TargetPlatform::kMetalDesktop: case TargetPlatform::kMetalIOS: diff --git a/impeller/compiler/compiler_unittests.cc b/impeller/compiler/compiler_unittests.cc index d19d9f00c98c0..23101e313f90a 100644 --- a/impeller/compiler/compiler_unittests.cc +++ b/impeller/compiler/compiler_unittests.cc @@ -50,6 +50,12 @@ TEST_P(CompilerTest, CanCompileComputeShader) { ASSERT_TRUE(CanCompileAndReflect("sample.comp", SourceType::kComputeShader)); } +TEST_P(CompilerTest, MustFailDueToExceedingResourcesLimit) { + ScopedValidationDisable disable_validation; + ASSERT_FALSE( + CanCompileAndReflect("resources_limit.vert", SourceType::kVertexShader)); +} + TEST_P(CompilerTest, MustFailDueToMultipleLocationPerStructMember) { if (GetParam() == TargetPlatform::kFlutterSPIRV) { // This is a failure of reflection which this target doesn't perform. diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index d955a90bfa9df..3a62e149c864d 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -42,6 +42,7 @@ test_fixtures("file_fixtures") { "boston.jpg", "embarcadero.jpg", "kalimba.jpg", + "resources_limit.vert", "sample.comp", "sample.tesc", "sample.tese", diff --git a/impeller/fixtures/resources_limit.vert b/impeller/fixtures/resources_limit.vert new file mode 100644 index 0000000000000..95c84ee8bfc76 --- /dev/null +++ b/impeller/fixtures/resources_limit.vert @@ -0,0 +1,9 @@ +// 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. + +uniform sampler1D tex; +void main() +{ + vec4 x = textureOffset(tex, 1.0, -10); +} From d6931cc4b586fd3d2e51add8a319450ee4a7ef4c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 05:52:05 -0400 Subject: [PATCH 119/558] Roll Fuchsia Mac SDK from CUZLMQ1lB... to b8WQvI4f0... (#35179) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 4259c072b05d1..405aaaa181ef1 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'CUZLMQ1lB9tR2iKDOs94gUVL5mnO_aC5kckqcyH1Z6MC' + 'version': 'b8WQvI4f0bUCdZLeBjaVjieKdkpiFhBOjnCOjUJLYlgC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From c1bb5d7513f06814d804aaa7629831b1e0e2e1d1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 06:41:04 -0400 Subject: [PATCH 120/558] Roll Dart SDK from 16cbbc9d5e4b to aada0a67f81e (1 revision) (#35180) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 405aaaa181ef1..c7386db1ed63e 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '16cbbc9d5e4ba2ecc25826c9e8426ef8bf09e87a', + 'dart_revision': 'aada0a67f81e3532921488ba41de4e3d69a73be1', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From d45c4c42dac5e225eda9f1832baad941086d41c5 Mon Sep 17 00:00:00 2001 From: JsouLiang Date: Fri, 5 Aug 2022 21:00:54 +0800 Subject: [PATCH 121/558] ColorFilterLayer change SkColorFilter to DLColorFilter (#34744) * change SkColorFilter to DlColorFilter * draft for SkColorFilter to DlColorFilter * draft for SkColorFilter to DlColorFilter * Formatting code * Use DlColorFilter for ColorFilterLayer; Change the test cases * Use DlObject for test cases * fix some nits * update code formats * update the local variable name --- flow/layers/color_filter_layer.cc | 30 ++-- flow/layers/color_filter_layer.h | 6 +- flow/layers/color_filter_layer_unittests.cc | 170 +++++++++++--------- flow/layers/layer.h | 8 +- lib/ui/compositing/scene_builder.cc | 4 +- 5 files changed, 128 insertions(+), 90 deletions(-) diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index c82ae04c0cd60..9c22dbfe258bf 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -3,12 +3,15 @@ // found in the LICENSE file. #include "flutter/flow/layers/color_filter_layer.h" + +#include "flutter/display_list/display_list_comparable.h" +#include "flutter/display_list/display_list_paint.h" #include "flutter/flow/raster_cache_item.h" #include "flutter/flow/raster_cache_util.h" namespace flutter { -ColorFilterLayer::ColorFilterLayer(sk_sp filter) +ColorFilterLayer::ColorFilterLayer(std::shared_ptr filter) : CacheableContainerLayer( RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer, true), @@ -19,7 +22,7 @@ void ColorFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { FML_DCHECK(prev); - if (filter_ != prev->filter_) { + if (NotEquals(filter_, prev->filter_)) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); } } @@ -45,23 +48,28 @@ void ColorFilterLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "ColorFilterLayer::Paint"); FML_DCHECK(needs_painting(context)); - AutoCachePaint cache_paint(context); - if (context.raster_cache) { + AutoCachePaint cache_paint(context); if (layer_raster_cache_item_->IsCacheChildren()) { - cache_paint.setColorFilter(filter_); + cache_paint.setColorFilter(filter_.get()); } if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { return; } } - cache_paint.setColorFilter(filter_); - - Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( - context, paint_bounds(), cache_paint.sk_paint()); - - PaintChildren(context); + AutoCachePaint cache_paint(context); + cache_paint.setColorFilter(filter_.get()); + if (context.leaf_nodes_builder) { + context.leaf_nodes_builder->saveLayer(&paint_bounds(), + cache_paint.dl_paint()); + PaintChildren(context); + context.leaf_nodes_builder->restore(); + } else { + Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( + context, paint_bounds(), cache_paint.sk_paint()); + PaintChildren(context); + } } } // namespace flutter diff --git a/flow/layers/color_filter_layer.h b/flow/layers/color_filter_layer.h index d896ff34fb7b8..62f702b33e01a 100644 --- a/flow/layers/color_filter_layer.h +++ b/flow/layers/color_filter_layer.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_FLOW_LAYERS_COLOR_FILTER_LAYER_H_ #define FLUTTER_FLOW_LAYERS_COLOR_FILTER_LAYER_H_ +#include "flutter/display_list/display_list_color_filter.h" #include "flutter/flow/layers/cacheable_layer.h" #include "flutter/flow/layers/layer.h" #include "third_party/skia/include/core/SkColorFilter.h" @@ -12,7 +13,7 @@ namespace flutter { class ColorFilterLayer : public CacheableContainerLayer { public: - explicit ColorFilterLayer(sk_sp filter); + explicit ColorFilterLayer(std::shared_ptr filter); void Diff(DiffContext* context, const Layer* old_layer) override; @@ -21,7 +22,8 @@ class ColorFilterLayer : public CacheableContainerLayer { void Paint(PaintContext& context) const override; private: - sk_sp filter_; + std::shared_ptr filter_; + FML_DISALLOW_COPY_AND_ASSIGN(ColorFilterLayer); }; diff --git a/flow/layers/color_filter_layer_unittests.cc b/flow/layers/color_filter_layer_unittests.cc index 5ec709f1ab54b..63ac582c5b527 100644 --- a/flow/layers/color_filter_layer_unittests.cc +++ b/flow/layers/color_filter_layer_unittests.cc @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/display_list/display_list.h" +#include "flutter/display_list/display_list_color.h" +#include "flutter/display_list/display_list_paint.h" #include "flutter/flow/compositor_context.h" #include "flutter/flow/layers/color_filter_layer.h" @@ -14,6 +17,7 @@ #include "flutter/flow/testing/mock_layer.h" #include "flutter/fml/macros.h" #include "flutter/testing/mock_canvas.h" +#include "include/core/SkColor.h" #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/effects/SkColorMatrixFilter.h" @@ -24,7 +28,8 @@ using ColorFilterLayerTest = LayerTest; #ifndef NDEBUG TEST_F(ColorFilterLayerTest, PaintingEmptyLayerDies) { - auto layer = std::make_shared(sk_sp()); + auto layer = std::make_shared( + std::make_shared(sk_sp())); layer->Preroll(preroll_context(), SkMatrix()); EXPECT_EQ(layer->paint_bounds(), kEmptyRect); @@ -39,7 +44,9 @@ TEST_F(ColorFilterLayerTest, PaintBeforePrerollDies) { const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f); const SkPath child_path = SkPath().addRect(child_bounds); auto mock_layer = std::make_shared(child_path); - auto layer = std::make_shared(sk_sp()); + + auto layer = std::make_shared( + std::make_shared(sk_sp())); layer->Add(mock_layer); EXPECT_EQ(layer->paint_bounds(), kEmptyRect); @@ -82,10 +89,10 @@ TEST_F(ColorFilterLayerTest, SimpleFilter) { 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); - auto layer_filter = - SkColorMatrixFilter::MakeLightingFilter(SK_ColorGREEN, SK_ColorYELLOW); + + auto dl_color_filter = DlLinearToSrgbGammaColorFilter::instance; auto mock_layer = std::make_shared(child_path, child_paint); - auto layer = std::make_shared(layer_filter); + auto layer = std::make_shared(dl_color_filter); layer->Add(mock_layer); layer->Preroll(preroll_context(), initial_transform); @@ -94,17 +101,23 @@ TEST_F(ColorFilterLayerTest, SimpleFilter) { EXPECT_TRUE(layer->needs_painting(paint_context())); EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); - SkPaint filter_paint; - filter_paint.setColorFilter(layer_filter); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, filter_paint, - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + DisplayListBuilder expected_builder; + /* ColorFilterLayer::Paint() */ { + DlPaint dl_paint; + dl_paint.setColorFilter(dl_color_filter.get()); + expected_builder.saveLayer(&child_bounds, &dl_paint); + { + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path, + DlPaint().setColor(DlColor::kYellow())); + } + } + } + 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(ColorFilterLayerTest, MultipleChildren) { @@ -115,11 +128,10 @@ TEST_F(ColorFilterLayerTest, MultipleChildren) { SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f)); const SkPaint child_paint1 = SkPaint(SkColors::kYellow); const SkPaint child_paint2 = SkPaint(SkColors::kCyan); - auto layer_filter = - SkColorMatrixFilter::MakeLightingFilter(SK_ColorGREEN, SK_ColorYELLOW); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); - auto layer = std::make_shared(layer_filter); + auto dl_color_filter = DlSrgbToLinearGammaColorFilter::instance; + auto layer = std::make_shared(dl_color_filter); layer->Add(mock_layer1); layer->Add(mock_layer2); @@ -136,19 +148,27 @@ TEST_F(ColorFilterLayerTest, MultipleChildren) { EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); - SkPaint filter_paint; - filter_paint.setColorFilter(layer_filter); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{children_bounds, - filter_paint, nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path2, child_paint2}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + DisplayListBuilder expected_builder; + /* ColorFilterLayer::Paint() */ { + DlPaint dl_paint; + dl_paint.setColorFilter(dl_color_filter.get()); + expected_builder.saveLayer(&children_bounds, &dl_paint); + { + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path1, + DlPaint().setColor(DlColor::kYellow())); + } + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path2, + DlPaint().setColor(DlColor::kCyan())); + } + } + } + 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(ColorFilterLayerTest, Nested) { @@ -159,14 +179,12 @@ TEST_F(ColorFilterLayerTest, Nested) { SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f)); const SkPaint child_paint1 = SkPaint(SkColors::kYellow); const SkPaint child_paint2 = SkPaint(SkColors::kCyan); - auto layer_filter1 = - SkColorMatrixFilter::MakeLightingFilter(SK_ColorGREEN, SK_ColorYELLOW); - auto layer_filter2 = - SkColorMatrixFilter::MakeLightingFilter(SK_ColorMAGENTA, SK_ColorBLUE); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); - auto layer1 = std::make_shared(layer_filter1); - auto layer2 = std::make_shared(layer_filter2); + auto dl_color_filter = DlSrgbToLinearGammaColorFilter::instance; + auto layer1 = std::make_shared(dl_color_filter); + + auto layer2 = std::make_shared(dl_color_filter); layer2->Add(mock_layer2); layer1->Add(mock_layer1); layer1->Add(layer2); @@ -187,32 +205,44 @@ TEST_F(ColorFilterLayerTest, Nested) { EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); - SkPaint filter_paint1, filter_paint2; - filter_paint1.setColorFilter(layer_filter1); - filter_paint2.setColorFilter(layer_filter2); - layer1->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{children_bounds, - filter_paint1, nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{child_path2.getBounds(), - filter_paint2, nullptr, 2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child_path2, child_paint2}}, - MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + DisplayListBuilder expected_builder; + /* ColorFilterLayer::Paint() */ { + DlPaint dl_paint; + dl_paint.setColorFilter(dl_color_filter.get()); + expected_builder.saveLayer(&children_bounds, &dl_paint); + { + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path1, + DlPaint().setColor(DlColor::kYellow())); + } + /* ColorFilter::Paint() */ { + DlPaint child_dl_paint; + child_dl_paint.setColor(DlColor::kBlack()); + child_dl_paint.setColorFilter(dl_color_filter.get()); + expected_builder.saveLayer(&child_path2.getBounds(), &child_dl_paint); + + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path2, + DlPaint().setColor(DlColor::kCyan())); + } + expected_builder.restore(); + } + } + } + expected_builder.restore(); + + auto expected_display_list = expected_builder.Build(); + + layer1->Paint(display_list_paint_context()); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list)); } TEST_F(ColorFilterLayerTest, Readback) { - auto layer_filter = SkColorFilters::LinearToSRGBGamma(); auto initial_transform = SkMatrix(); // ColorFilterLayer does not read from surface - auto layer = std::make_shared(layer_filter); + auto layer = std::make_shared( + DlLinearToSrgbGammaColorFilter::instance); preroll_context()->surface_needs_readback = false; layer->Preroll(preroll_context(), initial_transform); EXPECT_FALSE(preroll_context()->surface_needs_readback); @@ -227,8 +257,7 @@ TEST_F(ColorFilterLayerTest, Readback) { } TEST_F(ColorFilterLayerTest, CacheChild) { - auto layer_filter = - SkColorMatrixFilter::MakeLightingFilter(SK_ColorGREEN, SK_ColorYELLOW); + auto layer_filter = DlSrgbToLinearGammaColorFilter::instance; auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); @@ -268,8 +297,7 @@ TEST_F(ColorFilterLayerTest, CacheChild) { } TEST_F(ColorFilterLayerTest, CacheChildren) { - auto layer_filter = - SkColorMatrixFilter::MakeLightingFilter(SK_ColorGREEN, SK_ColorYELLOW); + auto layer_filter = DlSrgbToLinearGammaColorFilter::instance; auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); @@ -314,8 +342,7 @@ TEST_F(ColorFilterLayerTest, CacheChildren) { } TEST_F(ColorFilterLayerTest, CacheColorFilterLayerSelf) { - auto layer_filter = - SkColorMatrixFilter::MakeLightingFilter(SK_ColorGREEN, SK_ColorYELLOW); + auto layer_filter = DlSrgbToLinearGammaColorFilter::instance; auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); const SkPath child_path1 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); @@ -384,8 +411,8 @@ TEST_F(ColorFilterLayerTest, OpacityInheritance) { auto initial_transform = SkMatrix::Translate(50.0, 25.5); const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); auto mock_layer = std::make_shared(child_path); - auto color_filter_layer = - std::make_shared(layer_filter.skia_object()); + auto color_filter_layer = std::make_shared( + std::make_shared(matrix)); color_filter_layer->Add(mock_layer); PrerollContext* context = preroll_context(); @@ -409,13 +436,12 @@ TEST_F(ColorFilterLayerTest, OpacityInheritance) { { expected_builder.translate(offset.fX, offset.fY); /* ColorFilterLayer::Paint() */ { - expected_builder.setColor(opacity_alpha << 24); - expected_builder.setColorFilter(&layer_filter); - expected_builder.saveLayer(&child_path.getBounds(), true); + DlPaint dl_paint; + dl_paint.setColor(opacity_alpha << 24); + dl_paint.setColorFilter(&layer_filter); + expected_builder.saveLayer(&child_path.getBounds(), &dl_paint); /* MockLayer::Paint() */ { - expected_builder.setColor(0xFF000000); - expected_builder.setColorFilter(nullptr); - expected_builder.drawPath(child_path); + expected_builder.drawPath(child_path, DlPaint().setColor(0xFF000000)); } expected_builder.restore(); } diff --git a/flow/layers/layer.h b/flow/layers/layer.h index ef66af244e073..a87642d2c8cff 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -229,9 +229,11 @@ class Layer { update_needs_paint(); } - void setColorFilter(sk_sp filter) { - sk_paint_.setColorFilter(filter); - dl_paint_.setColorFilter(DlColorFilter::From(filter)); + void setColorFilter(const DlColorFilter* filter) { + if (!filter) + return; + sk_paint_.setColorFilter(filter->skia_object()); + dl_paint_.setColorFilter(filter); update_needs_paint(); } diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 5406c67675c02..74859e2b8df4b 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -139,8 +139,8 @@ void SceneBuilder::pushOpacity(Dart_Handle layer_handle, void SceneBuilder::pushColorFilter(Dart_Handle layer_handle, const ColorFilter* color_filter, fml::RefPtr oldLayer) { - auto layer = std::make_shared( - color_filter->filter()->skia_object()); + auto layer = + std::make_shared(color_filter->filter()); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); From 1a678d2ce6b9192c917b2b644eed44fd91fbb80a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 11:11:05 -0400 Subject: [PATCH 122/558] Roll Fuchsia Linux SDK from BRTz21cLl... to kURZcohuz... (#35182) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c7386db1ed63e..ef00308b3f8d1 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'BRTz21cLlhH2ZqgzoilIhU18cYA9axzlNywByomqJVgC' + 'version': 'kURZcohuz6mq5S1wEFQj9GX1TPgSbXJaR6bovSLYXNkC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index d8538082a3fa6..86cbe5612fbc3 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: a96ad7fa96a0d9334534d6e0b8fa0cec +Signature: f41310cddc9d45d4aa33637e4b56826e UNUSED LICENSES: From cdccc60ca53d26fc9bec5371c7cefe159389f1e1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 11:12:04 -0400 Subject: [PATCH 123/558] Roll Dart SDK from aada0a67f81e to 344a7d12b413 (1 revision) (#35181) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index ef00308b3f8d1..d0d7bf8c38d45 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'aada0a67f81e3532921488ba41de4e3d69a73be1', + 'dart_revision': '344a7d12b41317a9ee0b388caad7939f06f309b9', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 2c7b4f6d899ccd6d30326eb6b2c80649b2e8b7ed Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 5 Aug 2022 08:47:04 -0700 Subject: [PATCH 124/558] Update setAssetDirectory service extension to fail if provided path is invalid (#35178) --- assets/asset_manager.cc | 10 +++-- assets/asset_manager.h | 18 +++++++- shell/common/shell.cc | 13 ++++-- testing/dart/observatory/BUILD.gn | 1 + .../observatory/vmservice_methods_test.dart | 44 +++++++++++++++++++ 5 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 testing/dart/observatory/vmservice_methods_test.dart diff --git a/assets/asset_manager.cc b/assets/asset_manager.cc index ef73894d07647..ecf97a4ce5e69 100644 --- a/assets/asset_manager.cc +++ b/assets/asset_manager.cc @@ -13,20 +13,22 @@ AssetManager::AssetManager() = default; AssetManager::~AssetManager() = default; -void AssetManager::PushFront(std::unique_ptr resolver) { +bool AssetManager::PushFront(std::unique_ptr resolver) { if (resolver == nullptr || !resolver->IsValid()) { - return; + return false; } resolvers_.push_front(std::move(resolver)); + return true; } -void AssetManager::PushBack(std::unique_ptr resolver) { +bool AssetManager::PushBack(std::unique_ptr resolver) { if (resolver == nullptr || !resolver->IsValid()) { - return; + return false; } resolvers_.push_back(std::move(resolver)); + return true; } void AssetManager::UpdateResolverByType( diff --git a/assets/asset_manager.h b/assets/asset_manager.h index 335bd84116365..b9e704d58a18f 100644 --- a/assets/asset_manager.h +++ b/assets/asset_manager.h @@ -22,9 +22,23 @@ class AssetManager final : public AssetResolver { ~AssetManager() override; - void PushFront(std::unique_ptr resolver); + //-------------------------------------------------------------------------- + /// @brief Adds an asset resolver to the front of the resolver queue. + /// Assets would be loaded from this resolver before any follwing + /// resolvers. + /// + /// @return Returns whether this resolver is valid and has been added to + /// the resolver queue. + bool PushFront(std::unique_ptr resolver); - void PushBack(std::unique_ptr resolver); + //-------------------------------------------------------------------------- + /// @brief Adds an asset resolver to the end of the resolver queue. + /// Assets would be loaded from this resolver after any previous + /// resolvers. + /// + /// @return Returns whether this resolver is valid and has been added to + /// the resolver queue. + bool PushBack(std::unique_ptr resolver); //-------------------------------------------------------------------------- /// @brief Replaces an asset resolver of the specified `type` with diff --git a/shell/common/shell.cc b/shell/common/shell.cc index e28a0391a3552..721a95295c8e2 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -1773,10 +1773,15 @@ bool Shell::OnServiceProtocolSetAssetBundlePath( auto asset_manager = std::make_shared(); - asset_manager->PushFront(std::make_unique( - fml::OpenDirectory(params.at("assetDirectory").data(), false, - fml::FilePermission::kRead), - false)); + if (!asset_manager->PushFront(std::make_unique( + fml::OpenDirectory(params.at("assetDirectory").data(), false, + fml::FilePermission::kRead), + false))) { + // The new asset directory path was invalid. + FML_DLOG(ERROR) << "Could not update asset directory."; + ServiceProtocolFailureError(response, "Could not update asset directory."); + return false; + } // Preserve any original asset resolvers to avoid syncing unchanged assets // over the DevFS connection. diff --git a/testing/dart/observatory/BUILD.gn b/testing/dart/observatory/BUILD.gn index 3aca101451b36..a0e6afbe6be17 100644 --- a/testing/dart/observatory/BUILD.gn +++ b/testing/dart/observatory/BUILD.gn @@ -8,6 +8,7 @@ tests = [ "skp_test.dart", "tracing_test.dart", "shader_reload_test.dart", + "vmservice_methods_test.dart", ] foreach(test, tests) { diff --git a/testing/dart/observatory/vmservice_methods_test.dart b/testing/dart/observatory/vmservice_methods_test.dart new file mode 100644 index 0000000000000..8dbbf0dc6eccb --- /dev/null +++ b/testing/dart/observatory/vmservice_methods_test.dart @@ -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. + +import 'dart:developer' as developer; + +import 'package:litetest/litetest.dart'; +import 'package:vm_service/vm_service.dart' as vms; +import 'package:vm_service/vm_service_io.dart'; + +void main() { + test('Setting invalid directory returns an error', () async { + vms.VmService? vmService; + try { + final developer.ServiceProtocolInfo info = await developer.Service.getInfo(); + if (info.serverUri == null) { + fail('This test must not be run with --disable-observatory.'); + } + + vmService = await vmServiceConnectUri( + 'ws://localhost:${info.serverUri!.port}${info.serverUri!.path}ws', + ); + final vms.Response response = await vmService.callMethod('_flutter.listViews'); + final List? rawViews = response.json!['views'] as List?; + final String viewId = (rawViews![0]! as Map?)!['id']! as String; + + dynamic error; + try { + final vms.Response setAssetDirectoryPath = await vmService.callMethod( + '_flutter.setAssetBundlePath', + args: { + 'viewId': viewId, + 'assetDirectory': '' + }, + ); + } catch (err) { + error = err; + } + expect(error != null, true); + } finally { + await vmService?.dispose(); + } + }); +} From ce3397f950a4e6cdf35935d7c99f1fa1c81a7ed1 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 5 Aug 2022 09:55:14 -0700 Subject: [PATCH 125/558] fix analysis error (#35187) --- testing/dart/observatory/vmservice_methods_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/dart/observatory/vmservice_methods_test.dart b/testing/dart/observatory/vmservice_methods_test.dart index 8dbbf0dc6eccb..a6491797f248d 100644 --- a/testing/dart/observatory/vmservice_methods_test.dart +++ b/testing/dart/observatory/vmservice_methods_test.dart @@ -26,7 +26,7 @@ void main() { dynamic error; try { - final vms.Response setAssetDirectoryPath = await vmService.callMethod( + await vmService.callMethod( '_flutter.setAssetBundlePath', args: { 'viewId': viewId, From eaeae8e8370261bb357da170bf50f53c1449fb23 Mon Sep 17 00:00:00 2001 From: Pierre-Louis <6655696+guidezpl@users.noreply.github.com> Date: Fri, 5 Aug 2022 19:34:04 +0200 Subject: [PATCH 126/558] Make it possible to obtain `FontWeight` integer value (#35183) --- lib/ui/text.dart | 23 +++++++++++++---------- lib/web_ui/lib/text.dart | 21 +++++++++++---------- lib/web_ui/test/text_test.dart | 12 ++++++++++++ testing/dart/text_test.dart | 16 ++++++++++++++-- 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/lib/ui/text.dart b/lib/ui/text.dart index 4b329608da900..3627aa28ac367 100644 --- a/lib/ui/text.dart +++ b/lib/ui/text.dart @@ -14,37 +14,40 @@ enum FontStyle { /// The thickness of the glyphs used to draw the text class FontWeight { - const FontWeight._(this.index); + const FontWeight._(this.index, this.value); /// The encoded integer value of this font weight. final int index; + /// The thickness value of this font weight. + final int value; + /// Thin, the least thick - static const FontWeight w100 = FontWeight._(0); + static const FontWeight w100 = FontWeight._(0, 100); /// Extra-light - static const FontWeight w200 = FontWeight._(1); + static const FontWeight w200 = FontWeight._(1, 200); /// Light - static const FontWeight w300 = FontWeight._(2); + static const FontWeight w300 = FontWeight._(2, 300); /// Normal / regular / plain - static const FontWeight w400 = FontWeight._(3); + static const FontWeight w400 = FontWeight._(3, 400); /// Medium - static const FontWeight w500 = FontWeight._(4); + static const FontWeight w500 = FontWeight._(4, 500); /// Semi-bold - static const FontWeight w600 = FontWeight._(5); + static const FontWeight w600 = FontWeight._(5, 600); /// Bold - static const FontWeight w700 = FontWeight._(6); + static const FontWeight w700 = FontWeight._(6, 700); /// Extra-bold - static const FontWeight w800 = FontWeight._(7); + static const FontWeight w800 = FontWeight._(7, 800); /// Black, the most thick - static const FontWeight w900 = FontWeight._(8); + static const FontWeight w900 = FontWeight._(8, 900); /// The default font weight. static const FontWeight normal = w400; diff --git a/lib/web_ui/lib/text.dart b/lib/web_ui/lib/text.dart index e1c2a56fd1eb2..30e0ed35de273 100644 --- a/lib/web_ui/lib/text.dart +++ b/lib/web_ui/lib/text.dart @@ -19,17 +19,18 @@ enum PlaceholderAlignment { } class FontWeight { - const FontWeight._(this.index); + const FontWeight._(this.index, this.value); final int index; - static const FontWeight w100 = FontWeight._(0); - static const FontWeight w200 = FontWeight._(1); - static const FontWeight w300 = FontWeight._(2); - static const FontWeight w400 = FontWeight._(3); - static const FontWeight w500 = FontWeight._(4); - static const FontWeight w600 = FontWeight._(5); - static const FontWeight w700 = FontWeight._(6); - static const FontWeight w800 = FontWeight._(7); - static const FontWeight w900 = FontWeight._(8); + final int value; + static const FontWeight w100 = FontWeight._(0, 100); + static const FontWeight w200 = FontWeight._(1, 200); + static const FontWeight w300 = FontWeight._(2, 300); + static const FontWeight w400 = FontWeight._(3, 400); + static const FontWeight w500 = FontWeight._(4, 500); + static const FontWeight w600 = FontWeight._(5, 600); + static const FontWeight w700 = FontWeight._(6, 700); + static const FontWeight w800 = FontWeight._(7, 800); + static const FontWeight w900 = FontWeight._(8, 900); static const FontWeight normal = w400; static const FontWeight bold = w700; static const List values = [ diff --git a/lib/web_ui/test/text_test.dart b/lib/web_ui/test/text_test.dart index d1f8f3fbf6130..442e44bf1b630 100644 --- a/lib/web_ui/test/text_test.dart +++ b/lib/web_ui/test/text_test.dart @@ -352,4 +352,16 @@ Future testMain() async { equals('hello')); }); }); + + test('FontWeights have the correct value', () { + expect(FontWeight.w100.value, 100); + expect(FontWeight.w200.value, 200); + expect(FontWeight.w300.value, 300); + expect(FontWeight.w400.value, 400); + expect(FontWeight.w500.value, 500); + expect(FontWeight.w600.value, 600); + expect(FontWeight.w700.value, 700); + expect(FontWeight.w800.value, 800); + expect(FontWeight.w900.value, 900); + }); } diff --git a/testing/dart/text_test.dart b/testing/dart/text_test.dart index b845b654b41f7..13bb1645bb433 100644 --- a/testing/dart/text_test.dart +++ b/testing/dart/text_test.dart @@ -19,7 +19,7 @@ Future readFile(String fileName) async { return file.readAsBytes(); } -void testFontWeightLerp() { +void testFontWeight() { test('FontWeight.lerp works with non-null values', () { expect(FontWeight.lerp(FontWeight.w400, FontWeight.w600, .5), equals(FontWeight.w500)); }); @@ -35,6 +35,18 @@ void testFontWeightLerp() { test('FontWeight.lerp returns FontWeight.w400 if b is null', () { expect(FontWeight.lerp(FontWeight.w400, null, 1), equals(FontWeight.w400)); }); + + test('FontWeights have the correct value', () { + expect(FontWeight.w100.value, 100); + expect(FontWeight.w200.value, 200); + expect(FontWeight.w300.value, 300); + expect(FontWeight.w400.value, 400); + expect(FontWeight.w500.value, 500); + expect(FontWeight.w600.value, 600); + expect(FontWeight.w700.value, 700); + expect(FontWeight.w800.value, 800); + expect(FontWeight.w900.value, 900); + }); } void testParagraphStyle() { @@ -277,7 +289,7 @@ void testFontVariation() { } void main() { - testFontWeightLerp(); + testFontWeight(); testParagraphStyle(); testTextStyle(); testTextHeightBehavior(); From 1f9d87d6c632dcfbc7d39810293fe80448b590e9 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Fri, 5 Aug 2022 10:38:05 -0700 Subject: [PATCH 127/558] Analyze all dart code on CI (#35147) --- ci/analyze.sh | 24 +++++++------------ tools/analysis_options.yaml | 5 ++++ tools/api_check/lib/apicheck.dart | 4 ++-- tools/api_check/pubspec.yaml | 2 +- .../const_finder/test/const_finder_test.dart | 10 ++++---- tools/const_finder/test/fixtures/lib/box.dart | 4 ++-- .../test/fixtures/lib/consts.dart | 2 +- .../test/fixtures/lib/consts_and_non.dart | 2 +- .../test/fixtures/pkg/package.dart | 2 +- tools/gen_locale.dart | 5 +++- web_sdk/pubspec.yaml | 5 +++- web_sdk/sdk_rewriter.dart | 6 ++--- web_sdk/test/api_conform_test.dart | 11 +++++---- web_sdk/test/js_access_test.dart | 2 ++ web_sdk/test/sdk_rewriter_test.dart | 2 +- .../web_engine_tester/lib/golden_tester.dart | 2 +- .../web_engine_tester/lib/static/host.dart | 10 ++++---- web_sdk/web_engine_tester/pubspec.yaml | 1 + web_sdk/web_test_utils/lib/environment.dart | 20 ++++++++-------- web_sdk/web_test_utils/lib/goldens.dart | 24 +++++++++---------- web_sdk/web_test_utils/lib/image_compare.dart | 8 +++---- 21 files changed, 80 insertions(+), 71 deletions(-) create mode 100644 tools/analysis_options.yaml diff --git a/ci/analyze.sh b/ci/analyze.sh index 62886f53165c7..fbfa6b7805d94 100755 --- a/ci/analyze.sh +++ b/ci/analyze.sh @@ -54,29 +54,21 @@ echo "" "$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/flutter_frontend_server" -"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/tools/licenses" +"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/tools" -"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/testing/litetest" - -"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/testing/benchmark" - -"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/testing/smoke_test_failure" - -"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/testing/dart" - -"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/testing/scenario_app" - -"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/testing/symbols" - -"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/tools/githooks" - -"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/tools/clang_tidy" +(cd "$FLUTTER_DIR/testing/skia_gold_client"; "$DART" pub get) +"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/testing" echo "" # Check that dart libraries conform. echo "Checking the integrity of the Web SDK" (cd "$FLUTTER_DIR/web_sdk"; "$DART" pub get) +(cd "$FLUTTER_DIR/web_sdk/web_test_utils"; "$DART" pub get) +(cd "$FLUTTER_DIR/web_sdk/web_engine_tester"; "$DART" pub get) + +"$DART" analyze --fatal-infos --fatal-warnings "$FLUTTER_DIR/web_sdk" + WEB_SDK_TEST_FILES="$FLUTTER_DIR/web_sdk/test/*" for testFile in $WEB_SDK_TEST_FILES do diff --git a/tools/analysis_options.yaml b/tools/analysis_options.yaml new file mode 100644 index 0000000000000..7f47e0448b47f --- /dev/null +++ b/tools/analysis_options.yaml @@ -0,0 +1,5 @@ +include: ../analysis_options.yaml + +linter: + rules: + avoid_print: false diff --git a/tools/api_check/lib/apicheck.dart b/tools/api_check/lib/apicheck.dart index 1ba28a086c001..8413cc6f37e95 100644 --- a/tools/api_check/lib/apicheck.dart +++ b/tools/api_check/lib/apicheck.dart @@ -36,11 +36,11 @@ List getDartClassFields({ final RegExp fieldExp = RegExp(r'_k(\w*)Index'); final List fields = []; for (final CompilationUnitMember unitMember in result.unit.declarations) { - if (unitMember is ClassDeclaration && unitMember.name.name == className) { + if (unitMember is ClassDeclaration && unitMember.name.name == className) { // ignore: deprecated_member_use for (final ClassMember classMember in unitMember.members) { if (classMember is FieldDeclaration) { for (final VariableDeclaration field in classMember.fields.variables) { - final String fieldName = field.name.name; + final String fieldName = field.name.name; // ignore: deprecated_member_use final RegExpMatch? match = fieldExp.firstMatch(fieldName); if (match != null) { fields.add(match.group(1)!); diff --git a/tools/api_check/pubspec.yaml b/tools/api_check/pubspec.yaml index 8ac0e26b0dafc..60a1493a0247a 100644 --- a/tools/api_check/pubspec.yaml +++ b/tools/api_check/pubspec.yaml @@ -28,13 +28,13 @@ environment: dependencies: analyzer: any _fe_analyzer_shared: any + pub_semver: any dev_dependencies: async_helper: any expect: any litetest: any path: any - pub_semver: any smith: any dependency_overrides: diff --git a/tools/const_finder/test/const_finder_test.dart b/tools/const_finder/test/const_finder_test.dart index 4289c584fb312..9eac1900b7e97 100644 --- a/tools/const_finder/test/const_finder_test.dart +++ b/tools/const_finder/test/const_finder_test.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_dynamic_calls + import 'dart:convert' show jsonEncode; import 'dart:io'; @@ -175,7 +177,7 @@ Future main(List args) async { final String frontendServer = args[0]; final String sdkRoot = args[1]; try { - void _checkProcessResult(ProcessResult result) { + void checkProcessResult(ProcessResult result) { if (result.exitCode != 0) { stdout.writeln(result.stdout); stderr.writeln(result.stderr); @@ -186,7 +188,7 @@ Future main(List args) async { stdout.writeln('Generating kernel fixtures...'); stdout.writeln(consts); - _checkProcessResult(Process.runSync(dart, [ + checkProcessResult(Process.runSync(dart, [ frontendServer, '--sdk-root=$sdkRoot', '--target=flutter', @@ -197,7 +199,7 @@ Future main(List args) async { box, ])); - _checkProcessResult(Process.runSync(dart, [ + checkProcessResult(Process.runSync(dart, [ frontendServer, '--sdk-root=$sdkRoot', '--target=flutter', @@ -208,7 +210,7 @@ Future main(List args) async { consts, ])); - _checkProcessResult(Process.runSync(dart, [ + checkProcessResult(Process.runSync(dart, [ frontendServer, '--sdk-root=$sdkRoot', '--target=flutter', diff --git a/tools/const_finder/test/fixtures/lib/box.dart b/tools/const_finder/test/fixtures/lib/box.dart index f84961d10883b..ea31a1ed3be4e 100644 --- a/tools/const_finder/test/fixtures/lib/box.dart +++ b/tools/const_finder/test/fixtures/lib/box.dart @@ -9,9 +9,9 @@ // https://github.com/dart-lang/sdk/blob/ca3ad264a64937d5d336cd04dbf2746d1b7d8fc4/tests/language_2/canonicalize/hashing_memoize_instance_test.dart class Box { + const Box(this.content1, this.content2); final Object content1; final Object content2; - const Box(this.content1, this.content2); } const Box box1_0 = Box(null, null); @@ -217,7 +217,7 @@ const Box box2_98 = Box(box2_97, box2_97); const Box box2_99 = Box(box2_98, box2_98); Object confuse(Box x) { - try { throw x; } catch (e) { return e; } + try { throw x; } catch (e) { return e; } // ignore: only_throw_errors } void main() { diff --git a/tools/const_finder/test/fixtures/lib/consts.dart b/tools/const_finder/test/fixtures/lib/consts.dart index ba66e7a946fb0..a13a5772a4521 100644 --- a/tools/const_finder/test/fixtures/lib/consts.dart +++ b/tools/const_finder/test/fixtures/lib/consts.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: prefer_const_constructors, unused_local_variable +// ignore_for_file: prefer_const_constructors, unused_local_variable, depend_on_referenced_packages import 'dart:core'; import 'package:const_finder_fixtures_package/package.dart'; diff --git a/tools/const_finder/test/fixtures/lib/consts_and_non.dart b/tools/const_finder/test/fixtures/lib/consts_and_non.dart index 6b85ac2687cd3..fa91c318bcb7b 100644 --- a/tools/const_finder/test/fixtures/lib/consts_and_non.dart +++ b/tools/const_finder/test/fixtures/lib/consts_and_non.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: prefer_const_constructors, unused_local_variable +// ignore_for_file: prefer_const_constructors, unused_local_variable, depend_on_referenced_packages import 'dart:core'; import 'package:const_finder_fixtures_package/package.dart'; diff --git a/tools/const_finder/test/fixtures/pkg/package.dart b/tools/const_finder/test/fixtures/pkg/package.dart index 87a92bb57221d..b5256d53e154b 100644 --- a/tools/const_finder/test/fixtures/pkg/package.dart +++ b/tools/const_finder/test/fixtures/pkg/package.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore_for_file: prefer_const_constructors +// ignore_for_file: prefer_const_constructors, depend_on_referenced_packages import 'package:const_finder_fixtures/target.dart'; void createTargetInPackage() { diff --git a/tools/gen_locale.dart b/tools/gen_locale.dart index 22c4c894a6636..2c4cedcea0d2a 100644 --- a/tools/gen_locale.dart +++ b/tools/gen_locale.dart @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(goderbauer): Migrate this to null safety, https://github.com/flutter/flutter/issues/108933 +// @dart = 2.7 + // This file is used to generate the switch statements in the Locale class. // See: ../lib/ui/window.dart @@ -30,7 +33,7 @@ Map> parseSection(String section) { } final int colon = line.indexOf(':'); if (colon <= 0) { - throw 'not sure how to deal with "$line"'; + throw StateError('not sure how to deal with "$line"'); } final String name = line.substring(0, colon); final String value = line.substring(colon + 2); diff --git a/web_sdk/pubspec.yaml b/web_sdk/pubspec.yaml index cfc4aeca2f5d5..bd2d22bba6c72 100644 --- a/web_sdk/pubspec.yaml +++ b/web_sdk/pubspec.yaml @@ -1,10 +1,13 @@ name: web_sdk_tests -author: Flutter Authors # Keep the SDK version range in sync with lib/web_ui/pubspec.yaml environment: sdk: ">=2.12.0-0 <3.0.0" +dependencies: + args: 2.3.1 + path: 1.8.2 + dev_dependencies: analyzer: 4.3.1 test: 1.21.4 diff --git a/web_sdk/sdk_rewriter.dart b/web_sdk/sdk_rewriter.dart index c71e0d5f8a054..bacc7683443e0 100644 --- a/web_sdk/sdk_rewriter.dart +++ b/web_sdk/sdk_rewriter.dart @@ -10,8 +10,8 @@ import 'package:path/path.dart' as path; final ArgParser argParser = ArgParser() ..addOption('output-dir') ..addOption('input-dir') - ..addFlag('ui', defaultsTo: false) - ..addFlag('engine', defaultsTo: false) + ..addFlag('ui') + ..addFlag('engine') ..addMultiOption('input') ..addOption('stamp'); @@ -170,7 +170,7 @@ String _preprocessEnginePartFile(String source) { // Do nothing. } else { // Insert the part directive at the beginning of the file. - source = 'part of engine;\n' + source; + source = 'part of engine;\n$source'; } return source; } diff --git a/web_sdk/test/api_conform_test.dart b/web_sdk/test/api_conform_test.dart index 1a659ca3790ec..755b6f9a3345c 100644 --- a/web_sdk/test/api_conform_test.dart +++ b/web_sdk/test/api_conform_test.dart @@ -2,13 +2,14 @@ // 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:analyzer/dart/analysis/features.dart'; import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/analysis/utilities.dart'; import 'package:analyzer/dart/ast/ast.dart'; -import 'package:pub_semver/pub_semver.dart'; // Ignore members defined on Object. const Set _kObjectMembers = { @@ -187,8 +188,8 @@ void main() { // check nullability if (uiParam is SimpleFormalParameter && webParam is SimpleFormalParameter) { - bool isUiNullable = uiParam.type?.question != null; - bool isWebNullable = webParam.type?.question != null; + final bool isUiNullable = uiParam.type?.question != null; + final bool isWebNullable = webParam.type?.question != null; if (isUiNullable != isWebNullable) { failed = true; print('Warning: lib/ui/ui.dart $className.$methodName parameter $i ' @@ -263,8 +264,8 @@ void main() { '${uiParam.identifier!.name} is named, but not in lib/web_ui/ui.dart.'); } - bool isUiNullable = uiParam.type?.question != null; - bool isWebNullable = webParam.type?.question != null; + final bool isUiNullable = uiParam.type?.question != null; + final bool isWebNullable = webParam.type?.question != null; if (isUiNullable != isWebNullable) { failed = true; print('Warning: lib/ui/ui.dart $typeDefName parameter $i ' diff --git a/web_sdk/test/js_access_test.dart b/web_sdk/test/js_access_test.dart index ee41a1e83d880..985ab28e3180d 100644 --- a/web_sdk/test/js_access_test.dart +++ b/web_sdk/test/js_access_test.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 + /// Checks that JavaScript API is accessed properly. /// /// JavaScript access needs to be audited to make sure it follows security best diff --git a/web_sdk/test/sdk_rewriter_test.dart b/web_sdk/test/sdk_rewriter_test.dart index 36de7f6939798..4e17279f3353e 100644 --- a/web_sdk/test/sdk_rewriter_test.dart +++ b/web_sdk/test/sdk_rewriter_test.dart @@ -78,7 +78,7 @@ export 'engine/file3.dart'; '$caught', 'Exception: on line 3: unexpected code in /path/to/lib/web_ui/lib/src/engine.dart. ' 'This file may only contain comments and exports. Found:\n' - 'import \'dart:something\';', + "import 'dart:something';", ); }); diff --git a/web_sdk/web_engine_tester/lib/golden_tester.dart b/web_sdk/web_engine_tester/lib/golden_tester.dart index e5c2f04a9667a..732866637ec64 100644 --- a/web_sdk/web_engine_tester/lib/golden_tester.dart +++ b/web_sdk/web_engine_tester/lib/golden_tester.dart @@ -7,7 +7,7 @@ import 'dart:convert'; import 'package:test/test.dart'; // ignore: implementation_imports -import 'package:ui/src/engine.dart' show operatingSystem, OperatingSystem, useCanvasKit; +import 'package:ui/src/engine.dart' show OperatingSystem, operatingSystem, useCanvasKit; // ignore: implementation_imports import 'package:ui/src/engine/dom.dart'; import 'package:ui/ui.dart'; diff --git a/web_sdk/web_engine_tester/lib/static/host.dart b/web_sdk/web_engine_tester/lib/static/host.dart index e98cc23128f35..320dba2134da1 100644 --- a/web_sdk/web_engine_tester/lib/static/host.dart +++ b/web_sdk/web_engine_tester/lib/static/host.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_dynamic_calls + @JS() library test.host; @@ -22,7 +24,7 @@ class _TestRunner { /// Returns the current content shell runner, or `null` if none exists. @JS() -external _TestRunner? get testRunner; +external _TestRunner? get testRunner; // ignore: library_private_types_in_public_api /// A class that exposes the test API to JS. /// @@ -31,6 +33,8 @@ external _TestRunner? get testRunner; @JS() @anonymous class _JSApi { + external factory _JSApi({void Function() resume, void Function() restartCurrent}); + /// Causes the test runner to resume running, as though the user had clicked /// the "play" button. external Function get resume; @@ -38,8 +42,6 @@ class _JSApi { /// Causes the test runner to restart the current test once it finishes /// running. external Function get restartCurrent; - - external factory _JSApi({void Function() resume, void Function() restartCurrent}); } /// Sets the top-level `dartTest` object so that it's visible to JS. @@ -160,7 +162,7 @@ void main() { })); }, (dynamic error, StackTrace stackTrace) { - print('$error\n${Trace.from(stackTrace).terse}'); + print('$error\n${Trace.from(stackTrace).terse}'); // ignore: avoid_print }, ); } diff --git a/web_sdk/web_engine_tester/pubspec.yaml b/web_sdk/web_engine_tester/pubspec.yaml index 489401ff2913e..25219b1071327 100644 --- a/web_sdk/web_engine_tester/pubspec.yaml +++ b/web_sdk/web_engine_tester/pubspec.yaml @@ -9,5 +9,6 @@ dependencies: stream_channel: 2.1.0 test: 1.17.7 webkit_inspection_protocol: 1.0.0 + stack_trace: 1.10.0 ui: path: ../../lib/web_ui diff --git a/web_sdk/web_test_utils/lib/environment.dart b/web_sdk/web_test_utils/lib/environment.dart index 81466b4bba828..30ea72edb9e1f 100644 --- a/web_sdk/web_test_utils/lib/environment.dart +++ b/web_sdk/web_test_utils/lib/environment.dart @@ -36,6 +36,16 @@ class Environment { return _prepareEnvironmentFromEngineDir(script, directory); } + Environment._({ + required this.self, + required this.webUiRootDir, + required this.engineSrcDir, + required this.engineToolsDir, + required this.outDir, + required this.hostDebugUnoptDir, + required this.dartSdkDir, + }); + static Environment _prepareEnvironmentFromEngineDir( io.File self, io.Directory engineSrcDir) { final io.Directory engineToolsDir = @@ -72,16 +82,6 @@ class Environment { ); } - Environment._({ - required this.self, - required this.webUiRootDir, - required this.engineSrcDir, - required this.engineToolsDir, - required this.outDir, - required this.hostDebugUnoptDir, - required this.dartSdkDir, - }); - /// The Dart script that's currently running. final io.File self; diff --git a/web_sdk/web_test_utils/lib/goldens.dart b/web_sdk/web_test_utils/lib/goldens.dart index 2f3f199614b52..e39e1f7fa4863 100644 --- a/web_sdk/web_test_utils/lib/goldens.dart +++ b/web_sdk/web_test_utils/lib/goldens.dart @@ -26,12 +26,22 @@ void main(List args) { final Image imageB = decodeNamedImage(fileB.readAsBytesSync(), 'b.png')!; final ImageDiff diff = ImageDiff( golden: imageA, other: imageB, pixelComparison: PixelComparison.fuzzy); - print('Diff: ${(diff.rate * 100).toStringAsFixed(4)}%'); + print('Diff: ${(diff.rate * 100).toStringAsFixed(4)}%'); // ignore: avoid_print } /// This class encapsulates visually diffing an Image with any other. /// Both images need to be the exact same size. class ImageDiff { + /// Image diff constructor which requires two [Image]s to compare and + /// [PixelComparison] algorithm. + ImageDiff({ + required this.golden, + required this.other, + required this.pixelComparison, + }) { + _computeDiff(); + } + /// The image to match final Image golden; @@ -53,16 +63,6 @@ class ImageDiff { /// This gets set to 1 (100% difference) when golden and other aren't the same size. double get rate => _wrongPixels / _pixelCount; - /// Image diff constructor which requires two [Image]s to compare and - /// [PixelComparison] algorithm. - ImageDiff({ - required this.golden, - required this.other, - required this.pixelComparison, - }) { - _computeDiff(); - } - int _pixelCount = 0; int _wrongPixels = 0; @@ -136,8 +136,6 @@ class ImageDiff { getGreen(pixel), getBlue(pixel), ]; - default: - throw 'Unrecognized pixel comparison value: $pixelComparison'; } } diff --git a/web_sdk/web_test_utils/lib/image_compare.dart b/web_sdk/web_test_utils/lib/image_compare.dart index 29de42db0757e..aeadee1863841 100644 --- a/web_sdk/web_test_utils/lib/image_compare.dart +++ b/web_sdk/web_test_utils/lib/image_compare.dart @@ -72,7 +72,7 @@ Future compareImage( // At the moment, we don't support local screenshot testing because we use // Skia Gold to handle our screenshots and diffing. In the future, we might // implement local screenshot testing if there's a need. - print('Screenshot generated: file://$screenshotPath'); + print('Screenshot generated: file://$screenshotPath'); // ignore: avoid_print return 'OK'; } @@ -137,8 +137,8 @@ Golden file $filename did not match the image generated by the test. if (diff.rate < maxDiffRateFailure) { // Issue a warning but do not fail the test. - print('WARNING:'); - print(message); + print('WARNING:'); // ignore: avoid_print + print(message); // ignore: avoid_print return 'OK'; } else { // Fail test @@ -150,7 +150,7 @@ Golden file $filename did not match the image generated by the test. Future _getGolden(String filename) { // TODO(mdebbar): Fetch the golden from Skia Gold. - return Future.value(null); + return Future.value(); } String _getFullScreenshotPath(String filename) { From 1cf7023e263784e20d681e4e30289af9f505722a Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Fri, 5 Aug 2022 10:38:15 -0700 Subject: [PATCH 128/558] [impeller] [vulkan] Support textures backed by `vk::Image`s (#35163) --- .../renderer/backend/vulkan/allocator_vk.cc | 44 +++++++++++++- impeller/renderer/backend/vulkan/formats_vk.h | 28 +++++++++ .../renderer/backend/vulkan/texture_vk.cc | 59 ++++++++++++++++++- impeller/renderer/backend/vulkan/texture_vk.h | 15 ++++- 4 files changed, 143 insertions(+), 3 deletions(-) diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index c572363e6d1f7..ade9dd215fbf3 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -10,6 +10,8 @@ _Pragma("GCC diagnostic ignored \"-Wthread-safety-analysis\""); #define VMA_IMPLEMENTATION #include "impeller/renderer/backend/vulkan/allocator_vk.h" #include "impeller/renderer/backend/vulkan/device_buffer_vk.h" +#include "impeller/renderer/backend/vulkan/formats_vk.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" #include @@ -61,7 +63,47 @@ bool AllocatorVK::IsValid() const { std::shared_ptr AllocatorVK::CreateTexture( StorageMode mode, const TextureDescriptor& desc) { - FML_UNREACHABLE(); + auto image_create_info = vk::ImageCreateInfo{}; + image_create_info.imageType = vk::ImageType::e2D; + image_create_info.format = ToVKImageFormat(desc.format); + image_create_info.extent.width = desc.size.width; + image_create_info.extent.height = desc.size.height; + image_create_info.samples = ToVKSampleCount(desc.sample_count); + image_create_info.mipLevels = desc.mip_count; + + // TODO (kaushikiska): should we read these from desc? + image_create_info.extent.depth = 1; + image_create_info.arrayLayers = 1; + + image_create_info.tiling = vk::ImageTiling::eOptimal; + image_create_info.initialLayout = vk::ImageLayout::eUndefined; + image_create_info.usage = vk::ImageUsageFlagBits::eSampled | + vk::ImageUsageFlagBits::eColorAttachment; + + VmaAllocationCreateInfo alloc_create_info = {}; + alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO; + // docs recommend using `VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT` for image + // allocations, but setting them to be host visible for now. + alloc_create_info.flags = + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + + auto create_info_native = + static_cast(image_create_info); + + VkImage img; + VmaAllocation allocation; + VmaAllocationInfo allocation_info; + auto result = vk::Result{vmaCreateImage(allocator_, &create_info_native, + &alloc_create_info, &img, &allocation, + &allocation_info)}; + if (result != vk::Result::eSuccess) { + VALIDATION_LOG << "Unable to allocate an image"; + return nullptr; + } + + return std::make_shared(desc, context_, allocator_, img, + allocation, allocation_info); } // |Allocator| diff --git a/impeller/renderer/backend/vulkan/formats_vk.h b/impeller/renderer/backend/vulkan/formats_vk.h index 64becdf10d946..a3412715d4717 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -132,4 +132,32 @@ constexpr std::optional ToVKShaderStageFlagBits( FML_UNREACHABLE(); } +constexpr vk::Format ToVKImageFormat(PixelFormat format) { + switch (format) { + case PixelFormat::kUnknown: + return vk::Format::eUndefined; + case PixelFormat::kA8UNormInt: + return vk::Format::eA8B8G8R8UnormPack32; + case PixelFormat::kR8G8B8A8UNormInt: + return vk::Format::eR8G8B8A8Unorm; + case PixelFormat::kR8G8B8A8UNormIntSRGB: + return vk::Format::eR8G8B8A8Srgb; + case PixelFormat::kB8G8R8A8UNormInt: + return vk::Format::eB8G8R8A8Unorm; + case PixelFormat::kB8G8R8A8UNormIntSRGB: + return vk::Format::eB8G8R8A8Srgb; + case PixelFormat::kS8UInt: + return vk::Format::eS8Uint; + } +} + +constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count) { + switch (sample_count) { + case SampleCount::kCount1: + return vk::SampleCountFlagBits::e1; + case SampleCount::kCount4: + return vk::SampleCountFlagBits::e4; + } +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/texture_vk.cc b/impeller/renderer/backend/vulkan/texture_vk.cc index 7d29259d81f89..8d4661166769c 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_vk.cc @@ -6,6 +6,63 @@ namespace impeller { -// +TextureVK::TextureVK(TextureDescriptor desc, + ContextVK& context, + const VmaAllocator& allocator, + VkImage image, + VmaAllocation allocation, + VmaAllocationInfo allocation_info) + : Texture(desc), + context_(context), + allocator_(allocator), + image_(image), + allocation_(allocation), + allocation_info_(allocation_info) {} + +TextureVK::~TextureVK() { + if (image_) { + vmaDestroyImage(allocator_, image_, allocation_); + } +} + +void TextureVK::SetLabel(std::string_view label) { + context_.SetDebugName(vk::Image{image_}, label); +} + +bool TextureVK::OnSetContents(const uint8_t* contents, + size_t length, + size_t slice) { + if (!image_ || !contents) { + return false; + } + + const auto& desc = GetTextureDescriptor(); + + // Out of bounds access. + if (length != desc.GetByteSizeOfBaseMipLevel()) { + VALIDATION_LOG << "illegal to set contents for invalid size"; + return false; + } + + // currently we are only supporting 2d textures, no cube textures etc. + memcpy(allocation_info_.pMappedData, contents, length); + + return true; +} + +bool TextureVK::OnSetContents(std::shared_ptr mapping, + size_t slice) { + // Vulkan has no threading restrictions. So we can pass this data along to the + // client rendering API immediately. + return OnSetContents(mapping->GetMapping(), mapping->GetSize(), slice); +} + +bool TextureVK::IsValid() const { + return image_; +} + +ISize TextureVK::GetSize() const { + return GetTextureDescriptor().size; +} } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/texture_vk.h b/impeller/renderer/backend/vulkan/texture_vk.h index f4bc6ad4f8d5e..0bc53f7dc6c2d 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.h +++ b/impeller/renderer/backend/vulkan/texture_vk.h @@ -6,18 +6,31 @@ #include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/texture.h" namespace impeller { class TextureVK final : public Texture, public BackendCast { public: - TextureVK(TextureDescriptor desc); + TextureVK(TextureDescriptor desc, + ContextVK& context, + const VmaAllocator& allocator, + VkImage image, + VmaAllocation allocation, + VmaAllocationInfo allocation_info); // |Texture| ~TextureVK() override; private: + ContextVK& context_; + const VmaAllocator& allocator_; + VkImage image_; + VmaAllocation allocation_; + VmaAllocationInfo allocation_info_; + // |Texture| void SetLabel(std::string_view label) override; From 57f43bd3a901cbe6ade686ae596387375d95b829 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 14:35:05 -0400 Subject: [PATCH 129/558] Roll Skia from 098c234c05f7 to f1245dcd35f8 (23 revisions) (#35189) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d0d7bf8c38d45..c081e01d86bbf 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': '098c234c05f7680999f9a27ef98c6e116e21d2df', + 'skia_revision': 'f1245dcd35f8e3e315c1c9d90325cba2edf63715', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 80f19bff6b496..6b293292c6728 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: ec7e163e434e5dee311adfcd1fcd2d19 +Signature: bbf8e39570bc829b72496e3934c2ae6c UNUSED LICENSES: @@ -5581,6 +5581,9 @@ FILE: ../../../third_party/skia/src/gpu/graphite/AttachmentTypes.h FILE: ../../../third_party/skia/src/gpu/graphite/ClipStack.cpp FILE: ../../../third_party/skia/src/gpu/graphite/ClipStack_graphite.h FILE: ../../../third_party/skia/src/gpu/graphite/CommandTypes.h +FILE: ../../../third_party/skia/src/gpu/graphite/ComputePipeline.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/ComputePipeline.h +FILE: ../../../third_party/skia/src/gpu/graphite/ComputePipelineDesc.h FILE: ../../../third_party/skia/src/gpu/graphite/DrawAtlas.cpp FILE: ../../../third_party/skia/src/gpu/graphite/DrawAtlas.h FILE: ../../../third_party/skia/src/gpu/graphite/DrawCommands.h @@ -5613,6 +5616,8 @@ FILE: ../../../third_party/skia/src/gpu/graphite/UploadTask.cpp FILE: ../../../third_party/skia/src/gpu/graphite/UploadTask.h FILE: ../../../third_party/skia/src/gpu/graphite/geom/Geometry.h FILE: ../../../third_party/skia/src/gpu/graphite/geom/SubRunData.h +FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlComputePipeline.h +FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlComputePipeline.mm FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlQueueManager.h FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlQueueManager.mm FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlSampler.h @@ -6586,6 +6591,8 @@ FILE: ../../../third_party/skia/modules/skottie/src/BlendModes.cpp FILE: ../../../third_party/skia/modules/svg/include/SkSVGOpenTypeSVGDecoder.h FILE: ../../../third_party/skia/modules/svg/src/SkSVGOpenTypeSVGDecoder.cpp FILE: ../../../third_party/skia/samplecode/SampleSBIX.cpp +FILE: ../../../third_party/skia/src/codec/SkAvifCodec.cpp +FILE: ../../../third_party/skia/src/codec/SkAvifCodec.h FILE: ../../../third_party/skia/src/sfnt/SkOTTable_hmtx.h FILE: ../../../third_party/skia/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp FILE: ../../../third_party/skia/src/sksl/codegen/SkSLWGSLCodeGenerator.h From 05ccbd779f560b9e5c5f922d77129223be24d79b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 15:34:04 -0400 Subject: [PATCH 130/558] Roll Dart SDK from 344a7d12b413 to 5ef0a8c1132e (1 revision) (#35191) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c081e01d86bbf..05d11489094ae 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '344a7d12b41317a9ee0b388caad7939f06f309b9', + 'dart_revision': '5ef0a8c1132e74b66c81b4a9bc2c8b8c4f4c3766', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index c046e35202b92..658ea0ea7e31c 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 42fee749e6a564c97acc48f2e05cd339 +Signature: d864502672262ed1e8d350d67b9d64fe UNUSED LICENSES: From da4455d9c9257691c0a390eafb5e28ac04daf0c6 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 15:49:04 -0400 Subject: [PATCH 131/558] Roll Skia from f1245dcd35f8 to f5563a1a1420 (4 revisions) (#35192) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 05d11489094ae..c365277553af6 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': 'f1245dcd35f8e3e315c1c9d90325cba2edf63715', + 'skia_revision': 'f5563a1a142095db91b6ca2493081339c74750b1', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 6b293292c6728..d3a854d758aaa 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: bbf8e39570bc829b72496e3934c2ae6c +Signature: 2cde0bfc80dbfd3457fcca58f9cb7e56 UNUSED LICENSES: From 021ee4e16c82e83f5210d1491742fe2dfcc8f69e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 17:00:20 -0400 Subject: [PATCH 132/558] Roll Skia from f5563a1a1420 to 53182d5e2a93 (1 revision) (#35194) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c365277553af6..294f6c67921f9 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': 'f5563a1a142095db91b6ca2493081339c74750b1', + 'skia_revision': '53182d5e2a930114a488d7d0082e173b53e9d27d', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index d3a854d758aaa..1efad3595c198 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 2cde0bfc80dbfd3457fcca58f9cb7e56 +Signature: 00a77025f39035b13f5e650900229865 UNUSED LICENSES: From 4780caad406f653df8d2a14a60219b9e8ff27cf9 Mon Sep 17 00:00:00 2001 From: fatduckling Date: Sat, 6 Aug 2022 07:43:04 +1000 Subject: [PATCH 133/558] =?UTF-8?q?Fix=20#77084:=20flutter=20website=20doe?= =?UTF-8?q?sn't=20resize=20properly=20when=20zoomed=20in/ou=E2=80=A6=20(#3?= =?UTF-8?q?3695)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/src/engine/canvaskit/surface.dart | 1 + lib/web_ui/test/canvaskit/surface_test.dart | 48 ++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index 189a06158d35d..144aab63eb37f 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -161,6 +161,7 @@ class Surface { // The existing surface is still reusable. if (window.devicePixelRatio != _currentDevicePixelRatio) { _updateLogicalHtmlCanvasSize(); + _translateCanvas(); } return _surface!; } diff --git a/lib/web_ui/test/canvaskit/surface_test.dart b/lib/web_ui/test/canvaskit/surface_test.dart index 74038d52a4591..7253381aafa0d 100644 --- a/lib/web_ui/test/canvaskit/surface_test.dart +++ b/lib/web_ui/test/canvaskit/surface_test.dart @@ -31,16 +31,18 @@ void testMain() { expect(original.height, 19); expect(original.style.width, '9px'); expect(original.style.height, '19px'); + expect(original.style.transform, _isTranslate(0, 0)); expect(originalSurface.width(), 9); expect(originalSurface.height(), 19); - // Shrinking reuses the existing canvas straight-up. + // Shrinking reuses the existing canvas but translates it so Skia renders into the visible area. final CkSurface shrunkSurface = surface.acquireFrame(const ui.Size(5, 15)).skiaSurface; final DomCanvasElement shrunk = surface.htmlCanvas!; expect(shrunk, same(original)); expect(shrunk.style.width, '9px'); expect(shrunk.style.height, '19px'); + expect(shrunk.style.transform, _isTranslate(0, -4)); expect(shrunkSurface, isNot(same(original))); expect(shrunkSurface.width(), 5); expect(shrunkSurface.height(), 15); @@ -58,6 +60,7 @@ void testMain() { expect(firstIncrease.height, 28); expect(firstIncrease.style.width, '14px'); expect(firstIncrease.style.height, '28px'); + expect(firstIncrease.style.transform, _isTranslate(0, -8)); expect(firstIncreaseSurface.width(), 10); expect(firstIncreaseSurface.height(), 20); @@ -66,6 +69,7 @@ void testMain() { surface.acquireFrame(const ui.Size(11, 22)).skiaSurface; final DomCanvasElement secondIncrease = surface.htmlCanvas!; expect(secondIncrease, same(firstIncrease)); + expect(secondIncrease.style.transform, _isTranslate(0, -6)); expect(secondIncreaseSurface, isNot(same(firstIncreaseSurface))); expect(secondIncreaseSurface.width(), 11); expect(secondIncreaseSurface.height(), 22); @@ -81,6 +85,7 @@ void testMain() { expect(huge.height, 56); expect(huge.style.width, '28px'); expect(huge.style.height, '56px'); + expect(huge.style.transform, _isTranslate(0, -16)); expect(hugeSurface.width(), 20); expect(hugeSurface.height(), 40); @@ -89,9 +94,27 @@ void testMain() { surface.acquireFrame(const ui.Size(5, 15)).skiaSurface; final DomCanvasElement shrunk2 = surface.htmlCanvas!; expect(shrunk2, same(huge)); + expect(shrunk2.style.width, '28px'); + expect(shrunk2.style.height, '56px'); + expect(shrunk2.style.transform, _isTranslate(0, -41)); expect(shrunkSurface2, isNot(same(hugeSurface))); expect(shrunkSurface2.width(), 5); expect(shrunkSurface2.height(), 15); + + // Doubling the DPR should halve the CSS width, height, and translation of the canvas. + // This tests https://github.com/flutter/flutter/issues/77084 + window.debugOverrideDevicePixelRatio(2.0); + final CkSurface dpr2Surface2 = + surface.acquireFrame(const ui.Size(5, 15)).skiaSurface; + final DomCanvasElement dpr2Canvas = surface.htmlCanvas!; + expect(dpr2Canvas, same(huge)); + expect(dpr2Canvas.style.width, '14px'); + expect(dpr2Canvas.style.height, '28px'); + expect(dpr2Canvas.style.transform, _isTranslate(0, -20.5)); + expect(dpr2Surface2, isNot(same(hugeSurface))); + expect(dpr2Surface2.width(), 5); + expect(dpr2Surface2.height(), 15); + // Skipping on Firefox for now since Firefox headless doesn't support WebGL // This causes issues in the test since we create a Canvas-backed surface, // which cannot be a different size from the canvas. @@ -156,6 +179,7 @@ void testMain() { expect(original.height(), 16); expect(surface.htmlCanvas!.style.width, '10px'); expect(surface.htmlCanvas!.style.height, '16px'); + expect(surface.htmlCanvas!.style.transform, _isTranslate(0, 0)); // Increase device-pixel ratio: this makes CSS pixels bigger, so we need // fewer of them to cover the browser window. @@ -166,6 +190,7 @@ void testMain() { expect(highDpr.height(), 16); expect(surface.htmlCanvas!.style.width, '5px'); expect(surface.htmlCanvas!.style.height, '8px'); + expect(surface.htmlCanvas!.style.transform, _isTranslate(0, 0)); // Decrease device-pixel ratio: this makes CSS pixels smaller, so we need // more of them to cover the browser window. @@ -176,6 +201,7 @@ void testMain() { expect(lowDpr.height(), 16); expect(surface.htmlCanvas!.style.width, '20px'); expect(surface.htmlCanvas!.style.height, '32px'); + expect(surface.htmlCanvas!.style.transform, _isTranslate(0, 0)); // See https://github.com/flutter/flutter/issues/77084#issuecomment-1120151172 window.debugOverrideDevicePixelRatio(2.0); @@ -185,6 +211,26 @@ void testMain() { expect(changeRatioAndSize.height(), 16); expect(surface.htmlCanvas!.style.width, '5px'); expect(surface.htmlCanvas!.style.height, '8px'); + expect(surface.htmlCanvas!.style.transform, _isTranslate(0, 0)); }); }); } + +/// Checks that the CSS 'transform' property is a translation in a cross-browser way. +/// +/// Assumes that the `x` and `y` values are round enough for their `toString` values +/// to match the stringified CSS length value. +Matcher _isTranslate(double x, double y) { + // When the y coordinate is zero, Firefox omits it, e.g.: + // Chrome/Safari/Edge: translate(0px, 0px) + // Firefox: translate(0px) + final String fullFormat = 'translate(${x}px, ${y}px)'; + if (y != 0) { + return equals(fullFormat); + } else { + return anyOf( + fullFormat, // Non-Firefox browsers use this format. + 'translate(${x}px)', // Firefox omits y when it's zero. + ); + } +} From 8737ffbd5dc4c36e4792d4c53f1a9275e81bfa8a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 18:16:04 -0400 Subject: [PATCH 134/558] Roll Skia from 53182d5e2a93 to fa24af348971 (2 revisions) (#35197) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 294f6c67921f9..dd1a9da270550 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': '53182d5e2a930114a488d7d0082e173b53e9d27d', + 'skia_revision': 'fa24af34897155e2545498405691080060019395', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 1efad3595c198..8905b3c21262c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 00a77025f39035b13f5e650900229865 +Signature: ca946366708220961a75355aa20d865e UNUSED LICENSES: @@ -5571,6 +5571,8 @@ FILE: ../../../third_party/skia/src/core/SkShaderCodeDictionary.h FILE: ../../../third_party/skia/src/gpu/AtlasTypes.cpp FILE: ../../../third_party/skia/src/gpu/AtlasTypes.h FILE: ../../../third_party/skia/src/gpu/RefCntedCallback.h +FILE: ../../../third_party/skia/src/gpu/ganesh/GrBufferTransferRenderTask.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/GrBufferTransferRenderTask.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrImageInfo.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/tessellate/PathTessellator.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/tessellate/PathTessellator.h From ffb0ad778ee27300f03ecfc40c3472dc89b545fc Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Fri, 5 Aug 2022 15:36:04 -0700 Subject: [PATCH 135/558] [Impeller] Set the paint style to stroke for drawLine (#35198) --- impeller/display_list/display_list_dispatcher.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 77b935c1daa85..99b0e02881d5d 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -702,7 +702,9 @@ void DisplayListDispatcher::drawPaint() { // |flutter::Dispatcher| void DisplayListDispatcher::drawLine(const SkPoint& p0, const SkPoint& p1) { auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); - canvas_.DrawPath(std::move(path), paint_); + Paint paint = paint_; + paint.style = Paint::Style::kStroke; + canvas_.DrawPath(std::move(path), std::move(paint)); } // |flutter::Dispatcher| From 9dea289a38e603d2d048fa6182fde62430d275c7 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Fri, 5 Aug 2022 15:50:08 -0700 Subject: [PATCH 136/558] Roll mac clang, ignore spurious lints (#35196) --- DEPS | 2 +- common/graphics/persistent_cache.cc | 2 ++ lib/ui/painting/image_encoding.cc | 6 +++++- lib/ui/painting/multi_frame_codec.cc | 2 ++ lib/ui/painting/picture.cc | 2 ++ shell/common/shell.cc | 5 +++++ shell/platform/embedder/embedder.cc | 2 ++ .../platform/embedder/embedder_platform_message_response.cc | 2 ++ 8 files changed, 21 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index dd1a9da270550..0be5bee933e44 100644 --- a/DEPS +++ b/DEPS @@ -606,7 +606,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/clang/mac-amd64', - 'version': 'git_revision:3a20597776a5d2920e511d81653b4d2b6ca0c855' + 'version': 'git_revision:d9e02a30b16ea65a7da87913c40af03e22c9571f' } ], 'condition': 'host_os == "mac"', diff --git a/common/graphics/persistent_cache.cc b/common/graphics/persistent_cache.cc index ad96510fd588e..a68186688a0ba 100644 --- a/common/graphics/persistent_cache.cc +++ b/common/graphics/persistent_cache.cc @@ -347,6 +347,8 @@ static void PersistentCacheStore(fml::RefPtr worker, std::shared_ptr cache_directory, std::string key, std::unique_ptr value) { + // The static leak checker gets confused by the use of fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) auto task = fml::MakeCopyable([cache_directory, // file_name = std::move(key), // mapping = std::move(value) // diff --git a/lib/ui/painting/image_encoding.cc b/lib/ui/painting/image_encoding.cc index b3149f80d60bc..993e7d44a6826 100644 --- a/lib/ui/painting/image_encoding.cc +++ b/lib/ui/painting/image_encoding.cc @@ -233,7 +233,9 @@ void EncodeImageAndInvokeDataCallback( [callback = std::move(callback)](sk_sp encoded) mutable { InvokeDataCallback(std::move(callback), std::move(encoded)); }); - + // The static leak checker gets confused by the use of fml::MakeCopyable in + // EncodeImage. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) auto encode_task = [callback_task = std::move(callback_task), format, ui_task_runner](sk_sp raster_image) { sk_sp encoded = EncodeImage(std::move(raster_image), format); @@ -277,6 +279,8 @@ Dart_Handle EncodeImage(CanvasImage* canvas_image, const auto& task_runners = UIDartState::Current()->GetTaskRunners(); + // The static leak checker gets confused by the use of fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) task_runners.GetIOTaskRunner()->PostTask(fml::MakeCopyable( [callback = std::move(callback), image = canvas_image->image(), image_format, ui_task_runner = task_runners.GetUITaskRunner(), diff --git a/lib/ui/painting/multi_frame_codec.cc b/lib/ui/painting/multi_frame_codec.cc index 892dc7649e57a..0e949df080669 100644 --- a/lib/ui/painting/multi_frame_codec.cc +++ b/lib/ui/painting/multi_frame_codec.cc @@ -169,6 +169,8 @@ void MultiFrameCodec::State::GetNextFrameAndInvokeCallback( } nextFrameIndex_ = (nextFrameIndex_ + 1) % frameCount_; + // The static leak checker gets confused by the use of fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) ui_task_runner->PostTask(fml::MakeCopyable([callback = std::move(callback), image = std::move(image), duration, trace_id]() mutable { diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 2869c3fc779e7..c868101ef18cb 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -136,6 +136,8 @@ Dart_Handle Picture::RasterizeToImage( auto picture_bounds = SkISize::Make(width, height); auto ui_task = + // The static leak checker gets confused by the use of fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) fml::MakeCopyable([image_callback = std::move(image_callback), unref_queue](sk_sp raster_image) mutable { auto dart_state = image_callback->dart_state().lock(); diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 721a95295c8e2..e0931d17288f9 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -958,6 +958,8 @@ void Shell::OnPlatformViewDispatchPlatformMessage( FML_DCHECK(is_setup_); FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + // The static leak checker gets confused by the use of fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) task_runners_.GetUITaskRunner()->PostTask(fml::MakeCopyable( [engine = engine_->GetWeakPtr(), message = std::move(message)]() mutable { if (engine) { @@ -1230,6 +1232,9 @@ void Shell::OnEngineHandlePlatformMessage( [weak_platform_message_handler = std::weak_ptr(platform_message_handler_), message = std::move(message), ui_task_runner]() mutable { + // The static leak checker gets confused by the use of + // fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage) ui_task_runner->PostTask(fml::MakeCopyable( [weak_platform_message_handler, message = std::move(message), ui_task_runner]() mutable { diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index c733c1a44ec92..d69507b5f4c24 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -398,6 +398,8 @@ InferMetalPlatformViewCreationCallback( config->metal.present_command_queue), metal_dispatch_table, view_embedder); + // The static leak checker gets confused by the use of fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) return fml::MakeCopyable( [embedder_surface = std::move(embedder_surface), platform_dispatch_table, external_view_embedder = view_embedder](flutter::Shell& shell) mutable { diff --git a/shell/platform/embedder/embedder_platform_message_response.cc b/shell/platform/embedder/embedder_platform_message_response.cc index 633e1c4b0971f..6da7262a78f84 100644 --- a/shell/platform/embedder/embedder_platform_message_response.cc +++ b/shell/platform/embedder/embedder_platform_message_response.cc @@ -24,6 +24,8 @@ void EmbedderPlatformMessageResponse::Complete( } runner_->PostTask( + // The static leak checker gets confused by the use of fml::MakeCopyable. + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) fml::MakeCopyable([data = std::move(data), callback = callback_]() { callback(data->GetMapping(), data->GetSize()); })); From 7dc69ff678dcdd38e0383cd01189aae094d13f9f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 18:54:04 -0400 Subject: [PATCH 137/558] Roll Fuchsia Mac SDK from b8WQvI4f0... to -xgVZmTn2... (#35200) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 0be5bee933e44..a4093b32c9cae 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'b8WQvI4f0bUCdZLeBjaVjieKdkpiFhBOjnCOjUJLYlgC' + 'version': '-xgVZmTn2fVogC_9UuDDQg8l64i6reSC8sXF0bp4-IIC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 1ad699a60678405338a67eee64ca76d4c85976f9 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 19:25:04 -0400 Subject: [PATCH 138/558] Roll Skia from fa24af348971 to 61860c1148f3 (1 revision) (#35202) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index a4093b32c9cae..b54e39e7e3d7f 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': 'fa24af34897155e2545498405691080060019395', + 'skia_revision': '61860c1148f35fe66498be4b431372bea28872b2', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 8905b3c21262c..2c192486cc32d 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: ca946366708220961a75355aa20d865e +Signature: 10224790db3e447870f26f9112b8da30 UNUSED LICENSES: @@ -5586,6 +5586,7 @@ FILE: ../../../third_party/skia/src/gpu/graphite/CommandTypes.h FILE: ../../../third_party/skia/src/gpu/graphite/ComputePipeline.cpp FILE: ../../../third_party/skia/src/gpu/graphite/ComputePipeline.h FILE: ../../../third_party/skia/src/gpu/graphite/ComputePipelineDesc.h +FILE: ../../../third_party/skia/src/gpu/graphite/ComputeTypes.h FILE: ../../../third_party/skia/src/gpu/graphite/DrawAtlas.cpp FILE: ../../../third_party/skia/src/gpu/graphite/DrawAtlas.h FILE: ../../../third_party/skia/src/gpu/graphite/DrawCommands.h @@ -6595,6 +6596,7 @@ FILE: ../../../third_party/skia/modules/svg/src/SkSVGOpenTypeSVGDecoder.cpp FILE: ../../../third_party/skia/samplecode/SampleSBIX.cpp FILE: ../../../third_party/skia/src/codec/SkAvifCodec.cpp FILE: ../../../third_party/skia/src/codec/SkAvifCodec.h +FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlComputeCommandEncoder.h FILE: ../../../third_party/skia/src/sfnt/SkOTTable_hmtx.h FILE: ../../../third_party/skia/src/sksl/codegen/SkSLWGSLCodeGenerator.cpp FILE: ../../../third_party/skia/src/sksl/codegen/SkSLWGSLCodeGenerator.h From f047672a8f483e20b4a523bd4f94fa9032b11423 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Fri, 5 Aug 2022 16:37:41 -0700 Subject: [PATCH 139/558] [impellerc] Set file access mode of .iplr output to 0644 (#35186) --- impeller/compiler/impellerc_main.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/impeller/compiler/impellerc_main.cc b/impeller/compiler/impellerc_main.cc index 76d844c070c0c..b78807699f890 100644 --- a/impeller/compiler/impellerc_main.cc +++ b/impeller/compiler/impellerc_main.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include +#include #include "flutter/fml/backtrace.h" #include "flutter/fml/command_line.h" @@ -20,6 +21,21 @@ namespace impeller { namespace compiler { +// Sets the file access mode of the file at path 'p' to 0644. +static bool SetPermissiveAccess(const std::filesystem::path& p) { + auto permissions = + std::filesystem::perms::owner_read | std::filesystem::perms::owner_write | + std::filesystem::perms::group_read | std::filesystem::perms::others_read; + std::error_code error; + std::filesystem::permissions(p, permissions, error); + if (error) { + std::cerr << "Failed to set access on file '" << p + << "': " << error.message() << std::endl; + return false; + } + return true; +} + bool Main(const fml::CommandLine& command_line) { fml::InstallCrashHandler(); if (command_line.HasOption("help")) { @@ -110,6 +126,11 @@ bool Main(const fml::CommandLine& command_line) { << std::endl; return false; } + // Tools that consume the runtime stage data expect the access mode to + // be 0644. + if (!SetPermissiveAccess(sl_file_name)) { + return false; + } } else { if (!fml::WriteAtomically(*switches.working_directory, sl_file_name.string().c_str(), From d70259dca1e93bff0f6449283fbf63f9cc4a1456 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 5 Aug 2022 17:00:04 -0700 Subject: [PATCH 140/558] [impeller] move gaussian blur vertex uniforms to fragment uniforms (#35201) --- .../filters/gaussian_blur_filter_contents.cc | 27 ++++++++-------- impeller/entity/shaders/gaussian_blur.frag | 32 +++++++++++-------- impeller/entity/shaders/gaussian_blur.vert | 23 ------------- 3 files changed, 32 insertions(+), 50 deletions(-) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 1be110668a569..32a50b5b8ed8c 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -130,15 +130,18 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter( blur_direction_ * blur_sigma_.sigma); VS::FrameInfo frame_info; - frame_info.texture_size = Point(input_snapshot->GetCoverage().value().size); - frame_info.blur_sigma = transformed_blur.GetLength(); - frame_info.blur_radius = Radius{Sigma{frame_info.blur_sigma}}.radius; - frame_info.blur_direction = input_snapshot->transform.Invert() - .TransformDirection(transformed_blur) - .Normalize(); - frame_info.src_factor = src_color_factor_; - frame_info.inner_blur_factor = inner_blur_factor_; - frame_info.outer_blur_factor = outer_blur_factor_; + frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); + + FS::FragInfo frag_info; + frag_info.blur_sigma = transformed_blur.GetLength(); + frag_info.blur_radius = Radius{Sigma{frag_info.blur_sigma}}.radius; + frag_info.blur_direction = input_snapshot->transform.Invert() + .TransformDirection(transformed_blur) + .Normalize(); + frag_info.src_factor = src_color_factor_; + frag_info.inner_blur_factor = inner_blur_factor_; + frag_info.outer_blur_factor = outer_blur_factor_; + frag_info.texture_size = Point(input_snapshot->GetCoverage().value().size); SamplerDescriptor sampler_desc; sampler_desc.min_filter = MinMagFilter::kLinear; @@ -155,10 +158,8 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter( FS::BindTextureSampler(cmd, input_snapshot->texture, sampler); FS::BindAlphaMaskSampler(cmd, source_snapshot->texture, sampler); - - frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); - auto uniform_view = host_buffer.EmplaceUniform(frame_info); - VS::BindFrameInfo(cmd, uniform_view); + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); return pass.AddCommand(cmd); } diff --git a/impeller/entity/shaders/gaussian_blur.frag b/impeller/entity/shaders/gaussian_blur.frag index 76cac10343327..d43a05497cad8 100644 --- a/impeller/entity/shaders/gaussian_blur.frag +++ b/impeller/entity/shaders/gaussian_blur.frag @@ -14,31 +14,35 @@ uniform sampler2D texture_sampler; uniform sampler2D alpha_mask_sampler; +uniform FragInfo { + vec2 texture_size; + vec2 blur_direction; + + float blur_sigma; + float blur_radius; + float src_factor; + float inner_blur_factor; + float outer_blur_factor; +} frag_info; + in vec2 v_texture_coords; in vec2 v_src_texture_coords; -in vec2 v_texture_size; -in vec2 v_blur_direction; -in float v_blur_sigma; -in float v_blur_radius; -in float v_src_factor; -in float v_inner_blur_factor; -in float v_outer_blur_factor; out vec4 frag_color; const float kSqrtTwoPi = 2.50662827463; float Gaussian(float x) { - float variance = v_blur_sigma * v_blur_sigma; - return exp(-0.5 * x * x / variance) / (kSqrtTwoPi * v_blur_sigma); + float variance = frag_info.blur_sigma * frag_info.blur_sigma; + return exp(-0.5 * x * x / variance) / (kSqrtTwoPi * frag_info.blur_sigma); } void main() { vec4 total_color = vec4(0); float gaussian_integral = 0; - vec2 blur_uv_offset = v_blur_direction / v_texture_size; + vec2 blur_uv_offset = frag_info.blur_direction / frag_info.texture_size; - for (float i = -v_blur_radius; i <= v_blur_radius; i++) { + for (float i = -frag_info.blur_radius; i <= frag_info.blur_radius; i++) { float gaussian = Gaussian(i); gaussian_integral += gaussian; total_color += @@ -50,8 +54,8 @@ void main() { vec4 src_color = IPSampleClampToBorder(alpha_mask_sampler, v_src_texture_coords); - float blur_factor = v_inner_blur_factor * float(src_color.a > 0) + - v_outer_blur_factor * float(src_color.a == 0); + float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) + + frag_info.outer_blur_factor * float(src_color.a == 0); - frag_color = blur_color * blur_factor + src_color * v_src_factor; + frag_color = blur_color * blur_factor + src_color * frag_info.src_factor; } diff --git a/impeller/entity/shaders/gaussian_blur.vert b/impeller/entity/shaders/gaussian_blur.vert index 1a66dc0eb5a86..0fd3595a2d267 100644 --- a/impeller/entity/shaders/gaussian_blur.vert +++ b/impeller/entity/shaders/gaussian_blur.vert @@ -4,15 +4,6 @@ uniform FrameInfo { mat4 mvp; - vec2 texture_size; - - vec2 blur_direction; - float blur_sigma; - float blur_radius; - - float src_factor; - float inner_blur_factor; - float outer_blur_factor; } frame_info; @@ -22,23 +13,9 @@ in vec2 src_texture_coords; out vec2 v_texture_coords; out vec2 v_src_texture_coords; -out vec2 v_texture_size; -out vec2 v_blur_direction; -out float v_blur_sigma; -out float v_blur_radius; -out float v_src_factor; -out float v_inner_blur_factor; -out float v_outer_blur_factor; void main() { gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); v_texture_coords = texture_coords; v_src_texture_coords = src_texture_coords; - v_texture_size = frame_info.texture_size; - v_blur_direction = frame_info.blur_direction; - v_blur_sigma = frame_info.blur_sigma; - v_blur_radius = frame_info.blur_radius; - v_src_factor = frame_info.src_factor; - v_inner_blur_factor = frame_info.inner_blur_factor; - v_outer_blur_factor = frame_info.outer_blur_factor; } From d1e5b60361b771736b4ee3e62af1929bad202070 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 20:07:16 -0400 Subject: [PATCH 141/558] Roll Dart SDK from 5ef0a8c1132e to 6eebffce0ad0 (1 revision) (#35203) --- DEPS | 6 +++--- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index b54e39e7e3d7f..04d4ac719ab93 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '5ef0a8c1132e74b66c81b4a9bc2c8b8c4f4c3766', + 'dart_revision': '6eebffce0ad0ac5cbe0666151d1e0c214d79591f', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -46,7 +46,7 @@ vars = { 'dart_clock_rev': '2507a228773c5e877fc9e3330080b234aad965c0', 'dart_collection_rev': '414ffa1bc8ba18bd608bbf916d95715311d89ac1', 'dart_devtools_rev': 'd131d19091f6b89ac89486bd92440a25a523e8b0', - 'dart_protobuf_rev': '504eefeae9892602ea50c20159db1db3768012a9', + 'dart_protobuf_rev': '11983dafc42775c56698af06107d626780e9cb69', 'dart_pub_rev': 'ac7db6c07318efa4a8712110275eaf70f96a6d00', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': 'e00c0ea769e32821d91c0880da8eb736839a6e6d', @@ -203,7 +203,7 @@ deps = { Var('dart_git') + '/dart_style.git@d7b73536a8079331c888b7da539b80e6825270ea', 'src/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@bd57c0e7b7562abda6d556ce5a386b67fb4ff4c7', + Var('dart_git') + '/dartdoc.git@f419695f57c580f30ea142a0f6e13a9e0001b342', 'src/third_party/dart/third_party/pkg/ffi': Var('dart_git') + '/ffi.git@18b2b549d55009ff594600b04705ff6161681e07', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 658ea0ea7e31c..dbf95cdbed780 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: d864502672262ed1e8d350d67b9d64fe +Signature: 8b3783746d873aa6b4c122e923d8e021 UNUSED LICENSES: From 490e6e93d23fcb14c9f4d4ca9ee106449e5c1bc0 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 5 Aug 2022 22:15:04 -0400 Subject: [PATCH 142/558] Roll Skia from 61860c1148f3 to e8674a8843e2 (1 revision) (#35206) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 04d4ac719ab93..d6642b551242b 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': '61860c1148f35fe66498be4b431372bea28872b2', + 'skia_revision': 'e8674a8843e228a0a8b8cbc7d0c453f226a734d7', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 2c192486cc32d..01a88bee4b1c7 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 10224790db3e447870f26f9112b8da30 +Signature: 5c5f8a671d9d36bb88dc592299dbb538 UNUSED LICENSES: From 4f2c7a6c6d8970cb6cdb589249ff2a8fad10512f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 6 Aug 2022 00:42:04 -0400 Subject: [PATCH 143/558] Roll Fuchsia Linux SDK from kURZcohuz... to IquPxiSps... (#35208) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d6642b551242b..f55f1cadad7df 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'kURZcohuz6mq5S1wEFQj9GX1TPgSbXJaR6bovSLYXNkC' + 'version': 'IquPxiSps31Z9wg6QPR98cvs1kLzxAPV9buGL_JtWvkC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 86cbe5612fbc3..b4bb07b7d8f4b 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: f41310cddc9d45d4aa33637e4b56826e +Signature: 1d9fa08c738bc928c8e069e8818b1ca0 UNUSED LICENSES: From fa8e3dd8227c3964d2347ad4894ecd6ffa5603ac Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Fri, 5 Aug 2022 22:31:23 -0700 Subject: [PATCH 144/558] Disable clang-tidy pre-push hook by default (#35207) --- tools/githooks/lib/githooks.dart | 4 ++++ tools/githooks/lib/src/pre_push_command.dart | 13 +++++++++++-- tools/githooks/pre-push | 15 ++++++++++++--- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/tools/githooks/lib/githooks.dart b/tools/githooks/lib/githooks.dart index aedcac4db1479..14c3d4349fff7 100644 --- a/tools/githooks/lib/githooks.dart +++ b/tools/githooks/lib/githooks.dart @@ -19,6 +19,10 @@ Future run(List args) async { // Add top-level arguments. runner.argParser + ..addFlag( + 'enable-clang-tidy', + help: 'Enable running clang-tidy on changed files.', + ) ..addOption( 'flutter', abbr: 'f', diff --git a/tools/githooks/lib/src/pre_push_command.dart b/tools/githooks/lib/src/pre_push_command.dart index 80b653cbabe71..6b456cbe53ebe 100644 --- a/tools/githooks/lib/src/pre_push_command.dart +++ b/tools/githooks/lib/src/pre_push_command.dart @@ -20,10 +20,18 @@ class PrePushCommand extends Command { Future run() async { final Stopwatch sw = Stopwatch()..start(); final bool verbose = globalResults!['verbose']! as bool; + final bool enableClangTidy = globalResults!['enable-clang-tidy']! as bool; final String flutterRoot = globalResults!['flutter']! as String; + + if (!enableClangTidy) { + print('The clang-tidy check is disabled. To enable set the environment ' + 'variable PRE_PUSH_CLANG_TIDY to any value.'); + } + final List checkResults = [ await _runFormatter(flutterRoot, verbose), - await _runClangTidy(flutterRoot, verbose), + if (enableClangTidy) + await _runClangTidy(flutterRoot, verbose), ]; sw.stop(); io.stdout.writeln('pre-push checks finished in ${sw.elapsed}'); @@ -51,7 +59,8 @@ class PrePushCommand extends Command { 'compile_commands.json', )); if (!compileCommands.existsSync()) { - io.stderr.writeln('clang-tidy requires a fully built host_debug or host_debug_unopt build directory'); + io.stderr.writeln('clang-tidy requires a fully built host_debug or ' + 'host_debug_unopt build directory'); return false; } } diff --git a/tools/githooks/pre-push b/tools/githooks/pre-push index 2d0651e40ddaf..4e10ce870add5 100755 --- a/tools/githooks/pre-push +++ b/tools/githooks/pre-push @@ -15,15 +15,24 @@ import sys SRC_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) FLUTTER_DIR = os.path.join(SRC_ROOT, 'flutter') DART_BIN = os.path.join(SRC_ROOT, 'third_party', 'dart', 'tools', 'sdks', 'dart-sdk', 'bin') - +ENABLE_CLANG_TIDY = os.environ.get('PRE_PUSH_CLANG_TIDY') def Main(argv): + githook_args = [ + '--flutter', + FLUTTER_DIR, + ] + + if ENABLE_CLANG_TIDY is not None: + githook_args += [ + '--enable-clang-tidy', + ] + result = subprocess.run([ os.path.join(DART_BIN, 'dart'), '--disable-dart-dev', os.path.join(FLUTTER_DIR, 'tools', 'githooks', 'bin', 'main.dart'), - '--flutter', - FLUTTER_DIR, + ] + githook_args + [ 'pre-push', ], cwd=SRC_ROOT) return result.returncode From 2323f70cab3b481d2f586cdb1d5b45ebc417e3bd Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Fri, 5 Aug 2022 22:59:04 -0700 Subject: [PATCH 145/558] [Impeller] Implement drawPoints in Impeller (#35204) --- .../display_list/display_list_dispatcher.cc | 36 ++++++++++++++++++- .../display_list/display_list_unittests.cc | 33 +++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 99b0e02881d5d..9560f1991b2e4 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -762,7 +762,41 @@ void DisplayListDispatcher::drawArc(const SkRect& oval_bounds, void DisplayListDispatcher::drawPoints(SkCanvas::PointMode mode, uint32_t count, const SkPoint points[]) { - UNIMPLEMENTED; + // auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); + Paint paint = paint_; + paint.style = Paint::Style::kStroke; + switch (mode) { + case SkCanvas::kPoints_PointMode: + if (paint.stroke_cap == SolidStrokeContents::Cap::kButt) { + paint.stroke_cap = SolidStrokeContents::Cap::kSquare; + } + for (uint32_t i = 0; i < count; i++) { + SkPoint p0 = points[i]; + // kEhCloseEnough works around a bug where Impeller does not draw + // anything for zero-length lines. + // See: https://github.com/flutter/flutter/issues/109077 + SkPoint p1 = points[i] + SkPoint{kEhCloseEnough, 0.0}; + auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); + canvas_.DrawPath(std::move(path), paint); + } + break; + case SkCanvas::kLines_PointMode: + for (uint32_t i = 1; i < count; i += 2) { + SkPoint p0 = points[i - 1]; + SkPoint p1 = points[i]; + auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); + canvas_.DrawPath(std::move(path), paint); + } + break; + case SkCanvas::kPolygon_PointMode: + for (uint32_t i = 1; i < count; i++) { + SkPoint p0 = points[i - 1]; + SkPoint p1 = points[i]; + auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); + canvas_.DrawPath(std::move(path), paint); + } + break; + } } // |flutter::Dispatcher| diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index 6cfbec35cfac0..f895bb7f8f0ca 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -433,5 +433,38 @@ TEST_P(DisplayListTest, CanDrawNinePatchImageCornersScaledDown) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(DisplayListTest, CanDrawPoints) { + flutter::DisplayListBuilder builder; + SkPoint points[7] = { + {0, 0}, // + {100, 100}, // + {100, 0}, // + {0, 100}, // + {0, 0}, // + {48, 48}, // + {52, 52}, // + }; + std::vector caps = { + flutter::DlStrokeCap::kButt, + flutter::DlStrokeCap::kRound, + flutter::DlStrokeCap::kSquare, + }; + flutter::DlPaint paint = flutter::DlPaint().setStrokeWidth(20); + builder.translate(50, 50); + for (auto cap : caps) { + paint.setStrokeCap(cap); + paint.setColor(flutter::DlColor::kYellow().withAlpha(127)); + builder.save(); + builder.drawPoints(SkCanvas::kPoints_PointMode, 7, points, paint); + builder.translate(150, 0); + builder.drawPoints(SkCanvas::kLines_PointMode, 5, points, paint); + builder.translate(150, 0); + builder.drawPoints(SkCanvas::kPolygon_PointMode, 5, points, paint); + builder.restore(); + builder.translate(0, 150); + } + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller From d94fc416b1ff020df3c0b03e5430687fa43f8a25 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 6 Aug 2022 02:38:05 -0400 Subject: [PATCH 146/558] Roll Dart SDK from 6eebffce0ad0 to f5f8d3a6ed77 (1 revision) (#35210) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f55f1cadad7df..7ca91a6062644 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '6eebffce0ad0ac5cbe0666151d1e0c214d79591f', + 'dart_revision': 'f5f8d3a6ed779ca481a2a4499bfbc50c8f3db88f', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index dbf95cdbed780..e8aab7a3745d4 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 8b3783746d873aa6b4c122e923d8e021 +Signature: d49b5ea81116741dbea37072e33826d3 UNUSED LICENSES: From 1e05711b36dba3844e44676854f77a8e57ee329f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 6 Aug 2022 10:47:19 -0400 Subject: [PATCH 147/558] Roll Skia from e8674a8843e2 to 5fa8e1b9695b (1 revision) (#35211) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 7ca91a6062644..f05557da978b5 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': 'e8674a8843e228a0a8b8cbc7d0c453f226a734d7', + 'skia_revision': '5fa8e1b9695b8a0807690f53118a090eb80b3fc0', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 01a88bee4b1c7..550695af06070 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 5c5f8a671d9d36bb88dc592299dbb538 +Signature: 17b695b6185162d4a096c59505b4ffa8 UNUSED LICENSES: From a195b6b6f35a3751ab189fd10fd73df6e427cd9a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 6 Aug 2022 11:48:05 -0400 Subject: [PATCH 148/558] Roll Fuchsia Mac SDK from -xgVZmTn2... to hXdBVXep4... (#35212) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index f05557da978b5..510d00056e12b 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': '-xgVZmTn2fVogC_9UuDDQg8l64i6reSC8sXF0bp4-IIC' + 'version': 'hXdBVXep4gdAe3kQAZrmHFjSv4cnNhnWZoYtlhYnkWUC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From bb8a77c64f69b0306cd5f06a94c075751371209f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 6 Aug 2022 13:54:05 -0400 Subject: [PATCH 149/558] Roll Fuchsia Linux SDK from IquPxiSps... to LgfFaXyiR... (#35214) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 510d00056e12b..307e7ecd2d07b 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'IquPxiSps31Z9wg6QPR98cvs1kLzxAPV9buGL_JtWvkC' + 'version': 'LgfFaXyiR6MnCJ2p91rB3U7-ra5b7rylxu6aP5XgCK4C' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index b4bb07b7d8f4b..383a7a8b5f0bc 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 1d9fa08c738bc928c8e069e8818b1ca0 +Signature: ce3cce2f697b2ee926d72b8612f27e41 UNUSED LICENSES: @@ -3258,7 +3258,6 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.sys/access.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.sys/bootstrap.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.sys/host_watcher.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.sys/identity.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.sys/pairing_delegate.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth.sys/peer.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth/address.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.bluetooth/appearance.fidl From b6b8f310c4b2ef2bfc4dd2f8b8de2e95b2faa5c1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 6 Aug 2022 15:04:04 -0400 Subject: [PATCH 150/558] Roll Dart SDK from f5f8d3a6ed77 to b000b496801f (1 revision) (#35215) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 307e7ecd2d07b..3873d2a5fd0bb 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'f5f8d3a6ed779ca481a2a4499bfbc50c8f3db88f', + 'dart_revision': 'b000b496801fb2ba641a5a0a70081f7492f09734', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index e8aab7a3745d4..c862926ceff9c 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: d49b5ea81116741dbea37072e33826d3 +Signature: 66a27e79ea91d7a9d2435d0d9b248633 UNUSED LICENSES: From f441093e02a5eb5264f32cbbd2defe7aee7f00ff Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 7 Aug 2022 00:43:16 -0400 Subject: [PATCH 151/558] Roll Fuchsia Mac SDK from hXdBVXep4... to rEqCGReKL... (#35216) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 3873d2a5fd0bb..54a529721f697 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'hXdBVXep4gdAe3kQAZrmHFjSv4cnNhnWZoYtlhYnkWUC' + 'version': 'rEqCGReKLj3RZO_B8dU15y0PBaS-cBmxfbQGEEaAGRwC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From b813f1eeae04b04620a7c32202bc35b299275e33 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 7 Aug 2022 03:00:05 -0400 Subject: [PATCH 152/558] Roll Fuchsia Linux SDK from LgfFaXyiR... to Bt-IEfyRC... (#35217) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 54a529721f697..4f0b1ddab701f 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'LgfFaXyiR6MnCJ2p91rB3U7-ra5b7rylxu6aP5XgCK4C' + 'version': 'Bt-IEfyRCPemi3EPOLadg8UQLsKDK5474BtzmiRGJqAC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 383a7a8b5f0bc..5f8233bc69ee1 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: ce3cce2f697b2ee926d72b8612f27e41 +Signature: 4b254a6daed5421c5333fe7f46d4a596 UNUSED LICENSES: From 1736a5562c4fc521ffc6a81bff467706ed23699f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 7 Aug 2022 06:49:04 -0400 Subject: [PATCH 153/558] Roll Skia from 5fa8e1b9695b to 11422e1da7ea (1 revision) (#35218) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 4f0b1ddab701f..de7d608861011 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': '5fa8e1b9695b8a0807690f53118a090eb80b3fc0', + 'skia_revision': '11422e1da7ea8cc358ed31145beac52790b36db1', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 550695af06070..6dc25f46a84bd 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 17b695b6185162d4a096c59505b4ffa8 +Signature: 61bce20ac88459b1a7d4ec3dc12908f8 UNUSED LICENSES: From 31834da2d97ffd3d88aea66f1bcd69ce8fc802b1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 7 Aug 2022 13:37:04 -0400 Subject: [PATCH 154/558] Roll Fuchsia Mac SDK from rEqCGReKL... to K5pKmPOVD... (#35219) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index de7d608861011..a06e4ca929ad6 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'rEqCGReKLj3RZO_B8dU15y0PBaS-cBmxfbQGEEaAGRwC' + 'version': 'K5pKmPOVDmXgyUVnViVgYsjAEcir_VXDTSpNgy-Y--cC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From cae2f2b67449377799936dc64ffdfeb831ed6b07 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 7 Aug 2022 15:22:05 -0400 Subject: [PATCH 155/558] Roll Dart SDK from b000b496801f to f0036572af95 (1 revision) (#35220) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index a06e4ca929ad6..d196d92912076 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'b000b496801fb2ba641a5a0a70081f7492f09734', + 'dart_revision': 'f0036572af9511bbcd1bee7aaf872b394007c5c3', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From a8dec842673221ca65d7cf89cd1923687291bbc8 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 7 Aug 2022 16:12:05 -0400 Subject: [PATCH 156/558] Roll Fuchsia Linux SDK from Bt-IEfyRC... to 3P9_-_bI6... (#35221) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d196d92912076..93513abd45210 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'Bt-IEfyRCPemi3EPOLadg8UQLsKDK5474BtzmiRGJqAC' + 'version': '3P9_-_bI6KCZAMnhGITNDmLSos-tSSTA68e4LBYr_ZgC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 5f8233bc69ee1..1c01a69cd7846 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 4b254a6daed5421c5333fe7f46d4a596 +Signature: 35712eb420078e6972dc6230dfecfe33 UNUSED LICENSES: From 5e33a1f88a3e4fe8cabfdfaee0c67ee073fb40e0 Mon Sep 17 00:00:00 2001 From: magicianA Date: Mon, 8 Aug 2022 10:37:21 +0800 Subject: [PATCH 157/558] [Impeller] EntityPass should cover the whole screen for some blend modes (#35157) --- impeller/aiks/aiks_unittests.cc | 25 +++++++++++++++++++++++++ impeller/entity/entity.cc | 20 ++++++++++++++++++++ impeller/entity/entity.h | 2 ++ impeller/entity/entity_pass.cc | 6 +++++- impeller/entity/entity_pass.h | 2 +- 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 55e5a9f1e6dd3..edd552f17d84d 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -252,6 +252,31 @@ TEST_P(AiksTest, CanRenderRadialGradient) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, BlendModeShouldCoverWholeScreen) { + Canvas canvas; + Paint paint; + + paint.color = Color::Red(); + canvas.DrawPaint(paint); + + paint.blend_mode = Entity::BlendMode::kSourceOver; + canvas.SaveLayer(paint); + + paint.color = Color::White(); + canvas.DrawRect({100, 100, 400, 400}, paint); + + paint.blend_mode = Entity::BlendMode::kSource; + canvas.SaveLayer(paint); + + paint.color = Color::Blue(); + canvas.DrawRect({200, 200, 200, 200}, paint); + + canvas.Restore(); + canvas.Restore(); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + TEST_P(AiksTest, CanRenderGroupOpacity) { Canvas canvas; diff --git a/impeller/entity/entity.cc b/impeller/entity/entity.cc index e5695ef8017be..56f534a880da2 100644 --- a/impeller/entity/entity.cc +++ b/impeller/entity/entity.cc @@ -42,6 +42,9 @@ std::optional Entity::GetCoverage() const { } bool Entity::ShouldRender(const ISize& target_size) const { + if (BlendModeShouldCoverWholeScreen(blend_mode_)) { + return true; + } return contents_->ShouldRender(*this, target_size); } @@ -73,6 +76,23 @@ Entity::BlendMode Entity::GetBlendMode() const { return blend_mode_; } +bool Entity::BlendModeShouldCoverWholeScreen(BlendMode blend_mode) { + switch (blend_mode) { + case BlendMode::kClear: + case BlendMode::kSource: + case BlendMode::kSourceIn: + case BlendMode::kDestinationIn: + case BlendMode::kSourceOut: + case BlendMode::kDestinationOut: + case BlendMode::kDestinationATop: + case BlendMode::kXor: + case BlendMode::kModulate: + return true; + default: + return false; + } +} + bool Entity::Render(const ContentContext& renderer, RenderPass& parent_pass) const { if (!contents_) { diff --git a/impeller/entity/entity.h b/impeller/entity/entity.h index b79ce60699260..8c787e2c77359 100644 --- a/impeller/entity/entity.h +++ b/impeller/entity/entity.h @@ -121,6 +121,8 @@ class Entity { bool Render(const ContentContext& renderer, RenderPass& parent_pass) const; + static bool BlendModeShouldCoverWholeScreen(BlendMode blend_mode); + private: Matrix transformation_; std::shared_ptr contents_; diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 5cae1fc91b266..442862a7ac2b9 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -252,7 +252,10 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( auto subpass_coverage = GetSubpassCoverage(*subpass, Rect::MakeSize(root_pass_size)); - + if (subpass->cover_whole_screen) { + subpass_coverage = Rect( + position, Size(pass_context.GetRenderTarget().GetRenderTargetSize())); + } if (backdrop_contents) { auto backdrop_coverage = backdrop_contents->GetCoverage(Entity{}); if (backdrop_coverage.has_value()) { @@ -501,6 +504,7 @@ void EntityPass::SetStencilDepth(size_t stencil_depth) { void EntityPass::SetBlendMode(Entity::BlendMode blend_mode) { blend_mode_ = blend_mode; + cover_whole_screen = Entity::BlendModeShouldCoverWholeScreen(blend_mode); } void EntityPass::SetBackdropFilter(std::optional proc) { diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index 87c7bddd4cd33..7ec177f68f5c8 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -114,7 +114,7 @@ class EntityPass { Matrix xformation_; size_t stencil_depth_ = 0u; Entity::BlendMode blend_mode_ = Entity::BlendMode::kSourceOver; - + bool cover_whole_screen = false; /// This flag is set to `true` whenever an entity is added to the pass that /// requires reading the pass texture during rendering. This can happen in the /// following scenarios: From f1fcb7557335e24d506e7fbfd6dee27e3305e89d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 01:47:04 -0400 Subject: [PATCH 158/558] Roll Skia from 11422e1da7ea to 9277962b84de (1 revision) (#35222) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 93513abd45210..c6e6298d6776c 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': '11422e1da7ea8cc358ed31145beac52790b36db1', + 'skia_revision': '9277962b84deaf370cce1d64329ab5eef29fb303', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 6dc25f46a84bd..3f01346333838 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 61bce20ac88459b1a7d4ec3dc12908f8 +Signature: 2f02dba667d939ef4b75afa037c73bf8 UNUSED LICENSES: From e3477e47397059976ea2a704538ae638abc07487 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Sun, 7 Aug 2022 23:09:04 -0700 Subject: [PATCH 159/558] add check to prevent using DLCanvasRecorder after Build (#35172) --- display_list/display_list_canvas_recorder.cc | 42 ++++++++++++++++++++ display_list/display_list_unittests.cc | 11 +++++ 2 files changed, 53 insertions(+) diff --git a/display_list/display_list_canvas_recorder.cc b/display_list/display_list_canvas_recorder.cc index 37b27eb935735..406ee96015bc9 100644 --- a/display_list/display_list_canvas_recorder.cc +++ b/display_list/display_list_canvas_recorder.cc @@ -10,11 +10,21 @@ namespace flutter { +#define CHECK_DISPOSE(ret) \ + do { \ + if (!builder_) { \ + FML_DCHECK(builder_) \ + << "Calling method on DisplayListCanvasRecorder after Build()"; \ + return ret; \ + } \ + } while (0) + DisplayListCanvasRecorder::DisplayListCanvasRecorder(const SkRect& bounds) : SkCanvasVirtualEnforcer(bounds.width(), bounds.height()), builder_(sk_make_sp(bounds)) {} sk_sp DisplayListCanvasRecorder::Build() { + CHECK_DISPOSE(nullptr); sk_sp display_list = builder_->Build(); builder_.reset(); return display_list; @@ -22,44 +32,53 @@ sk_sp DisplayListCanvasRecorder::Build() { // clang-format off void DisplayListCanvasRecorder::didConcat44(const SkM44& m44) { + CHECK_DISPOSE(); builder_->transform(m44); } // clang-format on void DisplayListCanvasRecorder::didSetM44(const SkM44& matrix) { + CHECK_DISPOSE(); builder_->transformReset(); builder_->transform(matrix); } void DisplayListCanvasRecorder::didTranslate(SkScalar tx, SkScalar ty) { + CHECK_DISPOSE(); builder_->translate(tx, ty); } void DisplayListCanvasRecorder::didScale(SkScalar sx, SkScalar sy) { + CHECK_DISPOSE(); builder_->scale(sx, sy); } void DisplayListCanvasRecorder::onClipRect(const SkRect& rect, SkClipOp clip_op, ClipEdgeStyle edge_style) { + CHECK_DISPOSE(); builder_->clipRect(rect, clip_op, edge_style == ClipEdgeStyle::kSoft_ClipEdgeStyle); } void DisplayListCanvasRecorder::onClipRRect(const SkRRect& rrect, SkClipOp clip_op, ClipEdgeStyle edge_style) { + CHECK_DISPOSE(); builder_->clipRRect(rrect, clip_op, edge_style == ClipEdgeStyle::kSoft_ClipEdgeStyle); } void DisplayListCanvasRecorder::onClipPath(const SkPath& path, SkClipOp clip_op, ClipEdgeStyle edge_style) { + CHECK_DISPOSE(); builder_->clipPath(path, clip_op, edge_style == ClipEdgeStyle::kSoft_ClipEdgeStyle); } void DisplayListCanvasRecorder::willSave() { + CHECK_DISPOSE(); builder_->save(); } SkCanvas::SaveLayerStrategy DisplayListCanvasRecorder::getSaveLayerStrategy( const SaveLayerRec& rec) { + CHECK_DISPOSE(SaveLayerStrategy::kNoLayer_SaveLayerStrategy); std::shared_ptr backdrop = DlImageFilter::From(rec.fBackdrop); if (rec.fPaint) { builder_->setAttributesFromPaint(*rec.fPaint, kSaveLayerWithPaintFlags); @@ -72,31 +91,37 @@ SkCanvas::SaveLayerStrategy DisplayListCanvasRecorder::getSaveLayerStrategy( return SaveLayerStrategy::kNoLayer_SaveLayerStrategy; } void DisplayListCanvasRecorder::didRestore() { + CHECK_DISPOSE(); builder_->restore(); } void DisplayListCanvasRecorder::onDrawPaint(const SkPaint& paint) { + CHECK_DISPOSE(); builder_->setAttributesFromPaint(paint, kDrawPaintFlags); builder_->drawPaint(); } void DisplayListCanvasRecorder::onDrawRect(const SkRect& rect, const SkPaint& paint) { + CHECK_DISPOSE(); builder_->setAttributesFromPaint(paint, kDrawRectFlags); builder_->drawRect(rect); } void DisplayListCanvasRecorder::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { + CHECK_DISPOSE(); builder_->setAttributesFromPaint(paint, kDrawRRectFlags); builder_->drawRRect(rrect); } void DisplayListCanvasRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { + CHECK_DISPOSE(); builder_->setAttributesFromPaint(paint, kDrawDRRectFlags); builder_->drawDRRect(outer, inner); } void DisplayListCanvasRecorder::onDrawOval(const SkRect& rect, const SkPaint& paint) { + CHECK_DISPOSE(); builder_->setAttributesFromPaint(paint, kDrawOvalFlags); builder_->drawOval(rect); } @@ -105,6 +130,7 @@ void DisplayListCanvasRecorder::onDrawArc(const SkRect& rect, SkScalar sweepAngle, bool useCenter, const SkPaint& paint) { + CHECK_DISPOSE(); builder_->setAttributesFromPaint(paint, useCenter // ? kDrawArcWithCenterFlags @@ -113,6 +139,7 @@ void DisplayListCanvasRecorder::onDrawArc(const SkRect& rect, } void DisplayListCanvasRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) { + CHECK_DISPOSE(); builder_->setAttributesFromPaint(paint, kDrawPathFlags); builder_->drawPath(path); } @@ -121,6 +148,7 @@ void DisplayListCanvasRecorder::onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { + CHECK_DISPOSE(); switch (mode) { case SkCanvas::kPoints_PointMode: builder_->setAttributesFromPaint(paint, kDrawPointsAsPointsFlags); @@ -146,6 +174,7 @@ void DisplayListCanvasRecorder::onDrawPoints(SkCanvas::PointMode mode, void DisplayListCanvasRecorder::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) { + CHECK_DISPOSE(); builder_->setAttributesFromPaint(paint, kDrawVerticesFlags); builder_->drawSkVertices(sk_ref_sp(vertices), mode); } @@ -155,6 +184,7 @@ void DisplayListCanvasRecorder::onDrawImage2(const SkImage* image, SkScalar dy, const SkSamplingOptions& sampling, const SkPaint* paint) { + CHECK_DISPOSE(); if (paint != nullptr) { builder_->setAttributesFromPaint(*paint, kDrawImageWithPaintFlags); } @@ -168,6 +198,7 @@ void DisplayListCanvasRecorder::onDrawImageRect2( const SkSamplingOptions& sampling, const SkPaint* paint, SrcRectConstraint constraint) { + CHECK_DISPOSE(); if (paint != nullptr) { builder_->setAttributesFromPaint(*paint, kDrawImageRectWithPaintFlags); } @@ -179,6 +210,7 @@ void DisplayListCanvasRecorder::onDrawImageLattice2(const SkImage* image, const SkRect& dst, SkFilterMode filter, const SkPaint* paint) { + CHECK_DISPOSE(); if (paint != nullptr) { // SkCanvas will always construct a paint, // though it is a default paint most of the time @@ -201,6 +233,7 @@ void DisplayListCanvasRecorder::onDrawAtlas2(const SkImage* image, const SkSamplingOptions& sampling, const SkRect* cull, const SkPaint* paint) { + CHECK_DISPOSE(); if (paint != nullptr) { builder_->setAttributesFromPaint(*paint, kDrawAtlasWithPaintFlags); } @@ -213,6 +246,7 @@ void DisplayListCanvasRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { + CHECK_DISPOSE(); builder_->setAttributesFromPaint(paint, kDrawTextBlobFlags); builder_->drawTextBlob(sk_ref_sp(blob), x, y); } @@ -220,6 +254,7 @@ void DisplayListCanvasRecorder::onDrawTextBlob(const SkTextBlob* blob, void DisplayListCanvasRecorder::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { + CHECK_DISPOSE(); if (paint != nullptr) { builder_->setAttributesFromPaint(*paint, kDrawPictureWithPaintFlags); } @@ -228,6 +263,7 @@ void DisplayListCanvasRecorder::onDrawPicture(const SkPicture* picture, void DisplayListCanvasRecorder::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) { + CHECK_DISPOSE(); // Skia does not expose the SkDrawShadowRec structure in a public // header file so we cannot record this operation. // See: https://bugs.chromium.org/p/skia/issues/detail?id=12125 @@ -236,12 +272,14 @@ void DisplayListCanvasRecorder::onDrawShadowRec(const SkPath& path, } void DisplayListCanvasRecorder::onDrawBehind(const SkPaint&) { + CHECK_DISPOSE(); FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::" << __FUNCTION__; } void DisplayListCanvasRecorder::onDrawRegion(const SkRegion& region, const SkPaint& paint) { + CHECK_DISPOSE(); FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::" << __FUNCTION__; } @@ -251,6 +289,7 @@ void DisplayListCanvasRecorder::onDrawPatch(const SkPoint cubics[12], const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint) { + CHECK_DISPOSE(); FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::" << __FUNCTION__; } @@ -260,6 +299,7 @@ void DisplayListCanvasRecorder::onDrawEdgeAAQuad(const SkRect& rect, SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, SkBlendMode mode) { + CHECK_DISPOSE(); FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::" << __FUNCTION__; } @@ -267,12 +307,14 @@ void DisplayListCanvasRecorder::onDrawEdgeAAQuad(const SkRect& rect, void DisplayListCanvasRecorder::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) { + CHECK_DISPOSE(); FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::" << __FUNCTION__; } void DisplayListCanvasRecorder::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { + CHECK_DISPOSE(); FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::" << __FUNCTION__; } diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index 9f6a7675e7d4b..ea8dfc0cbee44 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -21,6 +21,17 @@ namespace testing { static std::vector allGroups = CreateAllGroups(); +#ifndef NDEBUG +TEST(DisplayList, CallMethodAfterBuild) { + DisplayListCanvasRecorder recorder(kTestBounds); + recorder.drawRect(kTestBounds, SkPaint()); + recorder.Build(); + EXPECT_DEATH_IF_SUPPORTED( + recorder.drawRect(kTestBounds, SkPaint()), + "Calling method on DisplayListCanvasRecorder after Build\\(\\)"); +} +#endif // NDEBUG + TEST(DisplayList, SingleOpSizes) { for (auto& group : allGroups) { for (size_t i = 0; i < group.variants.size(); i++) { From c0695b9ddd144c2d1e7c63c80b81f1873326f291 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 02:36:04 -0400 Subject: [PATCH 160/558] Roll Fuchsia Mac SDK from K5pKmPOVD... to kP-yebuRg... (#35223) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index c6e6298d6776c..0f96beded8cdf 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'K5pKmPOVDmXgyUVnViVgYsjAEcir_VXDTSpNgy-Y--cC' + 'version': 'kP-yebuRgWYJ6_f1FfLyRz5Ax98cvWNY5e3Z6STYNBkC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 5a7175265d6acca1e15ca7d7248da42ec857bc76 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 02:53:05 -0400 Subject: [PATCH 161/558] Roll Skia from 9277962b84de to 505175112b9c (1 revision) (#35224) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0f96beded8cdf..4f39e72bc10c1 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': '9277962b84deaf370cce1d64329ab5eef29fb303', + 'skia_revision': '505175112b9c33c99c26cc2e43fe05364f3a0916', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 3f01346333838..0d6838c25caef 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 2f02dba667d939ef4b75afa037c73bf8 +Signature: 599315b0c40514d4685fba7a698830d9 UNUSED LICENSES: From 88394df55a411bb235c943d1d4fa8a83e652974a Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Mon, 8 Aug 2022 14:58:04 +0800 Subject: [PATCH 162/558] [Impeller] Implement sweep gradient (#35124) --- ci/licenses_golden/licenses_flutter | 4 + impeller/aiks/aiks_unittests.cc | 33 +++++- impeller/aiks/paint.h | 1 + .../shader_lib/impeller/constants.glsl | 1 + .../display_list/display_list_dispatcher.cc | 22 +++- impeller/entity/BUILD.gn | 8 +- impeller/entity/contents/content_context.cc | 2 + impeller/entity/contents/content_context.h | 11 ++ .../contents/radial_gradient_contents.cc | 4 +- .../contents/radial_gradient_contents.h | 2 +- .../contents/sweep_gradient_contents.cc | 107 ++++++++++++++++++ .../entity/contents/sweep_gradient_contents.h | 56 +++++++++ .../entity/shaders/sweep_gradient_fill.frag | 33 ++++++ .../entity/shaders/sweep_gradient_fill.vert | 16 +++ 14 files changed, 289 insertions(+), 11 deletions(-) create mode 100644 impeller/entity/contents/sweep_gradient_contents.cc create mode 100644 impeller/entity/contents/sweep_gradient_contents.h create mode 100644 impeller/entity/shaders/sweep_gradient_fill.frag create mode 100644 impeller/entity/shaders/sweep_gradient_fill.vert diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 5343b8072b205..2ef7fd3b185bf 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -581,6 +581,8 @@ FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.cc FILE: ../../../flutter/impeller/entity/contents/solid_color_contents.h FILE: ../../../flutter/impeller/entity/contents/solid_stroke_contents.cc FILE: ../../../flutter/impeller/entity/contents/solid_stroke_contents.h +FILE: ../../../flutter/impeller/entity/contents/sweep_gradient_contents.cc +FILE: ../../../flutter/impeller/entity/contents/sweep_gradient_contents.h FILE: ../../../flutter/impeller/entity/contents/text_contents.cc FILE: ../../../flutter/impeller/entity/contents/text_contents.h FILE: ../../../flutter/impeller/entity/contents/texture_contents.cc @@ -635,6 +637,8 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_fill.frag FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.frag FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.vert +FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.frag +FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/texture_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert FILE: ../../../flutter/impeller/entity/shaders/vertices.frag diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index edd552f17d84d..d4fbf8c6361aa 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -216,8 +216,8 @@ TEST_P(AiksTest, CanRenderLinearGradient) { canvas.Translate(offsets[i]); auto contents = std::make_shared(); contents->SetEndPoints({0, 0}, {100, 100}); - std::vector colors = {Color{0.9019, 0.3921, 0.3960, 1.0}, - Color{0.5686, 0.5960, 0.8980, 1.0}}; + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; contents->SetColors(std::move(colors)); contents->SetTileMode(tile_modes[i]); paint.contents = contents; @@ -240,8 +240,33 @@ TEST_P(AiksTest, CanRenderRadialGradient) { canvas.Translate(offsets[i]); auto contents = std::make_shared(); contents->SetCenterAndRadius({50, 50}, 50); - std::vector colors = {Color{0.9019, 0.3921, 0.3960, 1.0}, - Color{0.5686, 0.5960, 0.8980, 1.0}}; + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; + contents->SetColors(std::move(colors)); + contents->SetTileMode(tile_modes[i]); + paint.contents = contents; + canvas.DrawRect({0, 0, 200, 200}, paint); + canvas.Restore(); + } + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + +TEST_P(AiksTest, CanRenderSweepGradient) { + Canvas canvas; + Paint paint; + std::vector offsets = { + {0, 0, 0}, {0, 300, 0}, {300, 0, 0}, {300, 300, 0}}; + std::vector tile_modes = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + for (int i = 0; i < 4; i++) { + canvas.Save(); + canvas.Translate(offsets[i]); + auto contents = std::make_shared(); + contents->SetCenterAndAngles({50, 50}, Degrees(45), Degrees(135)); + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; contents->SetColors(std::move(colors)); contents->SetTileMode(tile_modes[i]); paint.contents = contents; diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index 2a9f831bd06db..8a70d3428ed15 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -12,6 +12,7 @@ #include "impeller/entity/contents/linear_gradient_contents.h" #include "impeller/entity/contents/radial_gradient_contents.h" #include "impeller/entity/contents/solid_stroke_contents.h" +#include "impeller/entity/contents/sweep_gradient_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" diff --git a/impeller/compiler/shader_lib/impeller/constants.glsl b/impeller/compiler/shader_lib/impeller/constants.glsl index 5ccc5b298c661..b8e24739834f9 100644 --- a/impeller/compiler/shader_lib/impeller/constants.glsl +++ b/impeller/compiler/shader_lib/impeller/constants.glsl @@ -6,5 +6,6 @@ #define CONSTANTS_GLSL_ const float kEhCloseEnough = 0.000001; +const float k1Over2Pi = 0.1591549430918; #endif diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 9560f1991b2e4..a1d80528d6f09 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -18,6 +18,7 @@ #include "impeller/entity/contents/linear_gradient_contents.h" #include "impeller/entity/contents/radial_gradient_contents.h" #include "impeller/entity/contents/solid_stroke_contents.h" +#include "impeller/entity/contents/sweep_gradient_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/path.h" #include "impeller/geometry/path_builder.h" @@ -254,7 +255,7 @@ void DisplayListDispatcher::setColorSource( case flutter::DlColorSourceType::kRadialGradient: { const flutter::DlRadialGradientColorSource* radialGradient = source->asRadialGradient(); - FML_CHECK(radialGradient); + FML_DCHECK(radialGradient); auto contents = std::make_shared(); contents->SetCenterAndRadius(ToPoint(radialGradient->center()), radialGradient->radius()); @@ -268,9 +269,26 @@ void DisplayListDispatcher::setColorSource( paint_.contents = std::move(contents); return; } + case flutter::DlColorSourceType::kSweepGradient: { + const flutter::DlSweepGradientColorSource* sweepGradient = + source->asSweepGradient(); + FML_DCHECK(sweepGradient); + auto contents = std::make_shared(); + contents->SetCenterAndAngles(ToPoint(sweepGradient->center()), + Degrees(sweepGradient->start()), + Degrees(sweepGradient->end())); + std::vector colors; + for (auto i = 0; i < sweepGradient->stop_count(); i++) { + colors.emplace_back(ToColor(sweepGradient->colors()[i])); + } + contents->SetColors(std::move(colors)); + contents->SetTileMode( + static_cast(sweepGradient->tile_mode())); + paint_.contents = std::move(contents); + return; + } case flutter::DlColorSourceType::kImage: case flutter::DlColorSourceType::kConicalGradient: - case flutter::DlColorSourceType::kSweepGradient: case flutter::DlColorSourceType::kUnknown: UNIMPLEMENTED; break; diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 3ebfe3d3543dc..014d11484b232 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -36,18 +36,20 @@ impeller_shaders("entity_shaders") { "shaders/glyph_atlas.vert", "shaders/gradient_fill.frag", "shaders/gradient_fill.vert", - "shaders/radial_gradient_fill.vert", "shaders/radial_gradient_fill.frag", + "shaders/radial_gradient_fill.vert", "shaders/rrect_blur.vert", "shaders/rrect_blur.frag", "shaders/solid_fill.frag", "shaders/solid_fill.vert", "shaders/solid_stroke.frag", "shaders/solid_stroke.vert", + "shaders/sweep_gradient_fill.frag", + "shaders/sweep_gradient_fill.vert", "shaders/texture_fill.frag", "shaders/texture_fill.vert", - "shaders/vertices.vert", "shaders/vertices.frag", + "shaders/vertices.vert", ] } @@ -89,6 +91,8 @@ impeller_component("entity") { "contents/solid_color_contents.h", "contents/solid_stroke_contents.cc", "contents/solid_stroke_contents.h", + "contents/sweep_gradient_contents.cc", + "contents/sweep_gradient_contents.h", "contents/text_contents.cc", "contents/text_contents.h", "contents/texture_contents.cc", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index f53bdfcf18a95..941ed5f451cd7 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -155,6 +155,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); + sweep_gradient_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); rrect_blur_pipelines_[{}] = CreateDefaultPipeline(*context_); texture_blend_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 8f2457ae3a53a..d31eb9435d8ea 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -48,6 +48,8 @@ #include "impeller/entity/solid_fill.vert.h" #include "impeller/entity/solid_stroke.frag.h" #include "impeller/entity/solid_stroke.vert.h" +#include "impeller/entity/sweep_gradient_fill.frag.h" +#include "impeller/entity/sweep_gradient_fill.vert.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" #include "impeller/entity/vertices.frag.h" @@ -62,6 +64,8 @@ using SolidFillPipeline = PipelineT; using RadialGradientFillPipeline = PipelineT; +using SweepGradientFillPipeline = + PipelineT; using BlendPipeline = PipelineT; using RRectBlurPipeline = PipelineT; @@ -151,6 +155,7 @@ class ContentContext { ContentContextOptions opts) const { return GetPipeline(gradient_fill_pipelines_, opts); } + std::shared_ptr GetRadialGradientFillPipeline( ContentContextOptions opts) const { return GetPipeline(radial_gradient_fill_pipelines_, opts); @@ -160,6 +165,11 @@ class ContentContext { return GetPipeline(rrect_blur_pipelines_, opts); } + std::shared_ptr GetSweepGradientFillPipeline( + ContentContextOptions opts) const { + return GetPipeline(sweep_gradient_fill_pipelines_, opts); + } + std::shared_ptr GetSolidFillPipeline( ContentContextOptions opts) const { return GetPipeline(solid_fill_pipelines_, opts); @@ -309,6 +319,7 @@ class ContentContext { mutable Variants gradient_fill_pipelines_; mutable Variants solid_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; + mutable Variants sweep_gradient_fill_pipelines_; mutable Variants rrect_blur_pipelines_; mutable Variants texture_blend_pipelines_; mutable Variants texture_pipelines_; diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index 4ea50e0a1dd6d..e39b622dc4aec 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -20,8 +20,8 @@ void RadialGradientContents::SetPath(Path path) { path_ = std::move(path); } -void RadialGradientContents::SetCenterAndRadius(Point centre, Scalar radius) { - center_ = centre; +void RadialGradientContents::SetCenterAndRadius(Point center, Scalar radius) { + center_ = center; radius_ = radius; } diff --git a/impeller/entity/contents/radial_gradient_contents.h b/impeller/entity/contents/radial_gradient_contents.h index 3e936ae383fba..7db7cef5adf9b 100644 --- a/impeller/entity/contents/radial_gradient_contents.h +++ b/impeller/entity/contents/radial_gradient_contents.h @@ -33,7 +33,7 @@ class RadialGradientContents final : public PathContents { const Entity& entity, RenderPass& pass) const override; - void SetCenterAndRadius(Point centre, Scalar radius); + void SetCenterAndRadius(Point center, Scalar radius); void SetColors(std::vector colors); diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc new file mode 100644 index 0000000000000..d3874e1095bf7 --- /dev/null +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -0,0 +1,107 @@ +// 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 "sweep_gradient_contents.h" + +#include "flutter/fml/logging.h" +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/entity.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/tessellator/tessellator.h" + +namespace impeller { + +SweepGradientContents::SweepGradientContents() = default; + +SweepGradientContents::~SweepGradientContents() = default; + +void SweepGradientContents::SetPath(Path path) { + path_ = std::move(path); +} + +void SweepGradientContents::SetCenterAndAngles(Point center, + Degrees start_angle, + Degrees end_angle) { + center_ = center; + Scalar t0 = start_angle.degrees / 360; + Scalar t1 = end_angle.degrees / 360; + FML_DCHECK(t0 < t1); + bias_ = -t0; + scale_ = 1 / (t1 - t0); +} + +void SweepGradientContents::SetColors(std::vector colors) { + colors_ = std::move(colors); + if (colors_.empty()) { + colors_.push_back(Color::Black()); + colors_.push_back(Color::Black()); + } else if (colors_.size() < 2u) { + colors_.push_back(colors_.back()); + } +} + +void SweepGradientContents::SetTileMode(Entity::TileMode tile_mode) { + tile_mode_ = tile_mode; +} + +const std::vector& SweepGradientContents::GetColors() const { + return colors_; +} + +std::optional SweepGradientContents::GetCoverage( + const Entity& entity) const { + return path_.GetTransformedBoundingBox(entity.GetTransformation()); +}; + +bool SweepGradientContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + using VS = SweepGradientFillPipeline::VertexShader; + using FS = SweepGradientFillPipeline::FragmentShader; + + auto vertices_builder = VertexBufferBuilder(); + { + auto result = + Tessellator{}.Tessellate(path_.GetFillType(), path_.CreatePolyline(), + [&vertices_builder](Point point) { + VS::PerVertexData vtx; + vtx.vertices = point; + vertices_builder.AppendVertex(vtx); + }); + + if (result == Tessellator::Result::kInputError) { + return true; + } + if (result == Tessellator::Result::kTessellationError) { + return false; + } + } + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + + FS::GradientInfo gradient_info; + gradient_info.center = center_; + gradient_info.bias = bias_; + gradient_info.scale = scale_; + gradient_info.start_color = colors_[0].Premultiply(); + gradient_info.end_color = colors_[1].Premultiply(); + gradient_info.tile_mode = static_cast(tile_mode_); + + Command cmd; + cmd.label = "SweepGradientFill"; + cmd.pipeline = renderer.GetSweepGradientFillPipeline( + OptionsFromPassAndEntity(pass, entity)); + cmd.stencil_reference = entity.GetStencilDepth(); + cmd.BindVertices( + vertices_builder.CreateVertexBuffer(pass.GetTransientsBuffer())); + cmd.primitive_type = PrimitiveType::kTriangle; + FS::BindGradientInfo( + cmd, pass.GetTransientsBuffer().EmplaceUniform(gradient_info)); + VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + return pass.AddCommand(std::move(cmd)); +} + +} // namespace impeller diff --git a/impeller/entity/contents/sweep_gradient_contents.h b/impeller/entity/contents/sweep_gradient_contents.h new file mode 100644 index 0000000000000..cfd21249b49cb --- /dev/null +++ b/impeller/entity/contents/sweep_gradient_contents.h @@ -0,0 +1,56 @@ +// 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 + +#include "flutter/fml/macros.h" +#include "impeller/entity/contents/path_contents.h" +#include "impeller/entity/entity.h" +#include "impeller/geometry/color.h" +#include "impeller/geometry/path.h" +#include "impeller/geometry/point.h" +#include "impeller/geometry/scalar.h" + +namespace impeller { + +class SweepGradientContents final : public PathContents { + public: + SweepGradientContents(); + + ~SweepGradientContents() override; + + void SetPath(Path path) override; + + // |Contents| + std::optional GetCoverage(const Entity& entity) const override; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + void SetCenterAndAngles(Point center, Degrees start_angle, Degrees end_angle); + + void SetColors(std::vector colors); + + void SetTileMode(Entity::TileMode tile_mode); + + const std::vector& GetColors() const; + + private: + Path path_; + Point center_; + Scalar bias_; + Scalar scale_; + std::vector colors_; + Entity::TileMode tile_mode_; + + FML_DISALLOW_COPY_AND_ASSIGN(SweepGradientContents); +}; + +} // namespace impeller diff --git a/impeller/entity/shaders/sweep_gradient_fill.frag b/impeller/entity/shaders/sweep_gradient_fill.frag new file mode 100644 index 0000000000000..1be76ba7b4483 --- /dev/null +++ b/impeller/entity/shaders/sweep_gradient_fill.frag @@ -0,0 +1,33 @@ +// 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 + +uniform GradientInfo { + vec2 center; + float bias; + float scale; + vec4 start_color; + vec4 end_color; + float tile_mode; +} gradient_info; + +in vec2 interpolated_vertices; + +out vec4 frag_color; + +void main() { + vec2 coord = interpolated_vertices - 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 = IPTileTextureCoords(t, gradient_info.tile_mode); + frag_color = mix(gradient_info.start_color, gradient_info.end_color, t); +} diff --git a/impeller/entity/shaders/sweep_gradient_fill.vert b/impeller/entity/shaders/sweep_gradient_fill.vert new file mode 100644 index 0000000000000..f9d0ccdabfc3e --- /dev/null +++ b/impeller/entity/shaders/sweep_gradient_fill.vert @@ -0,0 +1,16 @@ +// 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. + +uniform FrameInfo { + mat4 mvp; +} frame_info; + +in vec2 vertices; + +out vec2 interpolated_vertices; + +void main() { + gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); + interpolated_vertices = vertices; +} From fa30c6879b4da2a2fd6d7bd16d0f89e00eb55adc Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 05:20:08 -0400 Subject: [PATCH 163/558] Roll Fuchsia Linux SDK from 3P9_-_bI6... to IfIhCrtMD... (#35225) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 4f39e72bc10c1..0540667c9f8a4 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': '3P9_-_bI6KCZAMnhGITNDmLSos-tSSTA68e4LBYr_ZgC' + 'version': 'IfIhCrtMDOZTReFzSAxoyboXKqNEH7WRdaFXWTjctD4C' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 1c01a69cd7846..c1df1a0ba0724 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 35712eb420078e6972dc6230dfecfe33 +Signature: 818c506d4bd552515c898e3da6aba1f3 UNUSED LICENSES: From c475ae7ce4b0e67bc3c90eab2f70788c83082de2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Aug 2022 09:22:13 +0000 Subject: [PATCH 164/558] Bump actions/setup-python from 4.1.0 to 4.2.0 (#35227) --- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 805b13aa22022..64c8a9058dfb4 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -26,7 +26,7 @@ jobs: persist-credentials: false - name: setup python - uses: actions/setup-python@c4e89fac7e8767b327bbad6cb4d859eda999cf08 + uses: actions/setup-python@b55428b1882923874294fa556849718a1d7f2ca5 with: python-version: '3.7.7' # install the python version needed From dde62a46ec5a3fd82a4576e8e2cf782086a9cbdd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Aug 2022 09:52:13 +0000 Subject: [PATCH 165/558] Bump github/codeql-action from 2.1.16 to 2.1.18 (#35226) --- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 64c8a9058dfb4..cd49ffe55f5c2 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -57,6 +57,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@3e7e3b32d0fb8283594bb0a76cc60a00918b0969 + uses: github/codeql-action/upload-sarif@2ca79b6fa8d3ec278944088b4aa5f46912db5d63 with: sarif_file: results.sarif From ecf05ddad85499134859d5ab127102975f814dcd Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 09:49:05 -0400 Subject: [PATCH 166/558] Roll Skia from 505175112b9c to 00bc9be5e324 (1 revision) (#35230) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0540667c9f8a4..5e382c469d27e 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': '505175112b9c33c99c26cc2e43fe05364f3a0916', + 'skia_revision': '00bc9be5e32445966a9b9bd1ba7fa333cd4d06aa', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 0d6838c25caef..c2506a3726a30 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 599315b0c40514d4685fba7a698830d9 +Signature: aadfc5b0273be8d58899d701a660e46b UNUSED LICENSES: From 518f223c34d705ba028bd01e2b72ed5e6928ce0f Mon Sep 17 00:00:00 2001 From: Erik Date: Mon, 8 Aug 2022 12:28:38 -0400 Subject: [PATCH 167/558] Change behavior of BuildTarget parameter 'additional_targets' and renamed to 'build_targets', targets must now be passed in otherwise it will default to building all of flutter (#35195) --- tools/fuchsia/build_fuchsia_artifacts.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/tools/fuchsia/build_fuchsia_artifacts.py b/tools/fuchsia/build_fuchsia_artifacts.py index c9171372510cc..302f9bf5e04d1 100755 --- a/tools/fuchsia/build_fuchsia_artifacts.py +++ b/tools/fuchsia/build_fuchsia_artifacts.py @@ -83,6 +83,7 @@ def RunGN(variant_dir, flags): def BuildNinjaTargets(variant_dir, targets): assert os.path.exists(os.path.join(_out_dir, variant_dir)) + print('Running autoninja for targets: %s', targets) RunExecutable(['autoninja', '-C', os.path.join(_out_dir, variant_dir)] + targets) @@ -310,15 +311,8 @@ def ProcessCIPDPackage(upload, engine_version): def BuildTarget( - runtime_mode, - arch, - optimized, - enable_lto, - enable_legacy, - asan, - dart_version_git_info, - prebuilt_dart_sdk, - additional_targets=[] + runtime_mode, arch, optimized, enable_lto, enable_legacy, asan, + dart_version_git_info, prebuilt_dart_sdk, build_targets ): unopt = "_unopt" if not optimized else "" out_dir = 'fuchsia_%s%s_%s' % (runtime_mode, unopt, arch) @@ -344,7 +338,7 @@ def BuildTarget( flags.append('--no-prebuilt-dart-sdk') RunGN(out_dir, flags) - BuildNinjaTargets(out_dir, ['flutter'] + additional_targets) + BuildNinjaTargets(out_dir, build_targets) return @@ -473,7 +467,7 @@ def main(): runtime_mode, arch, optimized, enable_lto, enable_legacy, args.asan, not args.no_dart_version_git_info, not args.no_prebuilt_dart_sdk, - args.targets.split(",") if args.targets else [] + args.targets.split(",") if args.targets else ['flutter'] ) CopyBuildToBucket(runtime_mode, arch, optimized, product) From 907143bbb451df83e927be96441e676aa81ca6c1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 13:06:04 -0400 Subject: [PATCH 168/558] Roll Skia from 00bc9be5e324 to 8a7dc12099c0 (4 revisions) (#35232) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 5e382c469d27e..eac0e45a1e539 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': '00bc9be5e32445966a9b9bd1ba7fa333cd4d06aa', + 'skia_revision': '8a7dc12099c0becd06e91f02cfbc32d01059ab55', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index c2506a3726a30..58c455fbfc636 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: aadfc5b0273be8d58899d701a660e46b +Signature: ec9fb1d49a9df0331e96c8cbbdf66244 UNUSED LICENSES: From 9c3950e03301f39db211c95268a98c5df5c4610d Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Tue, 9 Aug 2022 01:32:05 +0800 Subject: [PATCH 169/558] Change the time unit of 'DisplayListBuilderBenchmarks' to 'kMicrosecond' (#35228) --- .../display_list_builder_benchmarks.cc | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/display_list/display_list_builder_benchmarks.cc b/display_list/display_list_builder_benchmarks.cc index ed1d093de31e0..129eac3abd497 100644 --- a/display_list/display_list_builder_benchmarks.cc +++ b/display_list/display_list_builder_benchmarks.cc @@ -133,103 +133,103 @@ static void BM_DisplayListBuilderWithSaveLayerAndImageFilter( BENCHMARK_CAPTURE(BM_DisplayListBuilderDefault, kDefault, DisplayListBuilderBenchmarkType::kDefault) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderDefault, kBounds, DisplayListBuilderBenchmarkType::kBounds) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderDefault, kRtree, DisplayListBuilderBenchmarkType::kRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderDefault, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithScaleAndTranslate, kDefault, DisplayListBuilderBenchmarkType::kDefault) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithScaleAndTranslate, kBounds, DisplayListBuilderBenchmarkType::kBounds) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithScaleAndTranslate, kRtree, DisplayListBuilderBenchmarkType::kRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithScaleAndTranslate, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithPerspective, kDefault, DisplayListBuilderBenchmarkType::kDefault) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithPerspective, kBounds, DisplayListBuilderBenchmarkType::kBounds) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithPerspective, kRtree, DisplayListBuilderBenchmarkType::kRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithPerspective, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithClipRect, kDefault, DisplayListBuilderBenchmarkType::kDefault) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithClipRect, kBounds, DisplayListBuilderBenchmarkType::kBounds) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithClipRect, kRtree, DisplayListBuilderBenchmarkType::kRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithClipRect, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayer, kDefault, DisplayListBuilderBenchmarkType::kDefault) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayer, kBounds, DisplayListBuilderBenchmarkType::kBounds) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayer, kRtree, DisplayListBuilderBenchmarkType::kRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayer, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayerAndImageFilter, kDefault, DisplayListBuilderBenchmarkType::kDefault) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayerAndImageFilter, kBounds, DisplayListBuilderBenchmarkType::kBounds) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayerAndImageFilter, kRtree, DisplayListBuilderBenchmarkType::kRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); BENCHMARK_CAPTURE(BM_DisplayListBuilderWithSaveLayerAndImageFilter, kBoundsAndRtree, DisplayListBuilderBenchmarkType::kBoundsAndRtree) - ->Unit(benchmark::kMillisecond); + ->Unit(benchmark::kMicrosecond); } // namespace flutter From 8853dff9ee2315db6a9e4f703fc7cb4be836ac93 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 8 Aug 2022 11:06:05 -0700 Subject: [PATCH 170/558] Support hot reload of asset fonts (#35213) --- lib/ui/text/font_collection.cc | 18 ++++- runtime/service_protocol.cc | 3 + runtime/service_protocol.h | 1 + shell/common/shell.cc | 61 +++++++++++---- shell/common/shell.h | 11 +++ .../observatory/vmservice_methods_test.dart | 77 +++++++++++++++++-- 6 files changed, 145 insertions(+), 26 deletions(-) diff --git a/lib/ui/text/font_collection.cc b/lib/ui/text/font_collection.cc index 3ca89d964dff8..3a5327b6fec03 100644 --- a/lib/ui/text/font_collection.cc +++ b/lib/ui/text/font_collection.cc @@ -45,6 +45,22 @@ void FontCollection::SetupDefaultFontManager( collection_->SetupDefaultFontManager(font_initialization_data); } +// Font manifest yaml format: +// +// flutter: +// fonts: +// - family: Raleway +// fonts: +// - asset: fonts/Raleway-Regular.ttf +// - asset: fonts/Raleway-Italic.ttf +// style: italic +// - family: RobotoMono +// fonts: +// - asset: fonts/RobotoMono-Regular.ttf +// - asset: fonts/RobotoMono-Bold.ttf +// weight: 700 +// +// Structure described in https://docs.flutter.dev/cookbook/design/fonts void FontCollection::RegisterFonts( std::shared_ptr asset_manager) { std::unique_ptr manifest_mapping = @@ -65,8 +81,6 @@ void FontCollection::RegisterFonts( return; } - // Structure described in https://flutter.io/custom-fonts/ - if (!document.IsArray()) { return; } diff --git a/runtime/service_protocol.cc b/runtime/service_protocol.cc index 3a9c0d6e36bab..0f25565ada9b8 100644 --- a/runtime/service_protocol.cc +++ b/runtime/service_protocol.cc @@ -40,6 +40,8 @@ const std::string_view const std::string_view ServiceProtocol::kRenderFrameWithRasterStatsExtensionName = "_flutter.renderFrameWithRasterStats"; +const std::string_view ServiceProtocol::kReloadAssetFonts = + "_flutter.reloadAssetFonts"; static constexpr std::string_view kViewIdPrefx = "_flutterView/"; static constexpr std::string_view kListViewsExtensionName = @@ -60,6 +62,7 @@ ServiceProtocol::ServiceProtocol() kGetSkSLsExtensionName, kEstimateRasterCacheMemoryExtensionName, kRenderFrameWithRasterStatsExtensionName, + kReloadAssetFonts, }), handlers_mutex_(fml::SharedMutex::Create()) {} diff --git a/runtime/service_protocol.h b/runtime/service_protocol.h index e9df73d4d5648..dc3a4d186e1ca 100644 --- a/runtime/service_protocol.h +++ b/runtime/service_protocol.h @@ -30,6 +30,7 @@ class ServiceProtocol { static const std::string_view kGetSkSLsExtensionName; static const std::string_view kEstimateRasterCacheMemoryExtensionName; static const std::string_view kRenderFrameWithRasterStatsExtensionName; + static const std::string_view kReloadAssetFonts; class Handler { public: diff --git a/shell/common/shell.cc b/shell/common/shell.cc index e0931d17288f9..6c80032b46491 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -454,6 +454,10 @@ Shell::Shell(DartVMRef vm, task_runners_.GetRasterTaskRunner(), std::bind(&Shell::OnServiceProtocolRenderFrameWithRasterStats, this, std::placeholders::_1, std::placeholders::_2)}; + service_protocol_handlers_[ServiceProtocol::kReloadAssetFonts] = { + task_runners_.GetPlatformTaskRunner(), + std::bind(&Shell::OnServiceProtocolReloadAssetFonts, this, + std::placeholders::_1, std::placeholders::_2)}; } Shell::~Shell() { @@ -1900,6 +1904,45 @@ bool Shell::OnServiceProtocolRenderFrameWithRasterStats( } } +void Shell::SendFontChangeNotification() { + // After system fonts are reloaded, we send a system channel message + // to notify flutter framework. + rapidjson::Document document; + document.SetObject(); + auto& allocator = document.GetAllocator(); + rapidjson::Value message_value; + message_value.SetString(kFontChange, allocator); + document.AddMember(kTypeKey, message_value, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + std::string message = buffer.GetString(); + std::unique_ptr fontsChangeMessage = + std::make_unique( + kSystemChannel, + fml::MallocMapping::Copy(message.c_str(), message.length()), nullptr); + OnPlatformViewDispatchPlatformMessage(std::move(fontsChangeMessage)); +} + +bool Shell::OnServiceProtocolReloadAssetFonts( + const ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document* response) { + FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + if (!engine_) { + return false; + } + engine_->GetFontCollection().RegisterFonts(engine_->GetAssetManager()); + engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache(); + SendFontChangeNotification(); + + auto& allocator = response->GetAllocator(); + response->SetObject(); + response->AddMember("type", "Success", allocator); + + return true; +} + Rasterizer::Screenshot Shell::Screenshot( Rasterizer::ScreenshotType screenshot_type, bool base64_encode) { @@ -1962,23 +2005,7 @@ bool Shell::ReloadSystemFonts() { engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache(); // After system fonts are reloaded, we send a system channel message // to notify flutter framework. - rapidjson::Document document; - document.SetObject(); - auto& allocator = document.GetAllocator(); - rapidjson::Value message_value; - message_value.SetString(kFontChange, allocator); - document.AddMember(kTypeKey, message_value, allocator); - - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - document.Accept(writer); - std::string message = buffer.GetString(); - std::unique_ptr fontsChangeMessage = - std::make_unique( - kSystemChannel, - fml::MallocMapping::Copy(message.c_str(), message.length()), nullptr); - - OnPlatformViewDispatchPlatformMessage(std::move(fontsChangeMessage)); + SendFontChangeNotification(); return true; } diff --git a/shell/common/shell.h b/shell/common/shell.h index 75761b9177488..051e1a9c5d7b6 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -714,6 +714,17 @@ class Shell final : public PlatformView::Delegate, const ServiceProtocol::Handler::ServiceProtocolMap& params, rapidjson::Document* response); + // Service protocol handler + // + // Forces the FontCollection to reload the font manifest. Used to support hot + // reload for fonts. + bool OnServiceProtocolReloadAssetFonts( + const ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document* response); + + // Send a system font change notification. + void SendFontChangeNotification(); + // |ResourceCacheLimitItem| size_t GetResourceCacheLimit() override { return resource_cache_limit_; }; diff --git a/testing/dart/observatory/vmservice_methods_test.dart b/testing/dart/observatory/vmservice_methods_test.dart index a6491797f248d..ed62cb80cc3d8 100644 --- a/testing/dart/observatory/vmservice_methods_test.dart +++ b/testing/dart/observatory/vmservice_methods_test.dart @@ -2,7 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; +import 'dart:convert'; import 'dart:developer' as developer; +import 'dart:typed_data'; +import 'dart:ui' as ui; import 'package:litetest/litetest.dart'; import 'package:vm_service/vm_service.dart' as vms; @@ -20,18 +24,13 @@ void main() { vmService = await vmServiceConnectUri( 'ws://localhost:${info.serverUri!.port}${info.serverUri!.path}ws', ); - final vms.Response response = await vmService.callMethod('_flutter.listViews'); - final List? rawViews = response.json!['views'] as List?; - final String viewId = (rawViews![0]! as Map?)!['id']! as String; + final String viewId = await getViewId(vmService); dynamic error; try { await vmService.callMethod( '_flutter.setAssetBundlePath', - args: { - 'viewId': viewId, - 'assetDirectory': '' - }, + args: {'viewId': viewId, 'assetDirectory': ''}, ); } catch (err) { error = err; @@ -41,4 +40,68 @@ void main() { await vmService?.dispose(); } }); + + test('Reload fonts request sends font change notification', () async { + vms.VmService? vmService; + try { + final developer.ServiceProtocolInfo info = + await developer.Service.getInfo(); + if (info.serverUri == null) { + fail('This test must not be run with --disable-observatory.'); + } + + final Completer completer = Completer(); + ui.window.onPlatformMessage = (String name, ByteData? data, ui.PlatformMessageResponseCallback? callback) { + final ByteBuffer buffer = data!.buffer; + final Uint8List list = buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); + completer.complete(PlatformResponse(name: name, contents: utf8.decode(list))); + }; + + vmService = await vmServiceConnectUri( + 'ws://localhost:${info.serverUri!.port}${info.serverUri!.path}ws', + ); + final String viewId = await getViewId(vmService); + + final vms.Response fontChangeResponse = await vmService.callMethod( + '_flutter.reloadAssetFonts', + args: {'viewId': viewId}, + ); + + expect(fontChangeResponse.type, 'Success'); + expect( + await completer.future, + const PlatformResponse( + name: 'flutter/system', + contents: '{"type":"fontsChange"}', + ), + ); + } finally { + await vmService?.dispose(); + } + }); +} + +Future getViewId(vms.VmService vmService) async { + final vms.Response response = await vmService.callMethod('_flutter.listViews'); + final List? rawViews = response.json!['views'] as List?; + return (rawViews![0]! as Map?)!['id']! as String; +} + +class PlatformResponse { + const PlatformResponse({ + required this.name, + required this.contents, + }); + + final String name; + final String contents; + + @override + bool operator ==(Object other) => + other is PlatformResponse && + other.name == name && + other.contents == contents; + + @override + int get hashCode => Object.hash(name, contents); } From b9e8d09a7cd4fbc1e4835ac079decf5b1720a0d2 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 14:35:05 -0400 Subject: [PATCH 171/558] Roll Skia from 8a7dc12099c0 to 7525ca099719 (2 revisions) (#35234) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index eac0e45a1e539..e5fb007ea1601 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': '8a7dc12099c0becd06e91f02cfbc32d01059ab55', + 'skia_revision': '7525ca09971982717161466016c07fabf9f267ed', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 8adb92cfa296bbe67d01f75b8f900768d1ed3a6c Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Mon, 8 Aug 2022 11:56:11 -0700 Subject: [PATCH 172/558] Adds support for uniform arrays to FragmentPrograms (#35209) --- impeller/compiler/reflector.cc | 13 +++++ impeller/compiler/reflector.h | 2 + impeller/compiler/runtime_stage_data.cc | 1 + impeller/compiler/runtime_stage_data.h | 1 + impeller/compiler/spirv_sksl.cc | 1 + impeller/runtime_stage/runtime_stage.cc | 1 + impeller/runtime_stage/runtime_stage.fbs | 1 + impeller/runtime_stage/runtime_stage.h | 1 + .../fixtures/shaders/general_shaders/BUILD.gn | 1 + .../general_shaders/uniform_arrays.frag | 51 +++++++++++++++++++ lib/ui/painting/fragment_program.cc | 3 ++ testing/dart/fragment_shader_test.dart | 16 ++++++ 12 files changed, 92 insertions(+) create mode 100644 lib/ui/fixtures/shaders/general_shaders/uniform_arrays.frag diff --git a/impeller/compiler/reflector.cc b/impeller/compiler/reflector.cc index 69d61719e08b7..0df6098086df6 100644 --- a/impeller/compiler/reflector.cc +++ b/impeller/compiler/reflector.cc @@ -354,11 +354,24 @@ std::shared_ptr Reflector::GenerateRuntimeStageData() const { uniform_description.rows = spir_type.vecsize; uniform_description.columns = spir_type.columns; uniform_description.bit_width = spir_type.width; + uniform_description.array_elements = GetArrayElements(spir_type); data->AddUniformDescription(std::move(uniform_description)); }); return data; } +uint32_t Reflector::GetArrayElements(const spirv_cross::SPIRType& type) const { + if (type.array.empty()) { + return 0; + } + uint32_t elements = 1; + for (size_t i = 0; i < type.array.size(); i++) { + FML_CHECK(type.array_size_literal[i]); + elements *= type.array[i]; + } + return elements; +} + static std::string ToString(CompilerBackend::Type type) { switch (type) { case CompilerBackend::Type::kMSL: diff --git a/impeller/compiler/reflector.h b/impeller/compiler/reflector.h index 5a5be695034d9..808ce56d3b223 100644 --- a/impeller/compiler/reflector.h +++ b/impeller/compiler/reflector.h @@ -138,6 +138,8 @@ class Reflector { std::vector ReadStructMembers( const spirv_cross::TypeID& type_id) const; + uint32_t GetArrayElements(const spirv_cross::SPIRType& type) const; + FML_DISALLOW_COPY_AND_ASSIGN(Reflector); }; diff --git a/impeller/compiler/runtime_stage_data.cc b/impeller/compiler/runtime_stage_data.cc index af4c61118538d..70ebb3079a2a0 100644 --- a/impeller/compiler/runtime_stage_data.cc +++ b/impeller/compiler/runtime_stage_data.cc @@ -157,6 +157,7 @@ std::shared_ptr RuntimeStageData::CreateMapping() const { } desc->type = uniform_type.value(); desc->bit_width = uniform.bit_width; + desc->array_elements = uniform.array_elements; runtime_stage.uniforms.emplace_back(std::move(desc)); } diff --git a/impeller/compiler/runtime_stage_data.h b/impeller/compiler/runtime_stage_data.h index b0022a1402d42..d5da09dd02c0e 100644 --- a/impeller/compiler/runtime_stage_data.h +++ b/impeller/compiler/runtime_stage_data.h @@ -22,6 +22,7 @@ struct UniformDescription { size_t rows = 0u; size_t columns = 0u; size_t bit_width = 0u; + size_t array_elements = 0u; }; class RuntimeStageData { diff --git a/impeller/compiler/spirv_sksl.cc b/impeller/compiler/spirv_sksl.cc index 42fbeeb4a5e18..ab5727ded9d92 100644 --- a/impeller/compiler/spirv_sksl.cc +++ b/impeller/compiler/spirv_sksl.cc @@ -22,6 +22,7 @@ std::string CompilerSkSL::compile() { options.version = 100; options.vulkan_semantics = false; options.enable_420pack_extension = false; + options.flatten_multidimensional_arrays = true; backend.allow_precision_qualifiers = false; backend.basic_int16_type = "short"; diff --git a/impeller/runtime_stage/runtime_stage.cc b/impeller/runtime_stage/runtime_stage.cc index 01955ee373adc..353287d6a0caf 100644 --- a/impeller/runtime_stage/runtime_stage.cc +++ b/impeller/runtime_stage/runtime_stage.cc @@ -85,6 +85,7 @@ RuntimeStage::RuntimeStage(std::shared_ptr payload) desc.dimensions = RuntimeUniformDimensions{ static_cast(i->rows()), static_cast(i->columns())}; desc.bit_width = i->bit_width(); + desc.array_elements = i->array_elements(); uniforms_.emplace_back(std::move(desc)); } } diff --git a/impeller/runtime_stage/runtime_stage.fbs b/impeller/runtime_stage/runtime_stage.fbs index 1391fc565a5a8..bb3d04e00edab 100644 --- a/impeller/runtime_stage/runtime_stage.fbs +++ b/impeller/runtime_stage/runtime_stage.fbs @@ -41,6 +41,7 @@ table UniformDescription { bit_width: uint64; rows: uint64; columns: uint64; + array_elements: uint64; } table RuntimeStage { diff --git a/impeller/runtime_stage/runtime_stage.h b/impeller/runtime_stage/runtime_stage.h index 4f8f9b81488f9..2bbcf83d372fc 100644 --- a/impeller/runtime_stage/runtime_stage.h +++ b/impeller/runtime_stage/runtime_stage.h @@ -41,6 +41,7 @@ struct RuntimeUniformDescription { RuntimeUniformType type = kFloat; RuntimeUniformDimensions dimensions; size_t bit_width; + size_t array_elements; }; size_t SizeOfRuntimeUniformType(RuntimeUniformType type); diff --git a/lib/ui/fixtures/shaders/general_shaders/BUILD.gn b/lib/ui/fixtures/shaders/general_shaders/BUILD.gn index c99d06320baa4..640823715e8f2 100644 --- a/lib/ui/fixtures/shaders/general_shaders/BUILD.gn +++ b/lib/ui/fixtures/shaders/general_shaders/BUILD.gn @@ -16,6 +16,7 @@ if (enable_unittests) { "simple.frag", "uniforms.frag", "uniforms_sorted.frag", + "uniform_arrays.frag", ] group("general_shaders") { diff --git a/lib/ui/fixtures/shaders/general_shaders/uniform_arrays.frag b/lib/ui/fixtures/shaders/general_shaders/uniform_arrays.frag new file mode 100644 index 0000000000000..64878088a9f9d --- /dev/null +++ b/lib/ui/fixtures/shaders/general_shaders/uniform_arrays.frag @@ -0,0 +1,51 @@ +#version 100 core + +// 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. + +precision highp float; + +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 = 21 ) uniform float float2dArray[2][2]; + +void main() { + vec4 badColor = vec4(1.0, 0, 0, 1.0); + vec4 goodColor = vec4(0, 1.0, 0, 1.0); + + // 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 || + vec3Array[1].y >= vec3Array[1].z || + vec3Array[1].z >= mat2Array[0][0][0] || + mat2Array[0][0][0] >= mat2Array[0][0][1] || + mat2Array[0][0][1] >= mat2Array[0][1][0] || + mat2Array[0][1][0] >= mat2Array[0][1][1] || + mat2Array[0][1][1] >= mat2Array[1][0][0] || + mat2Array[1][0][0] >= mat2Array[1][0][1] || + mat2Array[1][0][1] >= mat2Array[1][1][0] || + mat2Array[1][1][0] >= mat2Array[1][1][1] || + mat2Array[1][1][1] >= float2dArray[0][0] || + float2dArray[0][0] >= float2dArray[0][1] || + float2dArray[0][1] >= float2dArray[1][0] || + float2dArray[1][0] >= float2dArray[1][1]) { + oColor = badColor; + } else { + oColor = goodColor; + } +} diff --git a/lib/ui/painting/fragment_program.cc b/lib/ui/painting/fragment_program.cc index a20e813167350..bcd2626d28b33 100644 --- a/lib/ui/painting/fragment_program.cc +++ b/lib/ui/painting/fragment_program.cc @@ -65,6 +65,9 @@ std::string FragmentProgram::initFromAsset(std::string asset_name) { size_t size = uniform_description.dimensions.rows * uniform_description.dimensions.cols * uniform_description.bit_width / 8u; + if (uniform_description.array_elements > 0) { + size *= uniform_description.array_elements; + } other_uniforms_bytes += size; } } diff --git a/testing/dart/fragment_shader_test.dart b/testing/dart/fragment_shader_test.dart index d19a59c0173b7..7fdcdf2742654 100644 --- a/testing/dart/fragment_shader_test.dart +++ b/testing/dart/fragment_shader_test.dart @@ -64,6 +64,22 @@ void main() async { expect(toFloat(renderedBytes.getUint8(3)), closeTo(1.0, epsilon)); }); + test('shader with array uniforms renders correctly', () async { + final FragmentProgram program = await FragmentProgram.fromAsset( + 'uniform_arrays.frag.iplr', + ); + + final List floatArray = List.generate( + 24, (int i) => i.toDouble(), + ); + final Shader shader = program.shader( + floatUniforms: Float32List.fromList([ + ...floatArray, + ])); + + await _expectShaderRendersGreen(shader); + }); + test('The ink_sparkle shader is accepted', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'ink_sparkle.frag.iplr', From a2546d4eaf2325e9971d121298d2078a6ec82f38 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 15:52:05 -0400 Subject: [PATCH 173/558] Roll Fuchsia Mac SDK from kP-yebuRg... to vSCmDPI74... (#35237) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e5fb007ea1601..d6315f10ec53a 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'kP-yebuRgWYJ6_f1FfLyRz5Ax98cvWNY5e3Z6STYNBkC' + 'version': 'vSCmDPI74CIaTFpcbjs1kCpUtkU9O2dUlkG7jLmDhWoC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 1edf99f3c9c02593ff92e75adc5fc83859180022 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 16:08:04 -0400 Subject: [PATCH 174/558] Roll Skia from 7525ca099719 to 4722605332ef (3 revisions) (#35238) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d6315f10ec53a..7c2ffd00ca4df 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': '7525ca09971982717161466016c07fabf9f267ed', + 'skia_revision': '4722605332ef875c451d29199782ad9676b6eb5e', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 58c455fbfc636..b1dcb89ad86e9 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: ec9fb1d49a9df0331e96c8cbbdf66244 +Signature: 14760e201b1fe3c8eb3ec43d2888fba0 UNUSED LICENSES: From 086c02e63ce4c2d5b30acaa29beeab35df103a96 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 16:25:04 -0400 Subject: [PATCH 175/558] Roll Dart SDK from f0036572af95 to 193ac812ac3a (1 revision) (#35239) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 7c2ffd00ca4df..0ae3007c002c5 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'f0036572af9511bbcd1bee7aaf872b394007c5c3', + 'dart_revision': '193ac812ac3a20e54f70373bb5836e3ab933655a', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -233,7 +233,7 @@ deps = { Var('dart_git') + '/json_rpc_2.git@805e6536dd961d66f6b8cd46d8f3e61774f957c9', 'src/third_party/dart/third_party/pkg/linter': - Var('dart_git') + '/linter.git@b4afc10055f3009478da1eac1827f9fef42c3759', + Var('dart_git') + '/linter.git@b677397483251d55ce1aec8d170be7720b53fe26', 'src/third_party/dart/third_party/pkg/logging': Var('dart_git') + '/logging.git@d10e24844c2e01d3f6d2b5a1a2bb8717359c6a87', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index c862926ceff9c..169bfa950e307 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 66a27e79ea91d7a9d2435d0d9b248633 +Signature: bf0ac66b620030bf241fca946db219da UNUSED LICENSES: From b263b546d3be1e78b8ff2399bbc707dee5e8a61c Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Mon, 8 Aug 2022 14:09:04 -0700 Subject: [PATCH 176/558] Add an //ignore now that we are analyzing the sample code (#35235) --- lib/ui/hash_codes.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ui/hash_codes.dart b/lib/ui/hash_codes.dart index 19cf712ad6c5c..ea0f5b9162ba7 100644 --- a/lib/ui/hash_codes.dart +++ b/lib/ui/hash_codes.dart @@ -4,6 +4,7 @@ part of dart.ui; // Examples can assume: +// // ignore_for_file: deprecated_member_use // int foo = 0; // int bar = 0; // List quux = []; From a51c7638e702b086dffaae3ce92f52130a2c23ff Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 8 Aug 2022 14:12:04 -0700 Subject: [PATCH 177/558] [Impeller] Respect the current transform for backdrop filter effect params (#35240) --- impeller/display_list/display_list_dispatcher.cc | 14 ++++++++++---- impeller/display_list/display_list_unittests.cc | 4 +++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index a1d80528d6f09..37f3aa63f0b62 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -387,7 +387,8 @@ void DisplayListDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) { } static std::optional ToImageFilterProc( - const flutter::DlImageFilter* filter) { + const flutter::DlImageFilter* filter, + const Vector2& effect_scale = {1, 1}) { if (filter == nullptr) { return std::nullopt; } @@ -395,8 +396,10 @@ static std::optional ToImageFilterProc( switch (filter->type()) { case flutter::DlImageFilterType::kBlur: { auto blur = filter->asBlur(); - auto sigma_x = Sigma(blur->sigma_x()); - auto sigma_y = Sigma(blur->sigma_y()); + Vector2 scaled_blur = + Vector2(blur->sigma_x(), blur->sigma_y()) * effect_scale; + auto sigma_x = Sigma(scaled_blur.x); + auto sigma_y = Sigma(scaled_blur.y); if (blur->tile_mode() != flutter::DlTileMode::kClamp) { // TODO(105072): Implement tile mode for blur filter. @@ -450,7 +453,10 @@ void DisplayListDispatcher::saveLayer(const SkRect* bounds, const flutter::SaveLayerOptions options, const flutter::DlImageFilter* backdrop) { auto paint = options.renders_with_attributes() ? paint_ : Paint{}; - canvas_.SaveLayer(paint, ToRect(bounds), ToImageFilterProc(backdrop)); + auto scale = canvas_.GetCurrentTransformation().GetScale(); + canvas_.SaveLayer( + paint, ToRect(bounds), + ToImageFilterProc(backdrop, Vector2::MakeXY(scale.x, scale.y))); } // |flutter::Dispatcher| diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index f895bb7f8f0ca..18bd21af98479 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -297,12 +297,14 @@ TEST_P(DisplayListTest, CanDrawBackdropFilter) { } static float sigma[] = {10, 10}; + static float ctm_scale = 1; static bool use_bounds = true; static bool draw_circle = true; static bool add_clip = true; ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); ImGui::SliderFloat2("Sigma", sigma, 0, 100); + ImGui::SliderFloat("Scale", &ctm_scale, 0, 10); ImGui::NewLine(); ImGui::TextWrapped( "If everything is working correctly, none of the options below should " @@ -314,7 +316,7 @@ TEST_P(DisplayListTest, CanDrawBackdropFilter) { flutter::DisplayListBuilder builder; - Vector2 scale = GetContentScale(); + Vector2 scale = ctm_scale * GetContentScale(); builder.scale(scale.x, scale.y); auto filter = flutter::DlBlurImageFilter(sigma[0], sigma[1], From 79f726cbc56095dfd6b5f6057e719c033f167fd5 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 18:37:04 -0400 Subject: [PATCH 178/558] Roll Fuchsia Linux SDK from IfIhCrtMD... to 7q0yjaQTj... (#35243) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0ae3007c002c5..8a0e8c4b58e00 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'IfIhCrtMDOZTReFzSAxoyboXKqNEH7WRdaFXWTjctD4C' + 'version': '7q0yjaQTjdbKoX4iHafZxQ5FRCyLHzwRlqK0YdweaP0C' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index c1df1a0ba0724..8e2f5a92a0bd3 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 818c506d4bd552515c898e3da6aba1f3 +Signature: 8d672f92969a1e9a2c2f5720700bd332 UNUSED LICENSES: From 55413b24a260eb805072cdcb44efd86789aee400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Mon, 8 Aug 2022 16:19:04 -0700 Subject: [PATCH 179/558] [Embedder API] Add next frame callback (#35244) --- shell/common/rasterizer.cc | 2 +- shell/platform/embedder/embedder.cc | 31 +++++++++++++++ shell/platform/embedder/embedder.h | 25 ++++++++++++ .../embedder/tests/embedder_unittests.cc | 38 +++++++++++++++++++ .../include/flutter/flutter_engine.h | 3 +- 5 files changed, 97 insertions(+), 2 deletions(-) diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index d121b90527fab..db5ef54055cc8 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -641,7 +641,7 @@ RasterStatus Rasterizer::DrawToSurfaceUnsafe( frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now()); std::unique_ptr damage; - // when leaf layer tracing is enabled we wish to repaing the whole frame for + // when leaf layer tracing is enabled we wish to repaint the whole frame for // accurate performance metrics. if (frame->framebuffer_info().supports_partial_repaint && !layer_tree.is_leaf_layer_tracing_enabled()) { diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index d69507b5f4c24..0868901fce3d6 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -2683,6 +2683,36 @@ FlutterEngineResult FlutterEngineScheduleFrame(FLUTTER_API_SYMBOL(FlutterEngine) "Could not schedule frame."); } +FlutterEngineResult FlutterEngineSetNextFrameCallback( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + VoidCallback callback, + void* user_data) { + if (engine == nullptr) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid engine handle."); + } + + if (callback == nullptr) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, + "Next frame callback was null."); + } + + flutter::EmbedderEngine* embedder_engine = + reinterpret_cast(engine); + + fml::WeakPtr weak_platform_view = + embedder_engine->GetShell().GetPlatformView(); + + if (!weak_platform_view) { + return LOG_EMBEDDER_ERROR(kInternalInconsistency, + "Platform view unavailable."); + } + + weak_platform_view->SetNextFrameCallback( + [callback, user_data]() { callback(user_data); }); + + return kSuccess; +} + FlutterEngineResult FlutterEngineGetProcAddresses( FlutterEngineProcTable* table) { if (!table) { @@ -2734,6 +2764,7 @@ FlutterEngineResult FlutterEngineGetProcAddresses( FlutterEnginePostCallbackOnAllNativeThreads); SET_PROC(NotifyDisplayUpdate, FlutterEngineNotifyDisplayUpdate); SET_PROC(ScheduleFrame, FlutterEngineScheduleFrame); + SET_PROC(SetNextFrameCallback, FlutterEngineSetNextFrameCallback); #undef SET_PROC return kSuccess; diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 43fd5bd5b1cde..88a3014f0218f 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -2510,6 +2510,26 @@ FLUTTER_EXPORT FlutterEngineResult FlutterEngineScheduleFrame(FLUTTER_API_SYMBOL(FlutterEngine) engine); +//------------------------------------------------------------------------------ +/// @brief Schedule a callback to be called after the next frame is drawn. +/// This must be called from the platform thread. The callback is +/// executed only once from the raster thread; embedders must +/// re-thread if necessary. Performing blocking calls +/// in this callback may introduce application jank. +/// +/// @param[in] engine A running engine instance. +/// @param[in] callback The callback to execute. +/// @param[in] user_data A baton passed by the engine to the callback. This +/// baton is not interpreted by the engine in any way. +/// +/// @return The result of the call. +/// +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineSetNextFrameCallback( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + VoidCallback callback, + void* user_data); + #endif // !FLUTTER_ENGINE_NO_PROTOTYPES // Typedefs for the function pointers in FlutterEngineProcTable. @@ -2628,6 +2648,10 @@ typedef FlutterEngineResult (*FlutterEngineNotifyDisplayUpdateFnPtr)( size_t display_count); typedef FlutterEngineResult (*FlutterEngineScheduleFrameFnPtr)( FLUTTER_API_SYMBOL(FlutterEngine) engine); +typedef FlutterEngineResult (*FlutterEngineSetNextFrameCallbackFnPtr)( + FLUTTER_API_SYMBOL(FlutterEngine) engine, + VoidCallback callback, + void* user_data); /// Function-pointer-based versions of the APIs above. typedef struct { @@ -2673,6 +2697,7 @@ typedef struct { PostCallbackOnAllNativeThreads; FlutterEngineNotifyDisplayUpdateFnPtr NotifyDisplayUpdate; FlutterEngineScheduleFrameFnPtr ScheduleFrame; + FlutterEngineSetNextFrameCallbackFnPtr SetNextFrameCallback; } FlutterEngineProcTable; //------------------------------------------------------------------------------ diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index d2b0c96b3c99b..74c3782c037fc 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -2126,6 +2126,44 @@ TEST_F(EmbedderTest, CanScheduleFrame) { check_latch.Wait(); } +TEST_F(EmbedderTest, CanSetNextFrameCallback) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext); + EmbedderConfigBuilder builder(context); + builder.SetSoftwareRendererConfig(); + builder.SetDartEntrypoint("draw_solid_red"); + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + // Register the callback that is executed once the next frame is drawn. + fml::AutoResetWaitableEvent callback_latch; + VoidCallback callback = [](void* user_data) { + fml::AutoResetWaitableEvent* callback_latch = + static_cast(user_data); + + callback_latch->Signal(); + }; + + auto result = FlutterEngineSetNextFrameCallback(engine.get(), callback, + &callback_latch); + ASSERT_EQ(result, kSuccess); + + // Send a window metrics events so frames may be scheduled. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 800; + event.height = 600; + event.pixel_ratio = 1.0; + event.physical_view_inset_top = 0.0; + event.physical_view_inset_right = 0.0; + event.physical_view_inset_bottom = 0.0; + event.physical_view_inset_left = 0.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); + + callback_latch.Wait(); +} + #if defined(FML_OS_MACOSX) static void MockThreadConfigSetter(const fml::Thread::ThreadConfig& config) { diff --git a/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h b/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h index 464c233fa9bfa..688361740ebc8 100644 --- a/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h +++ b/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h @@ -22,7 +22,8 @@ namespace flutter { // // In the future, this will be the API surface used for all interactions with // the engine, rather than having them duplicated on FlutterViewController. -// For now it is only used in the rare where you need a headless Flutter engine. +// For now it is only used in the rare case where you need a headless Flutter +// engine. class FlutterEngine : public PluginRegistry { public: // Creates a new engine for running the given project. From b5cad9f69d93acc792928cf2183cc621447a6e04 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 8 Aug 2022 16:25:50 -0700 Subject: [PATCH 180/558] Unify tiling functionality in shader lib (#35245) --- .../shader_lib/impeller/constants.glsl | 5 +++ .../compiler/shader_lib/impeller/texture.glsl | 39 ++++++++++++------- .../shaders/blending/advanced_blend.glsl | 13 ++++--- impeller/entity/shaders/gaussian_blur.frag | 21 ++++++---- impeller/entity/shaders/gradient_fill.frag | 2 +- .../entity/shaders/radial_gradient_fill.frag | 2 +- .../entity/shaders/sweep_gradient_fill.frag | 2 +- 7 files changed, 54 insertions(+), 30 deletions(-) diff --git a/impeller/compiler/shader_lib/impeller/constants.glsl b/impeller/compiler/shader_lib/impeller/constants.glsl index b8e24739834f9..0ead4981f6411 100644 --- a/impeller/compiler/shader_lib/impeller/constants.glsl +++ b/impeller/compiler/shader_lib/impeller/constants.glsl @@ -6,6 +6,11 @@ #define CONSTANTS_GLSL_ const float kEhCloseEnough = 0.000001; + +// 1 / (2 * pi) const float k1Over2Pi = 0.1591549430918; +// sqrt(2 * pi) +const float kSqrtTwoPi = 2.50662827463; + #endif diff --git a/impeller/compiler/shader_lib/impeller/texture.glsl b/impeller/compiler/shader_lib/impeller/texture.glsl index 9ef001303be88..99875b068837d 100644 --- a/impeller/compiler/shader_lib/impeller/texture.glsl +++ b/impeller/compiler/shader_lib/impeller/texture.glsl @@ -19,16 +19,6 @@ vec4 IPSample(sampler2D texture_sampler, vec2 coords, float y_coord_scale) { return texture(texture_sampler, coords); } -/// Sample a texture, emulating SamplerAddressMode::ClampToBorder. -/// -/// This is useful for Impeller graphics backend that don't support -/// ClampToBorder. -vec4 IPSampleClampToBorder(sampler2D tex, vec2 uv) { - float within_bounds = float(uv.x > 0 && uv.y > 0 && uv.x < 1 && uv.y < 1); - return texture(tex, uv) * within_bounds; -} - - // These values must correspond to the order of the items in the // 'Entity::TileMode' enum class. const float kTileModeClamp = 0; @@ -36,10 +26,13 @@ const float kTileModeRepeat = 1; const float kTileModeMirror = 2; const float kTileModeDecal = 3; -/// Compute an interpolant value "t". +/// Remap a float using a tiling mode. /// -/// The domain appears to be any value and the range is [0 to 1]. -float IPTileTextureCoords(float t, float tile_mode) { +/// When `tile_mode` is `kTileModeDecal`, no tiling is applied and `t` is +/// returned. In all other cases, a value between 0 and 1 is returned by tiling +/// `t`. +/// When `t` is between [0 to 1), the original unchanged `t` is always returned. +float IPFloatTile(float t, float tile_mode) { if (tile_mode == kTileModeClamp) { t = clamp(t, 0.0, 1.0); } else if (tile_mode == kTileModeRepeat) { @@ -52,4 +45,24 @@ float IPTileTextureCoords(float t, float tile_mode) { return t; } +/// Remap a vec2 using a tiling mode. +/// +/// Runs each component of the vec2 through `IPFloatTile`. +vec2 IPVec2Tile(vec2 uv, float tile_mode) { + return vec2(IPFloatTile(uv.x, tile_mode), IPFloatTile(uv.y, tile_mode)); +} + +/// Sample a texture, emulating a specific tile mode. +/// +/// This is useful for Impeller graphics backend that don't have native support +/// for Decal. +vec4 IPSampleWithTileMode(sampler2D tex, vec2 uv, float tile_mode) { + if (tile_mode == kTileModeDecal && + (uv.x < 0 || uv.y < 0 || uv.x >= 1 || uv.y >= 1)) { + return vec4(0); + } + + return texture(tex, IPVec2Tile(uv, tile_mode)); +} + #endif diff --git a/impeller/entity/shaders/blending/advanced_blend.glsl b/impeller/entity/shaders/blending/advanced_blend.glsl index 57547ca5fe5f3..3bbfe8a226703 100644 --- a/impeller/entity/shaders/blending/advanced_blend.glsl +++ b/impeller/entity/shaders/blending/advanced_blend.glsl @@ -21,12 +21,13 @@ in vec2 v_src_texture_coords; out vec4 frag_color; void main() { - vec4 dst = IPUnpremultiply( - IPSampleClampToBorder(texture_sampler_dst, v_dst_texture_coords)); - vec4 src = blend_info.color_factor > 0 - ? blend_info.color - : IPUnpremultiply(IPSampleClampToBorder(texture_sampler_src, - v_src_texture_coords)); + vec4 dst = IPUnpremultiply(IPSampleWithTileMode( + texture_sampler_dst, v_dst_texture_coords, kTileModeDecal)); + vec4 src = + blend_info.color_factor > 0 + ? blend_info.color + : IPUnpremultiply(IPSampleWithTileMode( + texture_sampler_src, v_src_texture_coords, kTileModeDecal)); vec3 blended = Blend(dst.rgb, src.rgb); diff --git a/impeller/entity/shaders/gaussian_blur.frag b/impeller/entity/shaders/gaussian_blur.frag index d43a05497cad8..8a9281a74c4dc 100644 --- a/impeller/entity/shaders/gaussian_blur.frag +++ b/impeller/entity/shaders/gaussian_blur.frag @@ -7,8 +7,13 @@ // Paths for future optimization: // * Remove the uv bounds multiplier in SampleColor by adding optional // support for SamplerAddressMode::ClampToBorder in the texture sampler. -// * Sample from higher mipmap levels when the blur radius is high enough. +// * Render both blur passes into a smaller texture than the source image +// (~1/radius size). +// * If doing the small texture render optimization, cache misses can be +// reduced in the first pass by sampling the source textures with a mip +// level of log2(min_radius). +#include #include uniform sampler2D texture_sampler; @@ -23,15 +28,14 @@ uniform FragInfo { float src_factor; float inner_blur_factor; float outer_blur_factor; -} frag_info; +} +frag_info; in vec2 v_texture_coords; in vec2 v_src_texture_coords; out vec4 frag_color; -const float kSqrtTwoPi = 2.50662827463; - float Gaussian(float x) { float variance = frag_info.blur_sigma * frag_info.blur_sigma; return exp(-0.5 * x * x / variance) / (kSqrtTwoPi * frag_info.blur_sigma); @@ -46,14 +50,15 @@ void main() { float gaussian = Gaussian(i); gaussian_integral += gaussian; total_color += - gaussian * IPSampleClampToBorder(texture_sampler, - v_texture_coords + blur_uv_offset * i); + gaussian * IPSampleWithTileMode(texture_sampler, + v_texture_coords + blur_uv_offset * i, + kTileModeDecal); } vec4 blur_color = total_color / gaussian_integral; - vec4 src_color = - IPSampleClampToBorder(alpha_mask_sampler, v_src_texture_coords); + vec4 src_color = IPSampleWithTileMode(alpha_mask_sampler, + v_src_texture_coords, kTileModeDecal); float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) + frag_info.outer_blur_factor * float(src_color.a == 0); diff --git a/impeller/entity/shaders/gradient_fill.frag b/impeller/entity/shaders/gradient_fill.frag index 858c56b83b8e8..407cd98bc2dfe 100644 --- a/impeller/entity/shaders/gradient_fill.frag +++ b/impeller/entity/shaders/gradient_fill.frag @@ -28,6 +28,6 @@ void main() { return; } - t = IPTileTextureCoords(t, gradient_info.tile_mode); + t = IPFloatTile(t, gradient_info.tile_mode); frag_color = mix(gradient_info.start_color, gradient_info.end_color, t); } diff --git a/impeller/entity/shaders/radial_gradient_fill.frag b/impeller/entity/shaders/radial_gradient_fill.frag index 1e6f46dace8fd..07a7f9eeb39a3 100644 --- a/impeller/entity/shaders/radial_gradient_fill.frag +++ b/impeller/entity/shaders/radial_gradient_fill.frag @@ -24,6 +24,6 @@ void main() { return; } - t = IPTileTextureCoords(t, gradient_info.tile_mode); + t = IPFloatTile(t, gradient_info.tile_mode); frag_color = mix(gradient_info.center_color, gradient_info.edge_color, t); } diff --git a/impeller/entity/shaders/sweep_gradient_fill.frag b/impeller/entity/shaders/sweep_gradient_fill.frag index 1be76ba7b4483..8a7365d0c291b 100644 --- a/impeller/entity/shaders/sweep_gradient_fill.frag +++ b/impeller/entity/shaders/sweep_gradient_fill.frag @@ -28,6 +28,6 @@ void main() { return; } - t = IPTileTextureCoords(t, gradient_info.tile_mode); + t = IPFloatTile(t, gradient_info.tile_mode); frag_color = mix(gradient_info.start_color, gradient_info.end_color, t); } From d138190874dbc202155f1f4c4a7b9e5eeffae78e Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Mon, 8 Aug 2022 16:53:28 -0700 Subject: [PATCH 181/558] [impeller] [vulkan] Add support for swapchain creation and swapchain (#35199) images Also wires up playground surface creation and swapchain setup. --- ci/licenses_golden/licenses_flutter | 4 + .../backend/vulkan/playground_impl_vk.cc | 39 +++++- .../backend/vulkan/playground_impl_vk.h | 13 ++ impeller/renderer/backend/vulkan/BUILD.gn | 4 + .../renderer/backend/vulkan/context_vk.cc | 29 +++++ impeller/renderer/backend/vulkan/context_vk.h | 7 + .../backend/vulkan/swapchain_details_vk.cc | 107 +++++++++++++++ .../backend/vulkan/swapchain_details_vk.h | 42 ++++++ .../renderer/backend/vulkan/swapchain_vk.cc | 123 ++++++++++++++++++ .../renderer/backend/vulkan/swapchain_vk.h | 55 ++++++++ 10 files changed, 421 insertions(+), 2 deletions(-) create mode 100644 impeller/renderer/backend/vulkan/swapchain_details_vk.cc create mode 100644 impeller/renderer/backend/vulkan/swapchain_details_vk.h create mode 100644 impeller/renderer/backend/vulkan/swapchain_vk.cc create mode 100644 impeller/renderer/backend/vulkan/swapchain_vk.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 2ef7fd3b185bf..24274f98c999c 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -795,6 +795,10 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/shader_library_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/shader_library_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_details_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_details_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/texture_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/texture_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/vertex_descriptor_vk.cc diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index ee3d7b477a6f8..ad67592a6d23a 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -6,6 +6,7 @@ #include "impeller/renderer/backend/vulkan/vk.h" +#define GLFW_INCLUDE_VULKAN #include #include "flutter/fml/logging.h" @@ -34,13 +35,35 @@ ShaderLibraryMappingsForPlayground() { }; } +void PlaygroundImplVK::DestroyWindowHandle(WindowHandle handle) { + if (!handle) { + return; + } + ::glfwDestroyWindow(reinterpret_cast(handle)); +} + PlaygroundImplVK::PlaygroundImplVK() - : concurrent_loop_(fml::ConcurrentMessageLoop::Create()) { + : concurrent_loop_(fml::ConcurrentMessageLoop::Create()), + handle_(nullptr, &DestroyWindowHandle) { if (!::glfwVulkanSupported()) { VALIDATION_LOG << "Attempted to initialize a Vulkan playground on a system " "that does not support Vulkan."; return; } + + ::glfwDefaultWindowHints(); + ::glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + ::glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + + auto window = + ::glfwCreateWindow(800, 600, "Test Vulkan Window", nullptr, nullptr); + if (!window) { + VALIDATION_LOG << "Unable to create glfw window"; + return; + } + + handle_.reset(window); + auto context = ContextVK::Create(reinterpret_cast( &::glfwGetInstanceProcAddress), // ShaderLibraryMappingsForPlayground(), // @@ -55,6 +78,18 @@ PlaygroundImplVK::PlaygroundImplVK() } context_ = std::move(context); + + SetupSwapchain(); +} + +void PlaygroundImplVK::SetupSwapchain() { + ContextVK* context_vk = reinterpret_cast(context_.get()); + auto window = reinterpret_cast(handle_.get()); + + ::glfwCreateWindowSurface(context_vk->GetInstance(), window, nullptr, + &surface_); + + swapchain_ = context_vk->CreateSwapchain(surface_); } PlaygroundImplVK::~PlaygroundImplVK() = default; @@ -66,7 +101,7 @@ std::shared_ptr PlaygroundImplVK::GetContext() const { // |PlaygroundImpl| PlaygroundImpl::WindowHandle PlaygroundImplVK::GetWindowHandle() const { - FML_UNREACHABLE(); + return handle_.get(); } // |PlaygroundImpl| diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.h b/impeller/playground/backend/vulkan/playground_impl_vk.h index 77747e72da07d..55dd7f72a13b8 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.h +++ b/impeller/playground/backend/vulkan/playground_impl_vk.h @@ -7,6 +7,8 @@ #include "flutter/fml/concurrent_message_loop.h" #include "flutter/fml/macros.h" #include "impeller/playground/playground_impl.h" +#include "impeller/renderer/backend/vulkan/swapchain_vk.h" +#include "impeller/renderer/backend/vulkan/vk.h" namespace impeller { @@ -20,6 +22,15 @@ class PlaygroundImplVK final : public PlaygroundImpl { std::shared_ptr concurrent_loop_; std::shared_ptr context_; + // windows + static void DestroyWindowHandle(WindowHandle handle); + using UniqueHandle = std::unique_ptr; + UniqueHandle handle_; + + // surface and swapchain + VkSurfaceKHR surface_; + std::unique_ptr swapchain_; + // |PlaygroundImpl| std::shared_ptr GetContext() const override; @@ -30,6 +41,8 @@ class PlaygroundImplVK final : public PlaygroundImpl { std::unique_ptr AcquireSurfaceFrame( std::shared_ptr context) override; + void SetupSwapchain(); + FML_DISALLOW_COPY_AND_ASSIGN(PlaygroundImplVK); }; diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn index bde65b844f691..f6e2c841aceb5 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -36,6 +36,10 @@ impeller_component("vulkan") { "shader_library_vk.h", "surface_vk.cc", "surface_vk.h", + "swapchain_details_vk.cc", + "swapchain_details_vk.h", + "swapchain_vk.cc", + "swapchain_vk.h", "texture_vk.cc", "texture_vk.h", "vertex_descriptor_vk.cc", diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 08006255503aa..132100b5d42b3 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -14,6 +14,7 @@ #include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/allocator_vk.h" #include "impeller/renderer/backend/vulkan/capabilities_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain_details_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE @@ -27,6 +28,10 @@ static std::set kRequiredDeviceExtensions = { #endif }; +#if FML_OS_MACOSX +static const char* MVK_MACOS_SURFACE_EXT = "VK_MVK_macos_surface"; +#endif + static bool HasRequiredQueues(const vk::PhysicalDevice& device) { auto present_flags = vk::QueueFlags{}; for (const auto& queue : device.getQueueFamilyProperties()) { @@ -205,6 +210,14 @@ ContextVK::ContextVK( // is a requirement for opting into Molten VK on Mac. enabled_extensions.push_back( VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + + // Required for glfw macOS surfaces. + if (!capabilities->HasExtension(MVK_MACOS_SURFACE_EXT)) { + VALIDATION_LOG << "On Mac: Required extension " << MVK_MACOS_SURFACE_EXT + << " absent."; + return; + } + enabled_extensions.push_back(MVK_MACOS_SURFACE_EXT); #endif // FML_OS_MACOSX //---------------------------------------------------------------------------- @@ -308,6 +321,8 @@ ContextVK::ContextVK( auto compute_queue = PickQueue(physical_device.value(), vk::QueueFlagBits::eCompute); + physical_device_ = physical_device.value(); + if (!graphics_queue.has_value() || !transfer_queue.has_value() || !compute_queue.has_value()) { VALIDATION_LOG << "Could not pick device queues."; @@ -423,4 +438,18 @@ std::shared_ptr ContextVK::CreateTransferCommandBuffer() const { FML_UNREACHABLE(); } +vk::Instance ContextVK::GetInstance() const { + return *instance_; +} + +std::unique_ptr ContextVK::CreateSwapchain( + vk::SurfaceKHR surface) const { + auto swapchain_details = + SwapchainDetailsVK::Create(physical_device_, surface); + if (!swapchain_details) { + return nullptr; + } + return SwapchainVK::Create(*device_, surface, *swapchain_details); +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 92e8db97335cd..c7cb39b70a7e7 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -13,6 +13,7 @@ #include "impeller/renderer/backend/vulkan/pipeline_library_vk.h" #include "impeller/renderer/backend/vulkan/sampler_library_vk.h" #include "impeller/renderer/backend/vulkan/shader_library_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/context.h" @@ -54,10 +55,16 @@ class ContextVK final : public Context, public BackendCast { return true; } + vk::Instance GetInstance() const; + + std::unique_ptr CreateSwapchain( + vk::SurfaceKHR surface) const; + private: std::shared_ptr worker_task_runner_; vk::UniqueInstance instance_; vk::UniqueDebugUtilsMessengerEXT debug_messenger_; + vk::PhysicalDevice physical_device_; vk::UniqueDevice device_; std::shared_ptr allocator_; std::shared_ptr shader_library_; diff --git a/impeller/renderer/backend/vulkan/swapchain_details_vk.cc b/impeller/renderer/backend/vulkan/swapchain_details_vk.cc new file mode 100644 index 0000000000000..726e04c87f0b2 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain_details_vk.cc @@ -0,0 +1,107 @@ +// 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/renderer/backend/vulkan/swapchain_details_vk.h" + +#include "impeller/base/validation.h" + +namespace impeller { + +std::unique_ptr SwapchainDetailsVK::Create( + vk::PhysicalDevice physical_device, + vk::SurfaceKHR surface) { + FML_DCHECK(surface) << "surface provided as nullptr"; + + auto capabilities_res = physical_device.getSurfaceCapabilitiesKHR(surface); + if (capabilities_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to get surface capabilities: " + << vk::to_string(capabilities_res.result); + return nullptr; + } + vk::SurfaceCapabilitiesKHR capabilities = capabilities_res.value; + + auto surface_formats_res = physical_device.getSurfaceFormatsKHR(surface); + if (surface_formats_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to get surface formats: " + << vk::to_string(surface_formats_res.result); + return nullptr; + } + std::vector surface_formats = surface_formats_res.value; + + auto surface_present_modes_res = + physical_device.getSurfacePresentModesKHR(surface); + if (surface_present_modes_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to get surface present modes: " + << vk::to_string(surface_present_modes_res.result); + return nullptr; + } + std::vector surface_present_modes = + surface_present_modes_res.value; + + return std::make_unique(capabilities, surface_formats, + surface_present_modes); +} + +vk::SurfaceFormatKHR SwapchainDetailsVK::PickSurfaceFormat() const { + for (const auto& format : surface_formats_) { + if ((format.format == vk::Format::eR8G8B8A8Unorm || + format.format == vk::Format::eB8G8R8A8Unorm) && + format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { + return format; + } + } + + VALIDATION_LOG << "Picking a sub-optimal surface format."; + return surface_formats_[0]; +} + +vk::PresentModeKHR SwapchainDetailsVK::PickPresentationMode() const { + for (const auto& mode : present_modes_) { + if (mode == vk::PresentModeKHR::eMailbox) { + return mode; + } + } + + VALIDATION_LOG << "Picking a sub-optimal presentation mode."; + // Vulkan spec dictates that FIFO is always available. + return vk::PresentModeKHR::eFifo; +} + +vk::Extent2D SwapchainDetailsVK::PickExtent() const { + if (surface_capabilities_.currentExtent.width != + std::numeric_limits::max()) { + return surface_capabilities_.currentExtent; + } + + vk::Extent2D actual_extent = { + std::max(surface_capabilities_.minImageExtent.width, + std::min(surface_capabilities_.maxImageExtent.width, + surface_capabilities_.currentExtent.width)), + std::max(surface_capabilities_.minImageExtent.height, + std::min(surface_capabilities_.maxImageExtent.height, + surface_capabilities_.currentExtent.height))}; + return actual_extent; +} + +uint32_t SwapchainDetailsVK::GetImageCount() const { + uint32_t image_count = surface_capabilities_.minImageCount; + // for triple buffering + return image_count + 1; +} + +vk::SurfaceTransformFlagBitsKHR SwapchainDetailsVK::GetTransform() const { + return surface_capabilities_.currentTransform; +} + +SwapchainDetailsVK::SwapchainDetailsVK( + vk::SurfaceCapabilitiesKHR capabilities, + std::vector surface_formats, + std::vector surface_present_modes) + : surface_capabilities_(capabilities), + surface_formats_(surface_formats), + present_modes_(surface_present_modes) {} + +SwapchainDetailsVK::~SwapchainDetailsVK() = default; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain_details_vk.h b/impeller/renderer/backend/vulkan/swapchain_details_vk.h new file mode 100644 index 0000000000000..1cfb2b1233c3f --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain_details_vk.h @@ -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. + +#pragma once + +#include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/vk.h" + +namespace impeller { + +class SwapchainDetailsVK { + public: + static std::unique_ptr Create( + vk::PhysicalDevice physical_device, + vk::SurfaceKHR surface); + + SwapchainDetailsVK(vk::SurfaceCapabilitiesKHR capabilities, + std::vector surface_formats, + std::vector surface_present_modes); + + ~SwapchainDetailsVK(); + + vk::SurfaceFormatKHR PickSurfaceFormat() const; + + vk::PresentModeKHR PickPresentationMode() const; + + vk::Extent2D PickExtent() const; + + uint32_t GetImageCount() const; + + vk::SurfaceTransformFlagBitsKHR GetTransform() const; + + private: + vk::SurfaceCapabilitiesKHR surface_capabilities_; + std::vector surface_formats_; + std::vector present_modes_; + + FML_DISALLOW_COPY_AND_ASSIGN(SwapchainDetailsVK); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain_vk.cc b/impeller/renderer/backend/vulkan/swapchain_vk.cc new file mode 100644 index 0000000000000..62b455a928fa8 --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain_vk.cc @@ -0,0 +1,123 @@ +// 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/renderer/backend/vulkan/swapchain_vk.h" + +#include "fml/logging.h" +#include "impeller/base/validation.h" + +namespace impeller { + +std::unique_ptr SwapchainVK::Create(vk::Device device, + vk::SurfaceKHR surface, + SwapchainDetailsVK& details) { + vk::SurfaceFormatKHR surface_format = details.PickSurfaceFormat(); + vk::PresentModeKHR present_mode = details.PickPresentationMode(); + vk::Extent2D extent = details.PickExtent(); + + vk::SwapchainCreateInfoKHR create_info; + create_info.surface = surface; + create_info.imageFormat = surface_format.format; + create_info.imageColorSpace = surface_format.colorSpace; + create_info.presentMode = present_mode; + create_info.imageExtent = extent; + + create_info.minImageCount = details.GetImageCount(); + create_info.imageArrayLayers = 1; + create_info.imageUsage = vk::ImageUsageFlagBits::eColorAttachment; + create_info.preTransform = details.GetTransform(); + create_info.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque; + create_info.clipped = VK_TRUE; + + create_info.imageSharingMode = vk::SharingMode::eExclusive; + { + // TODO (kaushikiska): This needs to change if graphics queue is not the + // same as present queue which is rare. + create_info.queueFamilyIndexCount = 0; + create_info.pQueueFamilyIndices = nullptr; + } + + create_info.oldSwapchain = nullptr; + + auto swapchain_res = device.createSwapchainKHRUnique(create_info); + if (swapchain_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to create swapchain: " + << vk::to_string(swapchain_res.result); + return nullptr; + } + + auto swapchain = std::make_unique(std::move(swapchain_res.value), + surface_format.format, extent); + if (!swapchain->CreateSwapchainImages(device)) { + VALIDATION_LOG << "Failed to create swapchain images."; + return nullptr; + } + + return swapchain; +} + +bool SwapchainVK::CreateSwapchainImages(vk::Device device) { + FML_DCHECK(swapchain_images_.empty()) << "Swapchain images already created"; + auto res = device.getSwapchainImagesKHR(*swapchain_); + if (res.result != vk::Result::eSuccess) { + FML_CHECK(false) << "Failed to get swapchain images: " + << vk::to_string(res.result); + return false; + } + + std::vector images = res.value; + for (const auto& image : images) { + vk::ImageViewCreateInfo create_info; + create_info.image = image; + create_info.viewType = vk::ImageViewType::e2D; + create_info.format = image_format_; + + create_info.components.r = vk::ComponentSwizzle::eIdentity; + create_info.components.g = vk::ComponentSwizzle::eIdentity; + create_info.components.b = vk::ComponentSwizzle::eIdentity; + create_info.components.a = vk::ComponentSwizzle::eIdentity; + + // TODO (kaushikiska): This has to match up to the texture we will be + // rendering to (TextureVK). + create_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; + create_info.subresourceRange.baseMipLevel = 0; + create_info.subresourceRange.levelCount = 1; + create_info.subresourceRange.baseArrayLayer = 0; + create_info.subresourceRange.layerCount = 1; + + auto img_view_res = device.createImageViewUnique(create_info); + if (img_view_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to create image view: " + << vk::to_string(img_view_res.result); + return false; + } + + swapchain_images_.push_back(std::make_unique( + image, std::move(img_view_res.value), image_format_, extent_)); + } + + return true; +} + +SwapchainVK::SwapchainVK(vk::UniqueSwapchainKHR swapchain, + vk::Format image_format, + vk::Extent2D extent) + : swapchain_(std::move(swapchain)), + image_format_(image_format), + extent_(extent) {} + +SwapchainVK::~SwapchainVK() = default; + +SwapchainImageVK::SwapchainImageVK(vk::Image image, + vk::UniqueImageView image_view, + vk::Format image_format, + vk::Extent2D extent) + : image_(image), + image_view_(std::move(image_view)), + image_format_(image_format), + extent_(extent) {} + +SwapchainImageVK::~SwapchainImageVK() = default; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain_vk.h b/impeller/renderer/backend/vulkan/swapchain_vk.h new file mode 100644 index 0000000000000..ad585c3b0c4dd --- /dev/null +++ b/impeller/renderer/backend/vulkan/swapchain_vk.h @@ -0,0 +1,55 @@ +// 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 "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/swapchain_details_vk.h" + +namespace impeller { + +class SwapchainImageVK { + public: + SwapchainImageVK(vk::Image image, + vk::UniqueImageView image_view, + vk::Format image_format, + vk::Extent2D extent); + + ~SwapchainImageVK(); + + private: + vk::Image image_; + vk::UniqueImageView image_view_; + vk::Format image_format_; + vk::Extent2D extent_; + + FML_DISALLOW_COPY_AND_ASSIGN(SwapchainImageVK); +}; + +class SwapchainVK { + public: + static std::unique_ptr Create(vk::Device device, + vk::SurfaceKHR surface, + SwapchainDetailsVK& details); + + SwapchainVK(vk::UniqueSwapchainKHR swapchain, + vk::Format image_format, + vk::Extent2D extent); + + ~SwapchainVK(); + + private: + bool CreateSwapchainImages(vk::Device device); + + vk::UniqueSwapchainKHR swapchain_; + vk::Format image_format_; + vk::Extent2D extent_; + std::vector> swapchain_images_; + + FML_DISALLOW_COPY_AND_ASSIGN(SwapchainVK); +}; + +} // namespace impeller From 9bfbc548a6c71a4d0341e934fb9f11bab448fa79 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Mon, 8 Aug 2022 17:04:40 -0700 Subject: [PATCH 182/558] [Windows] Fix dllimport issue in unit tests (#35246) In flutter/engine#35106, I landed a parameter type fix for the declaration of FlutterDesktopEngineGetTextureRegistrar in our public Windows C API. I also added a unit test that called this function. That function (and all others) in our public Windows API is marked FLUTTER_EXPORT, which resolves to __declspec(dllexport) or __declspec(dllimport) depending on whether FLUTTER_DESKTOP_LIBRARY is defined. It can be defined by adding the following build config: //flutter/shell/platform/common:desktop_library_implementation If the function is marked as an import, we get linker warnings that we're importing a function that's defined in the same executable image. This patch resolves this by marking the functions as export. An alternative fix would be to support a third macro resolution that resolves to nothing in the presence of some definition like FLUTTER_NO_EXPORT; however, since flutter_export.h is a public header, I'd prefer not to complicate it further, and this is a unit test that can't be linked against either way. Issue: https://github.com/flutter/flutter/issues/109184 Original issue: https://github.com/flutter/flutter/issues/86617 See: https://github.com/flutter/engine/blob/main/shell/platform/common/public/flutter_export.h See: https://github.com/flutter/engine/blob/a51c7638e702b086dffaae3ce92f52130a2c23ff/shell/platform/common/BUILD.gn#L8-L10 No new tests since this simply fixes a link warning message in unit tests. --- shell/platform/windows/BUILD.gn | 3 +++ 1 file changed, 3 insertions(+) diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index c83e5f2fdba99..09597e321851f 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -205,6 +205,9 @@ executable("flutter_windows_unittests") { "window_unittests.cc", ] + configs += + [ "//flutter/shell/platform/common:desktop_library_implementation" ] + public_configs = [ "//flutter:config" ] deps = [ From 6c14fb339fe10af4ee87dd891912ca7fcc595de3 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 8 Aug 2022 18:30:05 -0700 Subject: [PATCH 183/558] [Impeller] Add tile modes to gaussian blur (#35249) --- impeller/aiks/paint.cc | 3 +- .../display_list/display_list_dispatcher.cc | 33 ++++++++++++------- .../contents/filters/filter_contents.cc | 12 ++++--- .../entity/contents/filters/filter_contents.h | 4 ++- .../filters/gaussian_blur_filter_contents.cc | 6 ++++ .../filters/gaussian_blur_filter_contents.h | 3 ++ impeller/entity/entity_unittests.cc | 18 ++++++---- impeller/entity/shaders/gaussian_blur.frag | 13 ++++++-- 8 files changed, 65 insertions(+), 27 deletions(-) diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index e32b556a07fca..2d49996f3c485 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -65,7 +65,8 @@ std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( FilterInput::Ref input, bool is_solid_color) const { if (is_solid_color) { - return FilterContents::MakeGaussianBlur(input, sigma, sigma, style); + return FilterContents::MakeGaussianBlur(input, sigma, sigma, style, + Entity::TileMode::kDecal); } return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style); } diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 37f3aa63f0b62..a0678a2e8aa42 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -103,6 +103,19 @@ static Entity::BlendMode ToBlendMode(flutter::DlBlendMode mode) { FML_UNREACHABLE(); } +static Entity::TileMode ToTileMode(flutter::DlTileMode tile_mode) { + switch (tile_mode) { + case flutter::DlTileMode::kClamp: + return Entity::TileMode::kClamp; + case flutter::DlTileMode::kRepeat: + return Entity::TileMode::kRepeat; + case flutter::DlTileMode::kMirror: + return Entity::TileMode::kMirror; + case flutter::DlTileMode::kDecal: + return Entity::TileMode::kDecal; + } +} + // |flutter::Dispatcher| void DisplayListDispatcher::setAntiAlias(bool aa) { // Nothing to do because AA is implicit. @@ -248,7 +261,7 @@ void DisplayListDispatcher::setColorSource( colors.emplace_back(ToColor(linear->colors()[i])); } contents->SetColors(std::move(colors)); - contents->SetTileMode(static_cast(linear->tile_mode())); + contents->SetTileMode(ToTileMode(linear->tile_mode())); paint_.contents = std::move(contents); return; } @@ -264,8 +277,7 @@ void DisplayListDispatcher::setColorSource( colors.emplace_back(ToColor(radialGradient->colors()[i])); } contents->SetColors(std::move(colors)); - contents->SetTileMode( - static_cast(radialGradient->tile_mode())); + contents->SetTileMode(ToTileMode(radialGradient->tile_mode())); paint_.contents = std::move(contents); return; } @@ -282,8 +294,7 @@ void DisplayListDispatcher::setColorSource( colors.emplace_back(ToColor(sweepGradient->colors()[i])); } contents->SetColors(std::move(colors)); - contents->SetTileMode( - static_cast(sweepGradient->tile_mode())); + contents->SetTileMode(ToTileMode(sweepGradient->tile_mode())); paint_.contents = std::move(contents); return; } @@ -400,14 +411,12 @@ static std::optional ToImageFilterProc( Vector2(blur->sigma_x(), blur->sigma_y()) * effect_scale; auto sigma_x = Sigma(scaled_blur.x); auto sigma_y = Sigma(scaled_blur.y); + auto tile_mode = ToTileMode(blur->tile_mode()); - if (blur->tile_mode() != flutter::DlTileMode::kClamp) { - // TODO(105072): Implement tile mode for blur filter. - UNIMPLEMENTED; - } - - return [sigma_x, sigma_y](FilterInput::Ref input) { - return FilterContents::MakeGaussianBlur(input, sigma_x, sigma_y); + return [sigma_x, sigma_y, tile_mode](FilterInput::Ref input) { + return FilterContents::MakeGaussianBlur( + input, sigma_x, sigma_y, FilterContents::BlurStyle::kNormal, + tile_mode); }; break; diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index 36cc3ee94e718..af42a5cca3826 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -74,12 +74,14 @@ std::shared_ptr FilterContents::MakeDirectionalGaussianBlur( Sigma sigma, Vector2 direction, BlurStyle blur_style, + Entity::TileMode tile_mode, FilterInput::Ref source_override) { auto blur = std::make_shared(); blur->SetInputs({input}); blur->SetSigma(sigma); blur->SetDirection(direction); blur->SetBlurStyle(blur_style); + blur->SetTileMode(tile_mode); blur->SetSourceOverride(source_override); return blur; } @@ -88,11 +90,13 @@ std::shared_ptr FilterContents::MakeGaussianBlur( FilterInput::Ref input, Sigma sigma_x, Sigma sigma_y, - BlurStyle blur_style) { + BlurStyle blur_style, + Entity::TileMode tile_mode) { auto x_blur = MakeDirectionalGaussianBlur(input, sigma_x, Point(1, 0), - BlurStyle::kNormal); - auto y_blur = MakeDirectionalGaussianBlur(FilterInput::Make(x_blur), sigma_y, - Point(0, 1), blur_style, input); + BlurStyle::kNormal, tile_mode); + auto y_blur = + MakeDirectionalGaussianBlur(FilterInput::Make(x_blur), sigma_y, + Point(0, 1), blur_style, tile_mode, input); return y_blur; } diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 03231a3d78cba..84134060e18b5 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -41,13 +41,15 @@ class FilterContents : public Contents { Sigma sigma, Vector2 direction, BlurStyle blur_style = BlurStyle::kNormal, + Entity::TileMode tile_mode = Entity::TileMode::kDecal, FilterInput::Ref alpha_mask = nullptr); static std::shared_ptr MakeGaussianBlur( FilterInput::Ref input, Sigma sigma_x, Sigma sigma_y, - BlurStyle blur_style = BlurStyle::kNormal); + BlurStyle blur_style = BlurStyle::kNormal, + Entity::TileMode tile_mode = Entity::TileMode::kDecal); static std::shared_ptr MakeBorderMaskBlur( FilterInput::Ref input, diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 32a50b5b8ed8c..7982aa1b67989 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -70,6 +70,11 @@ void DirectionalGaussianBlurFilterContents::SetBlurStyle(BlurStyle blur_style) { } } +void DirectionalGaussianBlurFilterContents::SetTileMode( + Entity::TileMode tile_mode) { + tile_mode_ = tile_mode; +} + void DirectionalGaussianBlurFilterContents::SetSourceOverride( FilterInput::Ref source_override) { source_override_ = source_override; @@ -138,6 +143,7 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter( frag_info.blur_direction = input_snapshot->transform.Invert() .TransformDirection(transformed_blur) .Normalize(); + frag_info.tile_mode = static_cast(tile_mode_); frag_info.src_factor = src_color_factor_; frag_info.inner_blur_factor = inner_blur_factor_; frag_info.outer_blur_factor = outer_blur_factor_; diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index e85ad20dc5f0c..6091f1140233c 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h @@ -23,6 +23,8 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents { void SetBlurStyle(BlurStyle blur_style); + void SetTileMode(Entity::TileMode tile_mode); + void SetSourceOverride(FilterInput::Ref alpha_mask); // |FilterContents| @@ -39,6 +41,7 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents { Sigma blur_sigma_; Vector2 blur_direction_; BlurStyle blur_style_ = BlurStyle::kNormal; + Entity::TileMode tile_mode_ = Entity::TileMode::kDecal; bool src_color_factor_ = false; bool inner_blur_factor_ = true; bool outer_blur_factor_ = true; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index a38b6bb9744b9..7a9a7b02bbc89 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -842,16 +842,19 @@ TEST_P(EntityTest, GaussianBlurFilter) { auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { if (first_frame) { first_frame = false; - ImGui::SetNextWindowSize({500, 290}); - ImGui::SetNextWindowPos({300, 480}); + ImGui::SetNextWindowPos({10, 10}); } const char* input_type_names[] = {"Texture", "Solid Color"}; const char* blur_type_names[] = {"Image blur", "Mask blur"}; const char* blur_style_names[] = {"Normal", "Solid", "Outer", "Inner"}; + const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; const FilterContents::BlurStyle blur_styles[] = { FilterContents::BlurStyle::kNormal, FilterContents::BlurStyle::kSolid, FilterContents::BlurStyle::kOuter, FilterContents::BlurStyle::kInner}; + const Entity::TileMode tile_modes[] = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; // UI state. static int selected_input_type = 0; @@ -859,14 +862,15 @@ TEST_P(EntityTest, GaussianBlurFilter) { static int selected_blur_type = 0; static float blur_amount[2] = {20, 20}; static int selected_blur_style = 0; + static int selected_tile_mode = 3; static Color cover_color(1, 0, 0, 0.2); static Color bounds_color(0, 1, 0, 0.1); static float offset[2] = {500, 400}; static float rotation = 0; - static float scale[2] = {0.75, 0.75}; + static float scale[2] = {0.65, 0.65}; static float skew[2] = {0, 0}; - ImGui::Begin("Controls"); + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); { ImGui::Combo("Input type", &selected_input_type, input_type_names, sizeof(input_type_names) / sizeof(char*)); @@ -878,9 +882,11 @@ TEST_P(EntityTest, GaussianBlurFilter) { } ImGui::Combo("Blur type", &selected_blur_type, blur_type_names, sizeof(blur_type_names) / sizeof(char*)); - ImGui::SliderFloat2("Blur", &blur_amount[0], 0, 200); + ImGui::SliderFloat2("Sigma", &blur_amount[0], 0, 200); ImGui::Combo("Blur style", &selected_blur_style, blur_style_names, sizeof(blur_style_names) / sizeof(char*)); + ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); ImGui::ColorEdit4("Cover color", reinterpret_cast(&cover_color)); ImGui::ColorEdit4("Bounds color", reinterpret_cast(&bounds_color)); @@ -917,7 +923,7 @@ TEST_P(EntityTest, GaussianBlurFilter) { auto blur = FilterContents::MakeGaussianBlur( FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]}, - blur_styles[selected_blur_style]); + blur_styles[selected_blur_style], tile_modes[selected_tile_mode]); auto mask_blur = FilterContents::MakeBorderMaskBlur( FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]}, diff --git a/impeller/entity/shaders/gaussian_blur.frag b/impeller/entity/shaders/gaussian_blur.frag index 8a9281a74c4dc..65d449f33b68f 100644 --- a/impeller/entity/shaders/gaussian_blur.frag +++ b/impeller/entity/shaders/gaussian_blur.frag @@ -23,8 +23,15 @@ uniform FragInfo { vec2 texture_size; vec2 blur_direction; + float tile_mode; + + // The blur sigma and radius have a linear relationship which is defined + // host-side, but both are useful controls here. Sigma (pixels per standard + // deviation) is used to define the gaussian function itself, whereas the + // radius is used to limit how much of the function is integrated. float blur_sigma; float blur_radius; + float src_factor; float inner_blur_factor; float outer_blur_factor; @@ -52,13 +59,13 @@ void main() { total_color += gaussian * IPSampleWithTileMode(texture_sampler, v_texture_coords + blur_uv_offset * i, - kTileModeDecal); + frag_info.tile_mode); } vec4 blur_color = total_color / gaussian_integral; - vec4 src_color = IPSampleWithTileMode(alpha_mask_sampler, - v_src_texture_coords, kTileModeDecal); + vec4 src_color = IPSampleWithTileMode( + alpha_mask_sampler, v_src_texture_coords, frag_info.tile_mode); float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) + frag_info.outer_blur_factor * float(src_color.a == 0); From 82c8e2c0c6a098aa3361ef002524e6cc8e548dce Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 21:48:05 -0400 Subject: [PATCH 184/558] Roll Dart SDK from 193ac812ac3a to 52010f27d8f3 (1 revision) (#35248) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 8a0e8c4b58e00..f3516fae81d08 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '193ac812ac3a20e54f70373bb5836e3ab933655a', + 'dart_revision': '52010f27d8f3478d4e01b713e638272f8f7d7c89', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 169bfa950e307..218f41f0cf623 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: bf0ac66b620030bf241fca946db219da +Signature: bb7cf98580cf594e90b490c972749e97 UNUSED LICENSES: From 72ad23564c99d55ce50f251b3a6a2d3dd5901a49 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 22:23:38 -0400 Subject: [PATCH 185/558] Roll Skia from 4722605332ef to 82b9930b1312 (9 revisions) (#35242) https://skia.googlesource.com/skia.git/+log/4722605332ef..82b9930b1312 2022-08-08 brianosman@google.com Simplify some RP data layout and logic 2022-08-08 herb@google.com Drawable: Use the Read/WriteBuffer bulk API for points 2022-08-08 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from 4b211a6a98e6 to 5e532d83424e (2 revisions) 2022-08-08 cmumford@google.com Rename getRuleCMakeName() to getRuleSimpleName(). 2022-08-08 cmumford@google.com Move findRule() into bazel_util.go. 2022-08-08 cmumford@google.com Move isFileTarget() to bazel_util.go 2022-08-08 robertphillips@google.com [graphite] Add system to support client caching of images 2022-08-08 cmumford@google.com Exporting Bazel with more build flags. 2022-08-08 robertphillips@google.com Remove BaseDevice class If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC erikrose@google.com,kaushikiska@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index f3516fae81d08..de5c61a247111 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': '4722605332ef875c451d29199782ad9676b6eb5e', + 'skia_revision': '82b9930b13127a5db1ecb1f1e4680132da680b2c', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index b1dcb89ad86e9..357704d5eba73 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 14760e201b1fe3c8eb3ec43d2888fba0 +Signature: dd51d308be1e8a2ace245da2a5d977f8 UNUSED LICENSES: @@ -2561,8 +2561,6 @@ FILE: ../../../third_party/skia/src/effects/imagefilters/SkRuntimeImageFilter.h FILE: ../../../third_party/skia/src/gpu/KeyBuilder.h FILE: ../../../third_party/skia/src/gpu/ResourceKey.cpp FILE: ../../../third_party/skia/src/gpu/ShaderErrorHandler.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/BaseDevice.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/BaseDevice.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrDstProxyView.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrEagerVertexAllocator.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrMeshDrawTarget.cpp @@ -5543,6 +5541,7 @@ FILE: ../../../third_party/skia/include/core/SkColorType.h FILE: ../../../third_party/skia/include/core/SkCombinationBuilder.h FILE: ../../../third_party/skia/include/gpu/GpuTypes.h FILE: ../../../third_party/skia/include/gpu/graphite/ContextOptions.h +FILE: ../../../third_party/skia/include/gpu/graphite/ImageProvider.h FILE: ../../../third_party/skia/include/private/SkUniquePaintParamsID.h FILE: ../../../third_party/skia/include/sksl/SkSLVersion.h FILE: ../../../third_party/skia/infra/bots/task_drivers/bazel_build/bazel_build.go @@ -5596,6 +5595,8 @@ FILE: ../../../third_party/skia/src/gpu/graphite/GlobalCache.h FILE: ../../../third_party/skia/src/gpu/graphite/GpuWorkSubmission.cpp FILE: ../../../third_party/skia/src/gpu/graphite/GraphiteResourceKey.cpp FILE: ../../../third_party/skia/src/gpu/graphite/GraphiteResourceKey.h +FILE: ../../../third_party/skia/src/gpu/graphite/ImageUtils.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/ImageUtils.h FILE: ../../../third_party/skia/src/gpu/graphite/Log.h FILE: ../../../third_party/skia/src/gpu/graphite/PaintParams.cpp FILE: ../../../third_party/skia/src/gpu/graphite/PaintParams.h From b6dd604d906791401b9fa0d85b0af8203b89be7f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 8 Aug 2022 23:31:05 -0400 Subject: [PATCH 186/558] Roll Skia from 82b9930b1312 to 6df5d5f92381 (2 revisions) (#35252) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index de5c61a247111..e67f45c5865fc 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': '82b9930b13127a5db1ecb1f1e4680132da680b2c', + 'skia_revision': '6df5d5f92381d963b15003fc3277ebe6bcd96ef2', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 357704d5eba73..5865f7281e2d8 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: dd51d308be1e8a2ace245da2a5d977f8 +Signature: b9cce6a9a5ca42bf457066ceddba40b2 UNUSED LICENSES: From 8e87600bc0e8b1298ae21a7bad0a914b97cfcc81 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 8 Aug 2022 21:16:12 -0700 Subject: [PATCH 187/558] Account for the backend-dependent space of rendered textures in advanced blends (#35250) --- .../compiler/shader_lib/impeller/texture.glsl | 14 ++++++++----- .../contents/filters/blend_filter_contents.cc | 5 ++++- .../shaders/blending/advanced_blend.glsl | 21 +++++++++++++------ impeller/entity/shaders/gaussian_blur.frag | 18 +++++++++++----- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/impeller/compiler/shader_lib/impeller/texture.glsl b/impeller/compiler/shader_lib/impeller/texture.glsl index 99875b068837d..714e92ca81445 100644 --- a/impeller/compiler/shader_lib/impeller/texture.glsl +++ b/impeller/compiler/shader_lib/impeller/texture.glsl @@ -48,21 +48,25 @@ float IPFloatTile(float t, float tile_mode) { /// Remap a vec2 using a tiling mode. /// /// Runs each component of the vec2 through `IPFloatTile`. -vec2 IPVec2Tile(vec2 uv, float tile_mode) { - return vec2(IPFloatTile(uv.x, tile_mode), IPFloatTile(uv.y, tile_mode)); +vec2 IPVec2Tile(vec2 coords, float tile_mode) { + return vec2(IPFloatTile(coords.x, tile_mode), + IPFloatTile(coords.y, tile_mode)); } /// Sample a texture, emulating a specific tile mode. /// /// This is useful for Impeller graphics backend that don't have native support /// for Decal. -vec4 IPSampleWithTileMode(sampler2D tex, vec2 uv, float tile_mode) { +vec4 IPSampleWithTileMode(sampler2D tex, + vec2 coords, + float y_coord_scale, + float tile_mode) { if (tile_mode == kTileModeDecal && - (uv.x < 0 || uv.y < 0 || uv.x >= 1 || uv.y >= 1)) { + (coords.x < 0 || coords.y < 0 || coords.x >= 1 || coords.y >= 1)) { return vec4(0); } - return texture(tex, IPVec2Tile(uv, tile_mode)); + return IPSample(tex, IPVec2Tile(coords, tile_mode), y_coord_scale); } #endif diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index 5d9dc691c8326..75b276e5c4bff 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -91,10 +91,12 @@ static bool AdvancedBlend(const FilterInput::Vector& inputs, cmd.BindVertices(vtx_buffer); cmd.pipeline = std::move(pipeline); + typename FS::BlendInfo blend_info; + auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, sampler); + blend_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); - typename FS::BlendInfo blend_info; if (foreground_color.has_value()) { blend_info.color_factor = 1; blend_info.color = foreground_color.value(); @@ -104,6 +106,7 @@ static bool AdvancedBlend(const FilterInput::Vector& inputs, } else { blend_info.color_factor = 0; FS::BindTextureSamplerSrc(cmd, src_snapshot->texture, sampler); + blend_info.src_y_coord_scale = src_snapshot->texture->GetYCoordScale(); } auto blend_uniform = host_buffer.EmplaceUniform(blend_info); FS::BindBlendInfo(cmd, blend_uniform); diff --git a/impeller/entity/shaders/blending/advanced_blend.glsl b/impeller/entity/shaders/blending/advanced_blend.glsl index 3bbfe8a226703..20d7b40a0ec11 100644 --- a/impeller/entity/shaders/blending/advanced_blend.glsl +++ b/impeller/entity/shaders/blending/advanced_blend.glsl @@ -7,6 +7,8 @@ #include uniform BlendInfo { + float dst_y_coord_scale; + float src_y_coord_scale; float color_factor; vec4 color; // This color input is expected to be unpremultiplied. } @@ -22,12 +24,19 @@ out vec4 frag_color; void main() { vec4 dst = IPUnpremultiply(IPSampleWithTileMode( - texture_sampler_dst, v_dst_texture_coords, kTileModeDecal)); - vec4 src = - blend_info.color_factor > 0 - ? blend_info.color - : IPUnpremultiply(IPSampleWithTileMode( - texture_sampler_src, v_src_texture_coords, kTileModeDecal)); + texture_sampler_dst, // sampler + v_dst_texture_coords, // texture coordinates + blend_info.dst_y_coord_scale, // y coordinate scale + kTileModeDecal // tile mode + )); + vec4 src = blend_info.color_factor > 0 + ? blend_info.color + : IPUnpremultiply(IPSampleWithTileMode( + texture_sampler_src, // sampler + v_src_texture_coords, // texture coordinates + blend_info.src_y_coord_scale, // y coordinate scale + kTileModeDecal // tile mode + )); vec3 blended = Blend(dst.rgb, src.rgb); diff --git a/impeller/entity/shaders/gaussian_blur.frag b/impeller/entity/shaders/gaussian_blur.frag index 65d449f33b68f..53fe22a906006 100644 --- a/impeller/entity/shaders/gaussian_blur.frag +++ b/impeller/entity/shaders/gaussian_blur.frag @@ -57,15 +57,23 @@ void main() { float gaussian = Gaussian(i); gaussian_integral += gaussian; total_color += - gaussian * IPSampleWithTileMode(texture_sampler, - v_texture_coords + blur_uv_offset * i, - frag_info.tile_mode); + gaussian * + IPSampleWithTileMode( + texture_sampler, // sampler + v_texture_coords + blur_uv_offset * i, // texture coordinates + 1.0, // y coordinate scale + frag_info.tile_mode // tile mode + ); } vec4 blur_color = total_color / gaussian_integral; - vec4 src_color = IPSampleWithTileMode( - alpha_mask_sampler, v_src_texture_coords, frag_info.tile_mode); + vec4 src_color = + IPSampleWithTileMode(alpha_mask_sampler, // sampler + v_src_texture_coords, // texture coordinates + 1.0, // y coordinate scale + frag_info.tile_mode // tile mode + ); float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) + frag_info.outer_blur_factor * float(src_color.a == 0); From 9aaa21a290afe5df4f16b5d3ce03911278b781f3 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Mon, 8 Aug 2022 22:46:04 -0700 Subject: [PATCH 188/558] Updates objectc script to accept relative paths. (#35190) --- tools/gen_objcdoc.sh | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/tools/gen_objcdoc.sh b/tools/gen_objcdoc.sh index dd0583b939231..7f7d65d4f4bd6 100755 --- a/tools/gen_objcdoc.sh +++ b/tools/gen_objcdoc.sh @@ -7,27 +7,29 @@ set -e +if [[ $# -eq 0 ]]; then + echo "Error: Argument specifying output directory required." + exit 1 +fi + +# Move to the flutter checkout +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +pushd "$SCRIPT_DIR/../../flutter" + FLUTTER_UMBRELLA_HEADER=$(find ../out -maxdepth 4 -type f -name Flutter.h | grep 'ios_' | head -n 1) if [[ ! -f "$FLUTTER_UMBRELLA_HEADER" ]] then echo "Error: This script must be run at the root of the Flutter source tree with at least one built Flutter.framework in ../out/ios*/Flutter.framework." + echo "Running from: $(pwd)" exit 1 fi - -# If the script is running from within LUCI we use the LUCI_WORKDIR, if not we force the caller of the script -# to pass an output directory as the first parameter. -OUTPUT_DIR="" - -if [[ -z "$LUCI_CI" ]]; then - if [[ $# -eq 0 ]]; then - echo "Error: Argument specifying output directory required." - exit 1 - else - OUTPUT_DIR="$1" - fi -else - OUTPUT_DIR="$LUCI_WORKDIR/objectc_docs" +OUTPUT_DIR="$1/objectc_docs" +ZIP_DESTINATION="$1" +if [ "${OUTPUT_DIR:0:1}" != "/" ] +then + ZIP_DESTINATION="$SCRIPT_DIR/../../$1" + OUTPUT_DIR="$ZIP_DESTINATION/objectc_docs" fi # If GEM_HOME is set, prefer using its copy of jazzy. @@ -83,3 +85,8 @@ if [[ $EXPECTED_CLASSES != $ACTUAL_CLASSES ]]; then diff <(echo "$EXPECTED_CLASSES") <(echo "$ACTUAL_CLASSES") exit -1 fi + +# Create the final zip file. +pushd $OUTPUT_DIR +zip -r "$ZIP_DESTINATION/ios-objcdoc.zip" . +popd From 025ccb11f45b94641d928b4a290b53396e670c24 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 01:54:05 -0400 Subject: [PATCH 189/558] Roll Skia from 6df5d5f92381 to a2a6b3cb1ba9 (1 revision) (#35255) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e67f45c5865fc..3fe44a8ba045e 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': '6df5d5f92381d963b15003fc3277ebe6bcd96ef2', + 'skia_revision': 'a2a6b3cb1ba9cf14caeb197138e9dba4b99aa28c', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 5865f7281e2d8..23258da842c1f 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b9cce6a9a5ca42bf457066ceddba40b2 +Signature: 2b2162ba5e5130869577e2492382e7e0 UNUSED LICENSES: From 8af7994a1d3d603aa2dd0bf1f83a7132da87a57b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 02:06:05 -0400 Subject: [PATCH 190/558] Roll Dart SDK from 52010f27d8f3 to 0e14faf35fe7 (1 revision) (#35256) --- DEPS | 14 +++++++------- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/DEPS b/DEPS index 3fe44a8ba045e..4ce60b403df1d 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '52010f27d8f3478d4e01b713e638272f8f7d7c89', + 'dart_revision': '0e14faf35fe765f20d547b847cc288b054b6da6a', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -46,11 +46,11 @@ vars = { 'dart_clock_rev': '2507a228773c5e877fc9e3330080b234aad965c0', 'dart_collection_rev': '414ffa1bc8ba18bd608bbf916d95715311d89ac1', 'dart_devtools_rev': 'd131d19091f6b89ac89486bd92440a25a523e8b0', - 'dart_protobuf_rev': '11983dafc42775c56698af06107d626780e9cb69', + 'dart_protobuf_rev': '6f5360ba1d6c4605049fa3574357dab7c8d38400', 'dart_pub_rev': 'ac7db6c07318efa4a8712110275eaf70f96a6d00', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': 'e00c0ea769e32821d91c0880da8eb736839a6e6d', - 'dart_webdev_rev': '37bf4af1b0961f053e7cf4990a34ca5fd0ad0fd4', + 'dart_webdev_rev': '490d6a06f7ed75654bcfd5a0e8351f8a0f59df1c', 'dart_webkit_inspection_protocol_rev': '57522d6b29d94903b765c757079d906555d5a171', 'dart_yaml_edit_rev': '01589b3ce447b03aed991db49f1ec6445ad5476d', 'dart_zlib_rev': '27c2f474b71d0d20764f86f60ef8b00da1a16cda', @@ -167,7 +167,7 @@ deps = { {'packages': [{'version': 'git_revision:d131d19091f6b89ac89486bd92440a25a523e8b0', 'package': 'dart/third_party/flutter/devtools'}], 'dep_type': 'cipd'}, 'src/third_party/dart/third_party/pkg/args': - Var('dart_git') + '/args.git@73e8d3b55cbedc9765f8e266f3422d8914f8e62a', + Var('dart_git') + '/args.git@80d4abbd6b38b79bcdbc411b4b517628c7611232', 'src/third_party/dart/third_party/pkg/async': Var('dart_git') + '/async.git@f3ed5f690e2ec9dbe1bfc5184705575b4f6480e5', @@ -233,7 +233,7 @@ deps = { Var('dart_git') + '/json_rpc_2.git@805e6536dd961d66f6b8cd46d8f3e61774f957c9', 'src/third_party/dart/third_party/pkg/linter': - Var('dart_git') + '/linter.git@b677397483251d55ce1aec8d170be7720b53fe26', + Var('dart_git') + '/linter.git@075a3b6abf54b38c295690ec8e043607654f2da3', 'src/third_party/dart/third_party/pkg/logging': Var('dart_git') + '/logging.git@d10e24844c2e01d3f6d2b5a1a2bb8717359c6a87', @@ -272,7 +272,7 @@ deps = { Var('dart_git') + '/pub_semver.git@9fd28757ba45961ac5449e0f2b0020670e921475', 'src/third_party/dart/third_party/pkg/shelf': - Var('dart_git') + '/shelf.git@0371a64bd3b99044ee3158bacf8813bba735a9c7', + Var('dart_git') + '/shelf.git@0965d864d0e6c66d5bb6daece400e80484640bd5', 'src/third_party/dart/third_party/pkg/source_map_stack_trace': Var('dart_git') + '/source_map_stack_trace.git@72dbf21a33293b2b8434d0a9751e36f9463981ac', @@ -305,7 +305,7 @@ deps = { Var('dart_git') + '/test_reflective_loader.git@8d0de01bbe852fea1f8e33aba907abcba50a8a1e', 'src/third_party/dart/third_party/pkg/typed_data': - Var('dart_git') + '/typed_data.git@bb10b64f9a56b8fb49307d4465474bf1c1309f6d', + Var('dart_git') + '/typed_data.git@6369490ede1c87a4a5758304a606a6e4eee364b9', 'src/third_party/dart/third_party/pkg/usage': Var('dart_git') + '/usage.git@e287a72228974886d8a3b40ddcdf12f69d7c6a22', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 218f41f0cf623..a7ddb7263ee75 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: bb7cf98580cf594e90b490c972749e97 +Signature: 207f4dcfb35c484d7901cd25ea8eac26 UNUSED LICENSES: From d81133c6a2a581fe79836eccf743f6e55d0c10b4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 05:06:08 -0400 Subject: [PATCH 191/558] Roll Fuchsia Mac SDK from vSCmDPI74... to eJH_BpC8V... (#35259) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 4ce60b403df1d..98d4b302b168a 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'vSCmDPI74CIaTFpcbjs1kCpUtkU9O2dUlkG7jLmDhWoC' + 'version': 'eJH_BpC8Vtx6nYHBqmXoI7RQVU4dk4fPCl9GgTnG55kC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 1db5ef4c4986c2b4f6de9f8b48970ee9039edc87 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 05:39:04 -0400 Subject: [PATCH 192/558] Roll Skia from a2a6b3cb1ba9 to 9e6074e0922c (1 revision) (#35260) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 98d4b302b168a..ee5ff25dd1ed0 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': 'a2a6b3cb1ba9cf14caeb197138e9dba4b99aa28c', + 'skia_revision': '9e6074e0922c6eea5259146e65728441b9242a90', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 23258da842c1f..66ce3503d778d 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 2b2162ba5e5130869577e2492382e7e0 +Signature: 8a34bb469e9e2db35e1f5cf898872401 UNUSED LICENSES: From 60c4a9f1c2def2e3f2b40659505b6ef35bb00006 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 06:55:15 -0400 Subject: [PATCH 193/558] Roll Dart SDK from 0e14faf35fe7 to 49b3e80fca8e (1 revision) (#35261) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ee5ff25dd1ed0..6011b98736c38 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '0e14faf35fe765f20d547b847cc288b054b6da6a', + 'dart_revision': '49b3e80fca8e1f5c91ea626077915db942523e4f', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index a7ddb7263ee75..ccbd616e2c06e 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 207f4dcfb35c484d7901cd25ea8eac26 +Signature: 61a54344c7658984c1ab5ab04d497132 UNUSED LICENSES: From 7f09f17abad52a308b54f97ee40062c18ad8df0a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 07:50:05 -0400 Subject: [PATCH 194/558] Roll Fuchsia Linux SDK from 7q0yjaQTj... to n-AJfzUMF... (#35262) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6011b98736c38..b08906a6664ff 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': '7q0yjaQTjdbKoX4iHafZxQ5FRCyLHzwRlqK0YdweaP0C' + 'version': 'n-AJfzUMFozC7yzLvyxib4WOIUVVlukRzcWz9eni1yAC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 8e2f5a92a0bd3..892e5a2c90840 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 8d672f92969a1e9a2c2f5720700bd332 +Signature: 6b3771608fe842c48a7c2e6a85a8c398 UNUSED LICENSES: From 97ecb4681a258a1995e3948d08e2e29bb6b11acf Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 09:30:16 -0400 Subject: [PATCH 195/558] Roll Skia from 9e6074e0922c to fd3efc2b83b4 (1 revision) (#35263) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b08906a6664ff..34b25effcc758 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': '9e6074e0922c6eea5259146e65728441b9242a90', + 'skia_revision': 'fd3efc2b83b423c26adf463b635fd57a95aea5dc', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 66ce3503d778d..6583e4458ae46 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 8a34bb469e9e2db35e1f5cf898872401 +Signature: 96e53ee80fb32eff95761f1ef9e5cd47 UNUSED LICENSES: @@ -840,6 +840,7 @@ FILE: ../../../third_party/skia/infra/bots/assets/bazel/VERSION FILE: ../../../third_party/skia/infra/bots/assets/bazel_build_task_driver/VERSION FILE: ../../../third_party/skia/infra/bots/assets/bazelisk/VERSION FILE: ../../../third_party/skia/infra/bots/assets/bazelisk_mac_arm64/VERSION +FILE: ../../../third_party/skia/infra/bots/assets/binutils_linux_x64/VERSION FILE: ../../../third_party/skia/infra/bots/assets/bloaty/VERSION FILE: ../../../third_party/skia/infra/bots/assets/cast_toolchain/VERSION FILE: ../../../third_party/skia/infra/bots/assets/ccache_linux/VERSION From f390a595ee3e0e5cf2e2cf7addd61f19f458cbb9 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Tue, 9 Aug 2022 07:16:24 -0700 Subject: [PATCH 196/558] Revert "Updates objectc script to accept relative paths. (#35190)" (#35265) This reverts commit 9aaa21a290afe5df4f16b5d3ce03911278b781f3. --- tools/gen_objcdoc.sh | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/tools/gen_objcdoc.sh b/tools/gen_objcdoc.sh index 7f7d65d4f4bd6..dd0583b939231 100755 --- a/tools/gen_objcdoc.sh +++ b/tools/gen_objcdoc.sh @@ -7,29 +7,27 @@ set -e -if [[ $# -eq 0 ]]; then - echo "Error: Argument specifying output directory required." - exit 1 -fi - -# Move to the flutter checkout -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -pushd "$SCRIPT_DIR/../../flutter" - FLUTTER_UMBRELLA_HEADER=$(find ../out -maxdepth 4 -type f -name Flutter.h | grep 'ios_' | head -n 1) if [[ ! -f "$FLUTTER_UMBRELLA_HEADER" ]] then echo "Error: This script must be run at the root of the Flutter source tree with at least one built Flutter.framework in ../out/ios*/Flutter.framework." - echo "Running from: $(pwd)" exit 1 fi -OUTPUT_DIR="$1/objectc_docs" -ZIP_DESTINATION="$1" -if [ "${OUTPUT_DIR:0:1}" != "/" ] -then - ZIP_DESTINATION="$SCRIPT_DIR/../../$1" - OUTPUT_DIR="$ZIP_DESTINATION/objectc_docs" + +# If the script is running from within LUCI we use the LUCI_WORKDIR, if not we force the caller of the script +# to pass an output directory as the first parameter. +OUTPUT_DIR="" + +if [[ -z "$LUCI_CI" ]]; then + if [[ $# -eq 0 ]]; then + echo "Error: Argument specifying output directory required." + exit 1 + else + OUTPUT_DIR="$1" + fi +else + OUTPUT_DIR="$LUCI_WORKDIR/objectc_docs" fi # If GEM_HOME is set, prefer using its copy of jazzy. @@ -85,8 +83,3 @@ if [[ $EXPECTED_CLASSES != $ACTUAL_CLASSES ]]; then diff <(echo "$EXPECTED_CLASSES") <(echo "$ACTUAL_CLASSES") exit -1 fi - -# Create the final zip file. -pushd $OUTPUT_DIR -zip -r "$ZIP_DESTINATION/ios-objcdoc.zip" . -popd From 174d8ac23a856e4676e2e60c7e5f74d8dd1ce5a3 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 11:27:04 -0400 Subject: [PATCH 197/558] Roll Skia from fd3efc2b83b4 to faf97e5d2c2b (1 revision) (#35266) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 34b25effcc758..3a12f277f5d24 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': 'fd3efc2b83b423c26adf463b635fd57a95aea5dc', + 'skia_revision': 'faf97e5d2c2b879cb64db6da8599262b7674b807', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 6583e4458ae46..04a1a0f6068e7 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 96e53ee80fb32eff95761f1ef9e5cd47 +Signature: b6f5331435854515ced6a5ad3c423a32 UNUSED LICENSES: From 8be7930220f99ef3835648f7af454ad3564f1e62 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 12:24:04 -0400 Subject: [PATCH 198/558] Roll Dart SDK from 49b3e80fca8e to ac425a3ae2b1 (1 revision) (#35267) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 3a12f277f5d24..57f4fb629bb46 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '49b3e80fca8e1f5c91ea626077915db942523e4f', + 'dart_revision': 'ac425a3ae2b12ecb541ab5ecf47ec0e6a5a221a5', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index ccbd616e2c06e..4793613992030 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 61a54344c7658984c1ab5ab04d497132 +Signature: 09a6288a0799cbc460e5108a051ecdef UNUSED LICENSES: From 5ff21d558175add79784638b415e78f67c80156f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 12:36:06 -0400 Subject: [PATCH 199/558] Roll Skia from faf97e5d2c2b to 3c9ce6c56a00 (2 revisions) (#35268) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 57f4fb629bb46..71fe36127dea5 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': 'faf97e5d2c2b879cb64db6da8599262b7674b807', + 'skia_revision': '3c9ce6c56a00380005d65beec80d3de205df281f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 04a1a0f6068e7..5318d20864579 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b6f5331435854515ced6a5ad3c423a32 +Signature: d10a48279976919e319812ecf44c6026 UNUSED LICENSES: From d2489cd91788590e19d3077a6e40b40e7ffc9eee Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Tue, 9 Aug 2022 09:44:40 -0700 Subject: [PATCH 200/558] [Windows] Shut down VM on shutdown of last engine (#35251) All Flutter engines in the same process share a common Dart VM, which is launched with the start of the first engine in the process and should be terminated when the last engine in the process has been deallocated. Formerly, it was not possible to cleanly shut down and restart the VM in a process, but this was resolved in the Dart SDK and a flag exposed in flutter/engine#10652. Since some embedders take advantage of the fact that the VM remains running after engine shutdown, this flag is not enabled by default, however it should be enabled for the Windows embedder, which we control. No tests added since this is not testable via any API to which the Windows embedder has access. The behaviour of this flag is tested in the embedder API tests in `EmbedderTest.VMShutsDownWhenNoEnginesInProcess` in shell/platform/embedder/tests/embedder_unittests.cc. Issue: https://github.com/flutter/flutter/issues/109191 --- shell/platform/windows/flutter_windows_engine.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 3ed63ae3a3556..a1edfee1c46f3 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -254,6 +254,7 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { FlutterProjectArgs args = {}; args.struct_size = sizeof(FlutterProjectArgs); + args.shutdown_dart_vm_when_done = true; args.assets_path = assets_path_string.c_str(); args.icu_data_path = icu_path_string.c_str(); args.command_line_argc = static_cast(argv.size()); From 346f7a56a12d5b7ad06f7c4cb8396d935840a12c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 14:07:20 -0400 Subject: [PATCH 201/558] Roll Skia from 3c9ce6c56a00 to b2d197d7c22a (2 revisions) (#35271) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 71fe36127dea5..25e72e9f1657a 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': '3c9ce6c56a00380005d65beec80d3de205df281f', + 'skia_revision': 'b2d197d7c22a69bf89c7d9d897e4ccfedb64e0d6', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 5318d20864579..e28f314bc63c5 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d10a48279976919e319812ecf44c6026 +Signature: 68c72e207889dd5b97700e6d5896cc90 UNUSED LICENSES: From 0f386d5c0cdde02f9574d869b85b623effff6d7c Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Tue, 9 Aug 2022 11:35:32 -0700 Subject: [PATCH 202/558] Support fixture tests for Windows embedder (#35273) This adds support for running end-to-end tests that use a live engine to run Dart test fixtures. This enables testing the public Windows C API in //flutter/shell/platform/windows/public/flutter_windows.h This only adds support for a single test entrypoint (main). A followup patch will add support for this. See: https://github.com/flutter/flutter/issues/93537 Issue: https://github.com/flutter/flutter/issues/87299 --- shell/platform/windows/BUILD.gn | 7 ++ shell/platform/windows/fixtures/main.dart | 7 ++ .../windows/flutter_windows_unittests.cc | 20 ++++- .../platform/windows/testing/windows_test.cc | 26 ++++++ shell/platform/windows/testing/windows_test.h | 47 ++++++++++ .../testing/windows_test_config_builder.cc | 87 +++++++++++++++++++ .../testing/windows_test_config_builder.h | 79 +++++++++++++++++ .../windows/testing/windows_test_context.cc | 26 ++++++ .../windows/testing/windows_test_context.h | 40 +++++++++ 9 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 shell/platform/windows/fixtures/main.dart create mode 100644 shell/platform/windows/testing/windows_test.cc create mode 100644 shell/platform/windows/testing/windows_test.h create mode 100644 shell/platform/windows/testing/windows_test_config_builder.cc create mode 100644 shell/platform/windows/testing/windows_test_config_builder.h create mode 100644 shell/platform/windows/testing/windows_test_context.cc create mode 100644 shell/platform/windows/testing/windows_test_context.h diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 09597e321851f..d2df59b2cf740 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -158,6 +158,7 @@ shared_library("flutter_windows") { } test_fixtures("flutter_windows_fixtures") { + dart_main = "fixtures/main.dart" fixtures = [] } @@ -198,6 +199,12 @@ executable("flutter_windows_unittests") { "testing/test_keyboard.cc", "testing/test_keyboard.h", "testing/test_keyboard_unittests.cc", + "testing/windows_test.cc", + "testing/windows_test.h", + "testing/windows_test_config_builder.cc", + "testing/windows_test_config_builder.h", + "testing/windows_test_context.cc", + "testing/windows_test_context.h", "testing/wm_builders.cc", "testing/wm_builders.h", "text_input_plugin_unittest.cc", diff --git a/shell/platform/windows/fixtures/main.dart b/shell/platform/windows/fixtures/main.dart new file mode 100644 index 0000000000000..6d207279d54ee --- /dev/null +++ b/shell/platform/windows/fixtures/main.dart @@ -0,0 +1,7 @@ +// 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. + +void main() { + print('Hello windows engine test!'); +} diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index 52676d3fd7fd2..7b21046eac897 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -5,13 +5,17 @@ #include "flutter/shell/platform/windows/public/flutter_windows.h" #include +#include +#include "flutter/shell/platform/windows/testing/windows_test.h" +#include "flutter/shell/platform/windows/testing/windows_test_config_builder.h" +#include "flutter/shell/platform/windows/testing/windows_test_context.h" #include "gtest/gtest.h" namespace flutter { namespace testing { -TEST(FlutterWindowsTest, GetTextureRegistrar) { +TEST(WindowsNoFixtureTest, GetTextureRegistrar) { FlutterDesktopEngineProperties properties; memset(&properties, 0, sizeof(FlutterDesktopEngineProperties)); properties.assets_path = L""; @@ -23,5 +27,19 @@ TEST(FlutterWindowsTest, GetTextureRegistrar) { FlutterDesktopEngineDestroy(engine); } +TEST_F(WindowsTest, LaunchMain) { + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + ViewControllerPtr controller{builder.LaunchEngine()}; + ASSERT_NE(controller, nullptr); + + // Run for 1 second, then shut down. + // + // TODO(cbracken): Support registring a native function we can use to + // determine that execution has made it to a specific point in the Dart + // code. https://github.com/flutter/flutter/issues/109242 + std::this_thread::sleep_for(std::chrono::seconds(1)); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/testing/windows_test.cc b/shell/platform/windows/testing/windows_test.cc new file mode 100644 index 0000000000000..bd5bbb1c0012a --- /dev/null +++ b/shell/platform/windows/testing/windows_test.cc @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/windows/testing/windows_test.h" + +#include + +#include "flutter/shell/platform/windows/testing/windows_test_context.h" +#include "flutter/testing/testing.h" + +namespace flutter { +namespace testing { + +WindowsTest::WindowsTest() : context_(GetFixturesDirectory()) {} + +std::string WindowsTest::GetFixturesDirectory() const { + return GetFixturesPath(); +} + +WindowsTestContext& WindowsTest::GetContext() { + return context_; +} + +} // namespace testing +} // namespace flutter diff --git a/shell/platform/windows/testing/windows_test.h b/shell/platform/windows/testing/windows_test.h new file mode 100644 index 0000000000000..21744d0ea8634 --- /dev/null +++ b/shell/platform/windows/testing/windows_test.h @@ -0,0 +1,47 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_WINDOWS_TEST_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_WINDOWS_TEST_H_ + +#include + +#include "flutter/fml/macros.h" +#include "flutter/shell/platform/windows/testing/windows_test_context.h" +#include "flutter/testing/thread_test.h" + +namespace flutter { +namespace testing { + +/// A GoogleTest test fixture for Windows tests. +/// +/// Supports looking up the test fixture data defined in the GN `test_fixtures` +/// associated with the unit test executable target. This typically includes +/// the kernel bytecode `kernel_blob.bin` compiled from the Dart file specified +/// in the test fixture's `dart_main` property, as well as any other data files +/// used in tests, such as image files used in a screenshot golden test. +/// +/// This test class can be used in GoogleTest tests using the standard +/// `TEST_F(WindowsTest, TestName)` macro. +class WindowsTest : public ThreadTest { + public: + WindowsTest(); + + // Returns the path to test fixture data such as kernel bytecode or images + // used by the C++ side of the test. + std::string GetFixturesDirectory() const; + + // Returns the test context associated with this fixture. + WindowsTestContext& GetContext(); + + private: + WindowsTestContext context_; + + FML_DISALLOW_COPY_AND_ASSIGN(WindowsTest); +}; + +} // namespace testing +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_WINDOWS_TEST_H_ diff --git a/shell/platform/windows/testing/windows_test_config_builder.cc b/shell/platform/windows/testing/windows_test_config_builder.cc new file mode 100644 index 0000000000000..69843ea5bb061 --- /dev/null +++ b/shell/platform/windows/testing/windows_test_config_builder.cc @@ -0,0 +1,87 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/windows/testing/windows_test_config_builder.h" + +#include + +#include +#include +#include + +#include "flutter/fml/logging.h" +#include "flutter/shell/platform/windows/public/flutter_windows.h" +#include "flutter/shell/platform/windows/testing/windows_test_context.h" + +namespace flutter { +namespace testing { + +WindowsConfigBuilder::WindowsConfigBuilder(WindowsTestContext& context) + : context_(context) {} + +WindowsConfigBuilder::~WindowsConfigBuilder() = default; + +void WindowsConfigBuilder::AddDartEntrypointArgument(std::string_view arg) { + if (arg.empty()) { + return; + } + + dart_entrypoint_arguments_.emplace_back(std::move(arg)); +} + +FlutterDesktopEngineProperties WindowsConfigBuilder::GetEngineProperties() + const { + FlutterDesktopEngineProperties engine_properties = {}; + engine_properties.assets_path = context_.GetAssetsPath().c_str(); + engine_properties.icu_data_path = context_.GetIcuDataPath().c_str(); + + // Set Dart entrypoint argc, argv. + std::vector dart_args; + dart_args.reserve(dart_entrypoint_arguments_.size()); + for (const auto& arg : dart_entrypoint_arguments_) { + dart_args.push_back(arg.c_str()); + } + if (!dart_args.empty()) { + engine_properties.dart_entrypoint_argv = dart_args.data(); + engine_properties.dart_entrypoint_argc = dart_args.size(); + } else { + // Clear this out in case this is not the first engine launch from the + // embedder config builder. + engine_properties.dart_entrypoint_argv = nullptr; + engine_properties.dart_entrypoint_argc = 0; + } + + return engine_properties; +} + +ViewControllerPtr WindowsConfigBuilder::LaunchEngine() const { + InitializeCOM(); + + EnginePtr engine = InitializeEngine(); + if (!engine) { + return {}; + } + + int width = 600; + int height = 400; + ViewControllerPtr controller( + FlutterDesktopViewControllerCreate(width, height, engine.release())); + if (!controller) { + return {}; + } + + return controller; +} + +void WindowsConfigBuilder::InitializeCOM() const { + FML_CHECK(SUCCEEDED(::CoInitializeEx(nullptr, COINIT_MULTITHREADED))); +} + +EnginePtr WindowsConfigBuilder::InitializeEngine() const { + FlutterDesktopEngineProperties engine_properties = GetEngineProperties(); + return EnginePtr(FlutterDesktopEngineCreate(&engine_properties)); +} + +} // namespace testing +} // namespace flutter diff --git a/shell/platform/windows/testing/windows_test_config_builder.h b/shell/platform/windows/testing/windows_test_config_builder.h new file mode 100644 index 0000000000000..0a1bfb400002e --- /dev/null +++ b/shell/platform/windows/testing/windows_test_config_builder.h @@ -0,0 +1,79 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_WINDOWS_TEST_CONFIG_BUILDER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_WINDOWS_TEST_CONFIG_BUILDER_H_ + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "flutter/fml/unique_object.h" +#include "flutter/shell/platform/windows/public/flutter_windows.h" +#include "flutter/shell/platform/windows/testing/windows_test_context.h" + +namespace flutter { +namespace testing { + +// Deleter for FlutterDesktopEngineRef objects. +struct EngineDeleter { + typedef FlutterDesktopEngineRef pointer; + void operator()(FlutterDesktopEngineRef engine) { + FML_CHECK(FlutterDesktopEngineDestroy(engine)); + } +}; + +// Unique pointer wrapper for FlutterDesktopEngineRef. +using EnginePtr = std::unique_ptr; + +// Deleter for FlutterViewControllerRef objects. +struct ViewControllerDeleter { + typedef FlutterDesktopViewControllerRef pointer; + void operator()(FlutterDesktopViewControllerRef engine) { + FlutterDesktopViewControllerDestroy(engine); + } +}; + +// Unique pointer wrapper for FlutterDesktopViewControllerRef. +using ViewControllerPtr = + std::unique_ptr; + +// Test configuration builder for WindowsTests. +// +// Utility class for configuring engine and view controller launch arguments, +// and launching the engine to run a test fixture. +class WindowsConfigBuilder { + public: + explicit WindowsConfigBuilder(WindowsTestContext& context); + ~WindowsConfigBuilder(); + + // Returns the desktop engine properties configured for this test. + FlutterDesktopEngineProperties GetEngineProperties() const; + + // Adds an argument to the Dart entrypoint arguments List. + void AddDartEntrypointArgument(std::string_view arg); + + // Returns a configured and initialized view controller running the default + // Dart entrypoint. + ViewControllerPtr LaunchEngine() const; + + private: + // Initialize COM, so that it is available for use in the library and/or + // plugins. + void InitializeCOM() const; + + // Returns a configured and initialized engine. + EnginePtr InitializeEngine() const; + + WindowsTestContext& context_; + std::vector dart_entrypoint_arguments_; + + FML_DISALLOW_COPY_AND_ASSIGN(WindowsConfigBuilder); +}; + +} // namespace testing +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_WINDOWS_TEST_CONFIG_BUILDER_H_ diff --git a/shell/platform/windows/testing/windows_test_context.cc b/shell/platform/windows/testing/windows_test_context.cc new file mode 100644 index 0000000000000..42da7c1651341 --- /dev/null +++ b/shell/platform/windows/testing/windows_test_context.cc @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/windows/testing/windows_test_context.h" + +#include "flutter/fml/platform/win/wstring_conversion.h" + +namespace flutter { +namespace testing { + +WindowsTestContext::WindowsTestContext(std::string_view assets_path) + : assets_path_(fml::Utf8ToWideString(assets_path)) {} + +WindowsTestContext::~WindowsTestContext() = default; + +const std::wstring& WindowsTestContext::GetAssetsPath() const { + return assets_path_; +} + +const std::wstring& WindowsTestContext::GetIcuDataPath() const { + return icu_data_path_; +} + +} // namespace testing +} // namespace flutter diff --git a/shell/platform/windows/testing/windows_test_context.h b/shell/platform/windows/testing/windows_test_context.h new file mode 100644 index 0000000000000..bdc6fcc22a2de --- /dev/null +++ b/shell/platform/windows/testing/windows_test_context.h @@ -0,0 +1,40 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_WINDOWS_TEST_CONTEXT_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_WINDOWS_TEST_CONTEXT_H_ + +#include +#include + +#include "flutter/fml/macros.h" + +namespace flutter { +namespace testing { + +// Context associated with the current Windows test fixture. +// +// Context data includes global Flutter and Dart runtime context such as the +// path of Flutter's asset directory, ICU path, and resolvers for any +// registered native functions. +class WindowsTestContext { + public: + explicit WindowsTestContext(std::string_view assets_path = ""); + virtual ~WindowsTestContext(); + + const std::wstring& GetAssetsPath() const; + + const std::wstring& GetIcuDataPath() const; + + private: + std::wstring assets_path_; + std::wstring icu_data_path_ = L"icudtl.dat"; + + FML_DISALLOW_COPY_AND_ASSIGN(WindowsTestContext); +}; + +} // namespace testing +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_WINDOWS_TEST_CONTEXT_H_ From ebd679931858d897cdb48c5bc9a69e723eaec30f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 15:46:05 -0400 Subject: [PATCH 203/558] Roll Skia from b2d197d7c22a to b2b39a9cbdd6 (1 revision) (#35275) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 25e72e9f1657a..d31515bf323f2 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': 'b2d197d7c22a69bf89c7d9d897e4ccfedb64e0d6', + 'skia_revision': 'b2b39a9cbdd68e306616a267118e5164deda5378', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index e28f314bc63c5..4a8d585edb9f7 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 68c72e207889dd5b97700e6d5896cc90 +Signature: 8183da150c2a0a449ba2e35e6f6ed572 UNUSED LICENSES: From e79d12a8e38b88a2b9f79f76c0462119a7cc859f Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 9 Aug 2022 12:49:04 -0700 Subject: [PATCH 204/558] Automatically URI encode asset keys (#35270) --- impeller/compiler/compiler.cc | 14 ++++++- impeller/compiler/compiler_test.cc | 37 ++++++++++++++++++ impeller/compiler/compiler_test.h | 2 + impeller/compiler/compiler_unittests.cc | 5 +++ impeller/fixtures/BUILD.gn | 1 + impeller/fixtures/sa%m#ple.vert | 23 +++++++++++ lib/ui/BUILD.gn | 1 + .../fixtures/DashInNooglerHat%20WithSpace.jpg | Bin 0 -> 354679 bytes .../fixtures/shaders/general_shaders/BUILD.gn | 1 + .../functions%20with_space.frag | 34 ++++++++++++++++ lib/ui/painting.dart | 18 +++++++-- testing/dart/assets_test.dart | 7 ++++ testing/dart/fragment_shader_test.dart | 10 +++++ 13 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 impeller/fixtures/sa%m#ple.vert create mode 100644 lib/ui/fixtures/DashInNooglerHat%20WithSpace.jpg create mode 100644 lib/ui/fixtures/shaders/general_shaders/functions%20with_space.frag diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index 0d7af022cc36f..795f9962a7479 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -464,13 +464,24 @@ const std::vector& Compiler::GetIncludedFileNames() const { return included_file_names_; } +// Escape `%` and `#` characters according to doc comment at +// https://github.com/ninja-build/ninja/blob/master/src/depfile_parser.cc#L28 +static void EscapeString(std::string& str, std::stringstream& stream) { + for (auto it = str.begin(); it != str.end(); it++) { + if (*it == '%' || *it == '#') { + stream << '\\'; + } + stream << *it; + } +} + static std::string JoinStrings(std::vector items, std::string separator) { std::stringstream stream; for (size_t i = 0, count = items.size(); i < count; i++) { const auto is_last = (i == count - 1); - stream << items[i]; + EscapeString(items[i], stream); if (!is_last) { stream << separator; } @@ -486,6 +497,7 @@ std::string Compiler::GetDependencyNames(std::string separator) const { std::unique_ptr Compiler::CreateDepfileContents( std::initializer_list targets_names) const { + // https://github.com/ninja-build/ninja/blob/master/src/depfile_parser.cc#L28 const auto targets = JoinStrings(targets_names, " "); const auto dependencies = GetDependencyNames(" "); diff --git a/impeller/compiler/compiler_test.cc b/impeller/compiler/compiler_test.cc index 85b3abaa5f9c5..79285051f1f81 100644 --- a/impeller/compiler/compiler_test.cc +++ b/impeller/compiler/compiler_test.cc @@ -58,6 +58,37 @@ static std::string SLFileName(const char* fixture_name, return stream.str(); } +static std::string DepfileName(const char* fixture_name) { + std::stringstream stream; + stream << fixture_name << ".d"; + return stream.str(); +} + +bool CompilerTest::ValidateDepfileEscaped(const char* fixture_name) const { + auto depfile_name = DepfileName(fixture_name); + auto mapping = std::make_unique( + fml::OpenFile(intermediates_directory_, depfile_name.c_str(), false, + fml::FilePermission::kRead)); + + std::string contents(reinterpret_cast(mapping->GetMapping()), + mapping->GetSize()); + bool escaped = false; + for (auto it = contents.begin(); it != contents.end(); it++) { + if (*it == '\\') { + escaped = true; + } else if (*it == '%' || *it == '#') { + if (!escaped) { + VALIDATION_LOG << "Unescaped character " << *it << " in depfile."; + return false; + } + escaped = false; + } else { + escaped = false; + } + } + return true; +} + bool CompilerTest::CanCompileAndReflect(const char* fixture_name, SourceType source_type) const { auto fixture = flutter::testing::OpenFixtureAsMapping(fixture_name); @@ -160,6 +191,12 @@ bool CompilerTest::CanCompileAndReflect(const char* fixture_name, } } + auto mapping = compiler.CreateDepfileContents({fixture_name}); + if (!fml::WriteAtomically(intermediates_directory_, + DepfileName(fixture_name).c_str(), *mapping)) { + VALIDATION_LOG << "Could not write depfile."; + return false; + } return true; } diff --git a/impeller/compiler/compiler_test.h b/impeller/compiler/compiler_test.h index a7be1c688b198..be9504de15dac 100644 --- a/impeller/compiler/compiler_test.h +++ b/impeller/compiler/compiler_test.h @@ -25,6 +25,8 @@ class CompilerTest : public ::testing::TestWithParam { const char* fixture_name, SourceType source_type = SourceType::kUnknown) const; + bool ValidateDepfileEscaped(const char* fixture_name) const; + private: fml::UniqueFD intermediates_directory_; diff --git a/impeller/compiler/compiler_unittests.cc b/impeller/compiler/compiler_unittests.cc index 23101e313f90a..68084d62d35ca 100644 --- a/impeller/compiler/compiler_unittests.cc +++ b/impeller/compiler/compiler_unittests.cc @@ -65,6 +65,11 @@ TEST_P(CompilerTest, MustFailDueToMultipleLocationPerStructMember) { ASSERT_FALSE(CanCompileAndReflect("struct_def_bug.vert")); } +TEST_P(CompilerTest, ShaderWithSpecialCharactersHasEscapedDepfile) { + ASSERT_TRUE(CanCompileAndReflect("sa\%m#ple.vert")); + ASSERT_TRUE(ValidateDepfileEscaped("sa\%m#ple.vert")); +} + #define INSTANTIATE_TARGET_PLATFORM_TEST_SUITE_P(suite_name) \ INSTANTIATE_TEST_SUITE_P( \ suite_name, CompilerTest, \ diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index 3a62e149c864d..88a828942649a 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -47,6 +47,7 @@ test_fixtures("file_fixtures") { "sample.tesc", "sample.tese", "sample.vert", + "sa%m#ple.vert", "struct_def_bug.vert", "table_mountain_nx.png", "table_mountain_ny.png", diff --git a/impeller/fixtures/sa%m#ple.vert b/impeller/fixtures/sa%m#ple.vert new file mode 100644 index 0000000000000..fc7e9d1122000 --- /dev/null +++ b/impeller/fixtures/sa%m#ple.vert @@ -0,0 +1,23 @@ +// 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 "types.h" + +uniform UniformBufferObject { + Uniforms uniforms; +} ubo; + +uniform sampler2D world; + +in vec2 inPosition; +in vec3 inPosition22; +in vec4 inAnotherPosition; +in float stuff; + +out vec4 outStuff; + +void main() { + gl_Position = ubo.uniforms.projection * ubo.uniforms.view * ubo.uniforms.model * vec4(inPosition22, 1.0) * inAnotherPosition; + outStuff = texture(world, inPosition); +} diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 81433a10e754e..5be9029295f03 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -187,6 +187,7 @@ if (enable_unittests) { dart_main = "fixtures/ui_test.dart" fixtures = [ "fixtures/DashInNooglerHat.jpg", + "fixtures/DashInNooglerHat%20WithSpace.jpg", "fixtures/Horizontal.jpg", "fixtures/Horizontal.png", "fixtures/hello_loop_2.gif", diff --git a/lib/ui/fixtures/DashInNooglerHat%20WithSpace.jpg b/lib/ui/fixtures/DashInNooglerHat%20WithSpace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..488fdb4d5215cad1f7921544b2d9b632583befd9 GIT binary patch literal 354679 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�DSoz7VVlC7;|-V30? zB#6vO-X=nuN%sAII4^)kA5kDn2g|2Ms-$qdfp3DqidaWQPlycp9m9xmNz{>&Uaj|9 zYdkn_!1$+wQtJuQV!t4&n{&2U4_kI7<&F_-bth%xSQkQZ<`kiapTq=ck)?$JB~ptQ zv0g${myun(6=dAFkD*@ijObgDGnp^Oyad2$*5}^ke(>m^AV@N5g$G2=-BE^j){PP< z61fQpXG@^SA4+Kv8GRQY@eogs`tlfCZX%W`a5TJ&HKBz5!;O1!rUU{C{5Rm+iebya zF}IiW{J|R2G7SC;klHw~o|3w)5x4u9<=ZqD-W3t(RN@Ii-iUBPovtjT3AKa4L>WJfqXu{+@orzP4ezl(pW53~ zh=98^r;iTfd2-5su+yn^- z2QCF6k9dDa!~VbCPfxrPU`q=o`})6LK-YtBTt#_2oqvGBI|H)Gpn?MRxT3Mv;@541 zo{00{&yP0EVI8z=RZI26O=Uq*5r%zRFZBdpwqGOK%Qh&IzaU=`ltoE0<-bVRXi90K zou>K=x+1ELNrRc2`H4hxT^~OXE~RheWsZq? zuvy|?qEaCc+=$##E@V@PKv+C%JkG{RqnBLu>1#Q#bL=!eE~~fs*q&Xg=b&$$y=AKD zvt~6_wGXv8oz|2QHgKo-!juy#>PEzzmitck&yFX|=%D+?u)|O%xXT>lp zbAVBigz27-i7vA`)hPpofqVG4+z_;sMsRF77SiPv$usG%&g=5;4L6{yj7#oSk?JdI zNWWF!kE%qh7okj}`?8VW2F=T%Rx8YPJiPd1n=l)`{{F=UvviE1-ww9u? z<%L(IVOB)?fT!2<2#y+-F;sjfGJ{qg`cLe3SsmWDOd0IRHC;~8)C0hb4yJ?kLKG^Z zku%sfgve8&1Crkt=Ze0hxW9S9>~GAb*)Lvsx1vm}{W z^fyNQPqQ0Ethkd(A(>CZFA(dVb$#ga2x<+`!yOeah_UuXt+x2O@WcDudSEIM-sTQ| zl~R+cuBF_qd0LYt7wx)^eAkllRd2f4vqX83yRxd49PE6!E%K&)yyX?UbJx0p$_%&b zwy7HD1@~z}?mxd~KWjFkqGuhsFV4ShIO2AAN9^mvoQLX@g1GFeHnO~Bb|L2oIQt=u zM_K`^+R8JU!LVP(cbV8Q!1`=RIJb=?1L;^@A9&D`a0EK%SsVtbW1KBbE#L*ShRO_? zB|0HK0a#87#B@SeSrgG0h>_JGq2`J5@NI6dWZSwB(=2HqKdN_3oF_%Vn~qf{3Jd_H zzWlzkZVJVBlaSl_Q4wPxz5>I-!I5^Q1$|uwv*6GR`fWc#X=MLR`S(6DQ*<)$CPLR^uX`O;RV*?MMG%Dr3h#E-VNkE%Qs1~7e zm+?C`e4FU(+L9bw*cc04?{-IdfMut-q++mS!nQCK4-L~}SQ!hyU~Q)iaV0rKucX^k%di;At6)K*&q zbMPKb&aQ=N)lIo6hHF2k%d=rGP^fv5&nLCl<34fF(w>u5c>&bUuJDr&75;VN28~VO zz?^Wg{xZ|w48>*IEVOTP^dTrRl!VZ+uid`)TYLz;T#pX#D-IWheAenwuQIPL4YltO z;Qwr8gmM}*|3O)AFW3Ib?{!A0I6Zb||g z0tx#B?4`yf#6^;^K^(dbQVW2C@8B*oBY1B7H>eO?LbTI43bUs(GJHtTAT?HrEa88T zO96TaJ9_ML)plGaom{lf?;f=T#d<2^>KH0ZQrpQnHgj1?a z`CS(EfOeU}qYCXX3j;=JFcNn?CSQ)#hBaB+oPm({NR|?&KKODmpea)bhrVR0|lLVfkOh>IBZv;FbAdz6ay?6Bv(6o$y z1<=w!$78IbNJcAr`VJ7vg4W|?Q7i ztX|-;&B~{w`+7ciBihZpBXIH!TB=x-ypXmvmfm`$E``Fk`|fD@ZhcQ%)L=;~NaGwR zhvq`sNHP(EdKuFy1;jybFIxv#7Q}Mk+TciDqFk;i#iWpZw#QWegIPLpf8;-TxLg8d zZ}CpKw`g6ad4QIE_?o2B{PUEL&O6y82WOHJoX>SHPC32xdV%Nak1u(fRGd`_q?I2B z{T|z4|B3T}=Q5NPOH+pfzWY#Z`0 z_gb)OFv*v$odgH!yO8Z-Y%oWVhwWf=?fjDFGR{DNAK0OskYa;j0|t~jk%51MsoY=5 z%slJ#$y|048OQ~{VIcn6$=x78!v(~I!=f7`F<%r=LLvpmU3_ zwDz^K>Kq%iI@HLA6fLLccX!?38=9yE%nWV3(^)SLC-F zWabq&Xf81{d_~!0Qv+G}LG9L1bm`)fm6Z!n=l#9oR4Z4B%}7Ix&Aqt04Sb}(^Q7=G zIr&FTU4<6$`tX2L`R_rD}{u(6`Uj7ogJYOY{4VmKenCl zdOEnXW8^~AMCK^L(_Y+hYPW&2hu|J-UVcBAAoY)Hjb8+;zAoZcf0`F*_Vdx<3tK+% z3_kQM?b*ViU%2O5XI<4DKfgS1K?&WGQ=*glf4^1#wrtb2u$T(Xb9A)S(S?tD%JU=u z?BW)An6%kxQ`vIjM_axVy2gZ}uwqtN@jWx<`)5>JXR%XM54yJi-R=lJ!LJ#FKffzq zwv%E5+&i+HSZ7-L^5#I{3c;zT%qRYD-Z)4d0Bx(w6kD&p39q8Eo)Gk?Ge1#57 z=#yPwv;4WHlQ8mXJgzG%EjpACuPc)vnuf`}Bhon7UKJz~J3Fy&-R+wPyQ@6WJ3o&I z7ipn6T5h$w4?i&^Hqb8iDr-EYJ4`;;7r=b{*OCgxof4Yx{FQe1FLnl}Ty)MZ@fbNJ z@jGPJO`3pZj^v2`)ZVTi5AA;RYih&``o@L@gGaLA{~vGu^+n2$CGBos0*2xL8k{d}@H=PKxOt<4J!~6;E&Fd;IJ1j>k9uT=`n{=81T$#?xl~8ni7j zUDf*G&6Q!g2U(YwaN?Uky7nY)A)(#*v>%;Zka^O^Y(WvQo%a}S8$J;>?U^^LaxSC! zhwSoi$+uR0;Q2Ih(C?pDPjJ#ywN-5l=C!qpcgA#AtZzKClxUVB&KYaX)&!{+KMDt? z8Y`;&pN8z?2_jQJ9xRsBgXz6KUK;&@D9cS%LeHbxugOcjUNLxPd9WR#U+MFVa-6}1 z#gj#!NG*d`4CQ=JJ@6I3fOBEDo<33w`f1LNI-MOR`Z)$ZPGqGBBPGv~jVYV;6>R9q zF-D5No^MRcz9!{!-0r7JTAql`?srg{wSlit5m#ZINYHbuw)=nWC^uzqYf&n9xcK0K zf&t61-474aJ^v+sO}q zC?#HCuIsF_Cz^dQ;<9cmYWPTcuD-fX)I`nSx#gW?C71G2MfZ-186)}D2 zh!%+q`hVzp^RTAQZ*6!dfiTD*x>05s1QJwa2m%5c#4rRBNPNs6&aLCZ38H3 z1Oy3!F=8YWs933Bv5EyXfI|=hT12FXiXskGK$2%N(?i>z{asp7vmcQi9qq3b`q>a{Gda zX!EV?HMcm}u1u*`kk#eirUiGy8BHm|_4V!TFCEiKacElg5EfVNQLFI$8G$=q4HNSN` zxcFiSDuB4b93_+vfq-hJ5m$rIJ0j>XJ19(0;xpp@)j<;`ja%2MwJ$c4zuzI&W8Z{S z+BIrux_@{t4&;j%y2^f!4Cbtaa2oU&L3H_h)fcqY0M^Sl^u*AV`tGyZE>GcE&`7|% zn$`0k7p`}r_sq#wx>W{Fg)WgTvC6Ik~Fo%+-quFGz_ z8Odc1cx>OR7Z~}9MKi!^gF0D?nhun{pIkiGs= ztNu}*F9}JhC=g~$k)Htr`USV3fA|m&CnWA*4D;rG>=*S@IT&rLiPA^Hoae~a@4n<6 zG1b}OWU#3*2XWJvtO_DAlMh0YcT(AHGpQIy`oaJ@BuG5Ovm)OIIIpNs>4tinNp(oI z6E$XHZL`;*X968s?RqvdLXk%RZRp$;fKb!M5S=ds8IMK8<7v9>Bhs-(-Zd z5t&3LA)|w*2GA595G|1`D@`aeB;ID{`5ms+&4f@pqgoPh4px>%DWGCZc5ybt>8IDHp5HQ2H)c{9 zYyuD-vRc&xFYX!c$vklG^pWCtJ@2J)Gb8{*Y0HX*NX8A3MNp?=#a(lJRf7t#`w*Hy z9T`(+QEZ*f#Cq;+Q84cgF1F!D>hO^Z2AwRe>2JX?oxfKs4!C9 zR5F}Vu)b;?J0x!7ZXO;rekDvW^Q)2h`IT(4<9jG{WZoQ|CE@Q&41=4BOXOO=>;x(6 zalt^COV&zevsOADBvK zZQI2`boB8y#Ue(i+jp!rhgPx3M*gLIa+Z78F~xAnR9h5I@He6-hNuzE?sK)98274f zr3LFb@nW$n5q&4tInLI59not{nuku4jh_>yl%%3deB%bO_B)dJQ88_?i7;r|2+I0U z{xi;MV$UQ^%dK;YW;oQhz$SDm(C0DBQ%D>75T?W}2C|KR>0sb_(RT59<5o9Eos9R= z2bHQd8+7>I@%{0OE;^tm3eCK5R#ttnMif7cTVgQbL1po}TfA%d91`EI1XpljWXm|L${n%fg=1)4r>7j<$cgAi3tSr{mrlxp-#$@iHpCN2=)AKao7T=_jp$IcI@3S2r88 zrtL+MkN-f{E>MjOX=@c%(yx2jaB~xR3oF$%!t~E?sK)JxR^3c(QXnZ^iCt(wxGsO? z1nZ}tncGPt!iYMEYz!eCA6@@i?;A>pdJ=)FuO!Bow3%Kj$1BpU8;5q@0%nuaXJxcy zLS>Q+}` zse6QOsHwSW5@aV`kb@>Q`Y1OCpyiF#jvgXIVBBd~Ef(Ld1i=XkM?I3Ez$@K=BDklb z@K56C*6elgu8j3e5q|srBpCDwE_0#wo1>@w%As~9GlWYQ+8D-`CQqC!Z_Qd7-9oyl z-_}T$ZWKJf)y&b*gi1B@FrU`)oPf12I@QyfF$fK3lx=y-jl=Xy(c2R>+tB}gTlt@o z4IjZB07WzsYdkj)CLtshlGkv-MBat^qkJ~BHY!KdKu@z44uVzGc1RYfCQB9iTA>nC zTksxmTOblMQ$#JgwfZ^4`s1OATcr0RHEumsrrPkJP(2e{mQpg1p_Lj}J*q*f6R zI%g~+kTfzd_xTnljz(5X1j;C~ozxFdj?qRzGLuCEeFBT1!YvA;^+F<&F2&<`1nCH; zkf3lpfcpm4*Yq^?Gsmx5X|J+8wAbSn-x-=H z_xW8saVBJ?!-b3ui8G6OPi2pa9t;h5Mpy41Dyc#rscY1=h7e6#2Yco%TG_$wA!!86 z4t1u`Gproqle(#H?o@3A1VWsb!Flx%S+3^hiGi;uuW5HCwF57`o75YLex42m^c4Z6 zpG`{<4-@_}Of3Lj2N05K0icDHa|U2i`lTKoc- zNH?H&ah8QLe?HmwGOJQuVs6U*uYkiR?AXm$1XkM?(r-VHY$G-Ca-oJo=ECvJ zA6K$A)KPrq-Ym)&>nwV$zsahUAHVu4*~f>3A^81@7oJ`<+3$)yI%0iOEz1A;&fLwV7M#tQ6kbh6!fWcPZ#$==(mN&jI{X}ymFI&8 zLXB3jq7FYLdFIx4gkQv0xa;uuiAvS!W>YFZ?dy6^NxL5jci(7x?&9h32roRa&|}%* z*R<^8wd*`RlW^#5uQ%6EzS|u4ti8=dNPD;^YV<*w_Wp@e_YR2K)MtFX=F{DIEz>P#X!&4(F$Ez*WZVQvV_1pgLcUoj6qEU^M`oJX|ovzUTq*inp`R zc%fdPD*Q=k$efT$XY~P$p-*&?PQV+w`<~UFVB~M>jN%*liuaBD=G4RWotYP8Hm!Cm zCVM@&+E=#ekqw;H-fp89F~o{9Xu0Yz@C$R*Y18wZ9QwG|^Fl@V@rckGV*iRZ38 zQ_!DTxzr%<#0iH=*51r##CsL9q`0NgZ*4@)-a#>QsslLFvAJm6(si7B`J~?JT*rfp zqm%7EU9-r=Ho3ZF><=ESA6q{z&_8RkBeCqHF&d};hkfaM7SBBdjnj4Gp4K%@HVH)f zv{$mL1%GXO&^8r;?~lA67#D>jayeE&&vX!8T*#Iix!l@PIw31tNLlTLheYn)uH7Fb zUiiOeN*L6RNTK(-?@7#jLF^pAM(=ejmyhcFE5~>(8~BCyy^QOK2b~HS32|IGqlyxx z*&!4`$*(iP$$PBv56# ziYVK~F*kJ#Z?T{iw;~~w)mtoSSo1LYFxL%8KX*Gd1>pZa*a&jHX-D!<-Ru#I!#)h* zFvX?KE7Lw=7s|YIWS?hvcz6Wp&6s_5+2K%1N!M1BRD-+g1j9L|-4j)$TOiq66ebJ| z=f|5%RazEM8U`A{k3yel=)*J##m^5D8gW|;wi8GQFL(I$VpH4-G={U*KI?Eov0d(doJD~>+%>h?SQp=Hv8t~_B#aI2* zWZu)|9tu9f?qMAy1gG-zl_v=|V#Hb!D^`hT2yhlB!^$;CfJK}E=&)eD1xASqnT8N^ znOI;E*k$Nn!NIgo`l&0x-hzWjVE6nC!TE|amAEFbNYtn5*-pbs11<(;N0dA4&%vb{ zP3{AM84cuUAXi3nz(nQ^n4y7L&Jih|XFXiOAVbMM@+C?m|iV8M#n}0&G+KXuYETM~oB&drIwOr6*8UeYuC)d@`zCz09ShA~2j3`)( z3`={#AtMSA;c@kD^x;H@JfV#6DZZ98Trv3?QwLv}m-L#R(910YK;NoS2DlS#Kx!iBStXx6xU%|aL4}*%%N|CGWc1XDq_ePd95$rnpaMcIk zSJw?{iqna93bM%Kr&g_Lp|OK~xo#KHAjaGrD|lGr)6gx$@m;mv%=N3J3noq+bbLdv zav|GG8oG+_ldyqGo0((hV(dnq%5=)f^5V!I2UK@cW-(t+D_LJB0y2O4gm`Lc)@kjn z4hsW?9S3o|P3#4>NY{l;lC*E{WWV3R@+^*6RxY@BE-uH*2Bd4E*@o%L;8$)OEVH9r z(3i;|PSj;Vlcu91%9^?0GLUqohU^mjYkjj0EJAf;NTU10d%%6S(ssdu{| zqI|Ia*q%(JzDDMZ2Oa&-6|l0~NDM(o1xGZ7K4(c_%RrcWiBT^A|^1m4Qu5s9lUJfUEs;8tn0SU;WX2`~{?Bfa#suhD6D z;$~^su4d1<9@$Eu1n`Mm9uve#;8LrxWPwxKr~{U{6}z24grMgGYZhT%WN#Um<-DO| z>zZpOg|!=2pCOzzZNPbD+;1>XY3Sf>-#l>E^bMIMS|{7FJ%Hn_yJ}3VyLR&fZ9);b zfZ6hP(a)JtH5Ic-p?bSr^SX$mRA<+}kv%aZLtSBt&5O5994L%$|KWW$W51pC+`qi$ z?wj>z6{X4+TJPV}vvL1Nwb!lFc~|&b1@0xJ-D}&!NM{zHHEKW|bDGuaa%suu z#ll?7s-17cWU)85Nj<9G2NS)2X%y?!)^0nIn3dn~Q*!{#HQAvmRF5zAQF(7$BYs@R z?ZD7GvuMxql)mhxS*}tyngA^cGrhP zEF*Z$d=^+whPyvc^9Ym06_VqCGZksYgj_$}ZZ@*flj6B#Dlk4^lJ}x8{AbAnA#HRJ zvm$T2h(>8E9~`?U)_FWD$#gmjGzbdf@BTWxDk`CIsAdsStmkd9a?mmv5(O97v|v_n z#`p&koJ9E17UTts+=wkEM~L)YwYH5#rhR{C@N#$*7QZ!)aiKAS?t{K2?oDF)RW3{l zo|t6jCr|SkT6-&e#JP4i8LG&~Ju8M5X2BB zP^mphDTN1R4ey!7WMkPE$JA%?;$RxqT4{#YSnp$67%dDKPYv$}vU9lk;^aK35{Sl& z{{HoUlwk#irrVFlgnn;}xJ#$_1)7Ik;dzx6yC~NHke*XiB&Fq%m#_^X$Ol zDVhTm^44V*P7J|ZxcSm%dO~~tT(WwxmBp3NDaA6qKv_c<@k7Iki0uS9*mOqyjTFG~ zr7oNbO?b(aw8ZmP4mJ}Od98i*Rhga1``b-g>WR|SCigPcdf(o#acK&st)bU*!@xn7 zu;rtn%GY;uj$BJ`u>O`D$khUFa;f?Y$U#DkS`>E=0i6n+k>F4xfsp_iTg47sQ>6w{s~poKyWLB) zECv=8Psgf=8=F}-IREWqW`n^6EYBj)p}a-B0JyDaX=3FDFd{_fW^f!fWd<3npez{! zC@wZbS7EcB)L&wT@-v`v8>7TdrKcn+59|U(r&6t0wNGVU`;<cJRZ+m@OyvX=MUnu(w>e)H zT8^$z{R009j)9dED)^GZ0Aq(#qH_XbI)GxmGt>V#+zEzgn^!!0(Rf1Sz4YVx=b(Tb zvrM~vB&{7oDw%Mv>4G^CaU#<tBOV6HoTosl4sEB(p zlD%|E)&8V!er_4?e21{yr)W6Ri-n6ORyX;nzN@xDBt9^p<~ut#naR!ZJ}N@?2X{1O0>s`G~)b$Qi z?|X6YK2OH!+pzgxA6WmFlK9k?>D7!ghjBGweJf#O{weNOv%itp-*_^Q`@!_VrJOd? zqYC`dqJnkD&wEqI+HNBko@*n)XL~-M{L9PZegw1^B@;X2t&9^GN4^b+?bH6Dd6ma4 zZTxRrM>BN5X12SLB*wia-<11(`$<(rQ;E$MAD2ZBWrm&YTd>q~_#OV>N|X1j>64#~ zWvg!_+(xzc(|SX6wHKvT<{{BLbh1MkI=)iBd4K+xKJ>Y9)g9kgt6dJfw|zWuY$ABo zGjY)6erNWoJFYue{!<32Ztqb{JS}tRFTo?ygRqlz zNxKNsi<$w=|7uz$TW)vq=uobc!0#itMf!Qp2M)?UKb-LEr*{t+JwB@KT>YA6&@Jk} za8bC_>RO>Tp>)17sP)3A{Y)^_lV*Ts`$Fz&d`rVjHlNXLq zsd+(R=Xq`5I}aXla5h5?m%71H6x2a5e`2Eu5GUQBalq6d=am0AH3(W@|Ed{+rj#p= zkv0DDYaoYA6S)XvI4Fhx;cQVg4TPp&&`j@CBGiE|a5Q||0F3VcQAmB!Qy98(-C@$n zWe6j{Knv8Zf)?a+zwldUpj>fO9yKJ)-+i6+HFy}Tz&HnNU^Nj9Zu)hm+PsDxcRt1E zCci`bj^r7+)8!M#*yh@xX1xZ}yi{%r0IcAe6AX+Ni3{y3ga9RJw8sdmvE?}u!DN+z zQ?3FN7KtLFfjzE7B68P8psn&L9pH&|sTNyem2RN<(PBpLW@Q5LT|Lf^;JB1siGQm8 zVKB>fyZw)cymy~Y!5W5zPM#gFh;fel3i5@M2lk?6bKmd_9#@&5%DM(>25 zaUX3xZgRh>R1~e+Z(g434ywUpgi~u4)BvGTAMqfF0m=;z6GrsmF7$G4J5>QG3*j9i zybLGL$Z^?~;ll!>mSc@b`yL%DW)eS0h-6NM_4QM^`{*-9ExFDsN=>VE1F%2C!Xt1^&Q$is7I^WyjzSu{p+(X6MII1Ppn+IwXzbvzYn)LN=0Vxq;6edpuBURU8P=^Jx#_$|i5; zbmBs=oJUF%tM#sT!m}~P^RPMRJ%yHoOmF}GI~+{+g!ze32UNMZlyS%qaS^$Tf4?V9 zCmMx{b$)7)pLNU@Vh;l=9Up?P?kEuPw>Ft8b&7@S5p$N%Y&vjOl0!j=n@iOOCdEoy z|HO)93s?86XFNkkY>4d~(iv=>p#2<8D$B4Q=FuP(rOoIzspJrUJ*J>v81W`-^gt<_ zAXP0XbXjzi^kLPjw7L1?qFbSzQXD}_VqvmF(x4b?quG;GoXudIj$&ili_PSYlL@g_ zgEuUjQXR9ZmezFkW^k6@X76?|=_dWT8|pgY!~UO&8Ap&Y7R8SrcjA_9MI9npUdO#h z61-SaqBj-XSD@}E$EElAD00TZHwDj;bx6<-qV{roKAF%d8_SiV(kP5DVt_NjTXeD1 zVhzQEAMdwHa6t~|Qt!X}9RQY~eb2w0oDL+)k!B)}ljp-lTVtGo$ikYB`q9YyL zuRB#NIDg+cMrGHwXVvpNE6K8-S#7arf2EJ?!5)2ggxo>uM2~e5|3*@hK9iYkFV-d} zW(^)O^%h9}D3ohi@{*Jb=NJHK`i0?!<@1aM$%FV@|K&GBbI>(U8&^cDZ98)E>3Z#(9MlIKz3|)yA z8y@#z$BTJH503w=81WIGFJNv##kjjXi?8-ig1wy<4AY>yHS&v2ekYj#J0L#2+Jw6@ z34OvUts)!$#t(8iD05wHK|2McKjSK;)&(nl0T?oo4ZiMf@=Gb`SBp$RS6Db-U4uI- z)Bn(A_*MD6p;Se?t;-mL-?yN-;lpUnipqD_-`9^Z=X8@cC-qsJPk*%0B+cn(!P_E`>&Bb%Byx*$-%dxe; z<{ISL>Yoxarfmq=pv7hHYX^4<^MYp-`Ke;5pGmxaMq`f4pO31j$)y?AW3zk5H<%h>4lrK`W6d~)RS8!#X=pQt^v|GYfkYt^%L+0h-d3P`xs zarX@WbNJw`@4Ai%Jt@UU%BL64lGI_(;f`9rFyJC{Zi@wBZeposG0cWFB-vQ1w0$IV zh5m!<3+ySFQ$53#h!v9o+$zmPaeaYyRae&jtD` zQf0UZ{$W9>6*DSIpid;j4bO+g0q};tj4~Zi8_B?e0=_I1Kz0UL_{euF!I^uXc7%%^ z3#7BMFLU!h^Rs5?{qJ^s|AiAvp>qC5>h)g}HykLS==!&u8votj1q`{N`U*p(D`+vn zyWUKZ2xHc!H6yrbeF=MRvXe`F#D1j@i?XuC6Q=YU^qLcwm>C9<9`ZiI+~+~z6n6vo zzk`AfM5Z){?Rz3$^Dd@10KU=3j(RsPIWFLkCdIUIntKSv}t zhK-%h{pxa01&($d8^=$aI(xwgJP&U_q*7vcqbYFacnbYA7hkNAgU{(AkZMUU-b4T- zCK@lEA|tm8=mpF^7{ZY8@*)9q2Mg0Jb9Blgh{+kcvH+lF82G7eTAtHABecwAvfJ?6 zohr1K*}^G@836M~!URbEneQ~V(JjnAgiEA3B6d^3M%*2m-bf>NgtTXfgzu-r)us9| z-$}ttrXF^=9H_6-FiU)V>n@vC$gXrep_-)mEA{R$9axunf;s+FG&pg7_WK z>EgSf2C|;q5Wrp3>Xb!9+Jm`B&lJ^nT&T+;>w6dxeDNip?l)Tc^Z@S7Nf@naA|PnAWrz#TWGDo6Db;(=dA@`ZKI~HzUk+(1Ft5 zIsVzyvE{)qD{{db;mU#1Oy7yZ@)Dtu4{1JijL_jD1q15a1)jq77%magF&1L-K+2&v zQQfr+awHB_cQ7@ihd4O(;d8c+Out(!8@k%G5Cc=$U6Df){cZbXTyk`Z{O!5Xnj7`w zOTefw37oWM>c`f24hygk(&80j#f#0^l#abOZU@We)=39z(XjwR+rGOaKhY^Z8xB(Q zAn|JA0Pi+&FEwxf&ja6WWyk#lVBQv|noUMT(MNU3RyNrOukwHOnl>`plAbhLp`75; zUaOC_y+?T~vnhnMyh`^fvWa?{nP2(QB3HQg?g7jKL(}E8Emv;jN!?-f<8SNGv|OM# zQQr}Ah|rt%%@T(u&l~ZuI)yBUDkf?#oLi;wt#jp0c&Y_!A1D`KSFTCh>ew90y34b# z7e$xrN?it#5exT7-R@RPOLeV5y@;{L>DMW^8{*XQ{l(BZtpbB_Etx{wsi;)qR9gZ} zQ;@u5s==94e+~Cj*kr_GD9xS}LQH@*;BSIJ=k27~^A-IGac3xw-+c1KT$k5AVq8aG zEF>~w^j-5B8FuSFs1{()5V|+7yS?(kN(1$-rjQ2_Fe$9RSuw-TFA5yAsQe-Mg?4cI zgu@vE=JJMAWZjX!Kg|Cy=u+jGF_ z6-=+eTOIuoZSS7%24A1+DHyMD`w)8TZC!R~vS2oeWtsiw^U|*9Y4w3U`??DHTyC6R za@|*cL}2CehWe;^L3aQ;ShQgE4t@}+tZ%&btJ`lZybSgH5Bc%Q4MxUKqvr1D=jWK- zlwLVifl;mu2D!41R~%`FIH|m|mwT}t&()QR*Bri`7L`epPLk)%7pA*-JZ9$amAN@8 z9o-I-496Y|$^MU72DOT(cX_AC2BVR5qTAC(Wf*TIgO8LhN%C#PQ+$ZM#7?Uj*oy8` z5ukCH^^ZBUdT~6n&D1^ExZuuPJI1HG=T0RlxOd6`6oTXeA79&^|xB~C6Jw`8;1Y*9{bmJA%K+M zUd<;ygR7+QpXZi_sS~_BLr288i6oKQYPNB0R-(uuF`sm1Rm}Q{(l_d+&1L!NEm!UF z4=D>5EzfcU!I#|0sczu>D)!!6-?P0I>=Oj*jM^Xj(e78_>2RCR%;ZAl0;9y`OGBnNs5m zc*C%vB_hQi6Cw#gQ?%ilp`)87!yD1|XOR`GHQ>C5Uh~cD8?3M2*y;vA5}?}u{h_hi`M-0qruO_l z5701y3spY_RIz|f{rg`rf2*&<2^yis%&Xl651kqRJM> zlob7n=$&{UMT~QzQ>o#jT&i&Dk6kXh31M*(4z0rJup<=gmSv20bFI~E0 z&^d?2Hs}!_Dqtv0llSuoFgSr-xD%0%nF<5DB{;a+Vj9;{|rJ_XMJi#{k__5*I zIm3MSK%iiMxnkjP8NsUz077u90J|3YAhe4)^);|x&Wj2D7M~?H+&C?%YIRbs>>k-b+L&W9EHF+ZQ;Mk=uXtm22Chx4f8U6E#eddo zl}?(QHWGB!=!4=zk|_bq*n`$l`$e-d8N$RUgb@~1SU&bq2>QAB?okn7r`h3E!P;ix z+=WwAGbS^!(0FWC`XNwhD?tr5LVScLO~NPpH8~jqd9DGIBgEFtfVH3R}FWpqc*L?QDz`ufW?M1d5AFs>0RZvA6KL&%A z&`n}HAu7}vJ^APd^b)iaKc*b`BV>~1Z9Eih^(w@(+{b#j~J^iWn~icwINvXlBo!#2kJONW}451NLBQXB)Bn zIHQ(0y!vg6^sNoAt<<=Po7_d# z-wC=de>3(??>SB-OB|AHA_(cWK%W zN9~@|%$=(!d$t|Ght|Am_}o~M`$9X2PdJ<1+_gS{=3M)JU?l*HPh0}cr zpAG|vCb0R7v<7w$94Nt1T|?RtGm=2VE8(-_^uM5}L0pKESaAqMA+p95HnX;YlS1-( ztAVp=H@b$*C&Ql@jNvz>U} z(gmI4Rryw_O)-Wl%RdR$2ejXM3NsT6)@5{+&1mn>3cStEx;~|fnbwhc=8DBjH~c0H zbX@;nSon>#AtrGsb1F1BE+ehx$bI{&TV@lrv6nX3AHBqHe2Tac{h!Q=bC&A_sC=#~ zqZaDG9?8>TK5X+BkaEjsF8-eVRb7HYFWK5};B4$219uR;+?bYilgveRk)+cLyfDbD z?6xdr$pWu$!_d8nsS{$-_y>6uJCI5wQtV)x3!uS2cr-sA&}>b>w1(b5(cPhg63r`iLs|XzPsknC2XrLW|PtTldshIHcZ}(4s=}RDcsJm6B6CS ziz8suM3CE2maV8Eb#O_;Ii8@O^F+spox30r8b4lzK96HzJ%~u-d47aG!l1+cokuiW zhUZxj2YIXp40LD&ObfIrUBWH?1CUvfa`*_jn`LIP%dYWT$qGhEH#@~;q{qE7`ognK zdJaDx{n^G)Yg)C+YT@IQ!%3g6MsX-2;L>F>^}n^taA}^33Hy+_F4C*X)8Y{~PiZD= zDrZrLDowgpTd1IG@O|3E=7-*KyXO`4=Qw3;j3j~Lib3akDr0w(1h1Q%2neS?k*qSVR^ z8|LH9UWSK_9_D@VX%{f)fQJ;{)i7iUjpAxMDv#%xTd zT!d5F`NPQS|J0wg;SAU8snE0XHhVp$d+~O8abYp-x{k~oN^s{>eAQx`mSImymv4E# z%Fg#W_dzIW8%!IKP9%#Ymm1J3Mv(oj!!^3Tfs;+$$bC z)NKa!^4LPfzV+=(3fBwcEL!Fo5myvgV4v(Nqrd&*dZXK;_JCXq%;FpZ4DK+apSJCf9|uDRvRW z_-b@FE^-2p1MDN2pO*Ti1O&>%S5HU`>5D<{j_htlj#JqgVtf^!1BUR2YWPUXOn{-K zfccUgfg#VSh{PX@=#YtVkfx`vpMC>5#6OsNLADOup7K@Z^%WCf-%u4+BK^>S`Jfm- zaZ|rC>~*MieKF+XE+}tNKk8F&wGkj6-O0(MS40SEeNh;ugtt}&F^hol08Wx}5gQ2# z*{kMpy9S`1uX2} z*NqoFZ3Xk0SXayIX0p)-jcxS@w7c_n&q6@!jqQk!m*qj(io?7%i2s~6dnfggzo8U8 z`l;0>$%xp(h;REFac>yuZinqttgBY4Fr9c$6P|@89{pvw>@ldBn2$&ugP-|YW=d3( za{h|Yf!+Wu;t#Cw3p=9oRIoq3haOR)861pESn>G1A`_mQE!&OrfUZMAhU3(g5uGo| zM$Xn;Z+^nEU*fDS($8qr;(31 zxxVB5X4dBe(Vt!{@s(G%IY}Nv^_H@g1@V8iesjBg#SPbx6DMnDB&cqm_p4w;8N+>& zuHf&+1>$*Vvoq;98*wgVE_Hp-OzBSP=_S^m{$Td$7V%Tk#t*Wr3;JSupkn}U9{*80HXK&zV`;%iS{H0b;iv4Vg z`3cqc+e0XRu<*A5o=Lxun%MT7`bEd`UvytGqKGdT;JTBI0PpnGIDLYs1&kU=0wBt= zidwPrTOGri8%Mu#;@N2`;Wta)HO8!d9i{zsd*ef$?3hc<_xX7gt2(a!lR)#2gQw=? zHonKGD=tH+w13M(U)CS{rL>N?=T6&evN4jYc&yKJ>+(}?O&`R##~V7msY^TOo=$U` z{6#NFPti5>IyRQWp4-7ZLxc^3)BE|DNG0o6#R8vJ`alO za4V>fK4hXSSI467#Eoxzw#$HH@JmgIAX^n%U)`OES@gq0 z`n|$Jm`|@<+xX38;uX(GF(c!wHcqzk(BTSg)IyUirVmaq8U@jRQ0M=E)tc%_aYHq$ z)I@!4lx0F_+_P3vo~E(D{0G|p-#$VO)*Q?KKbW_sDF5ew{XGbD5q=eVl?*r;FmP+2 z>SdCZ8+Drqd2um$rs)e_(&pU^uG`B$K$`JN{xMEn4$j$E8Y&+URF2C$f=H0wI{-xj zkZkmMI!EPhq%zm=IRq>&1wLQ4;&7oRm=&HTlx=}nZ2{XZ8Yr7BL%BmzCC-up3(+9j z#BmC4UU4{0+O)T1RweWIsK;y;DuM{En71 z_{^@m$$z{2jqp2|kIO!;OC+CiC2ve?w$h~jeN}c{)|*edgro8nAf=D*D%=T$U<8gc zZ^&k^k63^-w7vYQUheuR5mNlt9YRx4eFCOnMqWw(2!2u)-bVKnIbsU}(jk>eMtNwK zuLRd*I~fjt`eb-7&BR53d|CX}KyXGuZrJMR3d1s3$Zwnx zAgMw&H4fStRKvo8Rj*7Az=t0rI8Ua;!AP7VE(ND|5Gj@FyLWLgZe%b|0dKtkg=C8@f<_9~Rm1QghEE$3W zxt`Q9KmRD-*AXzTy2JS>RXKq%KM{K1>`)r5%a89#do0W-D_aNxZ~x$XG86YH>X=)) zbD^-pX@^Cgc7a8OUlMvod+V};bk5t_b*HC$8gnTFT-bHJZRhTky+2hS8v2ChwB^(M zP|7z;jap8`$cGfKgn|vlz2y3_m|-HBF}Uvdxw>1#RlQH!NEp0MnhVQvIfI&zE{@V7 z3C4GC$MfXiCPw_k1>tmd2&n}x##SK%=PFg+cpgS+Wzz!pi+Uf|zjM{mJ=yv<2hnN|cJWsXVi*I>dTh z7mwSMVH2w}$=CDIM9FmiW7btL9k%A{N=GD(QX`O(wY1bF7W7}(&<^sKswOSWD4*;~ z7_WFU*rzMj?syqYLsEcAF`#nlj|9&dr0-;bdh^D?7fdiYK|*{RJ%!YWDD2KZ%bZ_B zJeyee?aYazQ{myzB@}kEnM3G}h$zf2!&Uh*C3FxUimeHTmBJi9A$a&>ckm&T6*)pW zaXTWafSDYHJ)Ax`(z+Vn)xUW8%nu(e2bGSHUcjgXQJZ(SwW`bdWOp_ig}+?M%(4EYbK)b}N=lZ3qJ7p7dD3P0P2eIX@lP7vV4;o;kPC2=k=Q!Sq-HbKy1d5DU;i7Yz?(({tPA^`mBE8N(_}W~b4rDI z+l&mU>uPz&4w(#1ZyI=I#KG<>3hGZ|Y;yHAC0-5?L@&!HP6E)w_A!_8f7`LM8;N$} zM#eZDz3}q{&&zX@?kuV6a#>#BSF-(9Y9r3sxSxOh@ob0L$(KvdtV(f`04mjF#X7so zCDQRA)s=K)L3Wt1`CXQ;3TtxwxT1B*!RqSY!5zw^Il$#Qhb42n{VNA*DRU&gBq;K& z@f(XWMU|I%N_v>0;Rlrcw!c7_WVV-mGNd2_ec^21Q|A?DD>s*>i=t6MY}||7TLr=h zeJYXv=-hBAu>9tNNfKO<#8LnxHL+nZKN34M^CJYiVTgbkBFh|ILkiY_oj$<|0t=!0 z8rwai_>ekDHen9dFMVv0chLG7*1#fXAjbbk?v;R+q9Gsq;I37Jy6w+guI3s6jruA2=Yh%aLh7R@cD@1HK1=iu z9fl(3;n^v<$=(I3D3X1-;Ds@jAa&!%GlEM5RF*yIV*o7kZU!O~% z;C%U=(9ityqkx`-{r3UW%s+q8>c8(?lZ#l5@cK6LW0s z!p56-Yge-FHWY22q&IXb*44*8r+S7(RMa09(%k1zUHk{mMd-N^cFIO?7DtZj zRPf_Ln7oP)RA!V3(qDt^j$e`k1c;{n(vmtIt}=(#KMZ0SLla>FHh{U(5h2|P8$3IH z#^MKCt(dIf!BH8d#~gJ}**w^6oAfKc?D89&__WcWE%x}Z1pOOH(_fq3o$g{Y_}+hv zwW)qi(4kX<5z+5D@;mCP@oB1awpEM&+RhwO8Mm+YXqb%tt2*W79jTe`qu)=CsQGPRjwFGJaibW{M-ZUOOrL! zHKla}CX#AQ^<#hu+9>R+~)Vb-reDV`>D*iwdlmHZAH%Hmm2lECVNGW)Ux# zDZNQ&v`+l!mbSDyfa_Tt=%B7~d*S*>)Yn~S=(!!ez{?4QYS;Oat_x+(+rG++P@0OD z>WUMqJDTo_(ALZ&WQ$A@L7~CNr_tNA(!95bm;JqQ1sPtPK^F@8<7v z(nfsz%DpWrXv>qL`pNV2-*M|`C~zo{ihfeoP|0`iPyz79QY=}#cJ&Fn8j@Xpp0lEkQ9HZ7Z#PA9+0 zCeQty*uk$--Tn<3EaG%@b&^egC*}y7C%PgZNT=&x9hV_7wtQ;q&kJmhvm=Q*G2^@? z%p#X9mEV6qBQsg^eL2ro%s=-oBj14dTWZf#sD5INX?(|Df?rargg1lMg=OS_#tI)SQU`iXTYXxr+@786OS~f!nwW z34%&Zwf?yh@?TO(ak>$Tv$AYa;)9<26ve&2=!6&iEg|Pb1N@0&WIS)K0i$%_ zgH(*)f-M7Y_^2lE(>;i`sUptyj1)$$c>6Jtw`7ZW8GXwWn1QgBohW7j(f8CQOy=9c z@w@&z;l9IX=(M_8s#`vvO17%}Fu)F9=QH*v0q2K5cDAni`;Fs(FF8+&((%~h(3zY!DptAG#ketz-@ zq+!7!vD^Pk%$6%05notsnps2#+$jN(01*OEB2gF+IyIz5T_Wcr19I*}gyCH-fi?wE zTF^2_I9Tf{boa8!G0IT;#i>nS>FU@Y6W}VzXV%Ou2cysBUUm+D8Xst!p*O?im+6tcX2OFh?kdhWzVb+_;$)Y<0no`2M}fZ!F}xsWT&zLY>N*=+NL@OZubnVX%8R$SYyW5>*iXh}T#| zsDgpusXwqlZ|vpZy4pRw%}l@kr&%q(_|oNGOsU%Y81=`OqQSk zsxy%|bCrBeGnZCekvO0qgB!lRR< z4`pv2(Bzr5jXw!{1l%4h;07p=pjf~lo7x}-lR%IpXf34{QE9?d1uZUEeS;`!j2I*$ zhQ$b3K&90-w%BTmOWdYZ2cBYF((jVy4jaLKb95N@cI&9io4&5nvj&H%q(xV>>MuG3 zoWCWy3VU|b1$^d9bZxvO1<>e4Zmj~;H@^mC2h=3aYFw&JQECTNBzU;njBb^kkF=sK zq(G47#m1O+DC3{SjG>pNN(iTu)(%IzG}L~tHBx#BboDtdp+z&&6rS_@q^m%<)49s^ zLwT&p$=`F1I;obfm9`ANCcetqs9T!1X2a>@UT(cVq`ws%7RWuic|r9KQEIu&cXr;Y zin1dy%p;hM_S#VI7W1YDs#lq&v(uV-hF?Fpgf_rUDrdIb;r>B|ho$P~i>b-k^o@G0 zQ;LcgBY%vckl&#cyp&&`OyknDDTc*w}hn$uvPhu#H zC>-73OjoZ8LHe(+bU`f`>3l2KB|s`Kil+{Zf;f6ureq7L6lc_5BD z92b!B8n;%?Y^~kQ=APHf-NQe*l;`c`H1U^1W4hMgIlRBBUODN( z#!lAP=p5UBtAhuE?62+8QTdl-^l>@!A6i3x-Z;NDK6Lwgl@r~gCZ~-!d-=f9WipZ9 zr^9(8)?fHfeZ_YduXF`oS*8E*4{EiI(d+hR(T;_0`8JK1<zH&caBV3JgD37TbdhFIWFR3W2ojoyI$_DZkMg^4Atvhw~VPfv#UOoqFSM%jQOp{i^kcIjcTT)$s)1%bD%l+?>0<2~3a4p1c00_=(&kun8+-q|xZGY>PcKxd&%ItD>1d+_;|p5H%lxW-5^|NY zEnMn?S1cz~rJ324wQ^Bhz4@oLof|g7CS9&Z&D!!|k*#YLfBTkr-TDQR`x!f?$?H${hOg-;+fbD& zYtNv;i-=k_*`~9_jq)#3O`LFOe4Pn%HU)&q?W!PzY#LA+2KmBr-ks$@;=l(XIR)6O z_N-)x1+5w2J=E83fM0v(c%EdW|Nrc^QkdPtTHDn#wa)TyCA$8OzP@-`&bg-2FE=;4 zb!$o|CQY|I@-M5e?tM8ab>gXV-Z15X>$Mf?OUu9hwa`==wmvU=-gR^FiO2e*vWwA! zhF%ggKF(J##vK|L@E^J(aGYme$OYT5!PD-lS1cOCxqWJI(dM|G>Xs%el{#{2Tu(!| z<)N*r?FaEc>rBeSQy|2Xme;bhz_z>KJNcpS#JVk?LF|Qla*clF`0HRMy{v<+5l0;6 zOfA4v^yP{*)7YaoZ&;T%XWOdrT><{PlANrJoC4;JRZVlF=Wo!xCx#3qDD5h0OIOCv zCK)aPxlpil=zgWE0u>5Q-XI49cfi9SL0f=v4CJqvtp5$nB=y|qo!5vOjus#XaL0kS zp>qt6m?BK010jcz5#R&iq|B;xXM0)le}z&9fKpQ8BMBv7RmTelsb%1oky$$Z@sAQ_ z8RuAs)ak>N78zUb_Pyb%qQ!_F+k4_OYKba4L>L{^$vJhsY1n!8H8H05b@&}#m8Sa0ReJZfDHwI_y3v3!O}i#qGWJya`ecpGJQ{IRWtdPWcwp)a zo?j#V+(YnL*A9()Tkz2XSKga^y+qhu^2RKWr5&&R^Y&=YvX6h5Gp#9n@lRWwZ}=~I z@R_u=xBmK%zxw{P@)ATvFW+0wz?#bRy?4?PZ+xaAn~Ml=?mZ}=E>$J(aJ z_?JRa+X(6r$6%TjH!!}%e zUsRM^Tx{B#8Lvt_2koa0@pSFRuB(go7-H{*MXeBh9-WdsVTI6gNz04x`t()XzQaBn z-EzG`XtR$pOhR`;KIYt8Hc(IDhr8gJIV}F>%)w)=Jkp~Pe zg1g+dYZ`xSzz<>!`SR}h-BiKcz_v15TId`N_&^1K2vT;)c=8YrBXoU>{No<*23gt} zR=;U?qt>P~AE3MP>b0ija-7CBYlwVEu6nO%KKn+xl;_s$YaO{cPkdeLeL|R`QLGLs z=0;WSZho0cpWtOQ{<2o8oGe&5QYgKFi8K0%QK~E{rVz?eB~up~61=Rz!s29xK2C5~ zVTBw}`iNnbyD4dQ`iPM!IHvo&c}v2lGSK37=mO_AamYV2nJ05g(!NgaW}af3AJ7Z< zj0F~1tK0E}JQQx`HTZ;H;KZ=?EB$~7IHmpbZp!B$u?Gcynz`Ln`+0ZuXUg{cr0caG zmmL{f)wQYmvhtJhLm#G{+)?!Y(c|)|9ofD79XmB2d*g%8p@_?wn5 zi?L}gT=Jpk#Z~=5MJ09VmITwRZ;BBGGoVF>W>RszvY)|+J4UuOOfwM@dHw}qWdRUE zLLlN?F|T>Yy{yvkQ}^E6V@1^FX5RxrugvFMpU-D3f6t~k;XW(|y`q?^D~x zSY8TgI5%2hJe#*5C$&P@HtU$JblSJRJv_rd#ZzrL%CVmZRqxG=Ok<(^kjGOO$u6yK z>KelKqqcwAc{w1yt5tSV#pA0g<0cRY6xTR z^hZ0mpcVNI`39%M$(&Ema6Vg12~#A?43E4hv2|3&$hMK^9`J_yhk2du+O{*SeBv7J zwJTWF?ll-ZlbV`iK2YN33KuNR1Iy>OH!Gb`~uz)ga!j6(?;2H>Rc%1ULuLL zaIh$Gc2G6X+sxX*)weraq%4RvqJW0%&|hRf4|2S&<*7kNQ#tS4_TZ^q@E!Cq_2o5F z%QN4Onh;&;+k03Se>aNX>PLTdxVUZVJB_11ey6Fl_wm?IVvdB0I1k^useU!_Ox(g; zzX#$Q1+Ol3FN-KqUtT@lwyh;%YCF5(c={%;q^5(nsU8-G3D7nQfGH3erI4&3<=zFH9FDkJl9ELzqSwzweWwH@yj`r zlWxWr5RtwzuOilPeU=YQRtzia)ZvhP`NVjX7IT5)O|98cv=l=qvUQcM7`vCxr+N&7 zwpDdeHI=- z4K>i`#Wt=HqFINS=Otu%M$T@s*jh}FQrg&Uh$+x}N1B+z{Y*p`$s2)N3eW3TX-7(% zgGMYZNIMVE8Di1IFVrK=$wto~#!uLL)X59bnR9S6;UFA!TQ*lpVhj?nB%`L=fiY)f z>05~6AjSvTSGp2`0%oVGR-&qdPS;ExJP#Kx9&Pek9E~ryu#P?YeWwGVlcSV{cwTf`Pr0RvNw|_r>G&nSYKIF4nw}S@UK3O+V9` z1E>|jh-`-WyS3Ph-}}LjT?~0tUnqUEu73aRtb)tcM|UbiALZwFZM?NuJnPfdcba2% zO>K|tnd|4e!RIJ_=EU99^O?+3U*7&!@!PJ=(PQ`2c}3KWfbphC+DX6sA-B7>xDb=76-?uY0I?#kMzKyB+kHqt*h1Hy{xG4HEw{Mki z)q}RAfL}h_6`Hnd_`iQB+7h0odOz`V(Wml*Y2R;Xy7c$gqyei6n?nzOv1REMOUuP; zjV{w)eKh{%`>FfOPA(AZJ2C>8l}ZIV{xF{sJsx1k6K3RO-boa4so*hv+Lg!=*mq$$ z*xaMs3y^caTw$D25uzNcOYH?0e0Z56%cU(aq*|wlo|JUxJKZ4v#goF8Cb*IaO>`5M zN&1i<;K`bwAX{%)1Tg`09VkasDZr(o0>)=t5H@m>hVr&?AEr+%+1Esu*os*~v+K?4 zReYKexPq6%fiyaES;QUZ&Qr#@w3K<}-9GN8o27aB8@;<%(e57}UB@Y?+pzz8(B4*?|nmK4Y&>5nTR6w z!IYE!2Rq|M+M{9*!GBN}lMWS4wt*3FAyWFb@ygovmx3C6BHqlbkTaD>=dlXKt=t>0 z9%mkXlis&{@?1)GPG5W6g|U1{ZPSSY(c-fbVQ+F#yHo3!u7y)o#hSv*+@CR*ih23F zLVB63HQK!@#!GVOVvsU4`>PAOw{-XNlk+Pv)CiN>Tc+Kn~&Y`?%* z^D@u4#*^m(P`F(OXYr7$%^{&o}%O&JO z66_@09)^={Pd@I7v_~6grPw|ZnK?h^o$Tu=R=vcmR*_K4;MA2{d+1Jc^r*LV>sRnj z`8Cl_j~kDgnf!p@p(QqrDgM!nx?XeE7>noDe9qM|+V|WflBQnGuo6{P=c*#xh(5iW zzi8=?vD^n=0q3sZcGh(fF|2BltDK=Ijl4hmZX%bFb-JjN3TiG8hYhB!Imdkhvt$L* zNaC;Q=N}fk`zOm<>mWBjTU&oJmi?%P+ ztFYyQDS@GDPouWSU|_0t?lTh+&|tchY(LPpNdjQemU6pt4W^+y&;1`J&+9#?6G>m? zZajFwIX~~?<>IVeQ#QCUoBA3z#D^tp)8#vFZ8 zGri@8a{xf*_gw{jnZeDi;HF0^Ku5=BF5^T+3S10r&S-O?ZYU-TVI*x5-7;?0!VjUh zZOb(t8m&`swFS~Er;YWMnp3dHA#8>ioG#KKdKWc?A)jZ)B8z~oN)OrmBJv7zGF64a zPNRI)8P#WvNhzr_zy8N%gZJjfwmC+((d?mr`+1heS0O|I+9-P21l z8@^b`+cq|`!RhG!-*z-lMZmuM_G5^+f1wiJJVFWUilkj@yS2l4gRS)5%%!)!lrv8M zW?Rp#E{)Gs*PT?3{+F%ruJDmmdA)@&0*98Fsx=9i=WF_2ma;>Hy!p*)+m4gU;amVE zRD&yq7rPy&Lcbx1C$oa9m)MX{K~$RrzEIvELZD<8BUzGmwF@F3MfNpW1xj2__$rbB zaoAQ!XaHVA>vs-8TI`(~=yu}BomT;Lv2#FB%d$@aAArYWi^tMu;Q_8PwC(Tp*iynGix;hz5KVL5Jj z2pK+wq<*PWbHeg5eeOKV+mDSm`na7fm~H={es^*AzKLBPLX5!qetzH4H#4_<5)Ex5if;cP&A@HGG8E4$mKSrcwA&~47=R{iGzB}Qq|qw(~?WB$2MWNI|{ zSQruIua`(Z*zrx{xjs|r1m3XH#rJ1>AHO#?LgvwDN*Ez3tFOPE7tmY#C;+)GATM-^$xW^Ty0=h+5muxLwv;H*Wr8 zk6rSpJ4QxM;ZOfi%eEEU_P=CW#`U(AR%PU7J!yoR^XRQHkE|mv=9OVm$-H)sC09B6 zvgS8wF4E=(;>(bGkkFCA;k&_XsF1cgd3IPs*tGk6PCoXS)A;oGjD5*rto1iB-tnq` zZ3N}>hOliOQ#mG|KVw#O=rqoi^f-gFQ``Zk>kZDs&*mMX?()tx-EW()acpMZ4QP4$ z8Q(Z{Wa@OzOyw#=ByW6?ZOMdLRo5U?-A8Q~3~u&Jyeokqh75C?+PEJsY@S?kSsD7J zB8nf8p+}@M$lu9-1;wHCZm#CsDn6y-O|OX*(*?X?L!c1e@iToxA!mLX=;Jg0M%U7k zI6ccEQ|XojkYE6zGl`{1_75P)UJUJzq5JWG0ce-ty+#tAIO6X957uy?2JDTCLm@73 zz{|vHBarMI&wf&`$_ak+wv4rPR#8=Yq`V)8umescPXAvX_LiAH1KI=N_A7sMs#I*p zpyGZ*Zub>3e*=^WGqx_=9ot(I-`)_U0{`c2x3-G(pVmuSbRtn43MG6$7!TD96mduFtmrP`xx8$v zeq67yqHfKjNp9{EsIQTQz3zL|P+w_aR;tnqc&F<(tY`~nj;P=QbgD>(-Bx<)L|G^U z!Wa-3)Cl|9k!G+D)syx(6s@S>V2r-N6)i?iL);OVqbW$4sT;Rs$4*IlDwX5CkN?Yf zp>CHKJ!n#hU6_dr-(SdotmWz z6MxocD^-rWC3@pQw=!gWot&|M^n>f$Pxt9PTF3vS z5R5tUX2G<(tAF4P(=;593EHFKBw^zMrLp}|Vyjqngo<6uit95ivyR+qaIX0^N0mFf z*>Adq`jxZCcuw!qvvc=y+X#rQauhKf!}x^+Q22Bcy8sH5I*G96NkfQoeC#;-OYNRK zZ#jUG^WS5}ic_QEOGTG*NhtSTBrdhO9RjB<4YcJ`3~5s+fW?FdkAl}Ll8BP!Xx=bF zN{Ipev5L(I~UX?yfe<^S3$pkWo^tyh9WR3E%@#@BO=V}c` z6S?hcZ23+B5v4`H#NOx>Rvd2p&w`X=Dym@B53{P)aq4p8RjUiRt#91x+Q`xGzZq0N zZZwAICDpO7_Ut*P%73?vjOzTJ^R>2Xk!nGZa(oylY(pjATgNQWFRFg>xM6u;nF~>Gp1JITz6@R)fEosi$0T|#}hDZ zs5j13GzZe3V@#72;z@2`E%QSZT~v1@G|XJ-wMb1oFdiH-Hf-=eMpR%E;5OjO2LlRn z2RudeWl24)E!=6Cc4&$!P3!(Y^mm>Gsm3;^G2ULn7VL~z%=~d~wT)5iYg%Cq@LAns z{HJwheCJlZ>xWCD!@9C`^NZ4>F5LKupAc3wCtEO0oQ9TcC()O!&`h~64nHg6#T0~w zXlir|BQMfUP)wUDOB~<%A*s7GC1tDzxsP|=w^tWy`rhd5PpwpZ)d&q_<=AqS`ol4i zQlE<=HFGeR5!MG~A!Sbmww59avXgq}anU1_c^8eToNIDsxo>^*E?K%|^(ZMbOq7L? zf(@k3*=P^v5L*zdOz@Ne<4T?#{$Suu*lRnw=TNdML|%vp89@gvBVKWc#Ue?a(IHG5 zqdhG+9=5<%kBVXh@d!^J1JLro7ykKK)L&I{fYf%)-)E@xA6=!0c7Xmm3QGN9e=sJB z%v`hY%hlE?%|Wk^m)(`BHpMmlLuW}E!!}ssn}%6wL|aEq0`$W5s?alnbQFVhQkgqz zLE3O7Vs-&0T_MK0u`~;PeBxH3CPcQd;&!PdKt5jjel zQ-5`x{A$-c4@IQ-y8NGQRBSPi{%1s=@t^m|kE{w0nF}^>kMex-ZM}1EWySKkzIDjO z_84LLyt^9GftoXy)o1GVcrYFbJkrK#^aKSn)akACLH65Gx_y8IC3=$#}>*bzz} z1;A7>Yr5s4ZbudBCXs#qI97WN`%&sj{7NRo2i#CC|Xt7U)Q0Lz0ex)l1gEX8FWAG%4Zg8k*vkXkEv$Z zlw*%3-cP%Jaq^Zv>fS9kBtU)ae1q<-Do)I=Eas_m)0$T5 za)0k@_#y~Ii4M_}vLkL)*Dcr1C=b7t{~$GrRia}L8ooxmruH5y(=A7O$uF)K5KtV* zX~=qf3BREdd{)NZ%*<5j4HS-3kpH-1pR>@T>x6*Bm3^W?7l(Lgm2Yo0=ulW}*Sfs6YL&W}<@^aQE=| z>HhC!&DwJ6t&k5deKhLQSHX$}gIa%`yKF^<#ArI)TRaz}5AAWpPy`hvi8l{+n26E& z>0Jz8a$;o5#VHF9J?Prg791{a6=fn?Q=>()r|q|UiBXDKHchRfPwZ$f>I}g1l z>0ZZnzrIT!@T={Yc5iS&1>rj|18zyD*IH*wy%yTVTnRJM)WK4R#?IQ^w{ zXLhfZWQSTOb#D|DsKjTKp;tKhVS^(-mF`*5tr?!3&TE`{D*2Ia;)sy?hGDXgQ7{Xs zZo_ETH5RHTQ|ZM`wXA8Nfx5rkCfPc-=8bi7##ht6JrO;&D#7;42IW{wyOZqQ_F43r zx<2aP@0VGsGc|&B@`?Dfm8;rDuDiRb@j8O;Cpu>5DkdjpZM*ZQiYaS5V@i@|W#Mf` z%E#9m+D0C}t_*H9v^M^18(y~pYA%hB4c5sk<2#PyYko_xJ$P(dQ*yZk)6a$qJ5?}= z0Kb%@+d?=o&4I8Ou_{HVan@(sf6===5_yci7v8tb&lI)fv~*eYh+mi9m4oilkf*& z1qhuk=MDX~g4|~ZjRTZqJCtv+gR#gIed~7?Z$sf0IbdW;ijGJ#^nr{=YO8_l`rTan zVmMu22{c|?WtKh$2#2+dxd#kIIY;&PFpbV6cMIdVG~`@#+SZ~4nDzZ!@|3OF+hpBFBIx1jkHA4TP*Ns z1bbQMni^;Npts6PfLy7iwIQTt7Tr2c&iLj~T+@)w2)5g34kO#sHiSQZxp!ah+wGBz z2Wg`^`C*5?1VkC*XReV=hS;ppms@xjmwi&&WYwCijJO}t+@`U8e}&?+ySr;cJ zITSYm)X8T6Fxfvuc6KV7eVL*2lk-G5y?c3fDBEtY2ca#hwiq@`Xdtd^U2O@$+{@G&0Pk zhNw)A@>g50#@ia>y1S5qXBHuZ^jr$Maf-mzUsQnRk8-h9DBwGdYc!nCV%4Z}Igt&_ zG~Zs$TSs2|L_MJ*eb&#VMRVW&%4@3sWLav}iOdbU>`4TArf5Xfj&sxK6urj7SET5W zYXU_*TLSgov(4dg8M@k>P`w#KgbeP#cfI}k$NQQ#HQviR%3r=EOO-Fvwf~gRQxo{J zIcKTlr;8>|&v3QwSfEcpdaN}8R@7r$nf4pT{mT~Sog)d0NBCS|Uj4ag=D6co9%*0k z-plxDbMu(YOFJ$5>y-iB@i{frw=VNq0gW6T(LJT^(#wb`r$7W_og3}0ZZZM5*SiZE zs|w}{8n@7%jdS-+C=0vksoS(EaF=`IxdW-@<1=4%)toEfzv5a!mqw{pPGegGw}UxF zYIi~&<6@pD)61SxDn-wES(0Os8k(=&91lQPs%L+p8L-8egstK@79cU<OP z=Zc>|svhD6>C+{^vthAX>UZDgc^T~*v~qJ!C8C5$96)F%46SBK3D5JaF(eF$YZdgM z^|=_>7MX@mT?OR?js2eWwW=A!9%7~kK@J&0@;|%r8!nLZTTD~m!zWhYazkqxVjFG2 z=*AwaTdC0ALk_S{c~_$2Fs4K9^?X}^IXx0Xv0Wnk^O1<}FV-m*bZ_wH>~rtc48EE- z-LzMybr~0{Uzk)NSYvp5rT!hgi>`vOquS2zAsrBZifhkCE=Ea{q%W?WFoFg6x9xd=|~EI|d^K7)_$^qO8J_mlQS zd^i2yja%RbkB-55!a7D2^Ic8wjrdt zLUi*`Pl33N&bSI8G3lmhjSLR2??B|&AFk|qZ`RulKlr~V$@+5Mp2Kr(U1NmN>vANW zM`nNQBOLbCoPhM{OU0=}RyOf^cGKs_eLcICewbp79D1{i-JQ_YLZ2i}lza+8N|ZUL zI8C3l@@FH8?Y?;HTfJ*Ln~P>yPTT{ue7J-YJXKbJ!URL@GUKE<2(__*poV};8#spa zsH0h3skPSEC+O559B*E}C#~;fSjXslL6(CFnjDQv+ssw*X7OW@{YPqZDz#EZ750P3 zH5dV+QY0$G=0ZX9DPPf1qmtOeMo+tUGGbjg+!S$Ks8>BTP{bw$u%3A^5|P^78Akj? z*bvYl+)yR4@L?DXe2D@t8n}{F7bCFs%@}J-maiR(K=Nb%B*BjCSq=Fqs7Yf}KC7PE zH}3$2vY#%IV?QRKVU(ptq66c=<}f)<{d)pPQojRr7}Mwcy`?+TK7EBjOew-BQXsMK z0#~%=5&IPn`kOs~hV5oV@&TX^+s#F~%C`E^i%=Ottc6lh1AR<-E8QtF<)cbRI+WPqHcll(O_f5=#SL0)DjyB8;9z6 zoI!v|QKj!u=QMb(lb-9@Y4n+!Uv{nL=@%D^PSIWF z#J(Q5&4VkTJtP8reK8Q9sC!K8i;1_Q*?g`S*VG@3zT}wELIk zQ*>pfmEqm>j<8jNYyRIJ(0sumIykQ+MlztzMCgZ%XXYz&S8`aOl+oVq+-G?XCDf9e z<{)fY?6I!>V*}pyFV6$s32T2K>cc3IznCvfAd!~_Bi6eHQmY46as5p6>C@-OkLD=! zoy8_(ruD_%AhvdHitw}*nq_k6r?fWcK!AZ8uJWi5h+X$oq$V{@7A65ITd9rpnb=tK z2X$HXt}5e^M0cUL=awy3#mUN%b^!PvqJ1pQ6ZA|hc(q4aQt2b~_@E{~@=4p9WiIo@ zuMI736HxmFrDy81WhYgIulURuSqzRNpXrIs)&=e;iSWU*$5D4j^3lVAoq*gZjm*?y zW#L4WPAU=h24?%gs#b_WM3ONkr?h~o#@y)@!Z!A5JOgB`UQJ+9?Z1zd;4hx#b@l*mROXWwXlEyXAzsoqDNdmONzzE$F!5Y*TZ?Y$@ z*u{8;SxVst3{xSTcFd3={>IKo!bm~wKyX2xwYZ`$uBUK(j;(h_D@6eaZo#xfu;95x zU^gRA!xMaiABm69sR6<~ncaF6FbGH$%np)I!Emj{=uW~K!SUD$Qw%UkG7W_5k<^$ zRi`_@u85Q^q3QD|h;MT{GLkPEwtHDDI>EcARM-q(tFqAV6T|w zgF?X#+he`EH6Hy%RJ!6u*J|TkfyZ)oTQUbHo>4ygnr>r+dBURhs4Pa?%r(&ymQR+n zI|&RIn`1jsh}7OnPvac!+so}+KRBD{j$9=Br_Seo>D(`n7At2A8>hjrU&7F3QMo z@8_caDKr~c1^KWPR6K}J{n42y8>=vYMc$4iHS>L}u);I3jV@^xcho_o?Jw3=kQ~}) zAc>ws=blFS_z6H;#DzV>5})yA39-N9&-RUxNJ}!uO<^PcZW?wPWRv~lGt)U1y)I|` z8MXm5nAR+t$|b%SQwYi|t)etiVYZZ3R+sRUx}^$naKw0(=T^O{ z(w2w~E-N$D&6z=aimxlfZuqO;i=R{9V)FS}zj%pB$DcROw#Op%W6-v+9B;)&soxk5 z8F92gMLOT7)Y@Ys+$MVjZMSG_Ye0X@^8C940d{|TV9rw;M-DNZmQq$elVq_s`i zsT}VtDNi-%Js7lJRaUH{w9(^Yj8Q5ozO#vKa#rQ>&g?U*cqzv&HMTD9Z7OWK5jsBI z<;N`vQf<=Lw6X?+Fg{X=eTA0u8zy-38V$wNg~v@h>(=;$`;5qaKv&aU@3p)w``hpZ z)oyv>swTN1D%|qvx;*TwYDEE{R@VpmfFEYpD}xsGH9nc6o55zj*PXhsdEVConTjfj zYhc#NE>~OHBU_ALr-;0mBLUv_b;EFGXmga~4AxlWpn6x;x{+cwO`R%F^LrpVrIPCx z6>pzjPe0^&pUIojV`!{yrqYy@x1zZ%dbY2T%b2>Rb#z$w!^@3l)*RSYAy~9&|A>XU z3fG1(VOzkcnli;N)`F1dyF}651@u+_Y+xl&N>|S3oT9&w zg2`cxDaIX@=2mJt8JrfgMCCl=ipl@*2lelu!9G*r6A~%pofCBmnzkpeuxZY@_clzJ zo3d8sHNo>e9;re2Jdl)&P6b(mr*;+y7Op`y$0KQ@C*m}6%SbRrE|>$JLN@udu55o{ z_i^O5LMQ>5q9dT=(<~}8oz1Lq2^g^(^K@*!RfZr^r5`#}LLZoiCNG}|esJcv=s_&%{h|l;9E& z6byAtf@>2w8dhrJb;b;b;Oy+=Pw{t!-kq|Qw^FkoHW-wQK{9EX4 zg?fe!l?Ha7)c7Y|t`$U_3M!tH_J(`oCl$$gdBrPas*XKD$Nv8NocZs^Ubr-IZd7Kq z^;>c*!bHa*lCZ#_&*>2AM9$%M97~I_73%g#_qG^#;G>YN80N(-(Nza@uAZ9ioTFOb z&S_0|&dB&Q@xFKhfHgq)3#=m(>oxvJ2>Fu~m@Ckhd=fM{)`8-*ahG=`yToglg$ESv zb0kWI@LZ2_;_lInb1zQcHE(#$lcvqhPNSfImYp%GLh|9yV?_%vUW-cb-k>|6D_@wi z`iHqQv)(>2gD|+DBek3#&a6$H zky95z1}L-^hI9S1NEs9@B3`(25v-*NosC?oTa=lUnxu#nDI!yyXq4tQ=hlTqUfx>* zJwp#Nht}O|3fS=UH^fNfo55@m&VVtK+8ABmNIHx4ZoSn4Avt@m0Is$)u<;F_Grk2f znPA^`x-xj~jX6h{+YekfFzc;X(>Xk&5vZ1R5+Koy=InNta4KMog&2n9unTAYpD4Hv)%ac*E(Wx~GaZEF!_!;#EYjD800BN@DoWT$k z)!^&nm#Nh$^sL_$oAOThfhK>!z*-u1B7HD@GVE;$gWeU$tQIVc#EWwPQav&^cO`E1Ui?Qbbwf4LLcgLJ;5y&I~>^noXrX z=bBI$8=|F8?pjE1Ob=@EHC@_Szi&ZFs{6MNXJv;yU7yb%|MHpu;WkHKNANQsoLug| zJ_hW=^9kY$)~Y{gbi4;MUQyHa@AdH(3B-?kuGg~ zgt+^+rpaOglA(D)>Yp7rwYSDAN}CR5-K~rqwT<~k*QeUPM!DYOBh?H``xR8EA~!AP zY!ZvDbZJrvqz^Fbf#14~&SycDsfcek(pt!Z+<1!7^#oOgBQ3Py19m%N_6H5p67hJFjibn2awIX}&o z&0cP}mGO?!Zl#|OMgIJnBOfpj}Xf5*lC+}7guN7r8hqjZ;WA9L`mr6bs5Pup-u?o)+0Xrp&uXNzq4+V+5em4={-f`-CKuk&UyIMF#sZD-82 z=v9SWo8Qn;odr^z!s-+hRK*u53{vK>&nzd8ypp-J+m$!BA?V=HRBPa_C%V*(+lo!= zIG&s7swQ_+xnQ9jr{iTXV@&)&;OZ+~;m8lQ%E zJ#ERU1PPl&P4+Gt@>$$-QiR9kO)IytsX+W7mG!-HMf#*BAU9DO@=6(_f%FhZg`-Bl1$0d&m-dY}&1cm=6U zl1+p|bv#NdHDLChtWI;hPfF;6(jEZ!PQL)wYKmY%MM{fJDrI~{Dwv}@z*|{Nx9(PD zZstDdqWlk4S?9K~7j`SdHD1YiL+%_k`*{G|-t1J8HjD~8oLwZF%p0LwSXScmMs+Cn zOEg72COhNLmVx{mhErd?y$#PR2bQ{) zKn|!Xis^ZUp&;50Pi#QhN8#5%n|3N+qL9tg%NqeA)2`)w&qka{(|M zS*pP~W3vy(&$P?xG_FTe3`Ek#9LD)HPbQH2d1T4l&t}$idIf4C=r1yEi@D7K6UxO0 zTnfbFoVf5>*LNC%bbP0gs62-N>m~^k(KzrOK)qiqQ!!DeQx2=E*RV9KB$~A{mZV7l zr7*ZLGm=C;*or8fQcHZzSjqtJ$Vx*=oInlGL3%CGhmq9XTrMnA6bm-Q+vc3fQqNhL znd4_~QMa249DvKf3z9lLLmBPSx1+|4)=Wgp_V|Ik3)}nLqxktXchVkTv!8B%<_rJs zPwfF*zVM;vzu?(xgfRqT52l|beUt^Ix@^1W2oCqP2k^K&m2eE4S*T8wdCP|$aJx3@ z(ta~_Gdh26s)gQmM$vV3g|2ZLKUjZcbn6#$f@j5@o)vBRDDw3^7K`>s`5|H~pIJ=; zNe%=~GI6{PkUvZamONr7Y+dwo7Q*$Va1do>sO^l*|CTY>uhgHSt^fX>!$h)^*3z3_Z0LBeqbpFgOUzPd$Pf*yLZ{>(2!6@crh zQ-h5qIAgQwwG=9TNX3@Wze|U}oa0DbG5!ddk>5w^oH~Ue-8r{fI#j4~oyiYz z5%8mw!wq^QS~ z=F|!W1m;3wfN%2%K)nRi&gZ2@~VU zS%Tp|Pm=PR-N*pxdv1X}#~8LdL0q-OfuN+{q}T^3^=~Y@HrNZx)1F*&=%{~?3F0Pd&GhC+}xEed?ql2sV$2c#uzJ0w^nD=VED$L6+jYW=wVI3c#)+>Q;(L#i?0>9#HL4BCjoC%iY+%H;UVno$Y3z|tkZRt zU-=%w7?#E&kmI^Yp7IctRv;dO1na&9X4<(a5KY>@+lD8ztyCy?1>$xW zdNbFuv7L!}{mv@ykm@u;5GpWPfDbU%l=uJe58smb(4*~4TuGaQ^+0m_=L$%>Yyg46&TqY6Yr{IMFa zYXLZwfkD;Z|300;JUPS zHgGzsqvNKby|wk=-LpPJrCx80$t9MR!$N1&8B{EDcH?lM;GliTS2BAKo-UcH+Txw}yJ)>OVrFA? zvP+5pD#&vu9x^`QhXED*ev+K)e^fQa>6vqJUA3K?t z*dr!ufw`0IOU4yBtOdKif^ibF|9&l%B4W~<#>R8VT)Y@UJs(c}_t(f6LB1nFEQ&?M zEFdbfkVG$nWj9YSo_JRhq$*czFrtN}NOl){=;X62gLMKGKzrKoXNdZ_@DGvpb4S)6 zShV36fk%=Y;J*-KaC2MQq{Asr*LB4u1PrRU2JVrW+l@dM*^FZyDOMO~%%|lLiIRM5t8q!dURZ)UGs0jU=Zc=?%7pY0I&}eN+QT`iR3=1)zh|%Rz0ILM ze`8i~JPqcYog@JdM)(X$3nL$k{-}XbLVVnmn#p`WE2*kLT_1%C$Nor%nW0vQ13K>- zkW3Z;O{D!f$8=z3NCb${5{*!-2Dt>EqfukZlIEbP92FWGL8Ltf>jCKD0@K8>!hO2h zw;kcm`zuU)RSN7ng&DDx=MJP5(j$H{-cVf}c|*CtbYsksV2JO3q?=^~Mv)#hQ6^|| zuh*PAoEl_C{y_0So2hAzp-X4*L&Bu68E0~K)(Ta;DV3ENUT9|Ms9vMQ8p37p?!wU@ z8He>RBS!E})UQn|#hUHL;n) zeW&er-7z}sHdnQZx%EcJ-0q0HkZtt$L9EEMalj;Dj-E9gI&6alKZ2cYCp&F`iv$nn znd`PAUgS77kOhmjPlsV4hif2s!ZVVD{rF$-Ujyd^jKRLf5$9Ig$;ys%8u(qTL2v>T zScDtvYXMSOEEXAMW-UXcT*$7ki_fXrNY1fmoBNWf;nbpsa~ss?7TU7)D(jeXp=x=M zs#<>V)&&7>ZA<-!?4_VTSe<-N9e?ZUd*18*Cj4Yh!lvNKcjtZ-`2Ab(IRn1f88*Se zKP2fY&dr(IU0_0fY#(?=c3P%LB2?Dz#dJ_&Aq<9R>DT|3K9CFa+&*=ffc`5tLWLcG z-zAR-@>hiXglnpm&2SWGeZrQnY21_w(eDLB0d2q-_Xk|i6BwWXKW_>gKL-~HC-}_R zJATE%xq>}H!Uo&@U$`Yu#0=9^-M}q!p4)i7xB(O2t&$*kS-=eGE=cGT#oVI}K~)}Y zY*I+G`EypA0=2Ra65x7)WrirWc)LV^{RHSOO|cq(=+%pWEQcycme(uCcui6qv#Ago z=$4>Kx<-0SwTaaB-fx^L3GKI$UxC8~tjFw>3K752y3`KTvlOMZ0y!i7#wDG( z#{Yx&+zn?ocZw$|ycM2H(ECDrM#)iMX=kL-RSiL!!FL7X7;cS@D)gnbEf@q-g2k*w z`9nFP7|2Y#Y8hdQSp#Xzug4W{qv%Cga>~-3dr{h8zyNwcivdtob~q$qyr@`-6;xjL zmBa%=6`!CRGC6dD2o``wE-SQTTpC;}VvX0p$^5{~6}3ZL&}B*i2WxO5qa-3L2g>t2#NJ8=HYI9wPJ;Z%$Yar^?{` zPL82h6LK%f*(bu_?j~9v_L_VNDnco$BztR*6RaK1kW_MPfMNQnFfH~n7^#swhXIh( zrvqBe)Kv_FCtH?uD-)|hQV=j!@jcxNdm-h6l61@bU2m(FxrqSnM#E(ZT+7ST<8RHW$w-aV zwO|yy+F$hU-qi>l`g0lkW+X)dXs_9KG8JgD0o_8lgE4$0qyiim;$)5Aqg%;O;t)8n zw13YJ?EU}pY%dNWwIJJ;oU|PUg4HFK7hlRkbnzl^kR43^Z+I}ShP+<2XopXf_ha`b z2L|zm{U64@1+1wv-Fhd1fDycIEFdbNU}6hHV5@*=gEmM4;gVpd!_W?*(rjk1Pzov? zogm(tB63L;0%8iefYnZIqs6J6!AtORnii61En1JFLyMQTPIac2>GWUU4%nWVbDrma zo>B>rWM}XFt#7^WyWaHz5B{S>MXrZ8N%U{ng}e!Op;nJ^LBa>g*H}>;hlM&i?>_|| zJf-wnlinPiUY*3Y9(+v1TPxj$&gJ)2w`^%6u}qr8XLilT4H}tatF|S)6fU?w)}BT$Sa#$*;IQ zFaZvPJdEL(o@I`+!uk>ETN!CvPTt3S;NA{%mc7lGq32fELRVV_iiOFms#}9|`rd}u z1dqABbz7ntGaiLuxN^XrM4oEIAV~LnX;dC7RYe2rQ77^fO`zLd6{JJH7(tK&EePsVf)upK71u{cTAPV99{fUoLcev_k+cQM_2OVWCKd$&W~kC&oGMQy=CnAMw5~LUGq?j4 z=W-FgH0k2W;Akm0fwwkB3LKBv2ig=k#{zEFT*Z-)N=2S`ZT1Iam7$1T%G zp%wWC;RZg;5T{u9Dfvc#j5J=lr=ZY`=Ru+GN8c`*9!zU`O*NNVKuL#NT{=-NB*iry zzWgxXSl{%nOXi%wRl04M%G>ej?HpV0uw@mz9r#s|Z?2qkI9Z$;QqtR#E1?_oHPxD( z`Bj05qH{-j(Gj(e3lCAP8i-FJ9=ne4nfl$|ajm7QAJV6@zA%q+<1k#YBHH@(u@Xm22HvanK z|KfePm-tUH2M@yTp!CdqiKmF9IzC0B029-BXp9w4v9^(o8cHe+t1I5RvZO%7@>^<| z_x32)W7{&%W$c&UGz}V9Nf~$NHX%kNgE~_ z^GjhV(}E6kdk&`N6?cW$iW|<3)VWzGB`|>ouHKyZU28To)Q*;omU*7FBP|m;O3uiN z-tgT2E~o$1aMwtqd`XZ1GY~GrHm)==lojeYCk&Sh2@aStQn_}Hrdt=@JIGB1Cq;TX}QV)cNA(J<90#-UN@Lgn;{bgGWz`I5Ov5? zzISIc0i{vN4Ff)Fk7$wF~7*zl?4U4bljVTO{9f1+^_)QLa!Ip*3@*emU}~ zMGfc9S%)noaFW-l^Lo+U*+YJ;BklXc81F+H?y4(DQj|cVBZ@Tm)B}kh6>_nyjpxz4 zsD%}e^15ysA{pe@@Rx*qK_=5;D}p?oM5TeK@8CM%00Dzyetbgi+X4;fTH(`Dz0P*@ zH;l_PSRR6dEpyyaNhjI+-pJ6mb~)m@$W*nWj?@QMH_xuV?iwc0i3$(h3pYvcGW9Zo z|9ijB$n>$093IEfNZ|(g;_yxq_myYJx&Gx9+<|*>kQ62f|Fm!2pP8D4!5c$MF>Fd% zP_D>}*mO_f+BcdO$fxJzPm=UT8u%NnJheFFVb}VVk!F8;->Ur9yd1st(Ao6`-{(Ze z)NQ%)I7u4QT4F#w4OTiUO!B{-gx>=bh#WTc_WV;Jes7(GMM8l7ynLisiAYj2Sx4( z0f@hHMV57;0KFwUI#_E%pk)*!eLZviU-k>)kVRi=vaTjytd5sI?)zV<$8E(2ci46^ zhnDOWY_P2j{o@JE>CmTVo!55%L-S6Df%;CF343yHSx@!Qz$^zRI6jKZl= z+x-s}2#{7ORZZ9fQ;Xcx!;Q^o<~2&LYUbrj({2pyW6mtL#Ik06vYSeQI4YEq*zG%j zV1~lMIt|aP*1TecVrb9d5G$o17WiJhMpT4lKK+5wC%NVTR53MC^j4z&B822LZ9`lH zoJE$lN)k{kIfa#xn`MRmgSQgF9YeKR+ug_=BxEMqjbJ3(e+Fhf+@m6cor)bVr@XL%F6wsVep+MlHYw1Q_S80CSUVb27KwZ%Yznfg??3s}yVfd}kAE!j(#D zGwS7cbNF9p&3D=vwoE$)kF?QiycqWy@z(E6*UJ%BbPpPxK6Z*ZZS(qo*0p({~r2k z9vGBht|OX5uSiF5k5m<@3qjl8{Zz8~8~zDUo2f@7T_7fzq%o!>O_P+bWQZ3O8q~?I z%w>2GfUg^fD_vwOkH0kPn~{2udg$VOiyP36eGegCR$TBgE0KJO*DnY-uZN zK>6_FAXqN^vASIk2lL`5m9H3Te|gUO+C#cPM6WuwtCHU(os+*|s!$@;(2-rs41GX> zWK4Y4qU45Xr4}!bdIIX7kC4|}b>_0Xh!JqohLKf61Z^PoW4pbtH0Bp{ZXu|ndiV7tfV!x!oP?K7HRwQ15;A#RYGbYHZ*J|E>)2qMe-+c!APk&jG-4M}@=1CW4GJm^!8u>PW-V^q9;A zQDF~zNG3!~UX1$!T#;~-#GUXSArSd3&y&Xp^UL4$=1F8#00A3&R%z!=OxUnP&sZd=2 zisM$E>IunZ%wm^O3=|YT!ChL5lQB|p5;M{?{>UY7ev$z2_!`V z$hm-rD43mu?a!L zkpb{-GHsg=X5z1FwGX<7f>QKH(a6nzWv6~k+JEKG+$`Ci;CO86{@RS%U!FLjnf=7q zS=Tiq%?qVzevO$|?qmuPqzz?OL#)8{6RjxIp0v48^vBZP3=f2IxdaR+7ch;4y#Z0218$*6e+0aZG>E*7;*c2y;0|3;}5cK9t!e@dr0J!zYomwl?^>cvjEW2Pdc zr)pZFP408342ew7bJA;X%1i(9rRZH+B=mnn#_J1eYgNuGKQ*N=4^GCGLs!I^uA9sW ztPYuPENKty^?Ry?&-gK4UCfix@AW(roBwIn)dg==S6#1GBf#x^ zJ@7LA=xILOU2EX`N~*}Zv5F(Kj2yEzk7FFEIAZA`?+tlC_j32g#&t{KsNv~s`SWYx z;1*tp<1(6DHJa?a2##~m06>`ePY4LuBhGf5R8^Xx&jF|Ewea`L5yMNfQLo0l(a%l( z_Yu|r71j}TNDHxfY~iFfz(-EV^Hcc%7n)?%23l^5&4+W_9y`1w7$@oCwB)+)bJI|b zL-_*+m7Fz(QIolRq`|c|w^0@dm-H_JqkZG1HMqM?D=1s8!Ws7%ZNF+nLW=}RVLaKy zRAw+saH+;$;<3ZGon=j$&v^-1@VrDAw?AE)WtPg9wHotf$!H|kQ!7*!#(=>?q2=h@LxqIa+0MjDN^)+@+;MW!hkS4(l8K7|nCWLZkN! z`Xy_#p2twOXw=)S$F#h@no9>7N~Wqwwk(0nnsqSnD5iupslrwxj9QMD4;sgg{0 zxs!TI6WRLLj*EqQ-?+$Ca}O&MEz!n`bYI5hD>e}f0hWOB)W{Rn!Lblid9_&z^-SfN+h zsSk4XTgaz|)4)G*IRK<&%jZWXD300iIYi$JE7I2p50zT3=nHcs;Gt&5UOTZPC zL&*!v$*XnD;Kx3&-?JT_nZ@cpvP1_e>~39B=c&0T>0bKlMwd>$gt}($ePAnB`h_sm zfVfAvL_OTHtLHNP&w%2Vv$G#iZ7cKn9SkkvL+W()+@D`ad@wd=UJ`<24!WNy@iQDV*8`*UMGH_P~q{ zl89=}S!SrLC-{c3%!KlU$m5WL@D??|k7Y=`8K@mb7Gt0LjU>GV$8%xB6s7QV z$7{}G@#S}(ed0vVn{5Bbkw)R7CcR|WIMMR{OX^qoD^R@A`*LK?*9^p)tgJa$JeqTq zN@MNTCL&VJG@WA$$<(s@sAe==w-zXy_tKx&nLL1-3>9?xE; z*Mc0+1b%&|L0>9`?YyuayXLkvmhh4GP1bu>exqtMs~-rkqS}o`g6g0#RpDwj7A7|g z0vdTb&(_ZQ#*NW6)6@`D!a^NWpOlL+(NNAz0{~9)5taSUooF$~XS(W)g_iSXpVrRS z=4^y?nET35hMi1ty^4zSR7TLJFSSg6D)EgVpJx}8?9I7bjGjTYI@k>1lnLzQWtR(6 zLv)+z5498T$R^!<{}-+r9q4E$2G$5@2&k^e{G#h$CZvQ)h;EmVV#jQlhJlDy(nHuX zi7=a(S>W$siP41!5wMP1xpo|!Tr=y}nX!KDa1Rp+{ga1^CE3cVBV-HUX5?Kv|u zFoEgY9L?Tf&D18?mm%ZV=Bh!a+5>uL!yONYGIGm@g`(6*!R-43q*Y_+Z3BT6t+{Vx zkR>7h{eKR@6 zlU=14aVncyO1Jr{^os_3mI&kIX#@SA%6|!tYNVdF}7&y{NBdF8Jiy5g3ix!sQS!F%^z zm~HrW`x-y(te)@F5)bc*NNAF5`Dp6DLX)=kOZPBugzfyI?)ysv@9us%@AWB@gyNBj zAymjGw z&+9MtnQAgxo>+VM$VblX@8dtK&G(f@OO-c|thjqY{Od~1onOLf|3*>JE>SB=*JbSR zt92V~wGIaJq*97HD64*>Y56d^n{7PVq~Z2Nljev_grtDI51k08DAtiO1*A$y>|-r4 zaJ>;m5pPG`OqI>J+6)QuaH3W7UXD+8-$JMJK-|Y!)xTU=e#WWd5%f*vOowlkwO(HD`&cZDk5YCXwc+@pFdTtIJvlmhSWZJ zZ<{fP#fX`Y^3iIsXEr9NM=u!!08Y;ePi*)jhBLI?Fnu(0xl2=#(RfKG%6f2HOr6I&TO%Ns2W7K3W*XGbyILll zGbftwqywMb^0;P9wS-@Md6qL_6uIMARrFG}LLUAYvz{>&)zk|+{JTd_>E_Yj)oC2W z&dXw!axGBkMR9|bhSojo2~69>^c|VnbMoLTj{Gpsk=J2FzkxRFpa$D>A(s(H!=~Fr zm0zkG#J=a_?sFjNWYD}N5hC17$c}8)Q)MsYSKY`R?f?=@x#gAxMJ3SG3H5bNHGH7> z5?N=9!sItCSzVWxXM*{LJE<#04U&A$v=9w`NEe}txJ*m(p&>{%AUODpQI|m&lc*kP zGm3eiMAt!T;V-NnkP+LY$C&=}BL|G&9rOuJxm?P#m~D{Uc}x{6Ud|Dy<|`2pVgJSm z7wVqfzSRJg?gm`v$13M*vaYC{0$SuxUIx3lp;$+YSo*lrr&u=yx#+H>9@$7k#Qit@ z7S7M7hHHNHP96+hdD%T;XgiSjUZEn=HWt+<2gSHFyQ9DYS`dfpLeeDP5Oam50}5zj zR12fYR*VYXvZk6k6nDOX74d9|KbH`wuOkTzYTXzG9;esi55eC_7{>uM;y8roycY9G zFYuZn*A0ZLj`%gCK2^2eK!x}iCUpwRDUs+B!u5?#)iQn9#L^)dZ&_9wp2xO zHH(8VtV*{F%&7$hACf_ips%WfPhmebqfnhiL;zuu;g$udnST0>08cBQ{8J^TQZ(D+ zG!FiF8niMF31aUMps_Y4=sAsSe*=AJ1rF(3Nl&K}+zL^uJC7;^4Ia0RyI za3Ds2?Em^YZgDQsQyZDv^>vtLtXYgTGYdkkR2!UTT}5WxJad@ioZK^DvAed;Epi1R zk|^`syY|{I=V@xyZxy`rr+o{5UCvzhJQMqjrJHwiVI*e5KfqLs?x(Up*1ws(aLLQ7 zs;vBCQoSSD1i`$QY%jc!FO!rTW$ACfHEdPX1V_J7)Sft+zV2dkZ%=Kb^Z9_A{Em4` zM|tMAE7X36?n}-pUt2dz%>O(I<**5q?NDuqX`OLF_=6vYVSYx9U_b>|NGBciW4nsC z2a!AggTqep(-)B{MInpk2L&Kf)(vMY2pp71-inaBoS*rzM?rbi8LijSa#QX$!QDJ44JtZ zN(se7LD?BYc)pF7v9%fvhX#?nKy&*U2g;G14gC#l9Q&zcf|c|SMJvom!_HkQ*_OAX zMaz5ImbP>OJz~uiWv;a`Lx!pP)pyd1kl8}B!Kpg;hFrLg-cx7CZOlQz+MmG~bf z-&?MiY`2Q=>^|3Y%mK+khQzo>Xoem_kG|z`xOpQIROg(@#;0}juG){zmS#CApBy2kHPHe2P_`!E zIwe-5!}z01uLPfvW}p-y?ztI~a&hzJHzqVJSevI%g`3Ya*B?(v9p2l3jGs~pY7vJt z?kI2w^Xqie8h}HpDUknvtOggf{ua)9<_7GIyI_9w~C5NZp$#rn2(dH{_uPGOU1|UT-`L% z5`=s}5n||{>e}S{6|e~58!-NovX3D`a5r2s?5IAr0OAoWj9(X0<0rL6ED?<7KpMSf zYNJAL(5sG{{Ex^uWL zMZ5s&WxX5&2XOxTu0h0)NTYDN@iEsx)VREOx^37vJybylsEcc1c9l3sx!m(Xv(h&= z@-t?e``ArmRz+S!g`&3#ZI9I&>W)05vqqSZB}#TzWMr=R{K7vN=W)~g_o-Njlw75J z!P+@EL-$K|VKZs;kv5;q5P z6+*B&%s(wqhlDdXGU4Zn@seBF2`EzBa+4SIF}aXA6uw?mQjv2^67bYj)vshL^SAq} z{d;QWxk6&^s&@pvP}waJ(M@^AvAMgDRM%4ESis&FInU-J1%rEG%9?=uFf z%9-8NNm@Nkg~o8iRY7WxasT3y2ZsU~6JfFJWu=*#q^%8Z6I5(FVGTXGa# z75i&(3uJ1(Vt2GmbnWZ5e#Ug^spbAQQ2`)IlmkUJE

bilR3c+Wp(!e-{rAdlTT+oj>=4u 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%0AF630q9?0|Ox%!YgRga6-4j_c>z%hU^U|*yN{4!* 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 dB#? fromAsset(String assetKey) { - final FragmentProgram? program = _shaderRegistry[assetKey]?.target; + // The flutter tool converts all asset keys with spaces into URI + // encoded paths (replacing ' ' with '%20', for example). We perform + // the same encoding here so that users can load assets with the same + // key they have written in the pubspec. + final String encodedKey = Uri(path: Uri.encodeFull(assetKey)).path; + final FragmentProgram? program = _shaderRegistry[encodedKey]?.target; if (program != null) { return Future.value(program); } return Future.microtask(() { - final FragmentProgram program = FragmentProgram._fromAsset(assetKey); - _shaderRegistry[assetKey] = WeakReference(program); + final FragmentProgram program = FragmentProgram._fromAsset(encodedKey); + _shaderRegistry[encodedKey] = WeakReference(program); return program; }); } @@ -5955,9 +5960,14 @@ class ImmutableBuffer extends NativeFieldWrapperClass1 { /// /// Throws an [Exception] if the asset does not exist. static Future fromAsset(String assetKey) { + // The flutter tool converts all asset keys with spaces into URI + // encoded paths (replacing ' ' with '%20', for example). We perform + // the same encoding here so that users can load assets with the same + // key they have written in the pubspec. + final String encodedKey = Uri(path: Uri.encodeFull(assetKey)).path; final ImmutableBuffer instance = ImmutableBuffer._(0); return _futurize((_Callback callback) { - return instance._initFromAsset(assetKey, callback); + return instance._initFromAsset(encodedKey, callback); }).then((int length) => instance.._length = length); } diff --git a/testing/dart/assets_test.dart b/testing/dart/assets_test.dart index 7a2522c399fc5..64943c2179a91 100644 --- a/testing/dart/assets_test.dart +++ b/testing/dart/assets_test.dart @@ -27,6 +27,13 @@ void main() { expect(buffer.length == 354679, true); }); + test('Can load an asset with a space in the key', () async { + // This assets actual path is "fixtures/DashInNooglerHat%20WithSpace.jpg" + final ImmutableBuffer buffer = await ImmutableBuffer.fromAsset('DashInNooglerHat WithSpace.jpg'); + + expect(buffer.length == 354679, true); + }); + test('can dispose immutable buffer', () async { final ImmutableBuffer buffer = await ImmutableBuffer.fromAsset('DashInNooglerHat.jpg'); diff --git a/testing/dart/fragment_shader_test.dart b/testing/dart/fragment_shader_test.dart index 7fdcdf2742654..d3b1b33521145 100644 --- a/testing/dart/fragment_shader_test.dart +++ b/testing/dart/fragment_shader_test.dart @@ -24,6 +24,16 @@ void main() async { _expectShaderRendersGreen(shader); }); + test('simple shader with space in key renders correctly', () async { + final FragmentProgram program = await FragmentProgram.fromAsset( + 'functions with_space.frag.iplr', + ); + final Shader shader = program.shader( + floatUniforms: Float32List.fromList([1]), + ); + _expectShaderRendersGreen(shader); + }); + test('blue-green image renders green', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'blue_green_sampler.frag.iplr', From 010813db12f6a5930c28522e8a6728f889c2ed74 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 9 Aug 2022 13:08:54 -0700 Subject: [PATCH 205/558] Migrate gen_locale.dart to null-safety (#35236) --- tools/gen_locale.dart | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/tools/gen_locale.dart b/tools/gen_locale.dart index 2c4cedcea0d2a..a154a8f2d9a73 100644 --- a/tools/gen_locale.dart +++ b/tools/gen_locale.dart @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(goderbauer): Migrate this to null safety, https://github.com/flutter/flutter/issues/108933 -// @dart = 2.7 - // This file is used to generate the switch statements in the Locale class. // See: ../lib/ui/window.dart @@ -14,6 +11,8 @@ // this script (the first set for _canonicalizeLanguageCode and the second set // for _canonicalizeRegionCode). +// ignore_for_file: avoid_print + import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -22,7 +21,7 @@ const String registry = 'https://www.iana.org/assignments/language-subtag-regist Map> parseSection(String section) { final Map> result = >{}; - List lastHeading; + late List lastHeading; for (final String line in section.split('\n')) { if (line == '') { continue; @@ -37,8 +36,7 @@ Map> parseSection(String section) { } final String name = line.substring(0, colon); final String value = line.substring(colon + 2); - lastHeading = result.putIfAbsent(name, () => []); - result[name].add(value); + lastHeading = result.putIfAbsent(name, () => [])..add(value); } return result; } @@ -48,29 +46,29 @@ Future main() async { final String body = (await (await (await client.getUrl(Uri.parse(registry))).close()).transform(utf8.decoder).toList()).join(); final List>> sections = body.split('%%').map>>(parseSection).toList(); final Map> outputs = >{'language': [], 'region': []}; - String fileDate; + String? fileDate; for (final Map> section in sections) { if (fileDate == null) { // first block should contain a File-Date metadata line. - fileDate = section['File-Date'].single; + fileDate = section['File-Date']!.single; continue; } assert(section.containsKey('Type'), section.toString()); - final String type = section['Type'].single; + final String type = section['Type']!.single; if ((type == 'language' || type == 'region') && (section.containsKey('Preferred-Value'))) { assert(section.containsKey('Subtag'), section.toString()); - final String subtag = section['Subtag'].single; - final List descriptions = section['Description']; + final String subtag = section['Subtag']!.single; + final List descriptions = section['Description']!; assert(descriptions.isNotEmpty); assert(section.containsKey('Deprecated')); - final String comment = section.containsKey('Comment') ? section['Comment'].single : 'deprecated ${section['Deprecated'].single}'; - final String preferredValue = section['Preferred-Value'].single; - outputs[type].add("'$subtag': '$preferredValue', // ${descriptions.join(", ")}; $comment"); + final String comment = section.containsKey('Comment') ? section['Comment']!.single : 'deprecated ${section['Deprecated']!.single}'; + final String preferredValue = section['Preferred-Value']!.single; + outputs[type]!.add("'$subtag': '$preferredValue', // ${descriptions.join(", ")}; $comment"); } } print('// Mappings generated for language subtag registry as of $fileDate.'); print('// For languageCode:'); - print(outputs['language'].join('\n')); + print(outputs['language']!.join('\n')); print('// For regionCode:'); - print(outputs['region'].join('\n')); + print(outputs['region']!.join('\n')); } From 4ac52f2e48d2aafc20f338a1e6747db48c49a6fc Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 9 Aug 2022 13:21:59 -0700 Subject: [PATCH 206/558] Collect textures from toImageSync safely (#35073) --- common/graphics/texture.cc | 30 ++++ common/graphics/texture.h | 32 +++- flow/compositor_context.cc | 11 +- flow/compositor_context.h | 6 +- flow/layers/layer.h | 4 +- flow/layers/layer_tree.cc | 5 +- flow/layers/layer_tree_unittests.cc | 10 +- .../performance_overlay_layer_unittests.cc | 3 +- flow/layers/texture_layer.cc | 4 +- flow/layers/texture_layer_unittests.cc | 10 +- flow/raster_cache_unittests.cc | 116 +++++++++---- flow/skia_gpu_object.h | 31 +++- flow/skia_gpu_object_unittests.cc | 1 + flow/testing/layer_test.h | 9 +- flow/testing/mock_raster_cache.cc | 54 +++--- flow/testing/mock_raster_cache.h | 11 +- lib/ui/BUILD.gn | 1 + .../display_list_deferred_image_gpu.cc | 159 +++++++++++++++--- .../display_list_deferred_image_gpu.h | 83 +++++++-- lib/ui/painting/image_encoding.cc | 96 +++++------ lib/ui/painting/picture.cc | 25 +-- lib/ui/snapshot_delegate.h | 40 ++++- shell/common/fixtures/shell_test.dart | 26 ++- shell/common/rasterizer.cc | 54 ++++-- shell/common/rasterizer.h | 16 +- shell/common/shell.cc | 6 +- shell/common/shell_unittests.cc | 16 +- 27 files changed, 602 insertions(+), 257 deletions(-) diff --git a/common/graphics/texture.cc b/common/graphics/texture.cc index c5ad5fdf29af8..f12a5959fc088 100644 --- a/common/graphics/texture.cc +++ b/common/graphics/texture.cc @@ -6,6 +6,10 @@ namespace flutter { +ContextListener::ContextListener() = default; + +ContextListener::~ContextListener() = default; + Texture::Texture(int64_t id) : id_(id) {} Texture::~Texture() = default; @@ -19,6 +23,12 @@ void TextureRegistry::RegisterTexture(std::shared_ptr texture) { mapping_[texture->Id()] = texture; } +void TextureRegistry::RegisterContextListener( + uintptr_t id, + std::weak_ptr image) { + images_[id] = std::move(image); +} + void TextureRegistry::UnregisterTexture(int64_t id) { auto found = mapping_.find(id); if (found == mapping_.end()) { @@ -28,16 +38,36 @@ void TextureRegistry::UnregisterTexture(int64_t id) { mapping_.erase(found); } +void TextureRegistry::UnregisterContextListener(uintptr_t id) { + images_.erase(id); +} + void TextureRegistry::OnGrContextCreated() { for (auto& it : mapping_) { it.second->OnGrContextCreated(); } + + for (const auto& [id, weak_image] : images_) { + if (auto image = weak_image.lock()) { + image->OnGrContextCreated(); + } else { + images_.erase(id); + } + } } void TextureRegistry::OnGrContextDestroyed() { for (auto& it : mapping_) { it.second->OnGrContextDestroyed(); } + + for (const auto& [id, weak_image] : images_) { + if (auto image = weak_image.lock()) { + image->OnGrContextDestroyed(); + } else { + images_.erase(id); + } + } } std::shared_ptr TextureRegistry::GetTexture(int64_t id) { diff --git a/common/graphics/texture.h b/common/graphics/texture.h index 57afa60a6361f..69cfa3ba0f9a4 100644 --- a/common/graphics/texture.h +++ b/common/graphics/texture.h @@ -16,7 +16,22 @@ class GrDirectContext; namespace flutter { -class Texture { +class ContextListener { + public: + ContextListener(); + ~ContextListener(); + + // Called from raster thread. + virtual void OnGrContextCreated() = 0; + + // Called from raster thread. + virtual void OnGrContextDestroyed() = 0; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(ContextListener); +}; + +class Texture : public ContextListener { public: explicit Texture(int64_t id); // Called from UI or raster thread. virtual ~Texture(); // Called from raster thread. @@ -29,12 +44,6 @@ class Texture { const SkSamplingOptions& sampling, const SkPaint* paint = nullptr) = 0; - // Called from raster thread. - virtual void OnGrContextCreated() = 0; - - // Called from raster thread. - virtual void OnGrContextDestroyed() = 0; - // Called on raster thread. virtual void MarkNewFrameAvailable() = 0; @@ -45,7 +54,6 @@ class Texture { private: int64_t id_; - FML_DISALLOW_COPY_AND_ASSIGN(Texture); }; @@ -56,9 +64,16 @@ class TextureRegistry { // Called from raster thread. void RegisterTexture(std::shared_ptr texture); + // Called from raster thread. + void RegisterContextListener(uintptr_t id, + std::weak_ptr image); + // Called from raster thread. void UnregisterTexture(int64_t id); + // Called from the raster thread. + void UnregisterContextListener(uintptr_t id); + // Called from raster thread. std::shared_ptr GetTexture(int64_t id); @@ -70,6 +85,7 @@ class TextureRegistry { private: std::map> mapping_; + std::map> images_; FML_DISALLOW_COPY_AND_ASSIGN(TextureRegistry); }; diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index 779a42c84eb92..7013bc86ee374 100644 --- a/flow/compositor_context.cc +++ b/flow/compositor_context.cc @@ -46,11 +46,14 @@ std::optional FrameDamage::ComputeClipRect( } CompositorContext::CompositorContext() - : raster_time_(fixed_refresh_rate_updater_), + : texture_registry_(std::make_shared()), + raster_time_(fixed_refresh_rate_updater_), ui_time_(fixed_refresh_rate_updater_) {} CompositorContext::CompositorContext(Stopwatch::RefreshRateUpdater& updater) - : raster_time_(updater), ui_time_(updater) {} + : texture_registry_(std::make_shared()), + raster_time_(updater), + ui_time_(updater) {} CompositorContext::~CompositorContext() = default; @@ -160,12 +163,12 @@ RasterStatus CompositorContext::ScopedFrame::Raster( } void CompositorContext::OnGrContextCreated() { - texture_registry_.OnGrContextCreated(); + texture_registry_->OnGrContextCreated(); raster_cache_.Clear(); } void CompositorContext::OnGrContextDestroyed() { - texture_registry_.OnGrContextDestroyed(); + texture_registry_->OnGrContextDestroyed(); raster_cache_.Clear(); } diff --git a/flow/compositor_context.h b/flow/compositor_context.h index 0981cdd2538b1..f7667640caa71 100644 --- a/flow/compositor_context.h +++ b/flow/compositor_context.h @@ -175,7 +175,9 @@ class CompositorContext { RasterCache& raster_cache() { return raster_cache_; } - TextureRegistry& texture_registry() { return texture_registry_; } + std::shared_ptr texture_registry() { + return texture_registry_; + } const Stopwatch& raster_time() const { return raster_time_; } @@ -185,7 +187,7 @@ class CompositorContext { private: RasterCache raster_cache_; - TextureRegistry texture_registry_; + std::shared_ptr texture_registry_; Stopwatch raster_time_; Stopwatch ui_time_; LayerSnapshotStore layer_snapshot_store_; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index a87642d2c8cff..5cdd3e7db028c 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -57,7 +57,7 @@ struct PrerollContext { // These allow us to paint in the end of subtree Preroll. const Stopwatch& raster_time; const Stopwatch& ui_time; - TextureRegistry& texture_registry; + std::shared_ptr texture_registry; const bool checkerboard_offscreen_layers; const float frame_device_pixel_ratio = 1.0f; @@ -132,7 +132,7 @@ struct PaintContext { ExternalViewEmbedder* view_embedder; const Stopwatch& raster_time; const Stopwatch& ui_time; - TextureRegistry& texture_registry; + std::shared_ptr texture_registry; const RasterCache* raster_cache; const bool checkerboard_offscreen_layers; const float frame_device_pixel_ratio = 1.0f; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 53748a42832b7..0fafe40f62861 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -167,7 +167,6 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { MutatorsStack unused_stack; const FixedRefreshRateStopwatch unused_stopwatch; - TextureRegistry unused_texture_registry; SkMatrix root_surface_transformation; // No root surface transformation. So assume identity. root_surface_transformation.reset(); @@ -183,7 +182,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .surface_needs_readback = false, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = unused_texture_registry, + .texture_registry = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_ // clang-format on @@ -202,7 +201,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .view_embedder = nullptr, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = unused_texture_registry, + .texture_registry = nullptr, .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_, diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc index 63de819e15808..a8decd5fc0846 100644 --- a/flow/layers/layer_tree_unittests.cc +++ b/flow/layers/layer_tree_unittests.cc @@ -204,7 +204,7 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { MutatorsStack mock_mutators; FixedRefreshRateStopwatch mock_raster_time; FixedRefreshRateStopwatch mock_ui_time; - TextureRegistry mock_registry; + std::shared_ptr mock_registry; auto expect_defaults = [&mock_mutators, &mock_raster_time, &mock_ui_time, &mock_registry](const PrerollContext& context) { @@ -218,7 +218,7 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { EXPECT_EQ(&context.raster_time, &mock_raster_time); EXPECT_EQ(&context.ui_time, &mock_ui_time); - EXPECT_EQ(&context.texture_registry, &mock_registry); + EXPECT_EQ(context.texture_registry.get(), mock_registry.get()); EXPECT_EQ(context.checkerboard_offscreen_layers, false); EXPECT_EQ(context.frame_device_pixel_ratio, 1.0f); @@ -244,11 +244,11 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { // PaintContext that this test must be revisited and updated. // If any fields get removed or replaced, then the expect_defaults closure // will fail to compile, again bringing attention to updating this test. - EXPECT_EQ(sizeof(PaintContext), size_t(104)); + EXPECT_EQ(sizeof(PaintContext), size_t(112)); FixedRefreshRateStopwatch mock_raster_time; FixedRefreshRateStopwatch mock_ui_time; - TextureRegistry mock_registry; + std::shared_ptr mock_registry; auto expect_defaults = [&mock_raster_time, &mock_ui_time, &mock_registry](const PaintContext& context) { @@ -258,7 +258,7 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { EXPECT_EQ(context.view_embedder, nullptr); EXPECT_EQ(&context.raster_time, &mock_raster_time); EXPECT_EQ(&context.ui_time, &mock_ui_time); - EXPECT_EQ(&context.texture_registry, &mock_registry); + EXPECT_EQ(context.texture_registry.get(), mock_registry.get()); EXPECT_EQ(context.raster_cache, nullptr); EXPECT_EQ(context.checkerboard_offscreen_layers, false); EXPECT_EQ(context.frame_device_pixel_ratio, 1.0f); diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc index ae9eec8b767e4..f7c20d24d2900 100644 --- a/flow/layers/performance_overlay_layer_unittests.cc +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -58,7 +58,6 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { ASSERT_TRUE(surface != nullptr); - flutter::TextureRegistry unused_texture_registry; flutter::PaintContext paintContext = { // clang-format off .internal_nodes_canvas = nullptr, @@ -67,7 +66,7 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { .view_embedder = nullptr, .raster_time = mock_stopwatch, .ui_time = mock_stopwatch, - .texture_registry = unused_texture_registry, + .texture_registry = nullptr, .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index fa760fe786e83..7ece96ebd4364 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -54,7 +54,9 @@ void TextureLayer::Paint(PaintContext& context) const { FML_DCHECK(needs_painting(context)); std::shared_ptr texture = - context.texture_registry.GetTexture(texture_id_); + context.texture_registry + ? context.texture_registry->GetTexture(texture_id_) + : nullptr; if (!texture) { TRACE_EVENT_INSTANT0("flutter", "null texture"); return; diff --git a/flow/layers/texture_layer_unittests.cc b/flow/layers/texture_layer_unittests.cc index 94e5469db702b..7d45d1d54e825 100644 --- a/flow/layers/texture_layer_unittests.cc +++ b/flow/layers/texture_layer_unittests.cc @@ -43,7 +43,7 @@ TEST_F(TextureLayerTest, PaintingEmptyLayerDies) { false, DlImageSampling::kNearestNeighbor); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry.RegisterTexture(mock_texture); + preroll_context()->texture_registry->RegisterTexture(mock_texture); layer->Preroll(preroll_context(), SkMatrix()); EXPECT_EQ(layer->paint_bounds(), kEmptyRect); @@ -62,7 +62,7 @@ TEST_F(TextureLayerTest, PaintBeforePrerollDies) { layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry.RegisterTexture(mock_texture); + preroll_context()->texture_registry->RegisterTexture(mock_texture); EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), "needs_painting\\(context\\)"); @@ -78,7 +78,7 @@ TEST_F(TextureLayerTest, PaintingWithLinearSampling) { layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry.RegisterTexture(mock_texture); + preroll_context()->texture_registry->RegisterTexture(mock_texture); layer->Preroll(preroll_context(), SkMatrix()); EXPECT_EQ(layer->paint_bounds(), @@ -124,12 +124,12 @@ TEST_F(TextureLayerTest, OpacityInheritance) { layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry.RegisterTexture(mock_texture); + preroll_context()->texture_registry->RegisterTexture(mock_texture); // The texture layer always reports opacity compatibility. PrerollContext* context = preroll_context(); context->subtree_can_inherit_opacity = false; - context->texture_registry.RegisterTexture(mock_texture); + context->texture_registry->RegisterTexture(mock_texture); layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(context->subtree_can_inherit_opacity); diff --git a/flow/raster_cache_unittests.cc b/flow/raster_cache_unittests.cc index a27b9e45cdfde..afd00392afa1d 100644 --- a/flow/raster_cache_unittests.cc +++ b/flow/raster_cache_unittests.cc @@ -38,9 +38,13 @@ TEST(RasterCache, MetricsOmitUnpopulatedEntries) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -90,9 +94,13 @@ TEST(RasterCache, ThresholdIsRespectedForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -130,7 +138,10 @@ TEST(RasterCache, SetCheckboardCacheImages) { SkMatrix matrix = SkMatrix::I(); auto display_list = GetSampleDisplayList(); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& paint_context = paint_context_holder.paint_context; auto dummy_draw_function = [](SkCanvas* canvas) {}; bool did_draw_checkerboard = false; @@ -163,14 +174,17 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForSkPicture) { SkMatrix matrix = SkMatrix::I(); auto display_list = GetSampleDisplayList(); - ; SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -193,9 +207,13 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -220,9 +238,13 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForSkPicture) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -252,9 +274,13 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -288,9 +314,13 @@ TEST(RasterCache, EvitUnusedCacheEntries) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -394,9 +424,13 @@ TEST(RasterCache, DeviceRectRoundOutForDisplayList) { SkCanvas canvas(100, 100, nullptr); canvas.setMatrix(ctm); - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -433,9 +467,13 @@ TEST(RasterCache, NestedOpCountMetricUsedForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -476,9 +514,13 @@ TEST(RasterCache, NaiveComplexityScoringDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -538,9 +580,13 @@ TEST(RasterCache, DisplayListWithSingularMatrixIsNotCached) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; diff --git a/flow/skia_gpu_object.h b/flow/skia_gpu_object.h index e694ef7ffcc2a..16251ec56f823 100644 --- a/flow/skia_gpu_object.h +++ b/flow/skia_gpu_object.h @@ -34,6 +34,16 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { } } + void DeleteTexture(GrBackendTexture texture) { + std::scoped_lock lock(mutex_); + textures_.push_back(texture); + if (!drain_pending_) { + drain_pending_ = true; + task_runner_->PostDelayedTask( + [strong = fml::Ref(this)]() { strong->Drain(); }, drain_delay_); + } + } + // Usually, the drain is called automatically. However, during IO manager // shutdown (when the platform side reference to the OpenGL context is about // to go away), we may need to pre-emptively drain the unref queue. It is the @@ -42,12 +52,14 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { void Drain() { TRACE_EVENT0("flutter", "SkiaUnrefQueue::Drain"); std::deque skia_objects; + std::deque textures; { std::scoped_lock lock(mutex_); objects_.swap(skia_objects); + textures_.swap(textures); drain_pending_ = false; } - DoDrain(skia_objects, context_); + DoDrain(skia_objects, textures, context_); } void UpdateResourceContext(sk_sp context) { @@ -59,6 +71,7 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { const fml::TimeDelta drain_delay_; std::mutex mutex_; std::deque objects_; + std::deque textures_; bool drain_pending_; sk_sp context_; @@ -79,22 +92,30 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { // into a task queued to that thread. ResourceContext* raw_context = context_.release(); fml::TaskRunner::RunNowOrPostTask( - task_runner_, [objects = std::move(objects_), raw_context]() mutable { + task_runner_, [objects = std::move(objects_), + textures = std::move(textures_), raw_context]() mutable { sk_sp context(raw_context); - DoDrain(objects, context); + DoDrain(objects, textures, context); context.reset(); }); } // static static void DoDrain(const std::deque& skia_objects, + const std::deque& textures, sk_sp context) { for (SkRefCnt* skia_object : skia_objects) { skia_object->unref(); } - if (context && !skia_objects.empty()) { - context->performDeferredCleanup(std::chrono::milliseconds(0)); + if (context) { + for (GrBackendTexture texture : textures) { + context->deleteBackendTexture(texture); + } + + if (!skia_objects.empty()) { + context->performDeferredCleanup(std::chrono::milliseconds(0)); + } } } diff --git a/flow/skia_gpu_object_unittests.cc b/flow/skia_gpu_object_unittests.cc index 61127256393a3..4b631fa6fb433 100644 --- a/flow/skia_gpu_object_unittests.cc +++ b/flow/skia_gpu_object_unittests.cc @@ -41,6 +41,7 @@ class TestResourceContext : public TestSkObject { : TestSkObject(latch, dtor_task_queue_id) {} ~TestResourceContext() = default; void performDeferredCleanup(std::chrono::milliseconds msNotUsed) {} + void deleteBackendTexture(GrBackendTexture texture) {} }; class SkiaGpuObjectTest : public ThreadTest { diff --git a/flow/testing/layer_test.h b/flow/testing/layer_test.h index e5672e1eacdd1..317c7109dc8dc 100644 --- a/flow/testing/layer_test.h +++ b/flow/testing/layer_test.h @@ -44,7 +44,8 @@ class LayerTestBase : public CanvasTestBase { public: LayerTestBase() - : preroll_context_{ + : texture_registry_(std::make_shared()), + preroll_context_{ // clang-format off .raster_cache = nullptr, .gr_context = nullptr, @@ -162,7 +163,9 @@ class LayerTestBase : public CanvasTestBase { std::vector& cacheable_items() { return cacheable_items_; } - TextureRegistry& texture_regitry() { return texture_registry_; } + std::shared_ptr texture_registry() { + return texture_registry_; + } RasterCache* raster_cache() { return raster_cache_.get(); } PrerollContext* preroll_context() { return &preroll_context_; } PaintContext& paint_context() { return paint_context_; } @@ -205,7 +208,7 @@ class LayerTestBase : public CanvasTestBase { FixedRefreshRateStopwatch raster_time_; FixedRefreshRateStopwatch ui_time_; MutatorsStack mutators_stack_; - TextureRegistry texture_registry_; + std::shared_ptr texture_registry_; std::unique_ptr raster_cache_; PrerollContext preroll_context_; diff --git a/flow/testing/mock_raster_cache.cc b/flow/testing/mock_raster_cache.cc index 3ce1be25cfcd8..33b81c15030b3 100644 --- a/flow/testing/mock_raster_cache.cc +++ b/flow/testing/mock_raster_cache.cc @@ -56,7 +56,10 @@ void MockRasterCache::AddMockPicture(int width, int height) { recorder.drawPath(path, SkPaint()); sk_sp display_list = recorder.Build(); - PaintContextHolder holder = GetSamplePaintContextHolder(this); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + PaintContextHolder holder = + GetSamplePaintContextHolder(this, &raster_time, &ui_time); holder.paint_context.dst_color_space = color_space_; DisplayListRasterCacheItem display_list_item(display_list.get(), SkPoint(), @@ -81,31 +84,31 @@ void MockRasterCache::AddMockPicture(int width, int height) { }); } -PrerollContextHolder GetSamplePrerollContextHolder(RasterCache* raster_cache) { - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - TextureRegistry texture_registry; +PrerollContextHolder GetSamplePrerollContextHolder( + RasterCache* raster_cache, + FixedRefreshRateStopwatch* raster_time, + FixedRefreshRateStopwatch* ui_time, + MutatorsStack* mutators_stack) { sk_sp srgb = SkColorSpace::MakeSRGB(); PrerollContextHolder holder = { { // clang-format off .raster_cache = raster_cache, - .gr_context = nullptr, - .view_embedder = nullptr, - .mutators_stack = mutators_stack, - .dst_color_space = srgb.get(), - .cull_rect = kGiantRect, + .gr_context = nullptr, + .view_embedder = nullptr, + .mutators_stack = *mutators_stack, + .dst_color_space = srgb.get(), + .cull_rect = kGiantRect, .surface_needs_readback = false, - .raster_time = raster_time, - .ui_time = ui_time, - .texture_registry = texture_registry, - .checkerboard_offscreen_layers = false, - .frame_device_pixel_ratio = 1.0f, - .has_platform_view = false, + .raster_time = *raster_time, + .ui_time = *ui_time, + .texture_registry = nullptr, + .checkerboard_offscreen_layers = false, + .frame_device_pixel_ratio = 1.0f, + .has_platform_view = false, .has_texture_layer = false, - .raster_cached_entries = &raster_cache_items_, + .raster_cached_entries = &raster_cache_items_, // clang-format on }, srgb}; @@ -113,11 +116,10 @@ PrerollContextHolder GetSamplePrerollContextHolder(RasterCache* raster_cache) { return holder; } -PaintContextHolder GetSamplePaintContextHolder(RasterCache* raster_cache) { - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - TextureRegistry texture_registry; +PaintContextHolder GetSamplePaintContextHolder( + RasterCache* raster_cache, + FixedRefreshRateStopwatch* raster_time, + FixedRefreshRateStopwatch* ui_time) { sk_sp srgb = SkColorSpace::MakeSRGB(); PaintContextHolder holder = {// clang-format off { @@ -126,9 +128,9 @@ PaintContextHolder GetSamplePaintContextHolder(RasterCache* raster_cache) { .gr_context = nullptr, .dst_color_space = srgb.get(), .view_embedder = nullptr, - .raster_time = raster_time, - .ui_time = ui_time, - .texture_registry = texture_registry, + .raster_time = *raster_time, + .ui_time = *ui_time, + .texture_registry = nullptr, .raster_cache = raster_cache, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, diff --git a/flow/testing/mock_raster_cache.h b/flow/testing/mock_raster_cache.h index d6b385b57d389..37742486409bb 100644 --- a/flow/testing/mock_raster_cache.h +++ b/flow/testing/mock_raster_cache.h @@ -72,7 +72,7 @@ class MockRasterCache : public RasterCache { MutatorsStack mutators_stack_; FixedRefreshRateStopwatch raster_time_; FixedRefreshRateStopwatch ui_time_; - TextureRegistry texture_registry_; + std::shared_ptr texture_registry_; PrerollContext preroll_context_ = { // clang-format off .raster_cache = this, @@ -122,10 +122,15 @@ struct PaintContextHolder { }; PrerollContextHolder GetSamplePrerollContextHolder( - RasterCache* raster_cache = nullptr); + RasterCache* raster_cache, + FixedRefreshRateStopwatch* raster_time, + FixedRefreshRateStopwatch* ui_time, + MutatorsStack* mutators_stack); PaintContextHolder GetSamplePaintContextHolder( - RasterCache* raster_cache = nullptr); + RasterCache* raster_cache, + FixedRefreshRateStopwatch* raster_time, + FixedRefreshRateStopwatch* ui_time); bool RasterCacheItemPrerollAndTryToRasterCache( DisplayListRasterCacheItem& display_list_item, diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 5be9029295f03..6a2916d9cb622 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -146,6 +146,7 @@ source_set("ui") { deps = [ "//flutter/assets", "//flutter/common", + "//flutter/common/graphics", "//flutter/display_list", "//flutter/fml", "//flutter/impeller/runtime_stage", diff --git a/lib/ui/painting/display_list_deferred_image_gpu.cc b/lib/ui/painting/display_list_deferred_image_gpu.cc index 3868cf1f06c0f..4580fe9801e2c 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.cc +++ b/lib/ui/painting/display_list_deferred_image_gpu.cc @@ -4,20 +4,45 @@ #include "flutter/lib/ui/painting/display_list_deferred_image_gpu.h" +#include "display_list_deferred_image_gpu.h" +#include "third_party/skia/include/core/SkColorSpace.h" + namespace flutter { -sk_sp DlDeferredImageGPU::Make(SkISize size) { - return sk_sp(new DlDeferredImageGPU(size)); +sk_sp DlDeferredImageGPU::Make( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + return sk_sp(new DlDeferredImageGPU( + ImageWrapper::Make(image_info, std::move(display_list), + std::move(snapshot_delegate), raster_task_runner, + std::move(unref_queue)), + raster_task_runner)); } -DlDeferredImageGPU::DlDeferredImageGPU(SkISize size) : size_(size) {} +DlDeferredImageGPU::DlDeferredImageGPU( + std::shared_ptr image_wrapper, + fml::RefPtr raster_task_runner) + : image_wrapper_(std::move(image_wrapper)), + raster_task_runner_(std::move(raster_task_runner)) {} // |DlImage| -DlDeferredImageGPU::~DlDeferredImageGPU() = default; +DlDeferredImageGPU::~DlDeferredImageGPU() { + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner_, [image_wrapper = std::move(image_wrapper_)]() { + if (!image_wrapper) { + return; + } + image_wrapper->Unregister(); + image_wrapper->DeleteTexture(); + }); +} // |DlImage| sk_sp DlDeferredImageGPU::skia_image() const { - return image_; + return image_wrapper_ ? image_wrapper_->CreateSkiaImage() : nullptr; }; // |DlImage| @@ -28,43 +53,127 @@ std::shared_ptr DlDeferredImageGPU::impeller_texture() // |DlImage| bool DlDeferredImageGPU::isTextureBacked() const { - if (auto image = skia_image()) { - return image->isTextureBacked(); - } - return false; + return image_wrapper_ ? image_wrapper_->isTextureBacked() : false; } // |DlImage| SkISize DlDeferredImageGPU::dimensions() const { - return size_; + return image_wrapper_ ? image_wrapper_->image_info().dimensions() + : SkISize::MakeEmpty(); } // |DlImage| size_t DlDeferredImageGPU::GetApproximateByteSize() const { - // This call is accessed on the UI thread, and image_ may not be available - // yet. The image is not mipmapped and it's created using N32 pixels, so this - // is safe. - if (size_.isEmpty()) { - return sizeof(this); + return sizeof(this) + (image_wrapper_ + ? image_wrapper_->image_info().computeMinByteSize() + : 0); +} + +std::optional DlDeferredImageGPU::get_error() const { + return image_wrapper_ ? image_wrapper_->get_error() : std::nullopt; +} + +std::shared_ptr +DlDeferredImageGPU::ImageWrapper::Make( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + auto wrapper = std::shared_ptr(new ImageWrapper( + image_info, std::move(display_list), std::move(snapshot_delegate), + std::move(raster_task_runner), std::move(unref_queue))); + wrapper->SnapshotDisplayList(); + return wrapper; +} + +DlDeferredImageGPU::ImageWrapper::ImageWrapper( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) + : image_info_(image_info), + display_list_(std::move(display_list)), + snapshot_delegate_(std::move(snapshot_delegate)), + raster_task_runner_(std::move(raster_task_runner)), + unref_queue_(std::move(unref_queue)) {} + +void DlDeferredImageGPU::ImageWrapper::OnGrContextCreated() { + FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); + SnapshotDisplayList(); +} + +void DlDeferredImageGPU::ImageWrapper::OnGrContextDestroyed() { + FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); + + DeleteTexture(); +} + +sk_sp DlDeferredImageGPU::ImageWrapper::CreateSkiaImage() const { + FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); + + if (texture_.isValid() && context_) { + return SkImage::MakeFromTexture( + context_.get(), texture_, kTopLeft_GrSurfaceOrigin, + image_info_.colorType(), image_info_.alphaType(), + image_info_.refColorSpace()); } - return sizeof(this) + size_.width() * size_.height() * 4; + return image_; } -void DlDeferredImageGPU::set_image(sk_sp image) { - FML_DCHECK(image); - FML_DCHECK(image->dimensions() == size_); - image_ = std::move(image); +bool DlDeferredImageGPU::ImageWrapper::isTextureBacked() const { + return texture_.isValid(); } -void DlDeferredImageGPU::set_error(const std::string& error) { - FML_DCHECK(!image_); - std::scoped_lock lock(error_mutex_); - error_ = std::move(error); +void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner_, [weak_this = weak_from_this()]() { + auto wrapper = weak_this.lock(); + if (!wrapper) { + return; + } + auto snapshot_delegate = wrapper->snapshot_delegate_; + if (!snapshot_delegate) { + return; + } + auto result = snapshot_delegate->MakeGpuImage(wrapper->display_list_, + wrapper->image_info_); + if (result->texture.isValid()) { + wrapper->texture_ = result->texture; + wrapper->context_ = std::move(result->context); + wrapper->texture_registry_ = + wrapper->snapshot_delegate_->GetTextureRegistry(); + wrapper->texture_registry_->RegisterContextListener( + reinterpret_cast(wrapper.get()), weak_this); + } else if (result->image) { + wrapper->image_ = std::move(result->image); + } else { + std::scoped_lock lock(wrapper->error_mutex_); + wrapper->error_ = std::move(result->error); + } + }); } -std::optional DlDeferredImageGPU::get_error() const { +std::optional DlDeferredImageGPU::ImageWrapper::get_error() { std::scoped_lock lock(error_mutex_); return error_; } +void DlDeferredImageGPU::ImageWrapper::Unregister() { + if (texture_registry_) { + texture_registry_->UnregisterContextListener( + reinterpret_cast(this)); + } +} + +void DlDeferredImageGPU::ImageWrapper::DeleteTexture() { + if (texture_.isValid()) { + unref_queue_->DeleteTexture(std::move(texture_)); + texture_ = GrBackendTexture(); + } + image_.reset(); + context_.reset(); +} + } // namespace flutter diff --git a/lib/ui/painting/display_list_deferred_image_gpu.h b/lib/ui/painting/display_list_deferred_image_gpu.h index 0cec807fe7a99..a98f4feaa4236 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.h +++ b/lib/ui/painting/display_list_deferred_image_gpu.h @@ -5,23 +5,37 @@ #ifndef FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_DEFERRED_IMAGE_GPU_H_ #define FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_DEFERRED_IMAGE_GPU_H_ +#include #include +#include "flutter/common/graphics/texture.h" +#include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_image.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/lib/ui/io_manager.h" +#include "flutter/lib/ui/snapshot_delegate.h" namespace flutter { class DlDeferredImageGPU final : public DlImage { public: - static sk_sp Make(SkISize size); + static sk_sp Make( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); // |DlImage| ~DlDeferredImageGPU() override; // |DlImage| // This method is only safe to call from the raster thread. + // Callers must not hold long term references to this image and + // only use it for the immediate painting operation. It must be + // collected on the raster task runner. sk_sp skia_image() const override; // |DlImage| @@ -36,12 +50,6 @@ class DlDeferredImageGPU final : public DlImage { // |DlImage| virtual size_t GetApproximateByteSize() const override; - // This method must only be called from the raster thread. - void set_image(sk_sp image); - - // This method is safe to call from any thread. - void set_error(const std::string& error); - // |DlImage| // This method is safe to call from any thread. std::optional get_error() const override; @@ -52,12 +60,61 @@ class DlDeferredImageGPU final : public DlImage { } private: - sk_sp image_; - SkISize size_; - mutable std::mutex error_mutex_; - std::optional error_; - - explicit DlDeferredImageGPU(SkISize size); + class ImageWrapper final : public std::enable_shared_from_this, + public ContextListener { + public: + static std::shared_ptr Make( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + + const SkImageInfo image_info() const { return image_info_; } + const GrBackendTexture& texture() const { return texture_; } + bool isTextureBacked() const; + std::optional get_error(); + sk_sp CreateSkiaImage() const; + void Unregister(); + void DeleteTexture(); + + private: + const SkImageInfo image_info_; + sk_sp display_list_; + fml::WeakPtr snapshot_delegate_; + fml::RefPtr raster_task_runner_; + fml::RefPtr unref_queue_; + std::shared_ptr texture_registry_; + + mutable std::mutex error_mutex_; + std::optional error_; + + GrBackendTexture texture_; + sk_sp context_; + // May be used if this image is not texture backed. + sk_sp image_; + + ImageWrapper(const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + + void SnapshotDisplayList(); + + // |ContextListener| + void OnGrContextCreated() override; + + // |ContextListener| + void OnGrContextDestroyed() override; + }; + + const std::shared_ptr image_wrapper_; + + fml::RefPtr raster_task_runner_; + + DlDeferredImageGPU(std::shared_ptr image_wrapper, + fml::RefPtr raster_task_runner); FML_DISALLOW_COPY_AND_ASSIGN(DlDeferredImageGPU); }; diff --git a/lib/ui/painting/image_encoding.cc b/lib/ui/painting/image_encoding.cc index 993e7d44a6826..1e28774932910 100644 --- a/lib/ui/painting/image_encoding.cc +++ b/lib/ui/painting/image_encoding.cc @@ -60,21 +60,6 @@ void InvokeDataCallback(std::unique_ptr callback, DartInvoke(callback->value(), {dart_data}); } -static void ConvertGpuImageToRaster( - sk_sp dl_image, - std::function)> encode_task, - fml::RefPtr raster_task_runner) { - fml::TaskRunner::RunNowOrPostTask( - raster_task_runner, [dl_image, encode_task = std::move(encode_task)]() { - auto image = dl_image->skia_image(); - if (image == nullptr) { - encode_task(nullptr); - return; - } - encode_task(image->makeRasterImage()); - }); -} - void ConvertImageToRaster( sk_sp dl_image, std::function)> encode_task, @@ -83,43 +68,48 @@ void ConvertImageToRaster( fml::WeakPtr resource_context, fml::WeakPtr snapshot_delegate, const std::shared_ptr& is_gpu_disabled_sync_switch) { - auto image = dl_image->skia_image(); - - // Check validity of the image. - if (image == nullptr) { - FML_LOG(ERROR) << "Image was null."; - encode_task(nullptr); - return; - } + // If the owning_context is kRaster, we can't access it on this task runner. + if (dl_image->owning_context() != DlImage::OwningContext::kRaster) { + auto image = dl_image->skia_image(); + + // Check validity of the image. + if (image == nullptr) { + FML_LOG(ERROR) << "Image was null."; + encode_task(nullptr); + return; + } - auto dimensions = image->dimensions(); + auto dimensions = image->dimensions(); - if (dimensions.isEmpty()) { - FML_LOG(ERROR) << "Image dimensions were empty."; - encode_task(nullptr); - return; - } + if (dimensions.isEmpty()) { + FML_LOG(ERROR) << "Image dimensions were empty."; + encode_task(nullptr); + return; + } - SkPixmap pixmap; - if (image->peekPixels(&pixmap)) { - // This is already a raster image. - encode_task(image); - return; - } + SkPixmap pixmap; + if (image->peekPixels(&pixmap)) { + // This is already a raster image. + encode_task(image); + return; + } - if (sk_sp raster_image = image->makeRasterImage()) { - // The image can be converted to a raster image. - encode_task(raster_image); - return; + if (sk_sp raster_image = image->makeRasterImage()) { + // The image can be converted to a raster image. + encode_task(raster_image); + return; + } } // Cross-context images do not support makeRasterImage. Convert these images // by drawing them into a surface. This must be done on the raster thread // to prevent concurrent usage of the image on both the IO and raster threads. - raster_task_runner->PostTask([image, encode_task = std::move(encode_task), + raster_task_runner->PostTask([dl_image, encode_task = std::move(encode_task), resource_context, snapshot_delegate, - io_task_runner, is_gpu_disabled_sync_switch]() { - if (!snapshot_delegate) { + io_task_runner, is_gpu_disabled_sync_switch, + raster_task_runner]() { + auto image = dl_image->skia_image(); + if (!image || !snapshot_delegate) { io_task_runner->PostTask( [encode_task = std::move(encode_task)]() mutable { encode_task(nullptr); @@ -132,8 +122,9 @@ void ConvertImageToRaster( io_task_runner->PostTask([image, encode_task = std::move(encode_task), raster_image = std::move(raster_image), - resource_context, - is_gpu_disabled_sync_switch]() mutable { + resource_context, is_gpu_disabled_sync_switch, + owning_context = dl_image->owning_context(), + raster_task_runner]() mutable { if (!raster_image) { // The rasterizer was unable to render the cross-context image // (presumably because it does not have a GrContext). In that case, @@ -142,6 +133,9 @@ void ConvertImageToRaster( image, resource_context, is_gpu_disabled_sync_switch); } encode_task(raster_image); + if (owning_context == DlImage::OwningContext::kRaster) { + raster_task_runner->PostTask([image = std::move(image)]() {}); + } }); }); } @@ -246,17 +240,9 @@ void EncodeImageAndInvokeDataCallback( }; FML_DCHECK(image); - switch (image->owning_context()) { - case DlImage::OwningContext::kRaster: - ConvertGpuImageToRaster(std::move(image), encode_task, - raster_task_runner); - break; - case DlImage::OwningContext::kIO: - ConvertImageToRaster(std::move(image), encode_task, raster_task_runner, - io_task_runner, resource_context, snapshot_delegate, - is_gpu_disabled_sync_switch); - break; - } + ConvertImageToRaster(std::move(image), encode_task, raster_task_runner, + io_task_runner, resource_context, snapshot_delegate, + is_gpu_disabled_sync_switch); } } // namespace diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index c868101ef18cb..dd64f1b2d7696 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -59,29 +59,20 @@ void Picture::RasterizeToImageSync(sk_sp display_list, uint32_t height, Dart_Handle raw_image_handle) { auto* dart_state = UIDartState::Current(); + if (!dart_state) { + return; + } auto unref_queue = dart_state->GetSkiaUnrefQueue(); auto snapshot_delegate = dart_state->GetSnapshotDelegate(); auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); auto image = CanvasImage::Create(); - auto dl_image = DlDeferredImageGPU::Make(SkISize::Make(width, height)); + const SkImageInfo image_info = SkImageInfo::Make( + width, height, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); + auto dl_image = DlDeferredImageGPU::Make( + image_info, std::move(display_list), std::move(snapshot_delegate), + std::move(raster_task_runner), std::move(unref_queue)); image->set_image(dl_image); - - fml::TaskRunner::RunNowOrPostTask( - raster_task_runner, - [snapshot_delegate, unref_queue, dl_image = std::move(dl_image), - display_list = std::move(display_list)]() { - sk_sp sk_image; - std::string error; - std::tie(sk_image, error) = snapshot_delegate->MakeGpuImage( - display_list, dl_image->dimensions()); - if (sk_image) { - dl_image->set_image(std::move(sk_image)); - } else { - dl_image->set_error(std::move(error)); - } - }); - image->AssociateWithDartWrapper(raw_image_handle); } diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 7c87a01c865d9..4158d28701cbb 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -7,18 +7,54 @@ #include +#include "flutter/common/graphics/texture.h" #include "flutter/display_list/display_list.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkPromiseImageTexture.h" #include "third_party/skia/include/gpu/GrContextThreadSafeProxy.h" + namespace flutter { class SnapshotDelegate { public: - virtual std::pair, std::string> MakeGpuImage( + struct GpuImageResult { + GpuImageResult(const GrBackendTexture& p_texture, + sk_sp p_context, + sk_sp p_image = nullptr, + const std::string& p_error = "") + : texture(p_texture), + context(std::move(p_context)), + image(std::move(p_image)), + error(p_error) {} + + const GrBackendTexture texture; + // If texture.isValid() == true, this is a pointer to a GrDirectContext that + // can be used to create an image from the texture. + sk_sp context; + // If MakeGpuImage could not create a GPU resident image, a raster copy + // is available in this member and texture.isValid() is false. + sk_sp image; + + // A non-empty string containing an error message if neither a GPU backed + // texture nor a raster backed image could be created. + const std::string error; + }; + + //---------------------------------------------------------------------------- + /// @brief Gets the registry of external textures currently in use by the + /// rasterizer. These textures may be updated at a cadence + /// different from that of the Flutter application. When an + /// external texture is referenced in the Flutter layer tree, that + /// texture is composited within the Flutter layer tree. + /// + /// @return A pointer to the external texture registry. + /// + virtual std::shared_ptr GetTextureRegistry() = 0; + + virtual std::unique_ptr MakeGpuImage( sk_sp display_list, - SkISize picture_size) = 0; + const SkImageInfo& image_info) = 0; virtual sk_sp MakeRasterSnapshot( std::function draw_callback, diff --git a/shell/common/fixtures/shell_test.dart b/shell/common/fixtures/shell_test.dart index b8908bdd24563..a41715add9a68 100644 --- a/shell/common/fixtures/shell_test.dart +++ b/shell/common/fixtures/shell_test.dart @@ -339,8 +339,28 @@ Future toImageSync() async { expect(image.width, 20); expect(image.height, 25); - final ByteData data = (await image.toByteData())!; - expect(data.lengthInBytes, 20 * 25 * 4); - expect(data.buffer.asUint32List().every((int byte) => byte == 0xFFAAAAAA), true); + final ByteData dataBefore = (await image.toByteData())!; + expect(dataBefore.lengthInBytes, 20 * 25 * 4); + for (final int byte in dataBefore.buffer.asUint32List()) { + expect(byte, 0xFFAAAAAA); + } + + // Cause the rasterizer to get torn down. + notifyNative(); + + final ByteData dataAfter = (await image.toByteData())!; + expect(dataAfter.lengthInBytes, 20 * 25 * 4); + for (final int byte in dataAfter.buffer.asUint32List()) { + expect(byte, 0xFFAAAAAA); + } + + // Verify that the image can be drawn successfully. + final PictureRecorder recorder2 = PictureRecorder(); + final Canvas canvas2 = Canvas(recorder2); + canvas2.drawImage(image, Offset.zero, Paint()); + final Picture picture2 = recorder2.endRecording(); + + picture.dispose(); + picture2.dispose(); notifyNative(); } diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index db5ef54055cc8..d3ecb11fee8ec 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -141,8 +141,8 @@ void Rasterizer::NotifyLowMemoryWarning() const { context->performDeferredCleanup(std::chrono::milliseconds(0)); } -flutter::TextureRegistry* Rasterizer::GetTextureRegistry() { - return &compositor_context_->texture_registry(); +std::shared_ptr Rasterizer::GetTextureRegistry() { + return compositor_context_->texture_registry(); } flutter::LayerTree* Rasterizer::GetLastLayerTree() { @@ -248,7 +248,7 @@ bool Rasterizer::ShouldResubmitFrame(const RasterStatus& raster_status) { } namespace { -std::pair, std::string> MakeBitmapImage( +std::unique_ptr MakeBitmapImage( sk_sp display_list, const SkImageInfo& image_info) { FML_DCHECK(display_list); @@ -258,8 +258,10 @@ std::pair, std::string> MakeBitmapImage( // This limit is taken from the Metal specification. D3D, Vulkan, and GL // generally have lower limits. if (image_info.width() > 16384 || image_info.height() > 16384) { - return {nullptr, "unable to create render target at specified size"}; - } + return std::make_unique( + GrBackendTexture(), nullptr, nullptr, + "unable to create render target at specified size"); + }; sk_sp surface = SkSurface::MakeRaster(image_info); SkCanvas* canvas = surface->getCanvas(); @@ -267,18 +269,26 @@ std::pair, std::string> MakeBitmapImage( display_list->RenderTo(canvas); sk_sp image = surface->makeImageSnapshot(); - return {image, image ? "" : "Unable to create image"}; + return std::make_unique( + GrBackendTexture(), nullptr, image, + image ? "" : "Unable to create image"); } } // namespace -std::pair, std::string> Rasterizer::MakeGpuImage( +std::unique_ptr Rasterizer::MakeGpuImage( sk_sp display_list, - SkISize picture_size) { + const SkImageInfo& image_info) { TRACE_EVENT0("flutter", "Rasterizer::MakeGpuImage"); FML_DCHECK(display_list); - const SkImageInfo image_info = SkImageInfo::MakeN32Premul(picture_size); - std::pair, std::string> result; +// TODO(dnfield): the Linux embedding is in a rough state right now and +// I can't seem to get the GPU path working on it. +// https://github.com/flutter/flutter/issues/108835 +#if FML_OS_LINUX + return MakeBitmapImage(std::move(display_list), image_info); +#endif + + std::unique_ptr result; delegate_.GetIsGpuDisabledSyncSwitch()->Execute( fml::SyncSwitch::Handlers() .SetIfTrue([&result, &image_info, &display_list] { @@ -299,11 +309,23 @@ std::pair, std::string> Rasterizer::MakeGpuImage( return; } - sk_sp sk_surface = SkSurface::MakeRenderTarget( - context, SkBudgeted::kYes, image_info); + GrBackendTexture texture = context->createBackendTexture( + image_info.width(), image_info.height(), image_info.colorType(), + GrMipmapped::kNo, GrRenderable::kYes); + if (!texture.isValid()) { + result = std::make_unique( + GrBackendTexture(), nullptr, nullptr, + "unable to create render target at specified size"); + return; + } + + sk_sp sk_surface = SkSurface::MakeFromBackendTexture( + context, texture, kTopLeft_GrSurfaceOrigin, /*sampleCnt=*/0, + image_info.colorType(), image_info.refColorSpace(), nullptr); if (!sk_surface) { - result = {nullptr, - "unable to create render target at specified size"}; + result = std::make_unique( + GrBackendTexture(), nullptr, nullptr, + "unable to create rendering surface for image"); return; } @@ -311,8 +333,8 @@ std::pair, std::string> Rasterizer::MakeGpuImage( canvas->clear(SK_ColorTRANSPARENT); display_list->RenderTo(canvas); - sk_sp image = sk_surface->makeImageSnapshot(); - result = {image, image ? "" : "Unable to create image"}; + result = std::make_unique( + texture, sk_ref_sp(context), nullptr, ""); })); return result; } diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 425b8214e5bd4..2f90ed5b1fe66 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -212,16 +212,8 @@ class Rasterizer final : public SnapshotDelegate, void DrawLastLayerTree( std::unique_ptr frame_timings_recorder); - //---------------------------------------------------------------------------- - /// @brief Gets the registry of external textures currently in use by the - /// rasterizer. These textures may be updated at a cadence - /// different from that of the Flutter application. When an - /// external texture is referenced in the Flutter layer tree, that - /// texture is composited within the Flutter layer tree. - /// - /// @return A pointer to the external texture registry. - /// - flutter::TextureRegistry* GetTextureRegistry(); + // |SnapshotDelegate| + std::shared_ptr GetTextureRegistry() override; using LayerTreeDiscardCallback = std::function; @@ -470,9 +462,9 @@ class Rasterizer final : public SnapshotDelegate, private: // |SnapshotDelegate| - std::pair, std::string> MakeGpuImage( + std::unique_ptr MakeGpuImage( sk_sp display_list, - SkISize picture_size) override; + const SkImageInfo& image_info) override; // |SnapshotDelegate| sk_sp MakeRasterSnapshot( diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 6c80032b46491..bc8594bc90cdb 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -1040,7 +1040,7 @@ void Shell::OnPlatformViewRegisterTexture( task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), texture] { if (rasterizer) { - if (auto* registry = rasterizer->GetTextureRegistry()) { + if (auto registry = rasterizer->GetTextureRegistry()) { registry->RegisterTexture(texture); } } @@ -1055,7 +1055,7 @@ void Shell::OnPlatformViewUnregisterTexture(int64_t texture_id) { task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { if (rasterizer) { - if (auto* registry = rasterizer->GetTextureRegistry()) { + if (auto registry = rasterizer->GetTextureRegistry()) { registry->UnregisterTexture(texture_id); } } @@ -1070,7 +1070,7 @@ void Shell::OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) { // Tell the rasterizer that one of its textures has a new frame available. task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { - auto* registry = rasterizer->GetTextureRegistry(); + auto registry = rasterizer->GetTextureRegistry(); if (!registry) { return; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index e4a86b5775a34..7bd244d98aba2 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -2382,7 +2382,6 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { FixedRefreshRateStopwatch raster_time; FixedRefreshRateStopwatch ui_time; MutatorsStack mutators_stack; - TextureRegistry texture_registry; PaintContext paint_context = { // clang-format off .internal_nodes_canvas = nullptr, @@ -2392,7 +2391,7 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { .view_embedder = nullptr, .raster_time = raster_time, .ui_time = ui_time, - .texture_registry = texture_registry, + .texture_registry = nullptr, .raster_cache = &raster_cache, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, @@ -2411,7 +2410,7 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { .surface_needs_readback = false, .raster_time = raster_time, .ui_time = ui_time, - .texture_registry = texture_registry, + .texture_registry = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, .has_platform_view = false, @@ -3765,7 +3764,7 @@ TEST_F(ShellTest, SpawnWorksWithOnError) { TEST_F(ShellTest, PictureToImageSync) { #if !SHELL_ENABLE_GL - // GL emulation does not exist on Fuchsia. + // This test uses the GL backend. GTEST_SKIP(); #endif // !SHELL_ENABLE_GL auto settings = CreateSettingsForFixture(); @@ -3778,9 +3777,12 @@ TEST_F(ShellTest, PictureToImageSync) { ShellTestPlatformView::BackendType::kGLBackend // ); - fml::AutoResetWaitableEvent latch; - AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&latch](auto args) { - latch.Signal(); + fml::CountDownLatch latch(2); + AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&](auto args) { + // Teardown and set up rasterizer again. + PlatformViewNotifyDestroyed(shell.get()); + PlatformViewNotifyCreated(shell.get()); + latch.CountDown(); })); ASSERT_NE(shell, nullptr); From 29aea24d0367993ece728aad86c80c92f7c8f295 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 9 Aug 2022 13:26:18 -0700 Subject: [PATCH 207/558] [Impeller] Account for the backend-dependent space of rendered textures in gaussian blur (#35257) * Add single pass variation to gaussian blur test * Account for the backend-dependent space of rendered textures in gaussian blur --- .../filters/gaussian_blur_filter_contents.cc | 4 ++++ impeller/entity/entity_unittests.cc | 22 +++++++++++++++--- impeller/entity/shaders/gaussian_blur.frag | 23 +++++++++++-------- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 7982aa1b67989..e1b40d4c9f989 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -138,6 +138,10 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter( frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); FS::FragInfo frag_info; + frag_info.texture_sampler_y_coord_scale = + input_snapshot->texture->GetYCoordScale(); + frag_info.alpha_mask_sampler_y_coord_scale = + source_snapshot->texture->GetYCoordScale(); frag_info.blur_sigma = transformed_blur.GetLength(); frag_info.blur_radius = Radius{Sigma{frag_info.blur_sigma}}.radius; frag_info.blur_direction = input_snapshot->transform.Invert() diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 7a9a7b02bbc89..2e28a2f0d18a2 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -847,6 +847,7 @@ TEST_P(EntityTest, GaussianBlurFilter) { const char* input_type_names[] = {"Texture", "Solid Color"}; const char* blur_type_names[] = {"Image blur", "Mask blur"}; + const char* pass_variation_names[] = {"Two pass", "Directional"}; const char* blur_style_names[] = {"Normal", "Solid", "Outer", "Inner"}; const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; const FilterContents::BlurStyle blur_styles[] = { @@ -860,6 +861,7 @@ TEST_P(EntityTest, GaussianBlurFilter) { static int selected_input_type = 0; static Color input_color = Color::Black(); static int selected_blur_type = 0; + static int selected_pass_variation = 0; static float blur_amount[2] = {20, 20}; static int selected_blur_style = 0; static int selected_tile_mode = 3; @@ -882,6 +884,11 @@ TEST_P(EntityTest, GaussianBlurFilter) { } ImGui::Combo("Blur type", &selected_blur_type, blur_type_names, sizeof(blur_type_names) / sizeof(char*)); + if (selected_blur_type == 0) { + ImGui::Combo("Pass variation", &selected_pass_variation, + pass_variation_names, + sizeof(pass_variation_names) / sizeof(char*)); + } ImGui::SliderFloat2("Sigma", &blur_amount[0], 0, 200); ImGui::Combo("Blur style", &selected_blur_style, blur_style_names, sizeof(blur_style_names) / sizeof(char*)); @@ -921,9 +928,18 @@ TEST_P(EntityTest, GaussianBlurFilter) { input_size = input_rect.size; } - auto blur = FilterContents::MakeGaussianBlur( - FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]}, - blur_styles[selected_blur_style], tile_modes[selected_tile_mode]); + std::shared_ptr blur; + if (selected_pass_variation == 0) { + blur = FilterContents::MakeGaussianBlur( + FilterInput::Make(input), Sigma{blur_amount[0]}, + Sigma{blur_amount[1]}, blur_styles[selected_blur_style], + tile_modes[selected_tile_mode]); + } else { + Vector2 blur_vector(blur_amount[0], blur_amount[1]); + blur = FilterContents::MakeDirectionalGaussianBlur( + FilterInput::Make(input), Sigma{blur_vector.GetLength()}, + blur_vector.Normalize()); + } auto mask_blur = FilterContents::MakeBorderMaskBlur( FilterInput::Make(input), Sigma{blur_amount[0]}, Sigma{blur_amount[1]}, diff --git a/impeller/entity/shaders/gaussian_blur.frag b/impeller/entity/shaders/gaussian_blur.frag index 53fe22a906006..ec099a6965bc4 100644 --- a/impeller/entity/shaders/gaussian_blur.frag +++ b/impeller/entity/shaders/gaussian_blur.frag @@ -20,6 +20,9 @@ uniform sampler2D texture_sampler; uniform sampler2D alpha_mask_sampler; uniform FragInfo { + float texture_sampler_y_coord_scale; + float alpha_mask_sampler_y_coord_scale; + vec2 texture_size; vec2 blur_direction; @@ -59,21 +62,21 @@ void main() { total_color += gaussian * IPSampleWithTileMode( - texture_sampler, // sampler - v_texture_coords + blur_uv_offset * i, // texture coordinates - 1.0, // y coordinate scale - frag_info.tile_mode // tile mode + texture_sampler, // sampler + v_texture_coords + blur_uv_offset * i, // texture coordinates + frag_info.texture_sampler_y_coord_scale, // y coordinate scale + frag_info.tile_mode // tile mode ); } vec4 blur_color = total_color / gaussian_integral; - vec4 src_color = - IPSampleWithTileMode(alpha_mask_sampler, // sampler - v_src_texture_coords, // texture coordinates - 1.0, // y coordinate scale - frag_info.tile_mode // tile mode - ); + vec4 src_color = IPSampleWithTileMode( + alpha_mask_sampler, // sampler + v_src_texture_coords, // texture coordinates + frag_info.alpha_mask_sampler_y_coord_scale, // y coordinate scale + frag_info.tile_mode // tile mode + ); float blur_factor = frag_info.inner_blur_factor * float(src_color.a > 0) + frag_info.outer_blur_factor * float(src_color.a == 0); From 3f7ccb24015b84eec79f5bc94f1ebb2e9d89f2f8 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 9 Aug 2022 14:32:32 -0700 Subject: [PATCH 208/558] Revert "Collect textures from toImageSync safely (#35073)" (#35281) This reverts commit 4ac52f2e48d2aafc20f338a1e6747db48c49a6fc. --- common/graphics/texture.cc | 30 ---- common/graphics/texture.h | 32 +--- flow/compositor_context.cc | 11 +- flow/compositor_context.h | 6 +- flow/layers/layer.h | 4 +- flow/layers/layer_tree.cc | 5 +- flow/layers/layer_tree_unittests.cc | 10 +- .../performance_overlay_layer_unittests.cc | 3 +- flow/layers/texture_layer.cc | 4 +- flow/layers/texture_layer_unittests.cc | 10 +- flow/raster_cache_unittests.cc | 116 ++++--------- flow/skia_gpu_object.h | 31 +--- flow/skia_gpu_object_unittests.cc | 1 - flow/testing/layer_test.h | 9 +- flow/testing/mock_raster_cache.cc | 54 +++--- flow/testing/mock_raster_cache.h | 11 +- lib/ui/BUILD.gn | 1 - .../display_list_deferred_image_gpu.cc | 159 +++--------------- .../display_list_deferred_image_gpu.h | 83 ++------- lib/ui/painting/image_encoding.cc | 96 ++++++----- lib/ui/painting/picture.cc | 25 ++- lib/ui/snapshot_delegate.h | 40 +---- shell/common/fixtures/shell_test.dart | 26 +-- shell/common/rasterizer.cc | 54 ++---- shell/common/rasterizer.h | 16 +- shell/common/shell.cc | 6 +- shell/common/shell_unittests.cc | 16 +- 27 files changed, 257 insertions(+), 602 deletions(-) diff --git a/common/graphics/texture.cc b/common/graphics/texture.cc index f12a5959fc088..c5ad5fdf29af8 100644 --- a/common/graphics/texture.cc +++ b/common/graphics/texture.cc @@ -6,10 +6,6 @@ namespace flutter { -ContextListener::ContextListener() = default; - -ContextListener::~ContextListener() = default; - Texture::Texture(int64_t id) : id_(id) {} Texture::~Texture() = default; @@ -23,12 +19,6 @@ void TextureRegistry::RegisterTexture(std::shared_ptr texture) { mapping_[texture->Id()] = texture; } -void TextureRegistry::RegisterContextListener( - uintptr_t id, - std::weak_ptr image) { - images_[id] = std::move(image); -} - void TextureRegistry::UnregisterTexture(int64_t id) { auto found = mapping_.find(id); if (found == mapping_.end()) { @@ -38,36 +28,16 @@ void TextureRegistry::UnregisterTexture(int64_t id) { mapping_.erase(found); } -void TextureRegistry::UnregisterContextListener(uintptr_t id) { - images_.erase(id); -} - void TextureRegistry::OnGrContextCreated() { for (auto& it : mapping_) { it.second->OnGrContextCreated(); } - - for (const auto& [id, weak_image] : images_) { - if (auto image = weak_image.lock()) { - image->OnGrContextCreated(); - } else { - images_.erase(id); - } - } } void TextureRegistry::OnGrContextDestroyed() { for (auto& it : mapping_) { it.second->OnGrContextDestroyed(); } - - for (const auto& [id, weak_image] : images_) { - if (auto image = weak_image.lock()) { - image->OnGrContextDestroyed(); - } else { - images_.erase(id); - } - } } std::shared_ptr TextureRegistry::GetTexture(int64_t id) { diff --git a/common/graphics/texture.h b/common/graphics/texture.h index 69cfa3ba0f9a4..57afa60a6361f 100644 --- a/common/graphics/texture.h +++ b/common/graphics/texture.h @@ -16,22 +16,7 @@ class GrDirectContext; namespace flutter { -class ContextListener { - public: - ContextListener(); - ~ContextListener(); - - // Called from raster thread. - virtual void OnGrContextCreated() = 0; - - // Called from raster thread. - virtual void OnGrContextDestroyed() = 0; - - private: - FML_DISALLOW_COPY_AND_ASSIGN(ContextListener); -}; - -class Texture : public ContextListener { +class Texture { public: explicit Texture(int64_t id); // Called from UI or raster thread. virtual ~Texture(); // Called from raster thread. @@ -44,6 +29,12 @@ class Texture : public ContextListener { const SkSamplingOptions& sampling, const SkPaint* paint = nullptr) = 0; + // Called from raster thread. + virtual void OnGrContextCreated() = 0; + + // Called from raster thread. + virtual void OnGrContextDestroyed() = 0; + // Called on raster thread. virtual void MarkNewFrameAvailable() = 0; @@ -54,6 +45,7 @@ class Texture : public ContextListener { private: int64_t id_; + FML_DISALLOW_COPY_AND_ASSIGN(Texture); }; @@ -64,16 +56,9 @@ class TextureRegistry { // Called from raster thread. void RegisterTexture(std::shared_ptr texture); - // Called from raster thread. - void RegisterContextListener(uintptr_t id, - std::weak_ptr image); - // Called from raster thread. void UnregisterTexture(int64_t id); - // Called from the raster thread. - void UnregisterContextListener(uintptr_t id); - // Called from raster thread. std::shared_ptr GetTexture(int64_t id); @@ -85,7 +70,6 @@ class TextureRegistry { private: std::map> mapping_; - std::map> images_; FML_DISALLOW_COPY_AND_ASSIGN(TextureRegistry); }; diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index 7013bc86ee374..779a42c84eb92 100644 --- a/flow/compositor_context.cc +++ b/flow/compositor_context.cc @@ -46,14 +46,11 @@ std::optional FrameDamage::ComputeClipRect( } CompositorContext::CompositorContext() - : texture_registry_(std::make_shared()), - raster_time_(fixed_refresh_rate_updater_), + : raster_time_(fixed_refresh_rate_updater_), ui_time_(fixed_refresh_rate_updater_) {} CompositorContext::CompositorContext(Stopwatch::RefreshRateUpdater& updater) - : texture_registry_(std::make_shared()), - raster_time_(updater), - ui_time_(updater) {} + : raster_time_(updater), ui_time_(updater) {} CompositorContext::~CompositorContext() = default; @@ -163,12 +160,12 @@ RasterStatus CompositorContext::ScopedFrame::Raster( } void CompositorContext::OnGrContextCreated() { - texture_registry_->OnGrContextCreated(); + texture_registry_.OnGrContextCreated(); raster_cache_.Clear(); } void CompositorContext::OnGrContextDestroyed() { - texture_registry_->OnGrContextDestroyed(); + texture_registry_.OnGrContextDestroyed(); raster_cache_.Clear(); } diff --git a/flow/compositor_context.h b/flow/compositor_context.h index f7667640caa71..0981cdd2538b1 100644 --- a/flow/compositor_context.h +++ b/flow/compositor_context.h @@ -175,9 +175,7 @@ class CompositorContext { RasterCache& raster_cache() { return raster_cache_; } - std::shared_ptr texture_registry() { - return texture_registry_; - } + TextureRegistry& texture_registry() { return texture_registry_; } const Stopwatch& raster_time() const { return raster_time_; } @@ -187,7 +185,7 @@ class CompositorContext { private: RasterCache raster_cache_; - std::shared_ptr texture_registry_; + TextureRegistry texture_registry_; Stopwatch raster_time_; Stopwatch ui_time_; LayerSnapshotStore layer_snapshot_store_; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 5cdd3e7db028c..a87642d2c8cff 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -57,7 +57,7 @@ struct PrerollContext { // These allow us to paint in the end of subtree Preroll. const Stopwatch& raster_time; const Stopwatch& ui_time; - std::shared_ptr texture_registry; + TextureRegistry& texture_registry; const bool checkerboard_offscreen_layers; const float frame_device_pixel_ratio = 1.0f; @@ -132,7 +132,7 @@ struct PaintContext { ExternalViewEmbedder* view_embedder; const Stopwatch& raster_time; const Stopwatch& ui_time; - std::shared_ptr texture_registry; + TextureRegistry& texture_registry; const RasterCache* raster_cache; const bool checkerboard_offscreen_layers; const float frame_device_pixel_ratio = 1.0f; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 0fafe40f62861..53748a42832b7 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -167,6 +167,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { MutatorsStack unused_stack; const FixedRefreshRateStopwatch unused_stopwatch; + TextureRegistry unused_texture_registry; SkMatrix root_surface_transformation; // No root surface transformation. So assume identity. root_surface_transformation.reset(); @@ -182,7 +183,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .surface_needs_readback = false, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = nullptr, + .texture_registry = unused_texture_registry, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_ // clang-format on @@ -201,7 +202,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .view_embedder = nullptr, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = nullptr, + .texture_registry = unused_texture_registry, .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_, diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc index a8decd5fc0846..63de819e15808 100644 --- a/flow/layers/layer_tree_unittests.cc +++ b/flow/layers/layer_tree_unittests.cc @@ -204,7 +204,7 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { MutatorsStack mock_mutators; FixedRefreshRateStopwatch mock_raster_time; FixedRefreshRateStopwatch mock_ui_time; - std::shared_ptr mock_registry; + TextureRegistry mock_registry; auto expect_defaults = [&mock_mutators, &mock_raster_time, &mock_ui_time, &mock_registry](const PrerollContext& context) { @@ -218,7 +218,7 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { EXPECT_EQ(&context.raster_time, &mock_raster_time); EXPECT_EQ(&context.ui_time, &mock_ui_time); - EXPECT_EQ(context.texture_registry.get(), mock_registry.get()); + EXPECT_EQ(&context.texture_registry, &mock_registry); EXPECT_EQ(context.checkerboard_offscreen_layers, false); EXPECT_EQ(context.frame_device_pixel_ratio, 1.0f); @@ -244,11 +244,11 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { // PaintContext that this test must be revisited and updated. // If any fields get removed or replaced, then the expect_defaults closure // will fail to compile, again bringing attention to updating this test. - EXPECT_EQ(sizeof(PaintContext), size_t(112)); + EXPECT_EQ(sizeof(PaintContext), size_t(104)); FixedRefreshRateStopwatch mock_raster_time; FixedRefreshRateStopwatch mock_ui_time; - std::shared_ptr mock_registry; + TextureRegistry mock_registry; auto expect_defaults = [&mock_raster_time, &mock_ui_time, &mock_registry](const PaintContext& context) { @@ -258,7 +258,7 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { EXPECT_EQ(context.view_embedder, nullptr); EXPECT_EQ(&context.raster_time, &mock_raster_time); EXPECT_EQ(&context.ui_time, &mock_ui_time); - EXPECT_EQ(context.texture_registry.get(), mock_registry.get()); + EXPECT_EQ(&context.texture_registry, &mock_registry); EXPECT_EQ(context.raster_cache, nullptr); EXPECT_EQ(context.checkerboard_offscreen_layers, false); EXPECT_EQ(context.frame_device_pixel_ratio, 1.0f); diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc index f7c20d24d2900..ae9eec8b767e4 100644 --- a/flow/layers/performance_overlay_layer_unittests.cc +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -58,6 +58,7 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { ASSERT_TRUE(surface != nullptr); + flutter::TextureRegistry unused_texture_registry; flutter::PaintContext paintContext = { // clang-format off .internal_nodes_canvas = nullptr, @@ -66,7 +67,7 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { .view_embedder = nullptr, .raster_time = mock_stopwatch, .ui_time = mock_stopwatch, - .texture_registry = nullptr, + .texture_registry = unused_texture_registry, .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index 7ece96ebd4364..fa760fe786e83 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -54,9 +54,7 @@ void TextureLayer::Paint(PaintContext& context) const { FML_DCHECK(needs_painting(context)); std::shared_ptr texture = - context.texture_registry - ? context.texture_registry->GetTexture(texture_id_) - : nullptr; + context.texture_registry.GetTexture(texture_id_); if (!texture) { TRACE_EVENT_INSTANT0("flutter", "null texture"); return; diff --git a/flow/layers/texture_layer_unittests.cc b/flow/layers/texture_layer_unittests.cc index 7d45d1d54e825..94e5469db702b 100644 --- a/flow/layers/texture_layer_unittests.cc +++ b/flow/layers/texture_layer_unittests.cc @@ -43,7 +43,7 @@ TEST_F(TextureLayerTest, PaintingEmptyLayerDies) { false, DlImageSampling::kNearestNeighbor); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry->RegisterTexture(mock_texture); + preroll_context()->texture_registry.RegisterTexture(mock_texture); layer->Preroll(preroll_context(), SkMatrix()); EXPECT_EQ(layer->paint_bounds(), kEmptyRect); @@ -62,7 +62,7 @@ TEST_F(TextureLayerTest, PaintBeforePrerollDies) { layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry->RegisterTexture(mock_texture); + preroll_context()->texture_registry.RegisterTexture(mock_texture); EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), "needs_painting\\(context\\)"); @@ -78,7 +78,7 @@ TEST_F(TextureLayerTest, PaintingWithLinearSampling) { layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry->RegisterTexture(mock_texture); + preroll_context()->texture_registry.RegisterTexture(mock_texture); layer->Preroll(preroll_context(), SkMatrix()); EXPECT_EQ(layer->paint_bounds(), @@ -124,12 +124,12 @@ TEST_F(TextureLayerTest, OpacityInheritance) { layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry->RegisterTexture(mock_texture); + preroll_context()->texture_registry.RegisterTexture(mock_texture); // The texture layer always reports opacity compatibility. PrerollContext* context = preroll_context(); context->subtree_can_inherit_opacity = false; - context->texture_registry->RegisterTexture(mock_texture); + context->texture_registry.RegisterTexture(mock_texture); layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(context->subtree_can_inherit_opacity); diff --git a/flow/raster_cache_unittests.cc b/flow/raster_cache_unittests.cc index afd00392afa1d..a27b9e45cdfde 100644 --- a/flow/raster_cache_unittests.cc +++ b/flow/raster_cache_unittests.cc @@ -38,13 +38,9 @@ TEST(RasterCache, MetricsOmitUnpopulatedEntries) { SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -94,13 +90,9 @@ TEST(RasterCache, ThresholdIsRespectedForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -138,10 +130,7 @@ TEST(RasterCache, SetCheckboardCacheImages) { SkMatrix matrix = SkMatrix::I(); auto display_list = GetSampleDisplayList(); - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& paint_context = paint_context_holder.paint_context; auto dummy_draw_function = [](SkCanvas* canvas) {}; bool did_draw_checkerboard = false; @@ -174,17 +163,14 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForSkPicture) { SkMatrix matrix = SkMatrix::I(); auto display_list = GetSampleDisplayList(); + ; SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -207,13 +193,9 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -238,13 +220,9 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForSkPicture) { SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -274,13 +252,9 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -314,13 +288,9 @@ TEST(RasterCache, EvitUnusedCacheEntries) { SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -424,13 +394,9 @@ TEST(RasterCache, DeviceRectRoundOutForDisplayList) { SkCanvas canvas(100, 100, nullptr); canvas.setMatrix(ctm); - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -467,13 +433,9 @@ TEST(RasterCache, NestedOpCountMetricUsedForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -514,13 +476,9 @@ TEST(RasterCache, NaiveComplexityScoringDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -580,13 +538,9 @@ TEST(RasterCache, DisplayListWithSingularMatrixIsNotCached) { SkCanvas dummy_canvas; SkPaint paint; - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( - &cache, &raster_time, &ui_time, &mutators_stack); - PaintContextHolder paint_context_holder = - GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); + PrerollContextHolder preroll_context_holder = + GetSamplePrerollContextHolder(&cache); + PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; diff --git a/flow/skia_gpu_object.h b/flow/skia_gpu_object.h index 16251ec56f823..e694ef7ffcc2a 100644 --- a/flow/skia_gpu_object.h +++ b/flow/skia_gpu_object.h @@ -34,16 +34,6 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { } } - void DeleteTexture(GrBackendTexture texture) { - std::scoped_lock lock(mutex_); - textures_.push_back(texture); - if (!drain_pending_) { - drain_pending_ = true; - task_runner_->PostDelayedTask( - [strong = fml::Ref(this)]() { strong->Drain(); }, drain_delay_); - } - } - // Usually, the drain is called automatically. However, during IO manager // shutdown (when the platform side reference to the OpenGL context is about // to go away), we may need to pre-emptively drain the unref queue. It is the @@ -52,14 +42,12 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { void Drain() { TRACE_EVENT0("flutter", "SkiaUnrefQueue::Drain"); std::deque skia_objects; - std::deque textures; { std::scoped_lock lock(mutex_); objects_.swap(skia_objects); - textures_.swap(textures); drain_pending_ = false; } - DoDrain(skia_objects, textures, context_); + DoDrain(skia_objects, context_); } void UpdateResourceContext(sk_sp context) { @@ -71,7 +59,6 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { const fml::TimeDelta drain_delay_; std::mutex mutex_; std::deque objects_; - std::deque textures_; bool drain_pending_; sk_sp context_; @@ -92,30 +79,22 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { // into a task queued to that thread. ResourceContext* raw_context = context_.release(); fml::TaskRunner::RunNowOrPostTask( - task_runner_, [objects = std::move(objects_), - textures = std::move(textures_), raw_context]() mutable { + task_runner_, [objects = std::move(objects_), raw_context]() mutable { sk_sp context(raw_context); - DoDrain(objects, textures, context); + DoDrain(objects, context); context.reset(); }); } // static static void DoDrain(const std::deque& skia_objects, - const std::deque& textures, sk_sp context) { for (SkRefCnt* skia_object : skia_objects) { skia_object->unref(); } - if (context) { - for (GrBackendTexture texture : textures) { - context->deleteBackendTexture(texture); - } - - if (!skia_objects.empty()) { - context->performDeferredCleanup(std::chrono::milliseconds(0)); - } + if (context && !skia_objects.empty()) { + context->performDeferredCleanup(std::chrono::milliseconds(0)); } } diff --git a/flow/skia_gpu_object_unittests.cc b/flow/skia_gpu_object_unittests.cc index 4b631fa6fb433..61127256393a3 100644 --- a/flow/skia_gpu_object_unittests.cc +++ b/flow/skia_gpu_object_unittests.cc @@ -41,7 +41,6 @@ class TestResourceContext : public TestSkObject { : TestSkObject(latch, dtor_task_queue_id) {} ~TestResourceContext() = default; void performDeferredCleanup(std::chrono::milliseconds msNotUsed) {} - void deleteBackendTexture(GrBackendTexture texture) {} }; class SkiaGpuObjectTest : public ThreadTest { diff --git a/flow/testing/layer_test.h b/flow/testing/layer_test.h index 317c7109dc8dc..e5672e1eacdd1 100644 --- a/flow/testing/layer_test.h +++ b/flow/testing/layer_test.h @@ -44,8 +44,7 @@ class LayerTestBase : public CanvasTestBase { public: LayerTestBase() - : texture_registry_(std::make_shared()), - preroll_context_{ + : preroll_context_{ // clang-format off .raster_cache = nullptr, .gr_context = nullptr, @@ -163,9 +162,7 @@ class LayerTestBase : public CanvasTestBase { std::vector& cacheable_items() { return cacheable_items_; } - std::shared_ptr texture_registry() { - return texture_registry_; - } + TextureRegistry& texture_regitry() { return texture_registry_; } RasterCache* raster_cache() { return raster_cache_.get(); } PrerollContext* preroll_context() { return &preroll_context_; } PaintContext& paint_context() { return paint_context_; } @@ -208,7 +205,7 @@ class LayerTestBase : public CanvasTestBase { FixedRefreshRateStopwatch raster_time_; FixedRefreshRateStopwatch ui_time_; MutatorsStack mutators_stack_; - std::shared_ptr texture_registry_; + TextureRegistry texture_registry_; std::unique_ptr raster_cache_; PrerollContext preroll_context_; diff --git a/flow/testing/mock_raster_cache.cc b/flow/testing/mock_raster_cache.cc index 33b81c15030b3..3ce1be25cfcd8 100644 --- a/flow/testing/mock_raster_cache.cc +++ b/flow/testing/mock_raster_cache.cc @@ -56,10 +56,7 @@ void MockRasterCache::AddMockPicture(int width, int height) { recorder.drawPath(path, SkPaint()); sk_sp display_list = recorder.Build(); - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - PaintContextHolder holder = - GetSamplePaintContextHolder(this, &raster_time, &ui_time); + PaintContextHolder holder = GetSamplePaintContextHolder(this); holder.paint_context.dst_color_space = color_space_; DisplayListRasterCacheItem display_list_item(display_list.get(), SkPoint(), @@ -84,31 +81,31 @@ void MockRasterCache::AddMockPicture(int width, int height) { }); } -PrerollContextHolder GetSamplePrerollContextHolder( - RasterCache* raster_cache, - FixedRefreshRateStopwatch* raster_time, - FixedRefreshRateStopwatch* ui_time, - MutatorsStack* mutators_stack) { +PrerollContextHolder GetSamplePrerollContextHolder(RasterCache* raster_cache) { + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + TextureRegistry texture_registry; sk_sp srgb = SkColorSpace::MakeSRGB(); PrerollContextHolder holder = { { // clang-format off .raster_cache = raster_cache, - .gr_context = nullptr, - .view_embedder = nullptr, - .mutators_stack = *mutators_stack, - .dst_color_space = srgb.get(), - .cull_rect = kGiantRect, + .gr_context = nullptr, + .view_embedder = nullptr, + .mutators_stack = mutators_stack, + .dst_color_space = srgb.get(), + .cull_rect = kGiantRect, .surface_needs_readback = false, - .raster_time = *raster_time, - .ui_time = *ui_time, - .texture_registry = nullptr, - .checkerboard_offscreen_layers = false, - .frame_device_pixel_ratio = 1.0f, - .has_platform_view = false, + .raster_time = raster_time, + .ui_time = ui_time, + .texture_registry = texture_registry, + .checkerboard_offscreen_layers = false, + .frame_device_pixel_ratio = 1.0f, + .has_platform_view = false, .has_texture_layer = false, - .raster_cached_entries = &raster_cache_items_, + .raster_cached_entries = &raster_cache_items_, // clang-format on }, srgb}; @@ -116,10 +113,11 @@ PrerollContextHolder GetSamplePrerollContextHolder( return holder; } -PaintContextHolder GetSamplePaintContextHolder( - RasterCache* raster_cache, - FixedRefreshRateStopwatch* raster_time, - FixedRefreshRateStopwatch* ui_time) { +PaintContextHolder GetSamplePaintContextHolder(RasterCache* raster_cache) { + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + TextureRegistry texture_registry; sk_sp srgb = SkColorSpace::MakeSRGB(); PaintContextHolder holder = {// clang-format off { @@ -128,9 +126,9 @@ PaintContextHolder GetSamplePaintContextHolder( .gr_context = nullptr, .dst_color_space = srgb.get(), .view_embedder = nullptr, - .raster_time = *raster_time, - .ui_time = *ui_time, - .texture_registry = nullptr, + .raster_time = raster_time, + .ui_time = ui_time, + .texture_registry = texture_registry, .raster_cache = raster_cache, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, diff --git a/flow/testing/mock_raster_cache.h b/flow/testing/mock_raster_cache.h index 37742486409bb..d6b385b57d389 100644 --- a/flow/testing/mock_raster_cache.h +++ b/flow/testing/mock_raster_cache.h @@ -72,7 +72,7 @@ class MockRasterCache : public RasterCache { MutatorsStack mutators_stack_; FixedRefreshRateStopwatch raster_time_; FixedRefreshRateStopwatch ui_time_; - std::shared_ptr texture_registry_; + TextureRegistry texture_registry_; PrerollContext preroll_context_ = { // clang-format off .raster_cache = this, @@ -122,15 +122,10 @@ struct PaintContextHolder { }; PrerollContextHolder GetSamplePrerollContextHolder( - RasterCache* raster_cache, - FixedRefreshRateStopwatch* raster_time, - FixedRefreshRateStopwatch* ui_time, - MutatorsStack* mutators_stack); + RasterCache* raster_cache = nullptr); PaintContextHolder GetSamplePaintContextHolder( - RasterCache* raster_cache, - FixedRefreshRateStopwatch* raster_time, - FixedRefreshRateStopwatch* ui_time); + RasterCache* raster_cache = nullptr); bool RasterCacheItemPrerollAndTryToRasterCache( DisplayListRasterCacheItem& display_list_item, diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 6a2916d9cb622..5be9029295f03 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -146,7 +146,6 @@ source_set("ui") { deps = [ "//flutter/assets", "//flutter/common", - "//flutter/common/graphics", "//flutter/display_list", "//flutter/fml", "//flutter/impeller/runtime_stage", diff --git a/lib/ui/painting/display_list_deferred_image_gpu.cc b/lib/ui/painting/display_list_deferred_image_gpu.cc index 4580fe9801e2c..3868cf1f06c0f 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.cc +++ b/lib/ui/painting/display_list_deferred_image_gpu.cc @@ -4,45 +4,20 @@ #include "flutter/lib/ui/painting/display_list_deferred_image_gpu.h" -#include "display_list_deferred_image_gpu.h" -#include "third_party/skia/include/core/SkColorSpace.h" - namespace flutter { -sk_sp DlDeferredImageGPU::Make( - const SkImageInfo& image_info, - sk_sp display_list, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue) { - return sk_sp(new DlDeferredImageGPU( - ImageWrapper::Make(image_info, std::move(display_list), - std::move(snapshot_delegate), raster_task_runner, - std::move(unref_queue)), - raster_task_runner)); +sk_sp DlDeferredImageGPU::Make(SkISize size) { + return sk_sp(new DlDeferredImageGPU(size)); } -DlDeferredImageGPU::DlDeferredImageGPU( - std::shared_ptr image_wrapper, - fml::RefPtr raster_task_runner) - : image_wrapper_(std::move(image_wrapper)), - raster_task_runner_(std::move(raster_task_runner)) {} +DlDeferredImageGPU::DlDeferredImageGPU(SkISize size) : size_(size) {} // |DlImage| -DlDeferredImageGPU::~DlDeferredImageGPU() { - fml::TaskRunner::RunNowOrPostTask( - raster_task_runner_, [image_wrapper = std::move(image_wrapper_)]() { - if (!image_wrapper) { - return; - } - image_wrapper->Unregister(); - image_wrapper->DeleteTexture(); - }); -} +DlDeferredImageGPU::~DlDeferredImageGPU() = default; // |DlImage| sk_sp DlDeferredImageGPU::skia_image() const { - return image_wrapper_ ? image_wrapper_->CreateSkiaImage() : nullptr; + return image_; }; // |DlImage| @@ -53,127 +28,43 @@ std::shared_ptr DlDeferredImageGPU::impeller_texture() // |DlImage| bool DlDeferredImageGPU::isTextureBacked() const { - return image_wrapper_ ? image_wrapper_->isTextureBacked() : false; + if (auto image = skia_image()) { + return image->isTextureBacked(); + } + return false; } // |DlImage| SkISize DlDeferredImageGPU::dimensions() const { - return image_wrapper_ ? image_wrapper_->image_info().dimensions() - : SkISize::MakeEmpty(); + return size_; } // |DlImage| size_t DlDeferredImageGPU::GetApproximateByteSize() const { - return sizeof(this) + (image_wrapper_ - ? image_wrapper_->image_info().computeMinByteSize() - : 0); -} - -std::optional DlDeferredImageGPU::get_error() const { - return image_wrapper_ ? image_wrapper_->get_error() : std::nullopt; -} - -std::shared_ptr -DlDeferredImageGPU::ImageWrapper::Make( - const SkImageInfo& image_info, - sk_sp display_list, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue) { - auto wrapper = std::shared_ptr(new ImageWrapper( - image_info, std::move(display_list), std::move(snapshot_delegate), - std::move(raster_task_runner), std::move(unref_queue))); - wrapper->SnapshotDisplayList(); - return wrapper; -} - -DlDeferredImageGPU::ImageWrapper::ImageWrapper( - const SkImageInfo& image_info, - sk_sp display_list, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue) - : image_info_(image_info), - display_list_(std::move(display_list)), - snapshot_delegate_(std::move(snapshot_delegate)), - raster_task_runner_(std::move(raster_task_runner)), - unref_queue_(std::move(unref_queue)) {} - -void DlDeferredImageGPU::ImageWrapper::OnGrContextCreated() { - FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); - SnapshotDisplayList(); -} - -void DlDeferredImageGPU::ImageWrapper::OnGrContextDestroyed() { - FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); - - DeleteTexture(); -} - -sk_sp DlDeferredImageGPU::ImageWrapper::CreateSkiaImage() const { - FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); - - if (texture_.isValid() && context_) { - return SkImage::MakeFromTexture( - context_.get(), texture_, kTopLeft_GrSurfaceOrigin, - image_info_.colorType(), image_info_.alphaType(), - image_info_.refColorSpace()); + // This call is accessed on the UI thread, and image_ may not be available + // yet. The image is not mipmapped and it's created using N32 pixels, so this + // is safe. + if (size_.isEmpty()) { + return sizeof(this); } - return image_; + return sizeof(this) + size_.width() * size_.height() * 4; } -bool DlDeferredImageGPU::ImageWrapper::isTextureBacked() const { - return texture_.isValid(); +void DlDeferredImageGPU::set_image(sk_sp image) { + FML_DCHECK(image); + FML_DCHECK(image->dimensions() == size_); + image_ = std::move(image); } -void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { - fml::TaskRunner::RunNowOrPostTask( - raster_task_runner_, [weak_this = weak_from_this()]() { - auto wrapper = weak_this.lock(); - if (!wrapper) { - return; - } - auto snapshot_delegate = wrapper->snapshot_delegate_; - if (!snapshot_delegate) { - return; - } - auto result = snapshot_delegate->MakeGpuImage(wrapper->display_list_, - wrapper->image_info_); - if (result->texture.isValid()) { - wrapper->texture_ = result->texture; - wrapper->context_ = std::move(result->context); - wrapper->texture_registry_ = - wrapper->snapshot_delegate_->GetTextureRegistry(); - wrapper->texture_registry_->RegisterContextListener( - reinterpret_cast(wrapper.get()), weak_this); - } else if (result->image) { - wrapper->image_ = std::move(result->image); - } else { - std::scoped_lock lock(wrapper->error_mutex_); - wrapper->error_ = std::move(result->error); - } - }); +void DlDeferredImageGPU::set_error(const std::string& error) { + FML_DCHECK(!image_); + std::scoped_lock lock(error_mutex_); + error_ = std::move(error); } -std::optional DlDeferredImageGPU::ImageWrapper::get_error() { +std::optional DlDeferredImageGPU::get_error() const { std::scoped_lock lock(error_mutex_); return error_; } -void DlDeferredImageGPU::ImageWrapper::Unregister() { - if (texture_registry_) { - texture_registry_->UnregisterContextListener( - reinterpret_cast(this)); - } -} - -void DlDeferredImageGPU::ImageWrapper::DeleteTexture() { - if (texture_.isValid()) { - unref_queue_->DeleteTexture(std::move(texture_)); - texture_ = GrBackendTexture(); - } - image_.reset(); - context_.reset(); -} - } // namespace flutter diff --git a/lib/ui/painting/display_list_deferred_image_gpu.h b/lib/ui/painting/display_list_deferred_image_gpu.h index a98f4feaa4236..0cec807fe7a99 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.h +++ b/lib/ui/painting/display_list_deferred_image_gpu.h @@ -5,37 +5,23 @@ #ifndef FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_DEFERRED_IMAGE_GPU_H_ #define FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_DEFERRED_IMAGE_GPU_H_ -#include #include -#include "flutter/common/graphics/texture.h" -#include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_image.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/fml/macros.h" -#include "flutter/fml/memory/weak_ptr.h" -#include "flutter/lib/ui/io_manager.h" -#include "flutter/lib/ui/snapshot_delegate.h" namespace flutter { class DlDeferredImageGPU final : public DlImage { public: - static sk_sp Make( - const SkImageInfo& image_info, - sk_sp display_list, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue); + static sk_sp Make(SkISize size); // |DlImage| ~DlDeferredImageGPU() override; // |DlImage| // This method is only safe to call from the raster thread. - // Callers must not hold long term references to this image and - // only use it for the immediate painting operation. It must be - // collected on the raster task runner. sk_sp skia_image() const override; // |DlImage| @@ -50,6 +36,12 @@ class DlDeferredImageGPU final : public DlImage { // |DlImage| virtual size_t GetApproximateByteSize() const override; + // This method must only be called from the raster thread. + void set_image(sk_sp image); + + // This method is safe to call from any thread. + void set_error(const std::string& error); + // |DlImage| // This method is safe to call from any thread. std::optional get_error() const override; @@ -60,61 +52,12 @@ class DlDeferredImageGPU final : public DlImage { } private: - class ImageWrapper final : public std::enable_shared_from_this, - public ContextListener { - public: - static std::shared_ptr Make( - const SkImageInfo& image_info, - sk_sp display_list, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue); - - const SkImageInfo image_info() const { return image_info_; } - const GrBackendTexture& texture() const { return texture_; } - bool isTextureBacked() const; - std::optional get_error(); - sk_sp CreateSkiaImage() const; - void Unregister(); - void DeleteTexture(); - - private: - const SkImageInfo image_info_; - sk_sp display_list_; - fml::WeakPtr snapshot_delegate_; - fml::RefPtr raster_task_runner_; - fml::RefPtr unref_queue_; - std::shared_ptr texture_registry_; - - mutable std::mutex error_mutex_; - std::optional error_; - - GrBackendTexture texture_; - sk_sp context_; - // May be used if this image is not texture backed. - sk_sp image_; - - ImageWrapper(const SkImageInfo& image_info, - sk_sp display_list, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue); - - void SnapshotDisplayList(); - - // |ContextListener| - void OnGrContextCreated() override; - - // |ContextListener| - void OnGrContextDestroyed() override; - }; - - const std::shared_ptr image_wrapper_; - - fml::RefPtr raster_task_runner_; - - DlDeferredImageGPU(std::shared_ptr image_wrapper, - fml::RefPtr raster_task_runner); + sk_sp image_; + SkISize size_; + mutable std::mutex error_mutex_; + std::optional error_; + + explicit DlDeferredImageGPU(SkISize size); FML_DISALLOW_COPY_AND_ASSIGN(DlDeferredImageGPU); }; diff --git a/lib/ui/painting/image_encoding.cc b/lib/ui/painting/image_encoding.cc index 1e28774932910..993e7d44a6826 100644 --- a/lib/ui/painting/image_encoding.cc +++ b/lib/ui/painting/image_encoding.cc @@ -60,6 +60,21 @@ void InvokeDataCallback(std::unique_ptr callback, DartInvoke(callback->value(), {dart_data}); } +static void ConvertGpuImageToRaster( + sk_sp dl_image, + std::function)> encode_task, + fml::RefPtr raster_task_runner) { + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner, [dl_image, encode_task = std::move(encode_task)]() { + auto image = dl_image->skia_image(); + if (image == nullptr) { + encode_task(nullptr); + return; + } + encode_task(image->makeRasterImage()); + }); +} + void ConvertImageToRaster( sk_sp dl_image, std::function)> encode_task, @@ -68,48 +83,43 @@ void ConvertImageToRaster( fml::WeakPtr resource_context, fml::WeakPtr snapshot_delegate, const std::shared_ptr& is_gpu_disabled_sync_switch) { - // If the owning_context is kRaster, we can't access it on this task runner. - if (dl_image->owning_context() != DlImage::OwningContext::kRaster) { - auto image = dl_image->skia_image(); - - // Check validity of the image. - if (image == nullptr) { - FML_LOG(ERROR) << "Image was null."; - encode_task(nullptr); - return; - } + auto image = dl_image->skia_image(); - auto dimensions = image->dimensions(); + // Check validity of the image. + if (image == nullptr) { + FML_LOG(ERROR) << "Image was null."; + encode_task(nullptr); + return; + } - if (dimensions.isEmpty()) { - FML_LOG(ERROR) << "Image dimensions were empty."; - encode_task(nullptr); - return; - } + auto dimensions = image->dimensions(); - SkPixmap pixmap; - if (image->peekPixels(&pixmap)) { - // This is already a raster image. - encode_task(image); - return; - } + if (dimensions.isEmpty()) { + FML_LOG(ERROR) << "Image dimensions were empty."; + encode_task(nullptr); + return; + } - if (sk_sp raster_image = image->makeRasterImage()) { - // The image can be converted to a raster image. - encode_task(raster_image); - return; - } + SkPixmap pixmap; + if (image->peekPixels(&pixmap)) { + // This is already a raster image. + encode_task(image); + return; + } + + if (sk_sp raster_image = image->makeRasterImage()) { + // The image can be converted to a raster image. + encode_task(raster_image); + return; } // Cross-context images do not support makeRasterImage. Convert these images // by drawing them into a surface. This must be done on the raster thread // to prevent concurrent usage of the image on both the IO and raster threads. - raster_task_runner->PostTask([dl_image, encode_task = std::move(encode_task), + raster_task_runner->PostTask([image, encode_task = std::move(encode_task), resource_context, snapshot_delegate, - io_task_runner, is_gpu_disabled_sync_switch, - raster_task_runner]() { - auto image = dl_image->skia_image(); - if (!image || !snapshot_delegate) { + io_task_runner, is_gpu_disabled_sync_switch]() { + if (!snapshot_delegate) { io_task_runner->PostTask( [encode_task = std::move(encode_task)]() mutable { encode_task(nullptr); @@ -122,9 +132,8 @@ void ConvertImageToRaster( io_task_runner->PostTask([image, encode_task = std::move(encode_task), raster_image = std::move(raster_image), - resource_context, is_gpu_disabled_sync_switch, - owning_context = dl_image->owning_context(), - raster_task_runner]() mutable { + resource_context, + is_gpu_disabled_sync_switch]() mutable { if (!raster_image) { // The rasterizer was unable to render the cross-context image // (presumably because it does not have a GrContext). In that case, @@ -133,9 +142,6 @@ void ConvertImageToRaster( image, resource_context, is_gpu_disabled_sync_switch); } encode_task(raster_image); - if (owning_context == DlImage::OwningContext::kRaster) { - raster_task_runner->PostTask([image = std::move(image)]() {}); - } }); }); } @@ -240,9 +246,17 @@ void EncodeImageAndInvokeDataCallback( }; FML_DCHECK(image); - ConvertImageToRaster(std::move(image), encode_task, raster_task_runner, - io_task_runner, resource_context, snapshot_delegate, - is_gpu_disabled_sync_switch); + switch (image->owning_context()) { + case DlImage::OwningContext::kRaster: + ConvertGpuImageToRaster(std::move(image), encode_task, + raster_task_runner); + break; + case DlImage::OwningContext::kIO: + ConvertImageToRaster(std::move(image), encode_task, raster_task_runner, + io_task_runner, resource_context, snapshot_delegate, + is_gpu_disabled_sync_switch); + break; + } } } // namespace diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index dd64f1b2d7696..c868101ef18cb 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -59,20 +59,29 @@ void Picture::RasterizeToImageSync(sk_sp display_list, uint32_t height, Dart_Handle raw_image_handle) { auto* dart_state = UIDartState::Current(); - if (!dart_state) { - return; - } auto unref_queue = dart_state->GetSkiaUnrefQueue(); auto snapshot_delegate = dart_state->GetSnapshotDelegate(); auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); auto image = CanvasImage::Create(); - const SkImageInfo image_info = SkImageInfo::Make( - width, height, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); - auto dl_image = DlDeferredImageGPU::Make( - image_info, std::move(display_list), std::move(snapshot_delegate), - std::move(raster_task_runner), std::move(unref_queue)); + auto dl_image = DlDeferredImageGPU::Make(SkISize::Make(width, height)); image->set_image(dl_image); + + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner, + [snapshot_delegate, unref_queue, dl_image = std::move(dl_image), + display_list = std::move(display_list)]() { + sk_sp sk_image; + std::string error; + std::tie(sk_image, error) = snapshot_delegate->MakeGpuImage( + display_list, dl_image->dimensions()); + if (sk_image) { + dl_image->set_image(std::move(sk_image)); + } else { + dl_image->set_error(std::move(error)); + } + }); + image->AssociateWithDartWrapper(raw_image_handle); } diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 4158d28701cbb..7c87a01c865d9 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -7,54 +7,18 @@ #include -#include "flutter/common/graphics/texture.h" #include "flutter/display_list/display_list.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkPromiseImageTexture.h" #include "third_party/skia/include/gpu/GrContextThreadSafeProxy.h" - namespace flutter { class SnapshotDelegate { public: - struct GpuImageResult { - GpuImageResult(const GrBackendTexture& p_texture, - sk_sp p_context, - sk_sp p_image = nullptr, - const std::string& p_error = "") - : texture(p_texture), - context(std::move(p_context)), - image(std::move(p_image)), - error(p_error) {} - - const GrBackendTexture texture; - // If texture.isValid() == true, this is a pointer to a GrDirectContext that - // can be used to create an image from the texture. - sk_sp context; - // If MakeGpuImage could not create a GPU resident image, a raster copy - // is available in this member and texture.isValid() is false. - sk_sp image; - - // A non-empty string containing an error message if neither a GPU backed - // texture nor a raster backed image could be created. - const std::string error; - }; - - //---------------------------------------------------------------------------- - /// @brief Gets the registry of external textures currently in use by the - /// rasterizer. These textures may be updated at a cadence - /// different from that of the Flutter application. When an - /// external texture is referenced in the Flutter layer tree, that - /// texture is composited within the Flutter layer tree. - /// - /// @return A pointer to the external texture registry. - /// - virtual std::shared_ptr GetTextureRegistry() = 0; - - virtual std::unique_ptr MakeGpuImage( + virtual std::pair, std::string> MakeGpuImage( sk_sp display_list, - const SkImageInfo& image_info) = 0; + SkISize picture_size) = 0; virtual sk_sp MakeRasterSnapshot( std::function draw_callback, diff --git a/shell/common/fixtures/shell_test.dart b/shell/common/fixtures/shell_test.dart index a41715add9a68..b8908bdd24563 100644 --- a/shell/common/fixtures/shell_test.dart +++ b/shell/common/fixtures/shell_test.dart @@ -339,28 +339,8 @@ Future toImageSync() async { expect(image.width, 20); expect(image.height, 25); - final ByteData dataBefore = (await image.toByteData())!; - expect(dataBefore.lengthInBytes, 20 * 25 * 4); - for (final int byte in dataBefore.buffer.asUint32List()) { - expect(byte, 0xFFAAAAAA); - } - - // Cause the rasterizer to get torn down. - notifyNative(); - - final ByteData dataAfter = (await image.toByteData())!; - expect(dataAfter.lengthInBytes, 20 * 25 * 4); - for (final int byte in dataAfter.buffer.asUint32List()) { - expect(byte, 0xFFAAAAAA); - } - - // Verify that the image can be drawn successfully. - final PictureRecorder recorder2 = PictureRecorder(); - final Canvas canvas2 = Canvas(recorder2); - canvas2.drawImage(image, Offset.zero, Paint()); - final Picture picture2 = recorder2.endRecording(); - - picture.dispose(); - picture2.dispose(); + final ByteData data = (await image.toByteData())!; + expect(data.lengthInBytes, 20 * 25 * 4); + expect(data.buffer.asUint32List().every((int byte) => byte == 0xFFAAAAAA), true); notifyNative(); } diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index d3ecb11fee8ec..db5ef54055cc8 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -141,8 +141,8 @@ void Rasterizer::NotifyLowMemoryWarning() const { context->performDeferredCleanup(std::chrono::milliseconds(0)); } -std::shared_ptr Rasterizer::GetTextureRegistry() { - return compositor_context_->texture_registry(); +flutter::TextureRegistry* Rasterizer::GetTextureRegistry() { + return &compositor_context_->texture_registry(); } flutter::LayerTree* Rasterizer::GetLastLayerTree() { @@ -248,7 +248,7 @@ bool Rasterizer::ShouldResubmitFrame(const RasterStatus& raster_status) { } namespace { -std::unique_ptr MakeBitmapImage( +std::pair, std::string> MakeBitmapImage( sk_sp display_list, const SkImageInfo& image_info) { FML_DCHECK(display_list); @@ -258,10 +258,8 @@ std::unique_ptr MakeBitmapImage( // This limit is taken from the Metal specification. D3D, Vulkan, and GL // generally have lower limits. if (image_info.width() > 16384 || image_info.height() > 16384) { - return std::make_unique( - GrBackendTexture(), nullptr, nullptr, - "unable to create render target at specified size"); - }; + return {nullptr, "unable to create render target at specified size"}; + } sk_sp surface = SkSurface::MakeRaster(image_info); SkCanvas* canvas = surface->getCanvas(); @@ -269,26 +267,18 @@ std::unique_ptr MakeBitmapImage( display_list->RenderTo(canvas); sk_sp image = surface->makeImageSnapshot(); - return std::make_unique( - GrBackendTexture(), nullptr, image, - image ? "" : "Unable to create image"); + return {image, image ? "" : "Unable to create image"}; } } // namespace -std::unique_ptr Rasterizer::MakeGpuImage( +std::pair, std::string> Rasterizer::MakeGpuImage( sk_sp display_list, - const SkImageInfo& image_info) { + SkISize picture_size) { TRACE_EVENT0("flutter", "Rasterizer::MakeGpuImage"); FML_DCHECK(display_list); -// TODO(dnfield): the Linux embedding is in a rough state right now and -// I can't seem to get the GPU path working on it. -// https://github.com/flutter/flutter/issues/108835 -#if FML_OS_LINUX - return MakeBitmapImage(std::move(display_list), image_info); -#endif - - std::unique_ptr result; + const SkImageInfo image_info = SkImageInfo::MakeN32Premul(picture_size); + std::pair, std::string> result; delegate_.GetIsGpuDisabledSyncSwitch()->Execute( fml::SyncSwitch::Handlers() .SetIfTrue([&result, &image_info, &display_list] { @@ -309,23 +299,11 @@ std::unique_ptr Rasterizer::MakeGpuImage( return; } - GrBackendTexture texture = context->createBackendTexture( - image_info.width(), image_info.height(), image_info.colorType(), - GrMipmapped::kNo, GrRenderable::kYes); - if (!texture.isValid()) { - result = std::make_unique( - GrBackendTexture(), nullptr, nullptr, - "unable to create render target at specified size"); - return; - } - - sk_sp sk_surface = SkSurface::MakeFromBackendTexture( - context, texture, kTopLeft_GrSurfaceOrigin, /*sampleCnt=*/0, - image_info.colorType(), image_info.refColorSpace(), nullptr); + sk_sp sk_surface = SkSurface::MakeRenderTarget( + context, SkBudgeted::kYes, image_info); if (!sk_surface) { - result = std::make_unique( - GrBackendTexture(), nullptr, nullptr, - "unable to create rendering surface for image"); + result = {nullptr, + "unable to create render target at specified size"}; return; } @@ -333,8 +311,8 @@ std::unique_ptr Rasterizer::MakeGpuImage( canvas->clear(SK_ColorTRANSPARENT); display_list->RenderTo(canvas); - result = std::make_unique( - texture, sk_ref_sp(context), nullptr, ""); + sk_sp image = sk_surface->makeImageSnapshot(); + result = {image, image ? "" : "Unable to create image"}; })); return result; } diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 2f90ed5b1fe66..425b8214e5bd4 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -212,8 +212,16 @@ class Rasterizer final : public SnapshotDelegate, void DrawLastLayerTree( std::unique_ptr frame_timings_recorder); - // |SnapshotDelegate| - std::shared_ptr GetTextureRegistry() override; + //---------------------------------------------------------------------------- + /// @brief Gets the registry of external textures currently in use by the + /// rasterizer. These textures may be updated at a cadence + /// different from that of the Flutter application. When an + /// external texture is referenced in the Flutter layer tree, that + /// texture is composited within the Flutter layer tree. + /// + /// @return A pointer to the external texture registry. + /// + flutter::TextureRegistry* GetTextureRegistry(); using LayerTreeDiscardCallback = std::function; @@ -462,9 +470,9 @@ class Rasterizer final : public SnapshotDelegate, private: // |SnapshotDelegate| - std::unique_ptr MakeGpuImage( + std::pair, std::string> MakeGpuImage( sk_sp display_list, - const SkImageInfo& image_info) override; + SkISize picture_size) override; // |SnapshotDelegate| sk_sp MakeRasterSnapshot( diff --git a/shell/common/shell.cc b/shell/common/shell.cc index bc8594bc90cdb..6c80032b46491 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -1040,7 +1040,7 @@ void Shell::OnPlatformViewRegisterTexture( task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), texture] { if (rasterizer) { - if (auto registry = rasterizer->GetTextureRegistry()) { + if (auto* registry = rasterizer->GetTextureRegistry()) { registry->RegisterTexture(texture); } } @@ -1055,7 +1055,7 @@ void Shell::OnPlatformViewUnregisterTexture(int64_t texture_id) { task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { if (rasterizer) { - if (auto registry = rasterizer->GetTextureRegistry()) { + if (auto* registry = rasterizer->GetTextureRegistry()) { registry->UnregisterTexture(texture_id); } } @@ -1070,7 +1070,7 @@ void Shell::OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) { // Tell the rasterizer that one of its textures has a new frame available. task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { - auto registry = rasterizer->GetTextureRegistry(); + auto* registry = rasterizer->GetTextureRegistry(); if (!registry) { return; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 7bd244d98aba2..e4a86b5775a34 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -2382,6 +2382,7 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { FixedRefreshRateStopwatch raster_time; FixedRefreshRateStopwatch ui_time; MutatorsStack mutators_stack; + TextureRegistry texture_registry; PaintContext paint_context = { // clang-format off .internal_nodes_canvas = nullptr, @@ -2391,7 +2392,7 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { .view_embedder = nullptr, .raster_time = raster_time, .ui_time = ui_time, - .texture_registry = nullptr, + .texture_registry = texture_registry, .raster_cache = &raster_cache, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, @@ -2410,7 +2411,7 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { .surface_needs_readback = false, .raster_time = raster_time, .ui_time = ui_time, - .texture_registry = nullptr, + .texture_registry = texture_registry, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, .has_platform_view = false, @@ -3764,7 +3765,7 @@ TEST_F(ShellTest, SpawnWorksWithOnError) { TEST_F(ShellTest, PictureToImageSync) { #if !SHELL_ENABLE_GL - // This test uses the GL backend. + // GL emulation does not exist on Fuchsia. GTEST_SKIP(); #endif // !SHELL_ENABLE_GL auto settings = CreateSettingsForFixture(); @@ -3777,12 +3778,9 @@ TEST_F(ShellTest, PictureToImageSync) { ShellTestPlatformView::BackendType::kGLBackend // ); - fml::CountDownLatch latch(2); - AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&](auto args) { - // Teardown and set up rasterizer again. - PlatformViewNotifyDestroyed(shell.get()); - PlatformViewNotifyCreated(shell.get()); - latch.CountDown(); + fml::AutoResetWaitableEvent latch; + AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&latch](auto args) { + latch.Signal(); })); ASSERT_NE(shell, nullptr); From cbaa8c0c44b0e9508efefc7943a9809f1dd56b6c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 18:13:04 -0400 Subject: [PATCH 209/558] Roll Dart SDK from ac425a3ae2b1 to 7f93725357f4 (1 revision) (#35277) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d31515bf323f2..f334c505755a9 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'ac425a3ae2b12ecb541ab5ecf47ec0e6a5a221a5', + 'dart_revision': '7f93725357f4fc52c3c4481b505affc2158e9f1d', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 4793613992030..355bb082d0192 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 09a6288a0799cbc460e5108a051ecdef +Signature: 691504f637938a2b417e565b3c11ff7e UNUSED LICENSES: From 700115e89379466594cc5760343f69629f65ca7d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 18:17:05 -0400 Subject: [PATCH 210/558] Roll Skia from b2b39a9cbdd6 to 93297d54df57 (2 revisions) (#35278) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f334c505755a9..f3253f2def73e 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': 'b2b39a9cbdd68e306616a267118e5164deda5378', + 'skia_revision': '93297d54df57ea3e77d37c804664d95122938e6d', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 4a8d585edb9f7..f51f038dbbd0f 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 8183da150c2a0a449ba2e35e6f6ed572 +Signature: 6c6e82c5524f9bdac315698ff1eb7b70 UNUSED LICENSES: From 330fff6c468a2007170f9ead9620fe2f9d70454a Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 9 Aug 2022 15:26:04 -0700 Subject: [PATCH 211/558] [Impeller] Cleanup Context API. (#35279) --- impeller/entity/contents/content_context.cc | 4 +- impeller/entity/contents/vertices_contents.cc | 2 +- impeller/entity/entity_pass.cc | 4 +- impeller/entity/inline_pass_context.cc | 4 +- .../playground/imgui/imgui_impl_impeller.cc | 4 +- impeller/playground/playground.cc | 18 ++++----- .../renderer/backend/gles/context_gles.cc | 31 ++++------------ impeller/renderer/backend/gles/context_gles.h | 13 ++----- impeller/renderer/backend/metal/context_mtl.h | 16 ++------ .../renderer/backend/metal/context_mtl.mm | 34 +++++------------ .../renderer/backend/metal/surface_mtl.mm | 4 +- .../renderer/backend/vulkan/context_vk.cc | 12 +----- impeller/renderer/backend/vulkan/context_vk.h | 10 +---- impeller/renderer/context.h | 16 ++------ impeller/renderer/render_target.cc | 4 +- impeller/renderer/renderer_unittests.cc | 37 +++++++++---------- .../backends/skia/text_render_context_skia.cc | 2 +- lib/ui/painting/image_decoder_impeller.cc | 2 +- 18 files changed, 71 insertions(+), 146 deletions(-) diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 941ed5f451cd7..2cc6218e08277 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -243,7 +243,7 @@ std::shared_ptr ContentContext::MakeSubpass( return nullptr; } - auto sub_command_buffer = context->CreateRenderCommandBuffer(); + auto sub_command_buffer = context->CreateCommandBuffer(); sub_command_buffer->SetLabel("Offscreen Contents Command Buffer"); if (!sub_command_buffer) { return nullptr; @@ -259,7 +259,7 @@ std::shared_ptr ContentContext::MakeSubpass( return nullptr; } - if (!sub_renderpass->EncodeCommands(context->GetTransientsAllocator())) { + if (!sub_renderpass->EncodeCommands(context->GetResourceAllocator())) { return nullptr; } diff --git a/impeller/entity/contents/vertices_contents.cc b/impeller/entity/contents/vertices_contents.cc index ef5bb6d844178..8d014aab24231 100644 --- a/impeller/entity/contents/vertices_contents.cc +++ b/impeller/entity/contents/vertices_contents.cc @@ -80,7 +80,7 @@ bool VerticesContents::Render(const ContentContext& renderer, size_t total_vtx_bytes = vertex_data.size() * sizeof(VS::PerVertexData); size_t total_idx_bytes = vertices_.GetIndices().size() * sizeof(uint16_t); - auto buffer = renderer.GetContext()->GetTransientsAllocator()->CreateBuffer( + auto buffer = renderer.GetContext()->GetResourceAllocator()->CreateBuffer( StorageMode::kHostVisible, total_vtx_bytes + total_idx_bytes); if (!buffer->CopyHostBuffer(reinterpret_cast(vertex_data.data()), diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 442862a7ac2b9..cec25f034b407 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -154,7 +154,7 @@ bool EntityPass::Render(ContentContext& renderer, return false; } - auto command_buffer = renderer.GetContext()->CreateRenderCommandBuffer(); + auto command_buffer = renderer.GetContext()->CreateCommandBuffer(); command_buffer->SetLabel("EntityPass Root Command Buffer"); auto render_pass = command_buffer->CreateRenderPass(render_target); render_pass->SetLabel("EntityPass Root Render Pass"); @@ -174,7 +174,7 @@ bool EntityPass::Render(ContentContext& renderer, } if (!render_pass->EncodeCommands( - renderer.GetContext()->GetTransientsAllocator())) { + renderer.GetContext()->GetResourceAllocator())) { return false; } if (!command_buffer->SubmitCommands()) { diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc index 0b41e8687e2d7..393cc1fa649d2 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -37,7 +37,7 @@ bool InlinePassContext::EndPass() { return true; } - if (!pass_->EncodeCommands(context_->GetTransientsAllocator())) { + if (!pass_->EncodeCommands(context_->GetResourceAllocator())) { return false; } @@ -59,7 +59,7 @@ std::shared_ptr InlinePassContext::GetRenderPass( uint32_t pass_depth) { // Create a new render pass if one isn't active. if (!IsActive()) { - command_buffer_ = context_->CreateRenderCommandBuffer(); + command_buffer_ = context_->CreateCommandBuffer(); if (!command_buffer_) { return nullptr; } diff --git a/impeller/playground/imgui/imgui_impl_impeller.cc b/impeller/playground/imgui/imgui_impl_impeller.cc index 619db79b4c5bb..eb3e09234c02a 100644 --- a/impeller/playground/imgui/imgui_impl_impeller.cc +++ b/impeller/playground/imgui/imgui_impl_impeller.cc @@ -74,7 +74,7 @@ bool ImGui_ImplImpeller_Init(std::shared_ptr context) { texture_descriptor.size = {width, height}; texture_descriptor.mip_count = 1u; - bd->font_texture = context->GetPermanentsAllocator()->CreateTexture( + bd->font_texture = context->GetResourceAllocator()->CreateTexture( impeller::StorageMode::kHostVisible, texture_descriptor); IM_ASSERT(bd->font_texture != nullptr && "Could not allocate ImGui font texture."); @@ -136,7 +136,7 @@ void ImGui_ImplImpeller_RenderDrawData(ImDrawData* draw_data, } // Allocate buffer for vertices + indices. - auto buffer = bd->context->GetTransientsAllocator()->CreateBuffer( + auto buffer = bd->context->GetResourceAllocator()->CreateBuffer( impeller::StorageMode::kHostVisible, total_vtx_bytes + total_idx_bytes); buffer->SetLabel(impeller::SPrintF("ImGui vertex+index buffer")); diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index 87a08954e2bbb..c91f8df98b1b0 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -224,7 +224,7 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) { // Render ImGui overlay. { - auto buffer = renderer->GetContext()->CreateRenderCommandBuffer(); + auto buffer = renderer->GetContext()->CreateCommandBuffer(); if (!buffer) { return false; } @@ -244,7 +244,7 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) { ImGui_ImplImpeller_RenderDrawData(ImGui::GetDrawData(), *pass); - pass->EncodeCommands(renderer->GetContext()->GetTransientsAllocator()); + pass->EncodeCommands(renderer->GetContext()->GetResourceAllocator()); if (!buffer->SubmitCommands()) { return false; } @@ -268,7 +268,7 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) { bool Playground::OpenPlaygroundHere(SinglePassCallback pass_callback) { return OpenPlaygroundHere( [context = GetContext(), &pass_callback](RenderTarget& render_target) { - auto buffer = context->CreateRenderCommandBuffer(); + auto buffer = context->CreateCommandBuffer(); if (!buffer) { return false; } @@ -284,7 +284,7 @@ bool Playground::OpenPlaygroundHere(SinglePassCallback pass_callback) { return false; } - pass->EncodeCommands(context->GetTransientsAllocator()); + pass->EncodeCommands(context->GetResourceAllocator()); if (!buffer->SubmitCommands()) { return false; } @@ -332,9 +332,8 @@ std::shared_ptr Playground::CreateTextureForFixture( texture_descriptor.mip_count = enable_mipmapping ? image->GetSize().MipCount() : 1u; - auto texture = - renderer_->GetContext()->GetPermanentsAllocator()->CreateTexture( - StorageMode::kHostVisible, texture_descriptor); + auto texture = renderer_->GetContext()->GetResourceAllocator()->CreateTexture( + StorageMode::kHostVisible, texture_descriptor); if (!texture) { VALIDATION_LOG << "Could not allocate texture for fixture " << fixture_name; return nullptr; @@ -367,9 +366,8 @@ std::shared_ptr Playground::CreateTextureCubeForFixture( texture_descriptor.size = images[0].GetSize(); texture_descriptor.mip_count = 1u; - auto texture = - renderer_->GetContext()->GetPermanentsAllocator()->CreateTexture( - StorageMode::kHostVisible, texture_descriptor); + auto texture = renderer_->GetContext()->GetResourceAllocator()->CreateTexture( + StorageMode::kHostVisible, texture_descriptor); if (!texture) { VALIDATION_LOG << "Could not allocate texture cube."; return nullptr; diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index f626504d62821..28f8d8418ca2d 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -42,19 +42,12 @@ ContextGLES::ContextGLES( std::shared_ptr(new PipelineLibraryGLES(reactor_)); } - // Create all allocators. + // Create allocators. { - permanents_allocator_ = + resource_allocator_ = std::shared_ptr(new AllocatorGLES(reactor_)); - if (!permanents_allocator_->IsValid()) { - VALIDATION_LOG << "Could not create permanents allocator."; - return; - } - - transients_allocator_ = - std::shared_ptr(new AllocatorGLES(reactor_)); - if (!transients_allocator_->IsValid()) { - VALIDATION_LOG << "Could not create transients allocator."; + if (!resource_allocator_->IsValid()) { + VALIDATION_LOG << "Could not create a resource allocator."; return; } } @@ -93,12 +86,8 @@ bool ContextGLES::IsValid() const { return is_valid_; } -std::shared_ptr ContextGLES::GetPermanentsAllocator() const { - return permanents_allocator_; -} - -std::shared_ptr ContextGLES::GetTransientsAllocator() const { - return transients_allocator_; +std::shared_ptr ContextGLES::GetResourceAllocator() const { + return resource_allocator_; } std::shared_ptr ContextGLES::GetShaderLibrary() const { @@ -113,16 +102,10 @@ std::shared_ptr ContextGLES::GetPipelineLibrary() const { return pipeline_library_; } -std::shared_ptr ContextGLES::CreateRenderCommandBuffer() const { +std::shared_ptr ContextGLES::CreateCommandBuffer() const { return std::shared_ptr(new CommandBufferGLES(reactor_)); } -std::shared_ptr ContextGLES::CreateTransferCommandBuffer() - const { - // There is no such concept. Just use a render command buffer. - return CreateRenderCommandBuffer(); -} - // |Context| bool ContextGLES::HasThreadingRestrictions() const { return true; diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 6f516e69c7197..f96efd2098760 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -38,8 +38,7 @@ class ContextGLES final : public Context, std::shared_ptr shader_library_; std::shared_ptr pipeline_library_; std::shared_ptr sampler_library_; - std::shared_ptr permanents_allocator_; - std::shared_ptr transients_allocator_; + std::shared_ptr resource_allocator_; bool is_valid_ = false; ContextGLES(std::unique_ptr gl, @@ -49,10 +48,7 @@ class ContextGLES final : public Context, bool IsValid() const override; // |Context| - std::shared_ptr GetPermanentsAllocator() const override; - - // |Context| - std::shared_ptr GetTransientsAllocator() const override; + std::shared_ptr GetResourceAllocator() const override; // |Context| std::shared_ptr GetShaderLibrary() const override; @@ -64,10 +60,7 @@ class ContextGLES final : public Context, std::shared_ptr GetPipelineLibrary() const override; // |Context| - std::shared_ptr CreateRenderCommandBuffer() const override; - - // |Context| - std::shared_ptr CreateTransferCommandBuffer() const override; + std::shared_ptr CreateCommandBuffer() const override; // |Context| bool HasThreadingRestrictions() const override; diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index 705978601b8f6..a08a9b252071c 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -37,13 +37,11 @@ class ContextMTL final : public Context, private: id device_ = nullptr; - id render_queue_ = nullptr; - id transfer_queue_ = nullptr; + id command_queue_ = nullptr; std::shared_ptr shader_library_; std::shared_ptr pipeline_library_; std::shared_ptr sampler_library_; - std::shared_ptr permanents_allocator_; - std::shared_ptr transients_allocator_; + std::shared_ptr resource_allocator_; bool is_valid_ = false; ContextMTL(id device, NSArray>* shader_libraries); @@ -52,10 +50,7 @@ class ContextMTL final : public Context, bool IsValid() const override; // |Context| - std::shared_ptr GetPermanentsAllocator() const override; - - // |Context| - std::shared_ptr GetTransientsAllocator() const override; + std::shared_ptr GetResourceAllocator() const override; // |Context| std::shared_ptr GetShaderLibrary() const override; @@ -67,10 +62,7 @@ class ContextMTL final : public Context, std::shared_ptr GetPipelineLibrary() const override; // |Context| - std::shared_ptr CreateRenderCommandBuffer() const override; - - // |Context| - std::shared_ptr CreateTransferCommandBuffer() const override; + std::shared_ptr CreateCommandBuffer() 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 af3ec0de7640b..726d56d904802 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -41,15 +41,13 @@ } // Setup command queues. - render_queue_ = device_.newCommandQueue; - transfer_queue_ = device_.newCommandQueue; + command_queue_ = device_.newCommandQueue; - if (!render_queue_ || !transfer_queue_) { + if (!command_queue_) { return; } - render_queue_.label = @"Impeller Render Queue"; - transfer_queue_.label = @"Impeller Transfer Queue"; + command_queue_.label = @"Impeller Command Queue"; // Setup the pipeline library. { // @@ -64,15 +62,9 @@ } { - transients_allocator_ = std::shared_ptr( - new AllocatorMTL(device_, "Impeller Transients Allocator")); - if (!transients_allocator_) { - return; - } - - permanents_allocator_ = std::shared_ptr( + resource_allocator_ = std::shared_ptr( new AllocatorMTL(device_, "Impeller Permanents Allocator")); - if (!permanents_allocator_) { + if (!resource_allocator_) { return; } } @@ -191,12 +183,8 @@ return sampler_library_; } -std::shared_ptr ContextMTL::CreateRenderCommandBuffer() const { - return CreateCommandBufferInQueue(render_queue_); -} - -std::shared_ptr ContextMTL::CreateTransferCommandBuffer() const { - return CreateCommandBufferInQueue(transfer_queue_); +std::shared_ptr ContextMTL::CreateCommandBuffer() const { + return CreateCommandBufferInQueue(command_queue_); } std::shared_ptr ContextMTL::CreateCommandBufferInQueue( @@ -212,12 +200,8 @@ return buffer; } -std::shared_ptr ContextMTL::GetPermanentsAllocator() const { - return permanents_allocator_; -} - -std::shared_ptr ContextMTL::GetTransientsAllocator() const { - return transients_allocator_; +std::shared_ptr ContextMTL::GetResourceAllocator() const { + return resource_allocator_; } id ContextMTL::GetMTLDevice() const { diff --git a/impeller/renderer/backend/metal/surface_mtl.mm b/impeller/renderer/backend/metal/surface_mtl.mm index dc540bb6e2117..216469d3bbfac 100644 --- a/impeller/renderer/backend/metal/surface_mtl.mm +++ b/impeller/renderer/backend/metal/surface_mtl.mm @@ -52,7 +52,7 @@ static_cast(current_drawable.texture.height)}; color0_tex_desc.usage = static_cast(TextureUsage::kRenderTarget); - auto msaa_tex = context->GetPermanentsAllocator()->CreateTexture( + auto msaa_tex = context->GetResourceAllocator()->CreateTexture( StorageMode::kDeviceTransient, color0_tex_desc); if (!msaa_tex) { VALIDATION_LOG << "Could not allocate MSAA resolve texture."; @@ -82,7 +82,7 @@ stencil0_tex.size = color0_tex_desc.size; stencil0_tex.usage = static_cast(TextureUsage::kRenderTarget); - auto stencil_texture = context->GetPermanentsAllocator()->CreateTexture( + auto stencil_texture = context->GetResourceAllocator()->CreateTexture( StorageMode::kDeviceTransient, stencil0_tex); if (!stencil_texture) { diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 132100b5d42b3..f71b28b6d9452 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -410,11 +410,7 @@ bool ContextVK::IsValid() const { return is_valid_; } -std::shared_ptr ContextVK::GetPermanentsAllocator() const { - return allocator_; -} - -std::shared_ptr ContextVK::GetTransientsAllocator() const { +std::shared_ptr ContextVK::GetResourceAllocator() const { return allocator_; } @@ -430,11 +426,7 @@ std::shared_ptr ContextVK::GetPipelineLibrary() const { return pipeline_library_; } -std::shared_ptr ContextVK::CreateRenderCommandBuffer() const { - FML_UNREACHABLE(); -} - -std::shared_ptr ContextVK::CreateTransferCommandBuffer() const { +std::shared_ptr ContextVK::CreateCommandBuffer() const { FML_UNREACHABLE(); } diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index c7cb39b70a7e7..c70fda779208c 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -83,10 +83,7 @@ class ContextVK final : public Context, public BackendCast { const std::string& label); // |Context| - std::shared_ptr GetPermanentsAllocator() const override; - - // |Context| - std::shared_ptr GetTransientsAllocator() const override; + std::shared_ptr GetResourceAllocator() const override; // |Context| std::shared_ptr GetShaderLibrary() const override; @@ -98,10 +95,7 @@ class ContextVK final : public Context, public BackendCast { std::shared_ptr GetPipelineLibrary() const override; // |Context| - std::shared_ptr CreateRenderCommandBuffer() const override; - - // |Context| - std::shared_ptr CreateTransferCommandBuffer() const override; + std::shared_ptr CreateCommandBuffer() const override; FML_DISALLOW_COPY_AND_ASSIGN(ContextVK); }; diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index 412361e3f35cd..db31bcf5236b8 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -24,16 +24,9 @@ class Context { virtual bool IsValid() const = 0; //---------------------------------------------------------------------------- - /// @return An allocator suitable for allocations that persist between - /// frames. + /// @return A resource allocator. /// - virtual std::shared_ptr GetPermanentsAllocator() const = 0; - - //---------------------------------------------------------------------------- - /// @return An allocator suitable for allocations that used only for one - /// frame or render pass. - /// - virtual std::shared_ptr GetTransientsAllocator() const = 0; + virtual std::shared_ptr GetResourceAllocator() const = 0; virtual std::shared_ptr GetShaderLibrary() const = 0; @@ -41,10 +34,7 @@ class Context { virtual std::shared_ptr GetPipelineLibrary() const = 0; - virtual std::shared_ptr CreateRenderCommandBuffer() const = 0; - - virtual std::shared_ptr CreateTransferCommandBuffer() - const = 0; + virtual std::shared_ptr CreateCommandBuffer() const = 0; virtual bool HasThreadingRestrictions() const; diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index 835ef4f5e16e5..1ec8c9d914173 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc @@ -204,7 +204,7 @@ RenderTarget RenderTarget::CreateOffscreen(const Context& context, color0.clear_color = Color::BlackTransparent(); color0.load_action = color_load_action; color0.store_action = color_store_action; - color0.texture = context.GetPermanentsAllocator()->CreateTexture( + color0.texture = context.GetResourceAllocator()->CreateTexture( color_storage_mode, color_tex0); if (!color0.texture) { @@ -217,7 +217,7 @@ RenderTarget RenderTarget::CreateOffscreen(const Context& context, stencil0.load_action = stencil_load_action; stencil0.store_action = stencil_store_action; stencil0.clear_stencil = 0u; - stencil0.texture = context.GetPermanentsAllocator()->CreateTexture( + stencil0.texture = context.GetResourceAllocator()->CreateTexture( stencil_storage_mode, stencil_tex0); if (!stencil0.texture) { diff --git a/impeller/renderer/renderer_unittests.cc b/impeller/renderer/renderer_unittests.cc index 5131479dd1c12..25160b94c5398 100644 --- a/impeller/renderer/renderer_unittests.cc +++ b/impeller/renderer/renderer_unittests.cc @@ -66,7 +66,7 @@ TEST_P(RendererTest, CanCreateBoxPrimitive) { {{100, 800, 0.0}, {0.0, 1.0}}, // 4 }); auto vertex_buffer = - vertex_builder.CreateVertexBuffer(*context->GetPermanentsAllocator()); + vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator()); ASSERT_TRUE(vertex_buffer); auto bridge = CreateTextureForFixture("bay_bridge.jpg"); @@ -145,9 +145,8 @@ TEST_P(RendererTest, CanRenderPerspectiveCube) { VertexBuffer vertex_buffer; { - auto device_buffer = - context->GetPermanentsAllocator()->CreateBufferWithCopy( - reinterpret_cast(&cube), sizeof(cube)); + auto device_buffer = context->GetResourceAllocator()->CreateBufferWithCopy( + reinterpret_cast(&cube), sizeof(cube)); vertex_buffer.vertex_buffer = { .buffer = device_buffer, .range = Range(offsetof(Cube, vertices), sizeof(Cube::vertices))}; @@ -231,7 +230,7 @@ TEST_P(RendererTest, CanRenderMultiplePrimitives) { {{100, 800, 0.0}, {0.0, 1.0}}, // 4 }); auto vertex_buffer = - vertex_builder.CreateVertexBuffer(*context->GetPermanentsAllocator()); + vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator()); ASSERT_TRUE(vertex_buffer); auto bridge = CreateTextureForFixture("bay_bridge.jpg"); @@ -303,7 +302,7 @@ TEST_P(RendererTest, CanRenderToTexture) { {{100, 800, 0.0}, {0.0, 1.0}}, // 4 }); auto vertex_buffer = - vertex_builder.CreateVertexBuffer(*context->GetPermanentsAllocator()); + vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator()); ASSERT_TRUE(vertex_buffer); auto bridge = CreateTextureForFixture("bay_bridge.jpg"); @@ -328,7 +327,7 @@ TEST_P(RendererTest, CanRenderToTexture) { texture_descriptor.usage = static_cast(TextureUsage::kRenderTarget); - color0.texture = context->GetPermanentsAllocator()->CreateTexture( + color0.texture = context->GetResourceAllocator()->CreateTexture( StorageMode::kHostVisible, texture_descriptor); ASSERT_TRUE(color0); @@ -343,13 +342,13 @@ TEST_P(RendererTest, CanRenderToTexture) { stencil_texture_desc.format = PixelFormat::kS8UInt; stencil_texture_desc.usage = static_cast(TextureUsage::kRenderTarget); - stencil0.texture = context->GetPermanentsAllocator()->CreateTexture( + stencil0.texture = context->GetResourceAllocator()->CreateTexture( StorageMode::kDeviceTransient, stencil_texture_desc); RenderTarget r2t_desc; r2t_desc.SetColorAttachment(color0, 0u); r2t_desc.SetStencilAttachment(stencil0); - auto cmd_buffer = context->CreateRenderCommandBuffer(); + auto cmd_buffer = context->CreateCommandBuffer(); r2t_pass = cmd_buffer->CreateRenderPass(r2t_desc); ASSERT_TRUE(r2t_pass && r2t_pass->IsValid()); } @@ -379,7 +378,7 @@ TEST_P(RendererTest, CanRenderToTexture) { VS::BindUniformBuffer( cmd, r2t_pass->GetTransientsBuffer().EmplaceUniform(uniforms)); ASSERT_TRUE(r2t_pass->AddCommand(std::move(cmd))); - ASSERT_TRUE(r2t_pass->EncodeCommands(context->GetTransientsAllocator())); + ASSERT_TRUE(r2t_pass->EncodeCommands(context->GetResourceAllocator())); } #if IMPELLER_ENABLE_METAL @@ -465,7 +464,7 @@ TEST_P(RendererTest, CanBlitTextureToTexture) { texture_desc.usage = static_cast(TextureUsage::kRenderTarget) | static_cast(TextureUsage::kShaderRead); - auto texture = context->GetPermanentsAllocator()->CreateTexture( + auto texture = context->GetResourceAllocator()->CreateTexture( StorageMode::kHostVisible, texture_desc); ASSERT_TRUE(texture); @@ -488,11 +487,11 @@ TEST_P(RendererTest, CanBlitTextureToTexture) { {{0, size.y}, {0.0, 1.0}}, // 4 }); auto vertex_buffer = - vertex_builder.CreateVertexBuffer(*context->GetTransientsAllocator()); + vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator()); ASSERT_TRUE(vertex_buffer); Renderer::RenderCallback callback = [&](RenderTarget& render_target) { - auto buffer = context->CreateRenderCommandBuffer(); + auto buffer = context->CreateCommandBuffer(); if (!buffer) { return false; } @@ -512,7 +511,7 @@ TEST_P(RendererTest, CanBlitTextureToTexture) { // Blit `bridge` to the top left corner of the texture. pass->AddCopy(bridge, texture); - pass->EncodeCommands(context->GetTransientsAllocator()); + pass->EncodeCommands(context->GetResourceAllocator()); } { @@ -544,7 +543,7 @@ TEST_P(RendererTest, CanBlitTextureToTexture) { pass->AddCommand(std::move(cmd)); } - pass->EncodeCommands(context->GetTransientsAllocator()); + pass->EncodeCommands(context->GetResourceAllocator()); } if (!buffer->SubmitCommands()) { @@ -584,7 +583,7 @@ TEST_P(RendererTest, CanGenerateMipmaps) { {{0, size.y}, {0.0, 1.0}}, // 4 }); auto vertex_buffer = - vertex_builder.CreateVertexBuffer(*context->GetPermanentsAllocator()); + vertex_builder.CreateVertexBuffer(*context->GetResourceAllocator()); ASSERT_TRUE(vertex_buffer); bool first_frame = true; @@ -613,7 +612,7 @@ TEST_P(RendererTest, CanGenerateMipmaps) { ImGui::SliderFloat("LOD", &lod, 0, boston->GetMipCount() - 1); ImGui::End(); - auto buffer = context->CreateRenderCommandBuffer(); + auto buffer = context->CreateCommandBuffer(); if (!buffer) { return false; } @@ -628,7 +627,7 @@ TEST_P(RendererTest, CanGenerateMipmaps) { pass->GenerateMipmap(boston, "Boston Mipmap"); - pass->EncodeCommands(context->GetTransientsAllocator()); + pass->EncodeCommands(context->GetResourceAllocator()); } first_frame = false; @@ -665,7 +664,7 @@ TEST_P(RendererTest, CanGenerateMipmaps) { pass->AddCommand(std::move(cmd)); } - pass->EncodeCommands(context->GetTransientsAllocator()); + pass->EncodeCommands(context->GetResourceAllocator()); } if (!buffer->SubmitCommands()) { diff --git a/impeller/typographer/backends/skia/text_render_context_skia.cc b/impeller/typographer/backends/skia/text_render_context_skia.cc index fb9bf2df3395f..5a0123ab88e5b 100644 --- a/impeller/typographer/backends/skia/text_render_context_skia.cc +++ b/impeller/typographer/backends/skia/text_render_context_skia.cc @@ -248,7 +248,7 @@ std::shared_ptr TextRenderContextSkia::CreateGlyphAtlas( // --------------------------------------------------------------------------- // Step 6: Upload the atlas as a texture. // --------------------------------------------------------------------------- - auto texture = UploadGlyphTextureAtlas(GetContext()->GetTransientsAllocator(), + auto texture = UploadGlyphTextureAtlas(GetContext()->GetResourceAllocator(), bitmap, atlas_size); if (!texture) { return nullptr; diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index 72c3cba4b471c..4e1108b01f668 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -149,7 +149,7 @@ static sk_sp UploadTexture(std::shared_ptr context, texture_descriptor.format = pixel_format.value(); texture_descriptor.size = {image_info.width(), image_info.height()}; - auto texture = context->GetPermanentsAllocator()->CreateTexture( + auto texture = context->GetResourceAllocator()->CreateTexture( impeller::StorageMode::kHostVisible, texture_descriptor); if (!texture) { FML_DLOG(ERROR) << "Could not create Impeller texture."; From a8a328bbe6f6aa9ba6aa4cbb338737add3afe6fd Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 9 Aug 2022 15:32:04 -0700 Subject: [PATCH 212/558] Reland toImageSync (#35283) --- common/graphics/texture.cc | 30 ++++ common/graphics/texture.h | 32 +++- flow/compositor_context.cc | 11 +- flow/compositor_context.h | 6 +- flow/layers/layer.h | 4 +- flow/layers/layer_tree.cc | 5 +- flow/layers/layer_tree_unittests.cc | 20 +-- .../performance_overlay_layer_unittests.cc | 3 +- flow/layers/texture_layer.cc | 4 +- flow/layers/texture_layer_unittests.cc | 10 +- flow/raster_cache_unittests.cc | 116 +++++++++---- flow/skia_gpu_object.h | 31 +++- flow/skia_gpu_object_unittests.cc | 1 + flow/testing/layer_test.h | 9 +- flow/testing/mock_raster_cache.cc | 54 +++--- flow/testing/mock_raster_cache.h | 11 +- lib/ui/BUILD.gn | 1 + .../display_list_deferred_image_gpu.cc | 159 +++++++++++++++--- .../display_list_deferred_image_gpu.h | 83 +++++++-- lib/ui/painting/image_encoding.cc | 96 +++++------ lib/ui/painting/picture.cc | 25 +-- lib/ui/snapshot_delegate.h | 40 ++++- shell/common/fixtures/shell_test.dart | 26 ++- shell/common/rasterizer.cc | 54 ++++-- shell/common/rasterizer.h | 16 +- shell/common/shell.cc | 6 +- shell/common/shell_unittests.cc | 16 +- 27 files changed, 601 insertions(+), 268 deletions(-) diff --git a/common/graphics/texture.cc b/common/graphics/texture.cc index c5ad5fdf29af8..f12a5959fc088 100644 --- a/common/graphics/texture.cc +++ b/common/graphics/texture.cc @@ -6,6 +6,10 @@ namespace flutter { +ContextListener::ContextListener() = default; + +ContextListener::~ContextListener() = default; + Texture::Texture(int64_t id) : id_(id) {} Texture::~Texture() = default; @@ -19,6 +23,12 @@ void TextureRegistry::RegisterTexture(std::shared_ptr texture) { mapping_[texture->Id()] = texture; } +void TextureRegistry::RegisterContextListener( + uintptr_t id, + std::weak_ptr image) { + images_[id] = std::move(image); +} + void TextureRegistry::UnregisterTexture(int64_t id) { auto found = mapping_.find(id); if (found == mapping_.end()) { @@ -28,16 +38,36 @@ void TextureRegistry::UnregisterTexture(int64_t id) { mapping_.erase(found); } +void TextureRegistry::UnregisterContextListener(uintptr_t id) { + images_.erase(id); +} + void TextureRegistry::OnGrContextCreated() { for (auto& it : mapping_) { it.second->OnGrContextCreated(); } + + for (const auto& [id, weak_image] : images_) { + if (auto image = weak_image.lock()) { + image->OnGrContextCreated(); + } else { + images_.erase(id); + } + } } void TextureRegistry::OnGrContextDestroyed() { for (auto& it : mapping_) { it.second->OnGrContextDestroyed(); } + + for (const auto& [id, weak_image] : images_) { + if (auto image = weak_image.lock()) { + image->OnGrContextDestroyed(); + } else { + images_.erase(id); + } + } } std::shared_ptr TextureRegistry::GetTexture(int64_t id) { diff --git a/common/graphics/texture.h b/common/graphics/texture.h index 57afa60a6361f..69cfa3ba0f9a4 100644 --- a/common/graphics/texture.h +++ b/common/graphics/texture.h @@ -16,7 +16,22 @@ class GrDirectContext; namespace flutter { -class Texture { +class ContextListener { + public: + ContextListener(); + ~ContextListener(); + + // Called from raster thread. + virtual void OnGrContextCreated() = 0; + + // Called from raster thread. + virtual void OnGrContextDestroyed() = 0; + + private: + FML_DISALLOW_COPY_AND_ASSIGN(ContextListener); +}; + +class Texture : public ContextListener { public: explicit Texture(int64_t id); // Called from UI or raster thread. virtual ~Texture(); // Called from raster thread. @@ -29,12 +44,6 @@ class Texture { const SkSamplingOptions& sampling, const SkPaint* paint = nullptr) = 0; - // Called from raster thread. - virtual void OnGrContextCreated() = 0; - - // Called from raster thread. - virtual void OnGrContextDestroyed() = 0; - // Called on raster thread. virtual void MarkNewFrameAvailable() = 0; @@ -45,7 +54,6 @@ class Texture { private: int64_t id_; - FML_DISALLOW_COPY_AND_ASSIGN(Texture); }; @@ -56,9 +64,16 @@ class TextureRegistry { // Called from raster thread. void RegisterTexture(std::shared_ptr texture); + // Called from raster thread. + void RegisterContextListener(uintptr_t id, + std::weak_ptr image); + // Called from raster thread. void UnregisterTexture(int64_t id); + // Called from the raster thread. + void UnregisterContextListener(uintptr_t id); + // Called from raster thread. std::shared_ptr GetTexture(int64_t id); @@ -70,6 +85,7 @@ class TextureRegistry { private: std::map> mapping_; + std::map> images_; FML_DISALLOW_COPY_AND_ASSIGN(TextureRegistry); }; diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index 779a42c84eb92..7013bc86ee374 100644 --- a/flow/compositor_context.cc +++ b/flow/compositor_context.cc @@ -46,11 +46,14 @@ std::optional FrameDamage::ComputeClipRect( } CompositorContext::CompositorContext() - : raster_time_(fixed_refresh_rate_updater_), + : texture_registry_(std::make_shared()), + raster_time_(fixed_refresh_rate_updater_), ui_time_(fixed_refresh_rate_updater_) {} CompositorContext::CompositorContext(Stopwatch::RefreshRateUpdater& updater) - : raster_time_(updater), ui_time_(updater) {} + : texture_registry_(std::make_shared()), + raster_time_(updater), + ui_time_(updater) {} CompositorContext::~CompositorContext() = default; @@ -160,12 +163,12 @@ RasterStatus CompositorContext::ScopedFrame::Raster( } void CompositorContext::OnGrContextCreated() { - texture_registry_.OnGrContextCreated(); + texture_registry_->OnGrContextCreated(); raster_cache_.Clear(); } void CompositorContext::OnGrContextDestroyed() { - texture_registry_.OnGrContextDestroyed(); + texture_registry_->OnGrContextDestroyed(); raster_cache_.Clear(); } diff --git a/flow/compositor_context.h b/flow/compositor_context.h index 0981cdd2538b1..f7667640caa71 100644 --- a/flow/compositor_context.h +++ b/flow/compositor_context.h @@ -175,7 +175,9 @@ class CompositorContext { RasterCache& raster_cache() { return raster_cache_; } - TextureRegistry& texture_registry() { return texture_registry_; } + std::shared_ptr texture_registry() { + return texture_registry_; + } const Stopwatch& raster_time() const { return raster_time_; } @@ -185,7 +187,7 @@ class CompositorContext { private: RasterCache raster_cache_; - TextureRegistry texture_registry_; + std::shared_ptr texture_registry_; Stopwatch raster_time_; Stopwatch ui_time_; LayerSnapshotStore layer_snapshot_store_; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index a87642d2c8cff..5cdd3e7db028c 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -57,7 +57,7 @@ struct PrerollContext { // These allow us to paint in the end of subtree Preroll. const Stopwatch& raster_time; const Stopwatch& ui_time; - TextureRegistry& texture_registry; + std::shared_ptr texture_registry; const bool checkerboard_offscreen_layers; const float frame_device_pixel_ratio = 1.0f; @@ -132,7 +132,7 @@ struct PaintContext { ExternalViewEmbedder* view_embedder; const Stopwatch& raster_time; const Stopwatch& ui_time; - TextureRegistry& texture_registry; + std::shared_ptr texture_registry; const RasterCache* raster_cache; const bool checkerboard_offscreen_layers; const float frame_device_pixel_ratio = 1.0f; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 53748a42832b7..0fafe40f62861 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -167,7 +167,6 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { MutatorsStack unused_stack; const FixedRefreshRateStopwatch unused_stopwatch; - TextureRegistry unused_texture_registry; SkMatrix root_surface_transformation; // No root surface transformation. So assume identity. root_surface_transformation.reset(); @@ -183,7 +182,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .surface_needs_readback = false, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = unused_texture_registry, + .texture_registry = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_ // clang-format on @@ -202,7 +201,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .view_embedder = nullptr, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = unused_texture_registry, + .texture_registry = nullptr, .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_, diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc index 63de819e15808..c39867508c002 100644 --- a/flow/layers/layer_tree_unittests.cc +++ b/flow/layers/layer_tree_unittests.cc @@ -195,16 +195,10 @@ TEST_F(LayerTreeTest, NeedsSystemComposite) { } TEST_F(LayerTreeTest, PrerollContextInitialization) { - // This EXPECT macro will ensure that if any fields get added to the - // PrerollContext that this test must be revisited and updated. - // If any fields get removed or replaced, then the expect_defaults closure - // will fail to compile, again bringing attention to updating this test. - EXPECT_EQ(sizeof(PrerollContext), size_t(120)); - MutatorsStack mock_mutators; FixedRefreshRateStopwatch mock_raster_time; FixedRefreshRateStopwatch mock_ui_time; - TextureRegistry mock_registry; + std::shared_ptr mock_registry; auto expect_defaults = [&mock_mutators, &mock_raster_time, &mock_ui_time, &mock_registry](const PrerollContext& context) { @@ -218,7 +212,7 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { EXPECT_EQ(&context.raster_time, &mock_raster_time); EXPECT_EQ(&context.ui_time, &mock_ui_time); - EXPECT_EQ(&context.texture_registry, &mock_registry); + EXPECT_EQ(context.texture_registry.get(), mock_registry.get()); EXPECT_EQ(context.checkerboard_offscreen_layers, false); EXPECT_EQ(context.frame_device_pixel_ratio, 1.0f); @@ -240,15 +234,9 @@ TEST_F(LayerTreeTest, PrerollContextInitialization) { } TEST_F(LayerTreeTest, PaintContextInitialization) { - // This EXPECT macro will ensure that if any fields get added to the - // PaintContext that this test must be revisited and updated. - // If any fields get removed or replaced, then the expect_defaults closure - // will fail to compile, again bringing attention to updating this test. - EXPECT_EQ(sizeof(PaintContext), size_t(104)); - FixedRefreshRateStopwatch mock_raster_time; FixedRefreshRateStopwatch mock_ui_time; - TextureRegistry mock_registry; + std::shared_ptr mock_registry; auto expect_defaults = [&mock_raster_time, &mock_ui_time, &mock_registry](const PaintContext& context) { @@ -258,7 +246,7 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { EXPECT_EQ(context.view_embedder, nullptr); EXPECT_EQ(&context.raster_time, &mock_raster_time); EXPECT_EQ(&context.ui_time, &mock_ui_time); - EXPECT_EQ(&context.texture_registry, &mock_registry); + EXPECT_EQ(context.texture_registry.get(), mock_registry.get()); EXPECT_EQ(context.raster_cache, nullptr); EXPECT_EQ(context.checkerboard_offscreen_layers, false); EXPECT_EQ(context.frame_device_pixel_ratio, 1.0f); diff --git a/flow/layers/performance_overlay_layer_unittests.cc b/flow/layers/performance_overlay_layer_unittests.cc index ae9eec8b767e4..f7c20d24d2900 100644 --- a/flow/layers/performance_overlay_layer_unittests.cc +++ b/flow/layers/performance_overlay_layer_unittests.cc @@ -58,7 +58,6 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { ASSERT_TRUE(surface != nullptr); - flutter::TextureRegistry unused_texture_registry; flutter::PaintContext paintContext = { // clang-format off .internal_nodes_canvas = nullptr, @@ -67,7 +66,7 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) { .view_embedder = nullptr, .raster_time = mock_stopwatch, .ui_time = mock_stopwatch, - .texture_registry = unused_texture_registry, + .texture_registry = nullptr, .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, diff --git a/flow/layers/texture_layer.cc b/flow/layers/texture_layer.cc index fa760fe786e83..7ece96ebd4364 100644 --- a/flow/layers/texture_layer.cc +++ b/flow/layers/texture_layer.cc @@ -54,7 +54,9 @@ void TextureLayer::Paint(PaintContext& context) const { FML_DCHECK(needs_painting(context)); std::shared_ptr texture = - context.texture_registry.GetTexture(texture_id_); + context.texture_registry + ? context.texture_registry->GetTexture(texture_id_) + : nullptr; if (!texture) { TRACE_EVENT_INSTANT0("flutter", "null texture"); return; diff --git a/flow/layers/texture_layer_unittests.cc b/flow/layers/texture_layer_unittests.cc index 94e5469db702b..7d45d1d54e825 100644 --- a/flow/layers/texture_layer_unittests.cc +++ b/flow/layers/texture_layer_unittests.cc @@ -43,7 +43,7 @@ TEST_F(TextureLayerTest, PaintingEmptyLayerDies) { false, DlImageSampling::kNearestNeighbor); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry.RegisterTexture(mock_texture); + preroll_context()->texture_registry->RegisterTexture(mock_texture); layer->Preroll(preroll_context(), SkMatrix()); EXPECT_EQ(layer->paint_bounds(), kEmptyRect); @@ -62,7 +62,7 @@ TEST_F(TextureLayerTest, PaintBeforePrerollDies) { layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry.RegisterTexture(mock_texture); + preroll_context()->texture_registry->RegisterTexture(mock_texture); EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), "needs_painting\\(context\\)"); @@ -78,7 +78,7 @@ TEST_F(TextureLayerTest, PaintingWithLinearSampling) { layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry.RegisterTexture(mock_texture); + preroll_context()->texture_registry->RegisterTexture(mock_texture); layer->Preroll(preroll_context(), SkMatrix()); EXPECT_EQ(layer->paint_bounds(), @@ -124,12 +124,12 @@ TEST_F(TextureLayerTest, OpacityInheritance) { layer_offset, layer_size, texture_id, false, DlImageSampling::kLinear); // Ensure the texture is located by the Layer. - preroll_context()->texture_registry.RegisterTexture(mock_texture); + preroll_context()->texture_registry->RegisterTexture(mock_texture); // The texture layer always reports opacity compatibility. PrerollContext* context = preroll_context(); context->subtree_can_inherit_opacity = false; - context->texture_registry.RegisterTexture(mock_texture); + context->texture_registry->RegisterTexture(mock_texture); layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(context->subtree_can_inherit_opacity); diff --git a/flow/raster_cache_unittests.cc b/flow/raster_cache_unittests.cc index a27b9e45cdfde..afd00392afa1d 100644 --- a/flow/raster_cache_unittests.cc +++ b/flow/raster_cache_unittests.cc @@ -38,9 +38,13 @@ TEST(RasterCache, MetricsOmitUnpopulatedEntries) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -90,9 +94,13 @@ TEST(RasterCache, ThresholdIsRespectedForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -130,7 +138,10 @@ TEST(RasterCache, SetCheckboardCacheImages) { SkMatrix matrix = SkMatrix::I(); auto display_list = GetSampleDisplayList(); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& paint_context = paint_context_holder.paint_context; auto dummy_draw_function = [](SkCanvas* canvas) {}; bool did_draw_checkerboard = false; @@ -163,14 +174,17 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForSkPicture) { SkMatrix matrix = SkMatrix::I(); auto display_list = GetSampleDisplayList(); - ; SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -193,9 +207,13 @@ TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -220,9 +238,13 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForSkPicture) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -252,9 +274,13 @@ TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -288,9 +314,13 @@ TEST(RasterCache, EvitUnusedCacheEntries) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -394,9 +424,13 @@ TEST(RasterCache, DeviceRectRoundOutForDisplayList) { SkCanvas canvas(100, 100, nullptr); canvas.setMatrix(ctm); - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -433,9 +467,13 @@ TEST(RasterCache, NestedOpCountMetricUsedForDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -476,9 +514,13 @@ TEST(RasterCache, NaiveComplexityScoringDisplayList) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; @@ -538,9 +580,13 @@ TEST(RasterCache, DisplayListWithSingularMatrixIsNotCached) { SkCanvas dummy_canvas; SkPaint paint; - PrerollContextHolder preroll_context_holder = - GetSamplePrerollContextHolder(&cache); - PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(&cache); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + MutatorsStack mutators_stack; + PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder( + &cache, &raster_time, &ui_time, &mutators_stack); + PaintContextHolder paint_context_holder = + GetSamplePaintContextHolder(&cache, &raster_time, &ui_time); auto& preroll_context = preroll_context_holder.preroll_context; auto& paint_context = paint_context_holder.paint_context; diff --git a/flow/skia_gpu_object.h b/flow/skia_gpu_object.h index e694ef7ffcc2a..16251ec56f823 100644 --- a/flow/skia_gpu_object.h +++ b/flow/skia_gpu_object.h @@ -34,6 +34,16 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { } } + void DeleteTexture(GrBackendTexture texture) { + std::scoped_lock lock(mutex_); + textures_.push_back(texture); + if (!drain_pending_) { + drain_pending_ = true; + task_runner_->PostDelayedTask( + [strong = fml::Ref(this)]() { strong->Drain(); }, drain_delay_); + } + } + // Usually, the drain is called automatically. However, during IO manager // shutdown (when the platform side reference to the OpenGL context is about // to go away), we may need to pre-emptively drain the unref queue. It is the @@ -42,12 +52,14 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { void Drain() { TRACE_EVENT0("flutter", "SkiaUnrefQueue::Drain"); std::deque skia_objects; + std::deque textures; { std::scoped_lock lock(mutex_); objects_.swap(skia_objects); + textures_.swap(textures); drain_pending_ = false; } - DoDrain(skia_objects, context_); + DoDrain(skia_objects, textures, context_); } void UpdateResourceContext(sk_sp context) { @@ -59,6 +71,7 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { const fml::TimeDelta drain_delay_; std::mutex mutex_; std::deque objects_; + std::deque textures_; bool drain_pending_; sk_sp context_; @@ -79,22 +92,30 @@ class UnrefQueue : public fml::RefCountedThreadSafe> { // into a task queued to that thread. ResourceContext* raw_context = context_.release(); fml::TaskRunner::RunNowOrPostTask( - task_runner_, [objects = std::move(objects_), raw_context]() mutable { + task_runner_, [objects = std::move(objects_), + textures = std::move(textures_), raw_context]() mutable { sk_sp context(raw_context); - DoDrain(objects, context); + DoDrain(objects, textures, context); context.reset(); }); } // static static void DoDrain(const std::deque& skia_objects, + const std::deque& textures, sk_sp context) { for (SkRefCnt* skia_object : skia_objects) { skia_object->unref(); } - if (context && !skia_objects.empty()) { - context->performDeferredCleanup(std::chrono::milliseconds(0)); + if (context) { + for (GrBackendTexture texture : textures) { + context->deleteBackendTexture(texture); + } + + if (!skia_objects.empty()) { + context->performDeferredCleanup(std::chrono::milliseconds(0)); + } } } diff --git a/flow/skia_gpu_object_unittests.cc b/flow/skia_gpu_object_unittests.cc index 61127256393a3..4b631fa6fb433 100644 --- a/flow/skia_gpu_object_unittests.cc +++ b/flow/skia_gpu_object_unittests.cc @@ -41,6 +41,7 @@ class TestResourceContext : public TestSkObject { : TestSkObject(latch, dtor_task_queue_id) {} ~TestResourceContext() = default; void performDeferredCleanup(std::chrono::milliseconds msNotUsed) {} + void deleteBackendTexture(GrBackendTexture texture) {} }; class SkiaGpuObjectTest : public ThreadTest { diff --git a/flow/testing/layer_test.h b/flow/testing/layer_test.h index e5672e1eacdd1..317c7109dc8dc 100644 --- a/flow/testing/layer_test.h +++ b/flow/testing/layer_test.h @@ -44,7 +44,8 @@ class LayerTestBase : public CanvasTestBase { public: LayerTestBase() - : preroll_context_{ + : texture_registry_(std::make_shared()), + preroll_context_{ // clang-format off .raster_cache = nullptr, .gr_context = nullptr, @@ -162,7 +163,9 @@ class LayerTestBase : public CanvasTestBase { std::vector& cacheable_items() { return cacheable_items_; } - TextureRegistry& texture_regitry() { return texture_registry_; } + std::shared_ptr texture_registry() { + return texture_registry_; + } RasterCache* raster_cache() { return raster_cache_.get(); } PrerollContext* preroll_context() { return &preroll_context_; } PaintContext& paint_context() { return paint_context_; } @@ -205,7 +208,7 @@ class LayerTestBase : public CanvasTestBase { FixedRefreshRateStopwatch raster_time_; FixedRefreshRateStopwatch ui_time_; MutatorsStack mutators_stack_; - TextureRegistry texture_registry_; + std::shared_ptr texture_registry_; std::unique_ptr raster_cache_; PrerollContext preroll_context_; diff --git a/flow/testing/mock_raster_cache.cc b/flow/testing/mock_raster_cache.cc index 3ce1be25cfcd8..33b81c15030b3 100644 --- a/flow/testing/mock_raster_cache.cc +++ b/flow/testing/mock_raster_cache.cc @@ -56,7 +56,10 @@ void MockRasterCache::AddMockPicture(int width, int height) { recorder.drawPath(path, SkPaint()); sk_sp display_list = recorder.Build(); - PaintContextHolder holder = GetSamplePaintContextHolder(this); + FixedRefreshRateStopwatch raster_time; + FixedRefreshRateStopwatch ui_time; + PaintContextHolder holder = + GetSamplePaintContextHolder(this, &raster_time, &ui_time); holder.paint_context.dst_color_space = color_space_; DisplayListRasterCacheItem display_list_item(display_list.get(), SkPoint(), @@ -81,31 +84,31 @@ void MockRasterCache::AddMockPicture(int width, int height) { }); } -PrerollContextHolder GetSamplePrerollContextHolder(RasterCache* raster_cache) { - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - TextureRegistry texture_registry; +PrerollContextHolder GetSamplePrerollContextHolder( + RasterCache* raster_cache, + FixedRefreshRateStopwatch* raster_time, + FixedRefreshRateStopwatch* ui_time, + MutatorsStack* mutators_stack) { sk_sp srgb = SkColorSpace::MakeSRGB(); PrerollContextHolder holder = { { // clang-format off .raster_cache = raster_cache, - .gr_context = nullptr, - .view_embedder = nullptr, - .mutators_stack = mutators_stack, - .dst_color_space = srgb.get(), - .cull_rect = kGiantRect, + .gr_context = nullptr, + .view_embedder = nullptr, + .mutators_stack = *mutators_stack, + .dst_color_space = srgb.get(), + .cull_rect = kGiantRect, .surface_needs_readback = false, - .raster_time = raster_time, - .ui_time = ui_time, - .texture_registry = texture_registry, - .checkerboard_offscreen_layers = false, - .frame_device_pixel_ratio = 1.0f, - .has_platform_view = false, + .raster_time = *raster_time, + .ui_time = *ui_time, + .texture_registry = nullptr, + .checkerboard_offscreen_layers = false, + .frame_device_pixel_ratio = 1.0f, + .has_platform_view = false, .has_texture_layer = false, - .raster_cached_entries = &raster_cache_items_, + .raster_cached_entries = &raster_cache_items_, // clang-format on }, srgb}; @@ -113,11 +116,10 @@ PrerollContextHolder GetSamplePrerollContextHolder(RasterCache* raster_cache) { return holder; } -PaintContextHolder GetSamplePaintContextHolder(RasterCache* raster_cache) { - FixedRefreshRateStopwatch raster_time; - FixedRefreshRateStopwatch ui_time; - MutatorsStack mutators_stack; - TextureRegistry texture_registry; +PaintContextHolder GetSamplePaintContextHolder( + RasterCache* raster_cache, + FixedRefreshRateStopwatch* raster_time, + FixedRefreshRateStopwatch* ui_time) { sk_sp srgb = SkColorSpace::MakeSRGB(); PaintContextHolder holder = {// clang-format off { @@ -126,9 +128,9 @@ PaintContextHolder GetSamplePaintContextHolder(RasterCache* raster_cache) { .gr_context = nullptr, .dst_color_space = srgb.get(), .view_embedder = nullptr, - .raster_time = raster_time, - .ui_time = ui_time, - .texture_registry = texture_registry, + .raster_time = *raster_time, + .ui_time = *ui_time, + .texture_registry = nullptr, .raster_cache = raster_cache, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, diff --git a/flow/testing/mock_raster_cache.h b/flow/testing/mock_raster_cache.h index d6b385b57d389..37742486409bb 100644 --- a/flow/testing/mock_raster_cache.h +++ b/flow/testing/mock_raster_cache.h @@ -72,7 +72,7 @@ class MockRasterCache : public RasterCache { MutatorsStack mutators_stack_; FixedRefreshRateStopwatch raster_time_; FixedRefreshRateStopwatch ui_time_; - TextureRegistry texture_registry_; + std::shared_ptr texture_registry_; PrerollContext preroll_context_ = { // clang-format off .raster_cache = this, @@ -122,10 +122,15 @@ struct PaintContextHolder { }; PrerollContextHolder GetSamplePrerollContextHolder( - RasterCache* raster_cache = nullptr); + RasterCache* raster_cache, + FixedRefreshRateStopwatch* raster_time, + FixedRefreshRateStopwatch* ui_time, + MutatorsStack* mutators_stack); PaintContextHolder GetSamplePaintContextHolder( - RasterCache* raster_cache = nullptr); + RasterCache* raster_cache, + FixedRefreshRateStopwatch* raster_time, + FixedRefreshRateStopwatch* ui_time); bool RasterCacheItemPrerollAndTryToRasterCache( DisplayListRasterCacheItem& display_list_item, diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 5be9029295f03..6a2916d9cb622 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -146,6 +146,7 @@ source_set("ui") { deps = [ "//flutter/assets", "//flutter/common", + "//flutter/common/graphics", "//flutter/display_list", "//flutter/fml", "//flutter/impeller/runtime_stage", diff --git a/lib/ui/painting/display_list_deferred_image_gpu.cc b/lib/ui/painting/display_list_deferred_image_gpu.cc index 3868cf1f06c0f..4580fe9801e2c 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.cc +++ b/lib/ui/painting/display_list_deferred_image_gpu.cc @@ -4,20 +4,45 @@ #include "flutter/lib/ui/painting/display_list_deferred_image_gpu.h" +#include "display_list_deferred_image_gpu.h" +#include "third_party/skia/include/core/SkColorSpace.h" + namespace flutter { -sk_sp DlDeferredImageGPU::Make(SkISize size) { - return sk_sp(new DlDeferredImageGPU(size)); +sk_sp DlDeferredImageGPU::Make( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + return sk_sp(new DlDeferredImageGPU( + ImageWrapper::Make(image_info, std::move(display_list), + std::move(snapshot_delegate), raster_task_runner, + std::move(unref_queue)), + raster_task_runner)); } -DlDeferredImageGPU::DlDeferredImageGPU(SkISize size) : size_(size) {} +DlDeferredImageGPU::DlDeferredImageGPU( + std::shared_ptr image_wrapper, + fml::RefPtr raster_task_runner) + : image_wrapper_(std::move(image_wrapper)), + raster_task_runner_(std::move(raster_task_runner)) {} // |DlImage| -DlDeferredImageGPU::~DlDeferredImageGPU() = default; +DlDeferredImageGPU::~DlDeferredImageGPU() { + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner_, [image_wrapper = std::move(image_wrapper_)]() { + if (!image_wrapper) { + return; + } + image_wrapper->Unregister(); + image_wrapper->DeleteTexture(); + }); +} // |DlImage| sk_sp DlDeferredImageGPU::skia_image() const { - return image_; + return image_wrapper_ ? image_wrapper_->CreateSkiaImage() : nullptr; }; // |DlImage| @@ -28,43 +53,127 @@ std::shared_ptr DlDeferredImageGPU::impeller_texture() // |DlImage| bool DlDeferredImageGPU::isTextureBacked() const { - if (auto image = skia_image()) { - return image->isTextureBacked(); - } - return false; + return image_wrapper_ ? image_wrapper_->isTextureBacked() : false; } // |DlImage| SkISize DlDeferredImageGPU::dimensions() const { - return size_; + return image_wrapper_ ? image_wrapper_->image_info().dimensions() + : SkISize::MakeEmpty(); } // |DlImage| size_t DlDeferredImageGPU::GetApproximateByteSize() const { - // This call is accessed on the UI thread, and image_ may not be available - // yet. The image is not mipmapped and it's created using N32 pixels, so this - // is safe. - if (size_.isEmpty()) { - return sizeof(this); + return sizeof(this) + (image_wrapper_ + ? image_wrapper_->image_info().computeMinByteSize() + : 0); +} + +std::optional DlDeferredImageGPU::get_error() const { + return image_wrapper_ ? image_wrapper_->get_error() : std::nullopt; +} + +std::shared_ptr +DlDeferredImageGPU::ImageWrapper::Make( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + auto wrapper = std::shared_ptr(new ImageWrapper( + image_info, std::move(display_list), std::move(snapshot_delegate), + std::move(raster_task_runner), std::move(unref_queue))); + wrapper->SnapshotDisplayList(); + return wrapper; +} + +DlDeferredImageGPU::ImageWrapper::ImageWrapper( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) + : image_info_(image_info), + display_list_(std::move(display_list)), + snapshot_delegate_(std::move(snapshot_delegate)), + raster_task_runner_(std::move(raster_task_runner)), + unref_queue_(std::move(unref_queue)) {} + +void DlDeferredImageGPU::ImageWrapper::OnGrContextCreated() { + FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); + SnapshotDisplayList(); +} + +void DlDeferredImageGPU::ImageWrapper::OnGrContextDestroyed() { + FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); + + DeleteTexture(); +} + +sk_sp DlDeferredImageGPU::ImageWrapper::CreateSkiaImage() const { + FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread()); + + if (texture_.isValid() && context_) { + return SkImage::MakeFromTexture( + context_.get(), texture_, kTopLeft_GrSurfaceOrigin, + image_info_.colorType(), image_info_.alphaType(), + image_info_.refColorSpace()); } - return sizeof(this) + size_.width() * size_.height() * 4; + return image_; } -void DlDeferredImageGPU::set_image(sk_sp image) { - FML_DCHECK(image); - FML_DCHECK(image->dimensions() == size_); - image_ = std::move(image); +bool DlDeferredImageGPU::ImageWrapper::isTextureBacked() const { + return texture_.isValid(); } -void DlDeferredImageGPU::set_error(const std::string& error) { - FML_DCHECK(!image_); - std::scoped_lock lock(error_mutex_); - error_ = std::move(error); +void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { + fml::TaskRunner::RunNowOrPostTask( + raster_task_runner_, [weak_this = weak_from_this()]() { + auto wrapper = weak_this.lock(); + if (!wrapper) { + return; + } + auto snapshot_delegate = wrapper->snapshot_delegate_; + if (!snapshot_delegate) { + return; + } + auto result = snapshot_delegate->MakeGpuImage(wrapper->display_list_, + wrapper->image_info_); + if (result->texture.isValid()) { + wrapper->texture_ = result->texture; + wrapper->context_ = std::move(result->context); + wrapper->texture_registry_ = + wrapper->snapshot_delegate_->GetTextureRegistry(); + wrapper->texture_registry_->RegisterContextListener( + reinterpret_cast(wrapper.get()), weak_this); + } else if (result->image) { + wrapper->image_ = std::move(result->image); + } else { + std::scoped_lock lock(wrapper->error_mutex_); + wrapper->error_ = std::move(result->error); + } + }); } -std::optional DlDeferredImageGPU::get_error() const { +std::optional DlDeferredImageGPU::ImageWrapper::get_error() { std::scoped_lock lock(error_mutex_); return error_; } +void DlDeferredImageGPU::ImageWrapper::Unregister() { + if (texture_registry_) { + texture_registry_->UnregisterContextListener( + reinterpret_cast(this)); + } +} + +void DlDeferredImageGPU::ImageWrapper::DeleteTexture() { + if (texture_.isValid()) { + unref_queue_->DeleteTexture(std::move(texture_)); + texture_ = GrBackendTexture(); + } + image_.reset(); + context_.reset(); +} + } // namespace flutter diff --git a/lib/ui/painting/display_list_deferred_image_gpu.h b/lib/ui/painting/display_list_deferred_image_gpu.h index 0cec807fe7a99..a98f4feaa4236 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.h +++ b/lib/ui/painting/display_list_deferred_image_gpu.h @@ -5,23 +5,37 @@ #ifndef FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_DEFERRED_IMAGE_GPU_H_ #define FLUTTER_LIB_UI_PAINTING_DISPLAY_LIST_DEFERRED_IMAGE_GPU_H_ +#include #include +#include "flutter/common/graphics/texture.h" +#include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_image.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/lib/ui/io_manager.h" +#include "flutter/lib/ui/snapshot_delegate.h" namespace flutter { class DlDeferredImageGPU final : public DlImage { public: - static sk_sp Make(SkISize size); + static sk_sp Make( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); // |DlImage| ~DlDeferredImageGPU() override; // |DlImage| // This method is only safe to call from the raster thread. + // Callers must not hold long term references to this image and + // only use it for the immediate painting operation. It must be + // collected on the raster task runner. sk_sp skia_image() const override; // |DlImage| @@ -36,12 +50,6 @@ class DlDeferredImageGPU final : public DlImage { // |DlImage| virtual size_t GetApproximateByteSize() const override; - // This method must only be called from the raster thread. - void set_image(sk_sp image); - - // This method is safe to call from any thread. - void set_error(const std::string& error); - // |DlImage| // This method is safe to call from any thread. std::optional get_error() const override; @@ -52,12 +60,61 @@ class DlDeferredImageGPU final : public DlImage { } private: - sk_sp image_; - SkISize size_; - mutable std::mutex error_mutex_; - std::optional error_; - - explicit DlDeferredImageGPU(SkISize size); + class ImageWrapper final : public std::enable_shared_from_this, + public ContextListener { + public: + static std::shared_ptr Make( + const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + + const SkImageInfo image_info() const { return image_info_; } + const GrBackendTexture& texture() const { return texture_; } + bool isTextureBacked() const; + std::optional get_error(); + sk_sp CreateSkiaImage() const; + void Unregister(); + void DeleteTexture(); + + private: + const SkImageInfo image_info_; + sk_sp display_list_; + fml::WeakPtr snapshot_delegate_; + fml::RefPtr raster_task_runner_; + fml::RefPtr unref_queue_; + std::shared_ptr texture_registry_; + + mutable std::mutex error_mutex_; + std::optional error_; + + GrBackendTexture texture_; + sk_sp context_; + // May be used if this image is not texture backed. + sk_sp image_; + + ImageWrapper(const SkImageInfo& image_info, + sk_sp display_list, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + + void SnapshotDisplayList(); + + // |ContextListener| + void OnGrContextCreated() override; + + // |ContextListener| + void OnGrContextDestroyed() override; + }; + + const std::shared_ptr image_wrapper_; + + fml::RefPtr raster_task_runner_; + + DlDeferredImageGPU(std::shared_ptr image_wrapper, + fml::RefPtr raster_task_runner); FML_DISALLOW_COPY_AND_ASSIGN(DlDeferredImageGPU); }; diff --git a/lib/ui/painting/image_encoding.cc b/lib/ui/painting/image_encoding.cc index 993e7d44a6826..1e28774932910 100644 --- a/lib/ui/painting/image_encoding.cc +++ b/lib/ui/painting/image_encoding.cc @@ -60,21 +60,6 @@ void InvokeDataCallback(std::unique_ptr callback, DartInvoke(callback->value(), {dart_data}); } -static void ConvertGpuImageToRaster( - sk_sp dl_image, - std::function)> encode_task, - fml::RefPtr raster_task_runner) { - fml::TaskRunner::RunNowOrPostTask( - raster_task_runner, [dl_image, encode_task = std::move(encode_task)]() { - auto image = dl_image->skia_image(); - if (image == nullptr) { - encode_task(nullptr); - return; - } - encode_task(image->makeRasterImage()); - }); -} - void ConvertImageToRaster( sk_sp dl_image, std::function)> encode_task, @@ -83,43 +68,48 @@ void ConvertImageToRaster( fml::WeakPtr resource_context, fml::WeakPtr snapshot_delegate, const std::shared_ptr& is_gpu_disabled_sync_switch) { - auto image = dl_image->skia_image(); - - // Check validity of the image. - if (image == nullptr) { - FML_LOG(ERROR) << "Image was null."; - encode_task(nullptr); - return; - } + // If the owning_context is kRaster, we can't access it on this task runner. + if (dl_image->owning_context() != DlImage::OwningContext::kRaster) { + auto image = dl_image->skia_image(); + + // Check validity of the image. + if (image == nullptr) { + FML_LOG(ERROR) << "Image was null."; + encode_task(nullptr); + return; + } - auto dimensions = image->dimensions(); + auto dimensions = image->dimensions(); - if (dimensions.isEmpty()) { - FML_LOG(ERROR) << "Image dimensions were empty."; - encode_task(nullptr); - return; - } + if (dimensions.isEmpty()) { + FML_LOG(ERROR) << "Image dimensions were empty."; + encode_task(nullptr); + return; + } - SkPixmap pixmap; - if (image->peekPixels(&pixmap)) { - // This is already a raster image. - encode_task(image); - return; - } + SkPixmap pixmap; + if (image->peekPixels(&pixmap)) { + // This is already a raster image. + encode_task(image); + return; + } - if (sk_sp raster_image = image->makeRasterImage()) { - // The image can be converted to a raster image. - encode_task(raster_image); - return; + if (sk_sp raster_image = image->makeRasterImage()) { + // The image can be converted to a raster image. + encode_task(raster_image); + return; + } } // Cross-context images do not support makeRasterImage. Convert these images // by drawing them into a surface. This must be done on the raster thread // to prevent concurrent usage of the image on both the IO and raster threads. - raster_task_runner->PostTask([image, encode_task = std::move(encode_task), + raster_task_runner->PostTask([dl_image, encode_task = std::move(encode_task), resource_context, snapshot_delegate, - io_task_runner, is_gpu_disabled_sync_switch]() { - if (!snapshot_delegate) { + io_task_runner, is_gpu_disabled_sync_switch, + raster_task_runner]() { + auto image = dl_image->skia_image(); + if (!image || !snapshot_delegate) { io_task_runner->PostTask( [encode_task = std::move(encode_task)]() mutable { encode_task(nullptr); @@ -132,8 +122,9 @@ void ConvertImageToRaster( io_task_runner->PostTask([image, encode_task = std::move(encode_task), raster_image = std::move(raster_image), - resource_context, - is_gpu_disabled_sync_switch]() mutable { + resource_context, is_gpu_disabled_sync_switch, + owning_context = dl_image->owning_context(), + raster_task_runner]() mutable { if (!raster_image) { // The rasterizer was unable to render the cross-context image // (presumably because it does not have a GrContext). In that case, @@ -142,6 +133,9 @@ void ConvertImageToRaster( image, resource_context, is_gpu_disabled_sync_switch); } encode_task(raster_image); + if (owning_context == DlImage::OwningContext::kRaster) { + raster_task_runner->PostTask([image = std::move(image)]() {}); + } }); }); } @@ -246,17 +240,9 @@ void EncodeImageAndInvokeDataCallback( }; FML_DCHECK(image); - switch (image->owning_context()) { - case DlImage::OwningContext::kRaster: - ConvertGpuImageToRaster(std::move(image), encode_task, - raster_task_runner); - break; - case DlImage::OwningContext::kIO: - ConvertImageToRaster(std::move(image), encode_task, raster_task_runner, - io_task_runner, resource_context, snapshot_delegate, - is_gpu_disabled_sync_switch); - break; - } + ConvertImageToRaster(std::move(image), encode_task, raster_task_runner, + io_task_runner, resource_context, snapshot_delegate, + is_gpu_disabled_sync_switch); } } // namespace diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index c868101ef18cb..dd64f1b2d7696 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -59,29 +59,20 @@ void Picture::RasterizeToImageSync(sk_sp display_list, uint32_t height, Dart_Handle raw_image_handle) { auto* dart_state = UIDartState::Current(); + if (!dart_state) { + return; + } auto unref_queue = dart_state->GetSkiaUnrefQueue(); auto snapshot_delegate = dart_state->GetSnapshotDelegate(); auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); auto image = CanvasImage::Create(); - auto dl_image = DlDeferredImageGPU::Make(SkISize::Make(width, height)); + const SkImageInfo image_info = SkImageInfo::Make( + width, height, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); + auto dl_image = DlDeferredImageGPU::Make( + image_info, std::move(display_list), std::move(snapshot_delegate), + std::move(raster_task_runner), std::move(unref_queue)); image->set_image(dl_image); - - fml::TaskRunner::RunNowOrPostTask( - raster_task_runner, - [snapshot_delegate, unref_queue, dl_image = std::move(dl_image), - display_list = std::move(display_list)]() { - sk_sp sk_image; - std::string error; - std::tie(sk_image, error) = snapshot_delegate->MakeGpuImage( - display_list, dl_image->dimensions()); - if (sk_image) { - dl_image->set_image(std::move(sk_image)); - } else { - dl_image->set_error(std::move(error)); - } - }); - image->AssociateWithDartWrapper(raw_image_handle); } diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 7c87a01c865d9..4158d28701cbb 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -7,18 +7,54 @@ #include +#include "flutter/common/graphics/texture.h" #include "flutter/display_list/display_list.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkPromiseImageTexture.h" #include "third_party/skia/include/gpu/GrContextThreadSafeProxy.h" + namespace flutter { class SnapshotDelegate { public: - virtual std::pair, std::string> MakeGpuImage( + struct GpuImageResult { + GpuImageResult(const GrBackendTexture& p_texture, + sk_sp p_context, + sk_sp p_image = nullptr, + const std::string& p_error = "") + : texture(p_texture), + context(std::move(p_context)), + image(std::move(p_image)), + error(p_error) {} + + const GrBackendTexture texture; + // If texture.isValid() == true, this is a pointer to a GrDirectContext that + // can be used to create an image from the texture. + sk_sp context; + // If MakeGpuImage could not create a GPU resident image, a raster copy + // is available in this member and texture.isValid() is false. + sk_sp image; + + // A non-empty string containing an error message if neither a GPU backed + // texture nor a raster backed image could be created. + const std::string error; + }; + + //---------------------------------------------------------------------------- + /// @brief Gets the registry of external textures currently in use by the + /// rasterizer. These textures may be updated at a cadence + /// different from that of the Flutter application. When an + /// external texture is referenced in the Flutter layer tree, that + /// texture is composited within the Flutter layer tree. + /// + /// @return A pointer to the external texture registry. + /// + virtual std::shared_ptr GetTextureRegistry() = 0; + + virtual std::unique_ptr MakeGpuImage( sk_sp display_list, - SkISize picture_size) = 0; + const SkImageInfo& image_info) = 0; virtual sk_sp MakeRasterSnapshot( std::function draw_callback, diff --git a/shell/common/fixtures/shell_test.dart b/shell/common/fixtures/shell_test.dart index b8908bdd24563..a41715add9a68 100644 --- a/shell/common/fixtures/shell_test.dart +++ b/shell/common/fixtures/shell_test.dart @@ -339,8 +339,28 @@ Future toImageSync() async { expect(image.width, 20); expect(image.height, 25); - final ByteData data = (await image.toByteData())!; - expect(data.lengthInBytes, 20 * 25 * 4); - expect(data.buffer.asUint32List().every((int byte) => byte == 0xFFAAAAAA), true); + final ByteData dataBefore = (await image.toByteData())!; + expect(dataBefore.lengthInBytes, 20 * 25 * 4); + for (final int byte in dataBefore.buffer.asUint32List()) { + expect(byte, 0xFFAAAAAA); + } + + // Cause the rasterizer to get torn down. + notifyNative(); + + final ByteData dataAfter = (await image.toByteData())!; + expect(dataAfter.lengthInBytes, 20 * 25 * 4); + for (final int byte in dataAfter.buffer.asUint32List()) { + expect(byte, 0xFFAAAAAA); + } + + // Verify that the image can be drawn successfully. + final PictureRecorder recorder2 = PictureRecorder(); + final Canvas canvas2 = Canvas(recorder2); + canvas2.drawImage(image, Offset.zero, Paint()); + final Picture picture2 = recorder2.endRecording(); + + picture.dispose(); + picture2.dispose(); notifyNative(); } diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index db5ef54055cc8..d3ecb11fee8ec 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -141,8 +141,8 @@ void Rasterizer::NotifyLowMemoryWarning() const { context->performDeferredCleanup(std::chrono::milliseconds(0)); } -flutter::TextureRegistry* Rasterizer::GetTextureRegistry() { - return &compositor_context_->texture_registry(); +std::shared_ptr Rasterizer::GetTextureRegistry() { + return compositor_context_->texture_registry(); } flutter::LayerTree* Rasterizer::GetLastLayerTree() { @@ -248,7 +248,7 @@ bool Rasterizer::ShouldResubmitFrame(const RasterStatus& raster_status) { } namespace { -std::pair, std::string> MakeBitmapImage( +std::unique_ptr MakeBitmapImage( sk_sp display_list, const SkImageInfo& image_info) { FML_DCHECK(display_list); @@ -258,8 +258,10 @@ std::pair, std::string> MakeBitmapImage( // This limit is taken from the Metal specification. D3D, Vulkan, and GL // generally have lower limits. if (image_info.width() > 16384 || image_info.height() > 16384) { - return {nullptr, "unable to create render target at specified size"}; - } + return std::make_unique( + GrBackendTexture(), nullptr, nullptr, + "unable to create render target at specified size"); + }; sk_sp surface = SkSurface::MakeRaster(image_info); SkCanvas* canvas = surface->getCanvas(); @@ -267,18 +269,26 @@ std::pair, std::string> MakeBitmapImage( display_list->RenderTo(canvas); sk_sp image = surface->makeImageSnapshot(); - return {image, image ? "" : "Unable to create image"}; + return std::make_unique( + GrBackendTexture(), nullptr, image, + image ? "" : "Unable to create image"); } } // namespace -std::pair, std::string> Rasterizer::MakeGpuImage( +std::unique_ptr Rasterizer::MakeGpuImage( sk_sp display_list, - SkISize picture_size) { + const SkImageInfo& image_info) { TRACE_EVENT0("flutter", "Rasterizer::MakeGpuImage"); FML_DCHECK(display_list); - const SkImageInfo image_info = SkImageInfo::MakeN32Premul(picture_size); - std::pair, std::string> result; +// TODO(dnfield): the Linux embedding is in a rough state right now and +// I can't seem to get the GPU path working on it. +// https://github.com/flutter/flutter/issues/108835 +#if FML_OS_LINUX + return MakeBitmapImage(std::move(display_list), image_info); +#endif + + std::unique_ptr result; delegate_.GetIsGpuDisabledSyncSwitch()->Execute( fml::SyncSwitch::Handlers() .SetIfTrue([&result, &image_info, &display_list] { @@ -299,11 +309,23 @@ std::pair, std::string> Rasterizer::MakeGpuImage( return; } - sk_sp sk_surface = SkSurface::MakeRenderTarget( - context, SkBudgeted::kYes, image_info); + GrBackendTexture texture = context->createBackendTexture( + image_info.width(), image_info.height(), image_info.colorType(), + GrMipmapped::kNo, GrRenderable::kYes); + if (!texture.isValid()) { + result = std::make_unique( + GrBackendTexture(), nullptr, nullptr, + "unable to create render target at specified size"); + return; + } + + sk_sp sk_surface = SkSurface::MakeFromBackendTexture( + context, texture, kTopLeft_GrSurfaceOrigin, /*sampleCnt=*/0, + image_info.colorType(), image_info.refColorSpace(), nullptr); if (!sk_surface) { - result = {nullptr, - "unable to create render target at specified size"}; + result = std::make_unique( + GrBackendTexture(), nullptr, nullptr, + "unable to create rendering surface for image"); return; } @@ -311,8 +333,8 @@ std::pair, std::string> Rasterizer::MakeGpuImage( canvas->clear(SK_ColorTRANSPARENT); display_list->RenderTo(canvas); - sk_sp image = sk_surface->makeImageSnapshot(); - result = {image, image ? "" : "Unable to create image"}; + result = std::make_unique( + texture, sk_ref_sp(context), nullptr, ""); })); return result; } diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 425b8214e5bd4..2f90ed5b1fe66 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -212,16 +212,8 @@ class Rasterizer final : public SnapshotDelegate, void DrawLastLayerTree( std::unique_ptr frame_timings_recorder); - //---------------------------------------------------------------------------- - /// @brief Gets the registry of external textures currently in use by the - /// rasterizer. These textures may be updated at a cadence - /// different from that of the Flutter application. When an - /// external texture is referenced in the Flutter layer tree, that - /// texture is composited within the Flutter layer tree. - /// - /// @return A pointer to the external texture registry. - /// - flutter::TextureRegistry* GetTextureRegistry(); + // |SnapshotDelegate| + std::shared_ptr GetTextureRegistry() override; using LayerTreeDiscardCallback = std::function; @@ -470,9 +462,9 @@ class Rasterizer final : public SnapshotDelegate, private: // |SnapshotDelegate| - std::pair, std::string> MakeGpuImage( + std::unique_ptr MakeGpuImage( sk_sp display_list, - SkISize picture_size) override; + const SkImageInfo& image_info) override; // |SnapshotDelegate| sk_sp MakeRasterSnapshot( diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 6c80032b46491..bc8594bc90cdb 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -1040,7 +1040,7 @@ void Shell::OnPlatformViewRegisterTexture( task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), texture] { if (rasterizer) { - if (auto* registry = rasterizer->GetTextureRegistry()) { + if (auto registry = rasterizer->GetTextureRegistry()) { registry->RegisterTexture(texture); } } @@ -1055,7 +1055,7 @@ void Shell::OnPlatformViewUnregisterTexture(int64_t texture_id) { task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { if (rasterizer) { - if (auto* registry = rasterizer->GetTextureRegistry()) { + if (auto registry = rasterizer->GetTextureRegistry()) { registry->UnregisterTexture(texture_id); } } @@ -1070,7 +1070,7 @@ void Shell::OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) { // Tell the rasterizer that one of its textures has a new frame available. task_runners_.GetRasterTaskRunner()->PostTask( [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { - auto* registry = rasterizer->GetTextureRegistry(); + auto registry = rasterizer->GetTextureRegistry(); if (!registry) { return; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index e4a86b5775a34..7bd244d98aba2 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -2382,7 +2382,6 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { FixedRefreshRateStopwatch raster_time; FixedRefreshRateStopwatch ui_time; MutatorsStack mutators_stack; - TextureRegistry texture_registry; PaintContext paint_context = { // clang-format off .internal_nodes_canvas = nullptr, @@ -2392,7 +2391,7 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { .view_embedder = nullptr, .raster_time = raster_time, .ui_time = ui_time, - .texture_registry = texture_registry, + .texture_registry = nullptr, .raster_cache = &raster_cache, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, @@ -2411,7 +2410,7 @@ TEST_F(ShellTest, OnServiceProtocolEstimateRasterCacheMemoryWorks) { .surface_needs_readback = false, .raster_time = raster_time, .ui_time = ui_time, - .texture_registry = texture_registry, + .texture_registry = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, .has_platform_view = false, @@ -3765,7 +3764,7 @@ TEST_F(ShellTest, SpawnWorksWithOnError) { TEST_F(ShellTest, PictureToImageSync) { #if !SHELL_ENABLE_GL - // GL emulation does not exist on Fuchsia. + // This test uses the GL backend. GTEST_SKIP(); #endif // !SHELL_ENABLE_GL auto settings = CreateSettingsForFixture(); @@ -3778,9 +3777,12 @@ TEST_F(ShellTest, PictureToImageSync) { ShellTestPlatformView::BackendType::kGLBackend // ); - fml::AutoResetWaitableEvent latch; - AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&latch](auto args) { - latch.Signal(); + fml::CountDownLatch latch(2); + AddNativeCallback("NotifyNative", CREATE_NATIVE_ENTRY([&](auto args) { + // Teardown and set up rasterizer again. + PlatformViewNotifyDestroyed(shell.get()); + PlatformViewNotifyCreated(shell.get()); + latch.CountDown(); })); ASSERT_NE(shell, nullptr); From a5668bb24209d46d80af8f636e65132ed2faba42 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 19:30:04 -0400 Subject: [PATCH 213/558] Roll Skia from 93297d54df57 to 0cc4b51ab9d5 (4 revisions) (#35286) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f3253f2def73e..7f89e8fe11af7 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': '93297d54df57ea3e77d37c804664d95122938e6d', + 'skia_revision': '0cc4b51ab9d5c72c052db4cf3782583df0dfa44e', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f51f038dbbd0f..d50ed0edd4e1e 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 6c6e82c5524f9bdac315698ff1eb7b70 +Signature: f779394be911a5e2b2e154726881571a UNUSED LICENSES: From 228c5a84da45559f3281fe186952069e97837af9 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 10 Aug 2022 01:55:41 +0200 Subject: [PATCH 214/558] [Linux] use top-level GTK IM client window (#35272) This PR takes a step back and changes the GTK IM client window back from FlView to GtkApplicationWindow as it was before #33111. The window was originally changed to FlView to make the code testable by cutting a dependency to gtk_widget_translate_coordinates(). The change was hard to revert because there were several conflicting changes on top. Therefore, this PR introduces an FlTextInputViewDelegate to be able to provide coordinate mapping in a testable way. Fixes: flutter/flutter#108832 --- ci/licenses_golden/licenses_flutter | 2 + shell/platform/linux/BUILD.gn | 2 + shell/platform/linux/fl_text_input_plugin.cc | 26 ++++++- shell/platform/linux/fl_text_input_plugin.h | 8 +- .../linux/fl_text_input_plugin_test.cc | 54 ++++++++++---- .../linux/fl_text_input_view_delegate.cc | 24 ++++++ .../linux/fl_text_input_view_delegate.h | 48 ++++++++++++ shell/platform/linux/fl_view.cc | 26 ++++++- .../testing/mock_text_input_view_delegate.cc | 74 +++++++++++++++++++ .../testing/mock_text_input_view_delegate.h | 39 ++++++++++ 10 files changed, 279 insertions(+), 24 deletions(-) create mode 100644 shell/platform/linux/fl_text_input_view_delegate.cc create mode 100644 shell/platform/linux/fl_text_input_view_delegate.h create mode 100644 shell/platform/linux/testing/mock_text_input_view_delegate.cc create mode 100644 shell/platform/linux/testing/mock_text_input_view_delegate.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 24274f98c999c..9c2ebc77f49ca 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2321,6 +2321,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_task_runner.h FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.cc FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin.h FILE: ../../../flutter/shell/platform/linux/fl_text_input_plugin_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_text_input_view_delegate.cc +FILE: ../../../flutter/shell/platform/linux/fl_text_input_view_delegate.h FILE: ../../../flutter/shell/platform/linux/fl_texture.cc FILE: ../../../flutter/shell/platform/linux/fl_texture_gl.cc FILE: ../../../flutter/shell/platform/linux/fl_texture_gl_private.h diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 6e70e49162033..4c1cbc4a75dea 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -141,6 +141,7 @@ source_set("flutter_linux_sources") { "fl_task_runner.cc", "fl_task_runner.h", "fl_text_input_plugin.cc", + "fl_text_input_view_delegate.cc", "fl_texture.cc", "fl_texture_gl.cc", "fl_texture_registrar.cc", @@ -234,6 +235,7 @@ executable("flutter_linux_unittests") { "testing/mock_settings.cc", "testing/mock_signal_handler.cc", "testing/mock_text_input_plugin.cc", + "testing/mock_text_input_view_delegate.cc", "testing/mock_texture_registrar.cc", ] diff --git a/shell/platform/linux/fl_text_input_plugin.cc b/shell/platform/linux/fl_text_input_plugin.cc index b4974c27101f7..bdc0762fe1f46 100644 --- a/shell/platform/linux/fl_text_input_plugin.cc +++ b/shell/platform/linux/fl_text_input_plugin.cc @@ -80,6 +80,8 @@ struct FlTextInputPluginPrivate { // Input method. GtkIMContext* im_context; + FlTextInputViewDelegate* view_delegate; + flutter::TextInputModel* text_model; // A 4x4 matrix that maps from `EditableText` local coordinates to the @@ -487,9 +489,13 @@ static void update_im_cursor_position(FlTextInputPlugin* self) { priv->composing_rect.y * priv->editabletext_transform[1][1] + priv->editabletext_transform[3][1] + priv->composing_rect.height; + // Transform from Flutter view coordinates to GTK window coordinates. + GdkRectangle preedit_rect = {}; + fl_text_input_view_delegate_translate_coordinates( + priv->view_delegate, x, y, &preedit_rect.x, &preedit_rect.y); + // Set the cursor location in window coordinates so that GTK can position any // system input method windows. - GdkRectangle preedit_rect = {x, y, 0, 0}; gtk_im_context_set_cursor_location(priv->im_context, &preedit_rect); } @@ -587,6 +593,12 @@ static void fl_text_input_plugin_dispose(GObject* object) { delete priv->text_model; priv->text_model = nullptr; } + if (priv->view_delegate != nullptr) { + g_object_remove_weak_pointer( + G_OBJECT(priv->view_delegate), + reinterpret_cast(&(priv->view_delegate))); + priv->view_delegate = nullptr; + } G_OBJECT_CLASS(fl_text_input_plugin_parent_class)->dispose(object); } @@ -719,10 +731,13 @@ static void init_im_context(FlTextInputPlugin* self, GtkIMContext* im_context) { G_CONNECT_SWAPPED); } -FlTextInputPlugin* fl_text_input_plugin_new(FlBinaryMessenger* messenger, - GtkIMContext* im_context) { +FlTextInputPlugin* fl_text_input_plugin_new( + FlBinaryMessenger* messenger, + GtkIMContext* im_context, + FlTextInputViewDelegate* view_delegate) { g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); g_return_val_if_fail(GTK_IS_IM_CONTEXT(im_context), nullptr); + g_return_val_if_fail(FL_IS_TEXT_INPUT_VIEW_DELEGATE(view_delegate), nullptr); FlTextInputPlugin* self = FL_TEXT_INPUT_PLUGIN( g_object_new(fl_text_input_plugin_get_type(), nullptr)); @@ -737,6 +752,11 @@ FlTextInputPlugin* fl_text_input_plugin_new(FlBinaryMessenger* messenger, init_im_context(self, im_context); + priv->view_delegate = view_delegate; + g_object_add_weak_pointer( + G_OBJECT(view_delegate), + reinterpret_cast(&(priv->view_delegate))); + return self; } diff --git a/shell/platform/linux/fl_text_input_plugin.h b/shell/platform/linux/fl_text_input_plugin.h index d432698ea5f63..d2c25ebb16b50 100644 --- a/shell/platform/linux/fl_text_input_plugin.h +++ b/shell/platform/linux/fl_text_input_plugin.h @@ -8,6 +8,7 @@ #include #include "flutter/shell/platform/linux/fl_key_event.h" +#include "flutter/shell/platform/linux/fl_text_input_view_delegate.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" G_BEGIN_DECLS @@ -38,14 +39,17 @@ struct _FlTextInputPluginClass { * fl_text_input_plugin_new: * @messenger: an #FlBinaryMessenger. * @im_context: (allow-none): a #GtkIMContext. + * @view_delegate: an #FlTextInputViewDelegate. * * Creates a new plugin that implements SystemChannels.textInput from the * Flutter services library. * * Returns: a new #FlTextInputPlugin. */ -FlTextInputPlugin* fl_text_input_plugin_new(FlBinaryMessenger* messenger, - GtkIMContext* im_context); +FlTextInputPlugin* fl_text_input_plugin_new( + FlBinaryMessenger* messenger, + GtkIMContext* im_context, + FlTextInputViewDelegate* view_delegate); /** * fl_text_input_plugin_filter_keypress diff --git a/shell/platform/linux/fl_text_input_plugin_test.cc b/shell/platform/linux/fl_text_input_plugin_test.cc index 3692e6584c9c8..8f0c55ccb02ac 100644 --- a/shell/platform/linux/fl_text_input_plugin_test.cc +++ b/shell/platform/linux/fl_text_input_plugin_test.cc @@ -11,6 +11,7 @@ #include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" #include "flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h" #include "flutter/shell/platform/linux/testing/mock_im_context.h" +#include "flutter/shell/platform/linux/testing/mock_text_input_view_delegate.h" #include "flutter/testing/testing.h" #include "gmock/gmock.h" @@ -189,9 +190,10 @@ static void send_key_event(FlTextInputPlugin* plugin, TEST(FlTextInputPluginTest, MessageHandler) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); EXPECT_TRUE(messenger.HasMessageHandler("flutter/textinput")); @@ -200,9 +202,10 @@ TEST(FlTextInputPluginTest, MessageHandler) { TEST(FlTextInputPluginTest, SetClient) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); g_autoptr(FlValue) args = build_input_config({.client_id = 1}); @@ -222,9 +225,10 @@ TEST(FlTextInputPluginTest, SetClient) { TEST(FlTextInputPluginTest, Show) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); EXPECT_CALL(context, @@ -246,9 +250,10 @@ TEST(FlTextInputPluginTest, Show) { TEST(FlTextInputPluginTest, Hide) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); EXPECT_CALL(context, @@ -270,9 +275,10 @@ TEST(FlTextInputPluginTest, Hide) { TEST(FlTextInputPluginTest, ClearClient) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); g_autoptr(FlValue) null = fl_value_new_null(); @@ -291,9 +297,10 @@ TEST(FlTextInputPluginTest, ClearClient) { TEST(FlTextInputPluginTest, PerformAction) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); // set input config @@ -366,9 +373,10 @@ TEST(FlTextInputPluginTest, PerformAction) { TEST(FlTextInputPluginTest, MoveCursor) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); // set input config @@ -443,9 +451,10 @@ TEST(FlTextInputPluginTest, MoveCursor) { TEST(FlTextInputPluginTest, Select) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); // set input config @@ -520,9 +529,10 @@ TEST(FlTextInputPluginTest, Select) { TEST(FlTextInputPluginTest, Composing) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); g_signal_emit_by_name(context, "preedit-start", nullptr); @@ -589,9 +599,10 @@ TEST(FlTextInputPluginTest, Composing) { TEST(FlTextInputPluginTest, SurroundingText) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); // set input config @@ -658,9 +669,10 @@ TEST(FlTextInputPluginTest, SurroundingText) { TEST(FlTextInputPluginTest, SetMarkedTextRect) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); g_signal_emit_by_name(context, "preedit-start", nullptr); @@ -719,11 +731,18 @@ TEST(FlTextInputPluginTest, SetMarkedTextRect) { ::testing::_, SuccessResponse(null), ::testing::_)) .WillOnce(::testing::Return(true)); + EXPECT_CALL(delegate, fl_text_input_view_delegate_translate_coordinates( + ::testing::Eq(delegate), + ::testing::Eq(27), ::testing::Eq(32), ::testing::_, + ::testing::_)) + .WillOnce(::testing::DoAll(::testing::SetArgPointee<3>(123), + ::testing::SetArgPointee<4>(456))); + EXPECT_CALL(context, gtk_im_context_set_cursor_location( ::testing::Eq(context), ::testing::Pointee(::testing::AllOf( - ::testing::Field(&GdkRectangle::x, 27), - ::testing::Field(&GdkRectangle::y, 32), + ::testing::Field(&GdkRectangle::x, 123), + ::testing::Field(&GdkRectangle::y, 456), ::testing::Field(&GdkRectangle::width, 0), ::testing::Field(&GdkRectangle::height, 0))))); @@ -733,9 +752,10 @@ TEST(FlTextInputPluginTest, SetMarkedTextRect) { TEST(FlTextInputPluginTest, TextInputTypeNone) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); g_autoptr(FlValue) args = build_input_config({ @@ -775,9 +795,10 @@ TEST(FlTextInputPluginTest, TextInputTypeNone) { TEST(FlTextInputPluginTest, TextEditingDelta) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); // set config @@ -846,9 +867,10 @@ TEST(FlTextInputPluginTest, TextEditingDelta) { TEST(FlTextInputPluginTest, ComposingDelta) { ::testing::NiceMock messenger; ::testing::NiceMock context; + ::testing::NiceMock delegate; g_autoptr(FlTextInputPlugin) plugin = - fl_text_input_plugin_new(messenger, context); + fl_text_input_plugin_new(messenger, context, delegate); EXPECT_NE(plugin, nullptr); // set config diff --git a/shell/platform/linux/fl_text_input_view_delegate.cc b/shell/platform/linux/fl_text_input_view_delegate.cc new file mode 100644 index 0000000000000..52e94d4391a88 --- /dev/null +++ b/shell/platform/linux/fl_text_input_view_delegate.cc @@ -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. + +#include "flutter/shell/platform/linux/fl_text_input_view_delegate.h" + +G_DEFINE_INTERFACE(FlTextInputViewDelegate, + fl_text_input_view_delegate, + G_TYPE_OBJECT) + +static void fl_text_input_view_delegate_default_init( + FlTextInputViewDelegateInterface* iface) {} + +void fl_text_input_view_delegate_translate_coordinates( + FlTextInputViewDelegate* self, + gint view_x, + gint view_y, + gint* window_x, + gint* window_y) { + g_return_if_fail(FL_IS_TEXT_INPUT_VIEW_DELEGATE(self)); + + FL_TEXT_INPUT_VIEW_DELEGATE_GET_IFACE(self)->translate_coordinates( + self, view_x, view_y, window_x, window_y); +} diff --git a/shell/platform/linux/fl_text_input_view_delegate.h b/shell/platform/linux/fl_text_input_view_delegate.h new file mode 100644 index 0000000000000..6c8b491f19f89 --- /dev/null +++ b/shell/platform/linux/fl_text_input_view_delegate.h @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXT_INPUT_VIEW_DELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXT_INPUT_VIEW_DELEGATE_H_ + +#include + +#include "flutter/shell/platform/embedder/embedder.h" + +G_BEGIN_DECLS + +G_DECLARE_INTERFACE(FlTextInputViewDelegate, + fl_text_input_view_delegate, + FL, + TEXT_INPUT_VIEW_DELEGATE, + GObject); + +/** + * FlTextInputViewDelegate: + * + * An interface for a class that provides `FlTextInputPlugin` with + * view-related features. + * + * This interface is typically implemented by `FlView`. + */ + +struct _FlTextInputViewDelegateInterface { + GTypeInterface g_iface; + + void (*translate_coordinates)(FlTextInputViewDelegate* delegate, + gint view_x, + gint view_y, + gint* window_x, + gint* window_y); +}; + +void fl_text_input_view_delegate_translate_coordinates( + FlTextInputViewDelegate* delegate, + gint view_x, + gint view_y, + gint* window_x, + gint* window_y); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_TEXT_INPUT_VIEW_DELEGATE_H_ diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index de676c90b0999..445fc77a23826 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -20,6 +20,7 @@ #include "flutter/shell/platform/linux/fl_scrolling_manager.h" #include "flutter/shell/platform/linux/fl_scrolling_view_delegate.h" #include "flutter/shell/platform/linux/fl_text_input_plugin.h" +#include "flutter/shell/platform/linux/fl_text_input_view_delegate.h" #include "flutter/shell/platform/linux/fl_view_accessible.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" @@ -82,6 +83,9 @@ static void fl_view_keyboard_delegate_iface_init( static void fl_view_scrolling_delegate_iface_init( FlScrollingViewDelegateInterface* iface); +static void fl_view_text_input_delegate_iface_init( + FlTextInputViewDelegateInterface* iface); + G_DEFINE_TYPE_WITH_CODE( FlView, fl_view, @@ -91,18 +95,22 @@ G_DEFINE_TYPE_WITH_CODE( G_IMPLEMENT_INTERFACE(fl_keyboard_view_delegate_get_type(), fl_view_keyboard_delegate_iface_init) G_IMPLEMENT_INTERFACE(fl_scrolling_view_delegate_get_type(), - fl_view_scrolling_delegate_iface_init)) + fl_view_scrolling_delegate_iface_init) + G_IMPLEMENT_INTERFACE(fl_text_input_view_delegate_get_type(), + fl_view_text_input_delegate_iface_init)) // Initialize keyboard manager. static void init_keyboard(FlView* self) { FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine); - GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(self)); + GdkWindow* window = + gtk_widget_get_window(gtk_widget_get_toplevel(GTK_WIDGET(self))); g_return_if_fail(GDK_IS_WINDOW(window)); g_autoptr(GtkIMContext) im_context = gtk_im_multicontext_new(); gtk_im_context_set_client_window(im_context, window); - self->text_input_plugin = fl_text_input_plugin_new(messenger, im_context); + self->text_input_plugin = fl_text_input_plugin_new( + messenger, im_context, FL_TEXT_INPUT_VIEW_DELEGATE(self)); self->keyboard_manager = fl_keyboard_manager_new(FL_KEYBOARD_VIEW_DELEGATE(self)); } @@ -333,6 +341,18 @@ static void fl_view_scrolling_delegate_iface_init( }; } +static void fl_view_text_input_delegate_iface_init( + FlTextInputViewDelegateInterface* iface) { + iface->translate_coordinates = [](FlTextInputViewDelegate* delegate, + gint view_x, gint view_y, gint* window_x, + gint* window_y) { + FlView* self = FL_VIEW(delegate); + gtk_widget_translate_coordinates(GTK_WIDGET(self), + gtk_widget_get_toplevel(GTK_WIDGET(self)), + view_x, view_y, window_x, window_y); + }; +} + // Signal handler for GtkWidget::button-press-event static gboolean button_press_event_cb(GtkWidget* widget, GdkEventButton* event, diff --git a/shell/platform/linux/testing/mock_text_input_view_delegate.cc b/shell/platform/linux/testing/mock_text_input_view_delegate.cc new file mode 100644 index 0000000000000..fa8259cb2696a --- /dev/null +++ b/shell/platform/linux/testing/mock_text_input_view_delegate.cc @@ -0,0 +1,74 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/testing/mock_text_input_view_delegate.h" + +using namespace flutter::testing; + +G_DECLARE_FINAL_TYPE(FlMockTextInputViewDelegate, + fl_mock_text_input_view_delegate, + FL, + MOCK_TEXT_INPUT_VIEW_DELEGATE, + GObject) + +struct _FlMockTextInputViewDelegate { + GObject parent_instance; + MockTextInputViewDelegate* mock; +}; + +static FlTextInputViewDelegate* fl_mock_text_input_view_delegate_new( + MockTextInputViewDelegate* mock) { + FlMockTextInputViewDelegate* self = FL_MOCK_TEXT_INPUT_VIEW_DELEGATE( + g_object_new(fl_mock_text_input_view_delegate_get_type(), nullptr)); + self->mock = mock; + return FL_TEXT_INPUT_VIEW_DELEGATE(self); +} + +MockTextInputViewDelegate::MockTextInputViewDelegate() + : instance_(fl_mock_text_input_view_delegate_new(this)) {} + +MockTextInputViewDelegate::~MockTextInputViewDelegate() { + if (FL_IS_TEXT_INPUT_VIEW_DELEGATE(instance_)) { + g_clear_object(&instance_); + } +} + +MockTextInputViewDelegate::operator FlTextInputViewDelegate*() { + return instance_; +} + +static void fl_mock_text_input_view_delegate_iface_init( + FlTextInputViewDelegateInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlMockTextInputViewDelegate, + fl_mock_text_input_view_delegate, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(fl_text_input_view_delegate_get_type(), + fl_mock_text_input_view_delegate_iface_init)) + +static void fl_mock_text_input_view_delegate_class_init( + FlMockTextInputViewDelegateClass* klass) {} + +static void fl_mock_text_input_view_delegate_translate_coordinates( + FlTextInputViewDelegate* view_delegate, + gint view_x, + gint view_y, + gint* window_x, + gint* window_y) { + g_return_if_fail(FL_IS_MOCK_TEXT_INPUT_VIEW_DELEGATE(view_delegate)); + FlMockTextInputViewDelegate* self = + FL_MOCK_TEXT_INPUT_VIEW_DELEGATE(view_delegate); + self->mock->fl_text_input_view_delegate_translate_coordinates( + view_delegate, view_x, view_y, window_x, window_y); +} + +static void fl_mock_text_input_view_delegate_iface_init( + FlTextInputViewDelegateInterface* iface) { + iface->translate_coordinates = + fl_mock_text_input_view_delegate_translate_coordinates; +} + +static void fl_mock_text_input_view_delegate_init( + FlMockTextInputViewDelegate* self) {} diff --git a/shell/platform/linux/testing/mock_text_input_view_delegate.h b/shell/platform/linux/testing/mock_text_input_view_delegate.h new file mode 100644 index 0000000000000..ae43045e15d92 --- /dev/null +++ b/shell/platform/linux/testing/mock_text_input_view_delegate.h @@ -0,0 +1,39 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_TEXT_INPUT_VIEW_DELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_TEXT_INPUT_VIEW_DELEGATE_H_ + +#include + +#include "flutter/shell/platform/linux/fl_text_input_view_delegate.h" + +#include "gmock/gmock.h" + +namespace flutter { +namespace testing { + +// Mock for FlTextInputVuewDelegate. +class MockTextInputViewDelegate { + public: + MockTextInputViewDelegate(); + ~MockTextInputViewDelegate(); + + operator FlTextInputViewDelegate*(); + + MOCK_METHOD5(fl_text_input_view_delegate_translate_coordinates, + void(FlTextInputViewDelegate* delegate, + gint view_x, + gint view_y, + gint* window_x, + gint* window_y)); + + private: + FlTextInputViewDelegate* instance_ = nullptr; +}; + +} // namespace testing +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_TEXT_INPUT_VIEW_DELEGATE_H_ From 598f4e4965c428f26c9c82f487d39cab7d1f5c7d Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 9 Aug 2022 18:31:05 -0700 Subject: [PATCH 215/558] [Impeller] Enable support for Apple Silicon Macs and tvOS devices. (#35287) --- impeller/renderer/allocator.cc | 14 --- impeller/renderer/allocator.h | 2 - .../renderer/backend/metal/allocator_mtl.h | 5 +- .../renderer/backend/metal/allocator_mtl.mm | 114 ++++++++++++++---- .../backend/metal/device_buffer_mtl.h | 6 +- .../backend/metal/device_buffer_mtl.mm | 16 +-- 6 files changed, 105 insertions(+), 52 deletions(-) diff --git a/impeller/renderer/allocator.cc b/impeller/renderer/allocator.cc index 8151eec3492fb..49e69483ac393 100644 --- a/impeller/renderer/allocator.cc +++ b/impeller/renderer/allocator.cc @@ -13,20 +13,6 @@ Allocator::Allocator() = default; Allocator::~Allocator() = default; -bool Allocator::RequiresExplicitHostSynchronization(StorageMode mode) { - if (mode != StorageMode::kHostVisible) { - return false; - } - -#if FML_OS_IOS - // StorageMode::kHostVisible is MTLStorageModeShared already. - return false; -#else // FML_OS_IOS - // StorageMode::kHostVisible is MTLResourceStorageModeManaged. - return true; -#endif // FML_OS_IOS -} - std::shared_ptr Allocator::CreateBufferWithCopy( const uint8_t* buffer, size_t length) { diff --git a/impeller/renderer/allocator.h b/impeller/renderer/allocator.h index 10e1eb3f0aaeb..eb88a620ff986 100644 --- a/impeller/renderer/allocator.h +++ b/impeller/renderer/allocator.h @@ -69,8 +69,6 @@ class Allocator { std::shared_ptr CreateBufferWithCopy( const fml::Mapping& mapping); - static bool RequiresExplicitHostSynchronization(StorageMode mode); - protected: Allocator(); diff --git a/impeller/renderer/backend/metal/allocator_mtl.h b/impeller/renderer/backend/metal/allocator_mtl.h index 256ed3a6fc6db..64f4c59c9f7c9 100644 --- a/impeller/renderer/backend/metal/allocator_mtl.h +++ b/impeller/renderer/backend/metal/allocator_mtl.h @@ -21,11 +21,10 @@ class AllocatorMTL final : public Allocator { private: friend class ContextMTL; - // In the prototype, we are going to be allocating resources directly with the - // MTLDevice APIs. But, in the future, this could be backed by named heaps - // with specific limits. id device_; std::string allocator_label_; + bool supports_memoryless_targets_ = false; + bool supports_uma_ = false; bool is_valid_ = false; AllocatorMTL(id device, std::string label); diff --git a/impeller/renderer/backend/metal/allocator_mtl.mm b/impeller/renderer/backend/metal/allocator_mtl.mm index 7b0120503d630..4a5dafae668a2 100644 --- a/impeller/renderer/backend/metal/allocator_mtl.mm +++ b/impeller/renderer/backend/metal/allocator_mtl.mm @@ -14,12 +14,51 @@ namespace impeller { +static bool DeviceSupportsMemorylessTargets(id device) { + // Refer to the "Memoryless render targets" feature in the table below: + // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf + if (@available(ios 13.0, tvos 13.0, macos 10.15, *)) { + return [device supportsFamily:MTLGPUFamilyApple2]; + } else { +#if FML_OS_IOS + // This is perhaps redundant. But, just in case we somehow get into a case + // where Impeller runs on iOS versions less than 8.0 and/or without A8 + // GPUs, we explicitly check feature set support. + return [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1]; +#else + // MacOS devices with Apple GPUs are only available with macos 10.15 and + // above. So, if we are here, it is safe to assume that memory-less targets + // are not supported. + return false; +#endif + } + FML_UNREACHABLE(); +} + +static bool DeviceHasUnifiedMemoryArchitecture(id device) { + if (@available(ios 13.0, tvos 13.0, macOS 10.15, *)) { + return [device hasUnifiedMemory]; + } else { +#if FML_OS_IOS + // iOS devices where the availability check can fail always have had UMA. + return true; +#else + // Mac devices where the availability check can fail have never had UMA. + return false; +#endif + } + FML_UNREACHABLE(); +} + AllocatorMTL::AllocatorMTL(id device, std::string label) : device_(device), allocator_label_(std::move(label)) { if (!device_) { return; } + supports_memoryless_targets_ = DeviceSupportsMemorylessTargets(device_); + supports_uma_ = DeviceHasUnifiedMemoryArchitecture(device_); + is_valid_ = true; } @@ -29,56 +68,86 @@ return is_valid_; } -static MTLResourceOptions ToMTLResourceOptions(StorageMode type) { +static MTLResourceOptions ToMTLResourceOptions(StorageMode type, + bool supports_memoryless_targets, + bool supports_uma) { switch (type) { case StorageMode::kHostVisible: #if FML_OS_IOS return MTLResourceStorageModeShared; #else - return MTLResourceStorageModeManaged; + if (supports_uma) { + return MTLResourceStorageModeShared; + } else { + return MTLResourceStorageModeManaged; + } #endif case StorageMode::kDevicePrivate: return MTLResourceStorageModePrivate; case StorageMode::kDeviceTransient: -#if FML_OS_IOS - return MTLResourceStorageModeMemoryless; -#else - return MTLResourceStorageModePrivate; -#endif + if (supports_memoryless_targets) { + // Device may support but the OS has not been updated. + if (@available(macOS 11.0, *)) { + return MTLResourceStorageModeMemoryless; + } else { + return MTLResourceStorageModePrivate; + } + } else { + return MTLResourceStorageModePrivate; + } + FML_UNREACHABLE(); } - - return MTLResourceStorageModePrivate; + FML_UNREACHABLE(); } -static MTLStorageMode ToMTLStorageMode(StorageMode mode) { +static MTLStorageMode ToMTLStorageMode(StorageMode mode, + bool supports_memoryless_targets, + bool supports_uma) { switch (mode) { case StorageMode::kHostVisible: #if FML_OS_IOS return MTLStorageModeShared; #else - return MTLStorageModeManaged; + if (supports_uma) { + return MTLStorageModeShared; + } else { + return MTLStorageModeManaged; + } #endif case StorageMode::kDevicePrivate: return MTLStorageModePrivate; case StorageMode::kDeviceTransient: -#if FML_OS_IOS - return MTLStorageModeMemoryless; -#else - return MTLStorageModePrivate; -#endif + if (supports_memoryless_targets) { + // Device may support but the OS has not been updated. + if (@available(macOS 11.0, *)) { + return MTLStorageModeMemoryless; + } else { + return MTLStorageModePrivate; + } + } else { + return MTLStorageModePrivate; + } + FML_UNREACHABLE(); } - return MTLStorageModeShared; + FML_UNREACHABLE(); } std::shared_ptr AllocatorMTL::CreateBuffer(StorageMode mode, size_t length) { - auto buffer = [device_ newBufferWithLength:length - options:ToMTLResourceOptions(mode)]; + const auto resource_options = + ToMTLResourceOptions(mode, supports_memoryless_targets_, supports_uma_); + const auto storage_mode = + ToMTLStorageMode(mode, supports_memoryless_targets_, supports_uma_); + + auto buffer = [device_ newBufferWithLength:length options:resource_options]; if (!buffer) { return nullptr; } - return std::shared_ptr( - new DeviceBufferMTL(buffer, length, mode)); + return std::shared_ptr(new DeviceBufferMTL(buffer, // + length, // + mode, // + storage_mode // + )); } std::shared_ptr AllocatorMTL::CreateTexture( @@ -95,7 +164,8 @@ static MTLStorageMode ToMTLStorageMode(StorageMode mode) { return nullptr; } - mtl_texture_desc.storageMode = ToMTLStorageMode(mode); + mtl_texture_desc.storageMode = + ToMTLStorageMode(mode, supports_memoryless_targets_, supports_uma_); auto texture = [device_ newTextureWithDescriptor:mtl_texture_desc]; if (!texture) { return nullptr; diff --git a/impeller/renderer/backend/metal/device_buffer_mtl.h b/impeller/renderer/backend/metal/device_buffer_mtl.h index e167dd86e66de..11207794b9dec 100644 --- a/impeller/renderer/backend/metal/device_buffer_mtl.h +++ b/impeller/renderer/backend/metal/device_buffer_mtl.h @@ -27,8 +27,12 @@ class DeviceBufferMTL final friend class AllocatorMTL; const id buffer_; + const MTLStorageMode storage_mode_; - DeviceBufferMTL(id buffer, size_t size, StorageMode mode); + DeviceBufferMTL(id buffer, + size_t size, + StorageMode mode, + MTLStorageMode storage_mode); // |DeviceBuffer| bool CopyHostBuffer(const uint8_t* source, diff --git a/impeller/renderer/backend/metal/device_buffer_mtl.mm b/impeller/renderer/backend/metal/device_buffer_mtl.mm index 32e7c551439c9..e784bcf1174c8 100644 --- a/impeller/renderer/backend/metal/device_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/device_buffer_mtl.mm @@ -13,8 +13,9 @@ DeviceBufferMTL::DeviceBufferMTL(id buffer, size_t size, - StorageMode mode) - : DeviceBuffer(size, mode), buffer_(buffer) {} + StorageMode mode, + MTLStorageMode storage_mode) + : DeviceBuffer(size, mode), buffer_(buffer), storage_mode_(storage_mode) {} DeviceBufferMTL::~DeviceBufferMTL() = default; @@ -45,15 +46,11 @@ ::memmove(dest + offset, source + source_range.offset, source_range.length); } -// |RequiresExplicitHostSynchronization| always returns false on iOS. But the -// compiler is mad that `didModifyRange:` appears in a TU meant for iOS. So, +// MTLStorageModeManaged is never present on always returns false on iOS. But +// the compiler is mad that `didModifyRange:` appears in a TU meant for iOS. So, // just compile it away. -// -// Making this call is never necessary on iOS because there is no -// MTLResourceStorageModeManaged mode. Only the MTLStorageModeShared mode is -// available. #if !FML_OS_IOS - if (Allocator::RequiresExplicitHostSynchronization(mode_)) { + if (storage_mode_ == MTLStorageModeManaged) { [buffer_ didModifyRange:NSMakeRange(offset, source_range.length)]; } #endif @@ -76,7 +73,6 @@ [buffer_ addDebugMarker:@(label.c_str()) range:NSMakeRange(range.offset, range.length)]; return true; - FML_UNREACHABLE(); } } // namespace impeller From b5ca22dcf017e8cfabcf9a59ca40895c5d7fe437 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 21:41:05 -0400 Subject: [PATCH 216/558] Roll Fuchsia Mac SDK from eJH_BpC8V... to 72lnik6ZJ... (#35289) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 7f89e8fe11af7..ad4afd991a775 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'eJH_BpC8Vtx6nYHBqmXoI7RQVU4dk4fPCl9GgTnG55kC' + 'version': '72lnik6ZJ4n0VM4P4_WMhY2sdi-YjFOsVidLcu5iydIC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 60cec043980748aab6eff57ee0b2b9418a345c68 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 22:18:05 -0400 Subject: [PATCH 217/558] Roll Fuchsia Linux SDK from n-AJfzUMF... to bmiwbb8nY... (#35290) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ad4afd991a775..584c7cb0f5bc3 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'n-AJfzUMFozC7yzLvyxib4WOIUVVlukRzcWz9eni1yAC' + 'version': 'bmiwbb8nYGWtGgvKF-P7XNZMltfRfn8QQXo3X7L8jyMC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 892e5a2c90840..ecf8aaf0c1e6b 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 6b3771608fe842c48a7c2e6a85a8c398 +Signature: ea9f0b6644c911e1260accd81c02b537 UNUSED LICENSES: From 75e17f1a6f19ef96a9badf07b7b6c5527d867187 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 9 Aug 2022 22:28:05 -0400 Subject: [PATCH 218/558] Roll Dart SDK from 7f93725357f4 to f06ac8474569 (1 revision) (#35294) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 584c7cb0f5bc3..e3df598d12705 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '7f93725357f4fc52c3c4481b505affc2158e9f1d', + 'dart_revision': 'f06ac84745697b1c231bcd37f094b3848bda289e', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -221,7 +221,7 @@ deps = { Var('dart_git') + '/html.git@8243e967caad9932c13971af3b2a7c8f028383d5', 'src/third_party/dart/third_party/pkg/http': - Var('dart_git') + '/http.git@5055b684ae45fb141a106ef6ced988aa37ed0ea6', + Var('dart_git') + '/http.git@45f91f23847d51df53bb704bd25a7f64fb117081', 'src/third_party/dart/third_party/pkg/http_multi_server': Var('dart_git') + '/http_multi_server.git@20bf079c8955d1250a45afb9cb096472a724a551', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 355bb082d0192..23716ae65f297 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 691504f637938a2b417e565b3c11ff7e +Signature: 2ec0b95d585df1f2e202fdf2c17389d5 UNUSED LICENSES: From dc17742b68432932a1536fffb193c4cc2afa298b Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Wed, 10 Aug 2022 13:47:06 +0800 Subject: [PATCH 219/558] Make 'DlImageColorSource' work with 'DlImage's (#35258) --- display_list/display_list_canvas_unittests.cc | 2 +- display_list/display_list_color_source.cc | 4 +-- display_list/display_list_color_source.h | 35 ++++++++++++------- .../display_list_color_source_unittests.cc | 16 +++++---- display_list/display_list_image.h | 15 ++++++++ display_list/display_list_test_utils.h | 2 +- lib/ui/painting/image_shader.cc | 12 +++---- lib/ui/painting/image_shader.h | 2 +- 8 files changed, 55 insertions(+), 33 deletions(-) diff --git a/display_list/display_list_canvas_unittests.cc b/display_list/display_list_canvas_unittests.cc index f6e4d6540d0ae..ab120ea686218 100644 --- a/display_list/display_list_canvas_unittests.cc +++ b/display_list/display_list_canvas_unittests.cc @@ -2200,7 +2200,7 @@ BoundsTolerance CanvasCompareTester::DefaultTolerance = const sk_sp CanvasCompareTester::kTestImage = makeTestImage(); const DlImageColorSource CanvasCompareTester::kTestImageColorSource( - kTestImage, + DlImage::Make(kTestImage), DlTileMode::kRepeat, DlTileMode::kRepeat, DlImageSampling::kLinear); diff --git a/display_list/display_list_color_source.cc b/display_list/display_list_color_source.cc index f799f8453806d..c8ff65b2aca03 100644 --- a/display_list/display_list_color_source.cc +++ b/display_list/display_list_color_source.cc @@ -17,8 +17,8 @@ std::shared_ptr DlColorSource::From(SkShader* sk_shader) { SkImage* image = sk_shader->isAImage(&local_matrix, xy); if (image) { return std::make_shared( - sk_ref_sp(image), ToDl(xy[0]), ToDl(xy[1]), DlImageSampling::kLinear, - &local_matrix); + DlImage::Make(image), ToDl(xy[0]), ToDl(xy[1]), + DlImageSampling::kLinear, &local_matrix); } } // Skia provides |SkShader->asAGradient(&info)| method to access the diff --git a/display_list/display_list_color_source.h b/display_list/display_list_color_source.h index fafdc7ed183dd..97c303714913b 100644 --- a/display_list/display_list_color_source.h +++ b/display_list/display_list_color_source.h @@ -8,6 +8,7 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_attributes.h" #include "flutter/display_list/display_list_color.h" +#include "flutter/display_list/display_list_image.h" #include "flutter/display_list/display_list_sampling_options.h" #include "flutter/display_list/display_list_tile_mode.h" #include "flutter/display_list/types.h" @@ -201,14 +202,13 @@ class DlMatrixColorSourceBase : public DlColorSource { class DlImageColorSource final : public SkRefCnt, public DlMatrixColorSourceBase { public: - // TODO(100984): Color sources must be DlImages instead of SkImages. - DlImageColorSource(sk_sp image, + DlImageColorSource(sk_sp image, DlTileMode horizontal_tile_mode, DlTileMode vertical_tile_mode, DlImageSampling sampling = DlImageSampling::kLinear, const SkMatrix* matrix = nullptr) : DlMatrixColorSourceBase(matrix), - sk_image_(image), + image_(image), horizontal_tile_mode_(horizontal_tile_mode), vertical_tile_mode_(vertical_tile_mode), sampling_(sampling) {} @@ -221,39 +221,48 @@ class DlImageColorSource final : public SkRefCnt, std::shared_ptr with_sampling( DlImageSampling sampling) const override { - return std::make_shared( - sk_image_, horizontal_tile_mode_, vertical_tile_mode_, sampling, - matrix_ptr()); + return std::make_shared(image_, horizontal_tile_mode_, + vertical_tile_mode_, sampling, + matrix_ptr()); } DlColorSourceType type() const override { return DlColorSourceType::kImage; } size_t size() const override { return sizeof(*this); } - bool is_opaque() const override { return sk_image_->isOpaque(); } + bool is_opaque() const override { + // TODO(109286): Consider implementing 'isOpaque' on 'DlImage'. + if (!image_->skia_image()) { + return false; + } + return image_->skia_image()->isOpaque(); + } - sk_sp image() const { return sk_image_; } + sk_sp image() const { return image_; } DlTileMode horizontal_tile_mode() const { return horizontal_tile_mode_; } DlTileMode vertical_tile_mode() const { return vertical_tile_mode_; } DlImageSampling sampling() const { return sampling_; } virtual sk_sp skia_object() const override { - return sk_image_->makeShader(ToSk(horizontal_tile_mode_), - ToSk(vertical_tile_mode_), ToSk(sampling_), - matrix_ptr()); + if (!image_->skia_image()) { + return nullptr; + } + return image_->skia_image()->makeShader(ToSk(horizontal_tile_mode_), + ToSk(vertical_tile_mode_), + ToSk(sampling_), matrix_ptr()); } protected: bool equals_(DlColorSource const& other) const override { FML_DCHECK(other.type() == DlColorSourceType::kImage); auto that = static_cast(&other); - return (sk_image_ == that->sk_image_ && matrix() == that->matrix() && + return (image_->Equals(that->image_) && matrix() == that->matrix() && horizontal_tile_mode_ == that->horizontal_tile_mode_ && vertical_tile_mode_ == that->vertical_tile_mode_ && sampling_ == that->sampling_); } private: - sk_sp sk_image_; + sk_sp image_; DlTileMode horizontal_tile_mode_; DlTileMode vertical_tile_mode_; DlImageSampling sampling_; diff --git a/display_list/display_list_color_source_unittests.cc b/display_list/display_list_color_source_unittests.cc index 6a1440aee24f0..9a23dfe415f7b 100644 --- a/display_list/display_list_color_source_unittests.cc +++ b/display_list/display_list_color_source_unittests.cc @@ -5,6 +5,7 @@ #include "flutter/display_list/display_list_attributes_testing.h" #include "flutter/display_list/display_list_builder.h" #include "flutter/display_list/display_list_color_source.h" +#include "flutter/display_list/display_list_image.h" #include "flutter/display_list/display_list_sampling_options.h" #include "flutter/display_list/types.h" #include "third_party/skia/include/core/SkSurface.h" @@ -12,7 +13,7 @@ namespace flutter { namespace testing { -static sk_sp MakeTestImage(int w, int h, SkColor color) { +static sk_sp MakeTestImage(int w, int h, SkColor color) { sk_sp surface; if (SkColorGetA(color) < 255) { surface = SkSurface::MakeRasterN32Premul(w, h); @@ -23,11 +24,11 @@ static sk_sp MakeTestImage(int w, int h, SkColor color) { } SkCanvas* canvas = surface->getCanvas(); canvas->drawColor(color); - return surface->makeImageSnapshot(); + return DlImage::Make(surface->makeImageSnapshot()); } -static const sk_sp kTestImage1 = MakeTestImage(10, 10, SK_ColorGREEN); -static const sk_sp kTestAlphaImage1 = +static const sk_sp kTestImage1 = MakeTestImage(10, 10, SK_ColorGREEN); +static const sk_sp kTestAlphaImage1 = MakeTestImage(10, 10, SK_ColorTRANSPARENT); // clang-format off static const SkMatrix kTestMatrix1 = @@ -117,15 +118,16 @@ TEST(DisplayListColorSource, FromSkiaColorShader) { } TEST(DisplayListColorSource, FromSkiaImageShader) { - sk_sp shader = - kTestImage1->makeShader(ToSk(DlImageSampling::kLinear), &kTestMatrix1); + sk_sp shader = kTestImage1->skia_image()->makeShader( + ToSk(DlImageSampling::kLinear), &kTestMatrix1); std::shared_ptr source = DlColorSource::From(shader); DlImageColorSource dl_source(kTestImage1, DlTileMode::kClamp, DlTileMode::kClamp, DlImageSampling::kLinear, &kTestMatrix1); ASSERT_EQ(source->type(), DlColorSourceType::kImage); ASSERT_EQ(*source->asImage(), dl_source); - ASSERT_EQ(source->asImage()->image(), kTestImage1); + ASSERT_TRUE(source->asImage()->image()->Equals(kTestImage1)); + ASSERT_TRUE(kTestImage1->Equals(source->asImage()->image())); ASSERT_EQ(source->asImage()->matrix(), kTestMatrix1); ASSERT_EQ(source->asImage()->horizontal_tile_mode(), DlTileMode::kClamp); ASSERT_EQ(source->asImage()->vertical_tile_mode(), DlTileMode::kClamp); diff --git a/display_list/display_list_image.h b/display_list/display_list_image.h index fafb1504f465b..6f22b31e29ab2 100644 --- a/display_list/display_list_image.h +++ b/display_list/display_list_image.h @@ -97,6 +97,21 @@ class DlImage : public SkRefCnt { /// image. virtual std::optional get_error() const; + bool Equals(const DlImage* other) const { + if (!other) { + return false; + } + if (this == other) { + return true; + } + return skia_image() == other->skia_image() && + impeller_texture() == other->impeller_texture(); + } + + bool Equals(const DlImage& other) const { return Equals(&other); } + + bool Equals(sk_sp other) const { return Equals(other.get()); } + protected: DlImage(); }; diff --git a/display_list/display_list_test_utils.h b/display_list/display_list_test_utils.h index 72d82b68faf82..711b7182a5815 100644 --- a/display_list/display_list_test_utils.h +++ b/display_list/display_list_test_utils.h @@ -99,7 +99,7 @@ static const sk_sp kTestBlender2 = SkBlenders::Arithmetic(0.2, 0.2, 0.2, 0.2, true); static const sk_sp kTestBlender3 = SkBlenders::Arithmetic(0.3, 0.3, 0.3, 0.3, true); -static const DlImageColorSource kTestSource1(TestImage1->skia_image(), +static const DlImageColorSource kTestSource1(TestImage1, DlTileMode::kClamp, DlTileMode::kMirror, kLinearSampling); diff --git a/lib/ui/painting/image_shader.cc b/lib/ui/painting/image_shader.cc index 589cc35daa37e..4567e016056a1 100644 --- a/lib/ui/painting/image_shader.cc +++ b/lib/ui/painting/image_shader.cc @@ -38,11 +38,7 @@ Dart_Handle ImageShader::initWithImage(CanvasImage* image, return ToDart("ImageShader constructor with GPU image is not supported."); } - auto raw_sk_image = image->image()->skia_image(); - if (!raw_sk_image) { - return ToDart("ImageShader constructor with Impeller is not supported."); - } - sk_image_ = UIDartState::CreateGPUObject(std::move(raw_sk_image)); + image_ = image->image(); tonic::Float64List matrix4(matrix_handle); SkMatrix local_matrix = ToSkMatrix(matrix4); matrix4.Release(); @@ -51,7 +47,7 @@ Dart_Handle ImageShader::initWithImage(CanvasImage* image, sampling_is_locked_ ? ImageFilter::SamplingFromIndex(filter_quality_index) : DlImageSampling::kLinear; cached_shader_ = UIDartState::CreateGPUObject(sk_make_sp( - sk_image_.skia_object(), ToDl(tmx), ToDl(tmy), sampling, &local_matrix)); + image_, ToDl(tmx), ToDl(tmy), sampling, &local_matrix)); return Dart_Null(); } @@ -72,11 +68,11 @@ std::shared_ptr ImageShader::shader(DlImageSampling sampling) { } int ImageShader::width() { - return sk_image_.skia_object()->width(); + return image_->width(); } int ImageShader::height() { - return sk_image_.skia_object()->height(); + return image_->height(); } ImageShader::ImageShader() = default; diff --git a/lib/ui/painting/image_shader.h b/lib/ui/painting/image_shader.h index 3cbf9ad8ea95c..27fd3f72e3888 100644 --- a/lib/ui/painting/image_shader.h +++ b/lib/ui/painting/image_shader.h @@ -38,7 +38,7 @@ class ImageShader : public Shader { private: ImageShader(); - flutter::SkiaGPUObject sk_image_; + sk_sp image_; bool sampling_is_locked_; flutter::SkiaGPUObject cached_shader_; From e12a8b322b71ea32b74db265ac245dbb47f7068d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 01:50:04 -0400 Subject: [PATCH 220/558] Roll Skia from 0cc4b51ab9d5 to bfbc0c9abd67 (1 revision) (#35295) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e3df598d12705..bb90252778ec5 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': '0cc4b51ab9d5c72c052db4cf3782583df0dfa44e', + 'skia_revision': 'bfbc0c9abd675f4804b97000a93837b157b43754', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index d50ed0edd4e1e..7ebaa130c4195 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: f779394be911a5e2b2e154726881571a +Signature: ee17c47556fdb3000669cf54787846bb UNUSED LICENSES: From 47972527fa70794ae7a40ba625554b1e7ca37cfc Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 02:48:04 -0400 Subject: [PATCH 221/558] Roll Dart SDK from f06ac8474569 to c0767c028f74 (1 revision) (#35296) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index bb90252778ec5..62737ddb1c7e9 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'f06ac84745697b1c231bcd37f094b3848bda289e', + 'dart_revision': 'c0767c028f74b345ab22692afa01d45527a86ef4', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 23716ae65f297..3a8d6323bdb69 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 2ec0b95d585df1f2e202fdf2c17389d5 +Signature: aa78447681930556c7b1cc3f63ea8d2e UNUSED LICENSES: From c7faefa35f5993fe263e32724553afb5fff6ea9c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 03:02:04 -0400 Subject: [PATCH 222/558] Roll Skia from bfbc0c9abd67 to 6d371c8f05a8 (1 revision) (#35297) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 62737ddb1c7e9..3fcbf25b1f955 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': 'bfbc0c9abd675f4804b97000a93837b157b43754', + 'skia_revision': '6d371c8f05a8dc9d8150c0c1c3ded32bcf03788f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 7ebaa130c4195..630a4c959aa37 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: ee17c47556fdb3000669cf54787846bb +Signature: ef9da023b57e115968d3ce1d888eebdb UNUSED LICENSES: From 424ad91dcec64ebb3c51c7c7048f8dff4972db36 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 06:43:05 -0400 Subject: [PATCH 223/558] Roll Skia from 6d371c8f05a8 to 77790f1d931e (1 revision) (#35301) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 3fcbf25b1f955..bb144bb25c52d 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': '6d371c8f05a8dc9d8150c0c1c3ded32bcf03788f', + 'skia_revision': '77790f1d931e8aeeaf12c2b89a4e318de755a298', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 630a4c959aa37..115c7311c79f8 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: ef9da023b57e115968d3ce1d888eebdb +Signature: 848b2ce54a3a09221ee519bb90f55d57 UNUSED LICENSES: From 23fb17ddb624de43781436549a3740b9c1c650c7 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 06:46:19 -0400 Subject: [PATCH 224/558] Roll Dart SDK from c0767c028f74 to 8a0afacdbf9a (1 revision) (#35300) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index bb144bb25c52d..5357feee98c89 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'c0767c028f74b345ab22692afa01d45527a86ef4', + 'dart_revision': '8a0afacdbf9a40320efceb46854b15710173b92f', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 91f4618f13915e4251eac10e600cf9969f773725 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 09:18:09 -0400 Subject: [PATCH 225/558] Roll Skia from 77790f1d931e to 63059a86098e (1 revision) (#35303) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 5357feee98c89..a8e2de802572a 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': '77790f1d931e8aeeaf12c2b89a4e318de755a298', + 'skia_revision': '63059a86098e530eae7a22bb5128279e1c090b3b', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 115c7311c79f8..c42dfa7f4a3fd 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 848b2ce54a3a09221ee519bb90f55d57 +Signature: 88685aba5af9efa403192b96048ae488 UNUSED LICENSES: @@ -892,6 +892,7 @@ FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.ex FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-arm64-Debug-Android_FrameworkWorkarounds.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-arm64-Debug-Android_HWASAN.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-arm64-Release-Android_Wuffs.json +FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Debug-AVIF.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Debug-Chromebook_GLES.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Debug-Coverage.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Debug-MSAN.json @@ -905,6 +906,7 @@ FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.ex FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-OptimizeForSize.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Release-ANGLE.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Release-ASAN.json +FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Release-AVIF.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Release-CMake.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Release-Fast.json FILE: ../../../third_party/skia/infra/bots/recipe_modules/build/examples/full.expected/Build-Debian10-Clang-x86_64-Release-NoDEPS.json From e4a1cbc3f23b432c610a6be583c512e7f9ea086a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 10:34:04 -0400 Subject: [PATCH 226/558] Roll Skia from 63059a86098e to 497fdaa6f647 (2 revisions) (#35304) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index a8e2de802572a..ecef3f9150056 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': '63059a86098e530eae7a22bb5128279e1c090b3b', + 'skia_revision': '497fdaa6f647a691544e8cc17c6b572a09b866b8', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index c42dfa7f4a3fd..c3a9a5711393e 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 88685aba5af9efa403192b96048ae488 +Signature: 85ddec3c0a511ce44c45f0ebd9e5826b UNUSED LICENSES: From 18f3893f4de919e992d093cd2940b2bdf07c6018 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 11:42:12 -0400 Subject: [PATCH 227/558] Roll Fuchsia Mac SDK from 72lnik6ZJ... to tdJUKQ0dM... (#35306) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index ecef3f9150056..35c0cb384fc3d 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': '72lnik6ZJ4n0VM4P4_WMhY2sdi-YjFOsVidLcu5iydIC' + 'version': 'tdJUKQ0dMvgPqjPx8hyE1L3hARwGJOd9RV3zp-j66hgC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 0dd59d2f7ab8fbb50652f34817ce324a29faffd3 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 11:47:08 -0400 Subject: [PATCH 228/558] Roll Skia from 497fdaa6f647 to e83282daf351 (5 revisions) (#35305) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 35c0cb384fc3d..c4eecb747b0aa 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': '497fdaa6f647a691544e8cc17c6b572a09b866b8', + 'skia_revision': 'e83282daf351a63ec7be825c9cf1a2dba7cf87e0', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index c3a9a5711393e..cd803966fba82 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 85ddec3c0a511ce44c45f0ebd9e5826b +Signature: 195e72115fb2a826b1b42c28c9af880f UNUSED LICENSES: From 9a14d0b1490b28c32f9d2ef03700bb96ddeda32a Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Wed, 10 Aug 2022 08:49:44 -0700 Subject: [PATCH 229/558] [Impeller] [vulkan] Implement command pool and sampler library (#35282) --- ci/licenses_golden/licenses_flutter | 2 + impeller/renderer/backend/vulkan/BUILD.gn | 2 + .../backend/vulkan/command_pool_vk.cc | 29 ++++++++++++ .../renderer/backend/vulkan/command_pool_vk.h | 27 ++++++++++++ .../renderer/backend/vulkan/context_vk.cc | 2 + impeller/renderer/backend/vulkan/context_vk.h | 2 + impeller/renderer/backend/vulkan/formats_vk.h | 39 ++++++++++++++++ .../backend/vulkan/sampler_library_vk.cc | 44 ++++++++++++++++++- .../backend/vulkan/sampler_library_vk.h | 2 +- .../renderer/backend/vulkan/sampler_vk.cc | 10 ++++- impeller/renderer/backend/vulkan/sampler_vk.h | 7 ++- 11 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 impeller/renderer/backend/vulkan/command_pool_vk.cc create mode 100644 impeller/renderer/backend/vulkan/command_pool_vk.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 9c2ebc77f49ca..8386fee41b039 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -773,6 +773,8 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/capabilities_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/capabilities_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_buffer_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/command_pool_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/context_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/device_buffer_vk.cc diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn index f6e2c841aceb5..78c9d5c66874f 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -14,6 +14,8 @@ impeller_component("vulkan") { "capabilities_vk.h", "command_buffer_vk.cc", "command_buffer_vk.h", + "command_pool_vk.cc", + "command_pool_vk.h", "context_vk.cc", "context_vk.h", "device_buffer_vk.cc", diff --git a/impeller/renderer/backend/vulkan/command_pool_vk.cc b/impeller/renderer/backend/vulkan/command_pool_vk.cc new file mode 100644 index 0000000000000..58fb3f45c4ed2 --- /dev/null +++ b/impeller/renderer/backend/vulkan/command_pool_vk.cc @@ -0,0 +1,29 @@ +// 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/renderer/backend/vulkan/command_pool_vk.h" + +namespace impeller { + +std::unique_ptr CommandPoolVK::Create(vk::Device device, + uint32_t queue_index) { + vk::CommandPoolCreateInfo create_info; + create_info.setQueueFamilyIndex(queue_index); + + auto res = device.createCommandPoolUnique(create_info); + if (res.result != vk::Result::eSuccess) { + FML_CHECK(false) << "Failed to create command pool: " + << vk::to_string(res.result); + return nullptr; + } + + return std::make_unique(std::move(res.value)); +} + +CommandPoolVK::CommandPoolVK(vk::UniqueCommandPool command_pool) + : command_pool_(std::move(command_pool)) {} + +CommandPoolVK::~CommandPoolVK() = default; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/command_pool_vk.h b/impeller/renderer/backend/vulkan/command_pool_vk.h new file mode 100644 index 0000000000000..3e57556fc53fd --- /dev/null +++ b/impeller/renderer/backend/vulkan/command_pool_vk.h @@ -0,0 +1,27 @@ +// 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/fml/macros.h" +#include "impeller/renderer/backend/vulkan/vk.h" + +namespace impeller { + +class CommandPoolVK { + public: + static std::unique_ptr Create(vk::Device device, + uint32_t queue_index); + + explicit CommandPoolVK(vk::UniqueCommandPool command_pool); + + ~CommandPoolVK(); + + private: + vk::UniqueCommandPool command_pool_; + + FML_DISALLOW_COPY_AND_ASSIGN(CommandPoolVK); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index f71b28b6d9452..563f812322f13 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -401,6 +401,8 @@ ContextVK::ContextVK( device_->getQueue(compute_queue->family, compute_queue->index); transfer_queue_ = device_->getQueue(transfer_queue->family, transfer_queue->index); + graphics_command_pool_ = + CommandPoolVK::Create(*device_, graphics_queue->index); is_valid_ = true; } diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index c70fda779208c..7284008ccbea6 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -10,6 +10,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" #include "impeller/base/backend_cast.h" +#include "impeller/renderer/backend/vulkan/command_pool_vk.h" #include "impeller/renderer/backend/vulkan/pipeline_library_vk.h" #include "impeller/renderer/backend/vulkan/sampler_library_vk.h" #include "impeller/renderer/backend/vulkan/shader_library_vk.h" @@ -73,6 +74,7 @@ class ContextVK final : public Context, public BackendCast { vk::Queue graphics_queue_; vk::Queue compute_queue_; vk::Queue transfer_queue_; + std::unique_ptr graphics_command_pool_; bool is_valid_ = false; ContextVK( diff --git a/impeller/renderer/backend/vulkan/formats_vk.h b/impeller/renderer/backend/vulkan/formats_vk.h index a3412715d4717..dede9aa884b82 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -160,4 +160,43 @@ constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count) { } } +constexpr vk::Filter ToVKSamplerMinMagFilter(MinMagFilter filter) { + switch (filter) { + case MinMagFilter::kNearest: + return vk::Filter::eNearest; + case MinMagFilter::kLinear: + return vk::Filter::eLinear; + } + + FML_UNREACHABLE(); +} + +constexpr vk::SamplerMipmapMode ToVKSamplerMipmapMode(MipFilter filter) { + vk::SamplerCreateInfo sampler_info; + switch (filter) { + case MipFilter::kNearest: + return vk::SamplerMipmapMode::eNearest; + case MipFilter::kLinear: + return vk::SamplerMipmapMode::eLinear; + case MipFilter::kNone: + return vk::SamplerMipmapMode::eNearest; + } + + FML_UNREACHABLE(); +} + +constexpr vk::SamplerAddressMode ToVKSamplerAddressMode( + SamplerAddressMode mode) { + switch (mode) { + case SamplerAddressMode::kRepeat: + return vk::SamplerAddressMode::eRepeat; + case SamplerAddressMode::kMirror: + return vk::SamplerAddressMode::eMirroredRepeat; + case SamplerAddressMode::kClampToEdge: + return vk::SamplerAddressMode::eClampToEdge; + } + + FML_UNREACHABLE(); +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/sampler_library_vk.cc b/impeller/renderer/backend/vulkan/sampler_library_vk.cc index 6c5c239f222c1..149c1ae957d4c 100644 --- a/impeller/renderer/backend/vulkan/sampler_library_vk.cc +++ b/impeller/renderer/backend/vulkan/sampler_library_vk.cc @@ -4,6 +4,9 @@ #include "impeller/renderer/backend/vulkan/sampler_library_vk.h" +#include "impeller/renderer/backend/vulkan/formats_vk.h" +#include "impeller/renderer/backend/vulkan/sampler_vk.h" + namespace impeller { SamplerLibraryVK::SamplerLibraryVK(vk::Device device) : device_(device) {} @@ -11,8 +14,45 @@ SamplerLibraryVK::SamplerLibraryVK(vk::Device device) : device_(device) {} SamplerLibraryVK::~SamplerLibraryVK() = default; std::shared_ptr SamplerLibraryVK::GetSampler( - SamplerDescriptor descriptor) { - FML_UNREACHABLE(); + SamplerDescriptor desc) { + auto found = samplers_.find(desc); + if (found != samplers_.end()) { + return found->second; + } + if (!device_) { + return nullptr; + } + + const auto mip_map = ToVKSamplerMipmapMode(desc.mip_filter); + + const auto min_filter = ToVKSamplerMinMagFilter(desc.min_filter); + const auto mag_filter = ToVKSamplerMinMagFilter(desc.mag_filter); + + const auto address_mode_u = ToVKSamplerAddressMode(desc.width_address_mode); + const auto address_mode_v = ToVKSamplerAddressMode(desc.height_address_mode); + const auto address_mode_w = ToVKSamplerAddressMode(desc.depth_address_mode); + + const auto sampler_create_info = vk::SamplerCreateInfo() + .setMagFilter(mag_filter) + .setMinFilter(min_filter) + .setAddressModeU(address_mode_u) + .setAddressModeV(address_mode_v) + .setAddressModeW(address_mode_w) + .setMipmapMode(mip_map); + + auto res = device_.createSamplerUnique(sampler_create_info); + if (res.result != vk::Result::eSuccess) { + FML_LOG(ERROR) << "Failed to create sampler: " << vk::to_string(res.result); + return nullptr; + } + + auto sampler = std::make_shared(desc, std::move(res.value)); + + if (!sampler->IsValid()) { + return nullptr; + } + samplers_[desc] = sampler; + return sampler; } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/sampler_library_vk.h b/impeller/renderer/backend/vulkan/sampler_library_vk.h index 8823377dcc001..72129ca496757 100644 --- a/impeller/renderer/backend/vulkan/sampler_library_vk.h +++ b/impeller/renderer/backend/vulkan/sampler_library_vk.h @@ -26,7 +26,7 @@ class SamplerLibraryVK final vk::Device device_; SamplerMap samplers_; - SamplerLibraryVK(vk::Device device); + explicit SamplerLibraryVK(vk::Device device); // |SamplerLibrary| std::shared_ptr GetSampler( diff --git a/impeller/renderer/backend/vulkan/sampler_vk.cc b/impeller/renderer/backend/vulkan/sampler_vk.cc index 30d21e0af5d27..161fa57378222 100644 --- a/impeller/renderer/backend/vulkan/sampler_vk.cc +++ b/impeller/renderer/backend/vulkan/sampler_vk.cc @@ -5,7 +5,15 @@ #include "impeller/renderer/backend/vulkan/sampler_vk.h" namespace impeller { +SamplerVK::~SamplerVK() {} -// +SamplerVK::SamplerVK(SamplerDescriptor desc, vk::UniqueSampler sampler) + : Sampler(desc), sampler_(std::move(sampler)) { + is_valid_ = true; +} + +bool SamplerVK::IsValid() const { + return is_valid_; +} } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/sampler_vk.h b/impeller/renderer/backend/vulkan/sampler_vk.h index fce2a4bd11939..15d08205fa754 100644 --- a/impeller/renderer/backend/vulkan/sampler_vk.h +++ b/impeller/renderer/backend/vulkan/sampler_vk.h @@ -6,7 +6,9 @@ #include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" +#include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/sampler.h" +#include "vulkan/vulkan_handles.hpp" namespace impeller { @@ -14,7 +16,7 @@ class SamplerLibraryVK; class SamplerVK final : public Sampler, public BackendCast { public: - SamplerVK(); + SamplerVK(SamplerDescriptor desc, vk::UniqueSampler sampler); // |Sampler| ~SamplerVK() override; @@ -22,7 +24,8 @@ class SamplerVK final : public Sampler, public BackendCast { private: friend SamplerLibraryVK; - SamplerVK(SamplerDescriptor desc); + vk::UniqueSampler sampler_; + bool is_valid_ = false; // |Sampler| bool IsValid() const override; From 773bf598c66377efedad38a827006e950c880de7 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Wed, 10 Aug 2022 09:22:01 -0700 Subject: [PATCH 230/558] Formatting: Correct whitespace in flutter_export.h (#35292) Fixes a minor whitespace inconsistency on the documentation for FLUTTER_EXPORT. No test change since there is no change to code semantics. Related: https://github.com/flutter/flutter/issues/93537 --- shell/platform/common/public/flutter_export.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/common/public/flutter_export.h b/shell/platform/common/public/flutter_export.h index 38cac85b7ba2e..d71b3fb5607aa 100644 --- a/shell/platform/common/public/flutter_export.h +++ b/shell/platform/common/public/flutter_export.h @@ -6,8 +6,8 @@ #define FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_EXPORT_H_ #ifdef FLUTTER_DESKTOP_LIBRARY -// Add visibility/export annotations when building the library. +// Add visibility/export annotations when building the library. #ifdef _WIN32 #define FLUTTER_EXPORT __declspec(dllexport) #else From c1dc9c1806b8f08d933623e7b88d1edbc785bb3d Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Wed, 10 Aug 2022 09:23:09 -0700 Subject: [PATCH 231/558] Add FLUTTER_DEPRECATED macro and flutter_macros.h (#35293) Adds a new header, flutter_macros.h which includes a FLUTTER_DEPRECATED macro that can be used to mark deprecated API as such, with a hopefully-informative message, ideally describing the expected removal version and any migration tips. This will need to be #included in flutter_windows.h and flutter_linux.h, but prior to doing so, we'll need to update the engine recipe to bundle the new header, here: https://flutter.googlesource.com/recipes/+/refs/heads/main/recipes/engine/engine.py#1457 No tests since this adds a compiler macro that will be used for future C/C++ API deprecation once the above recipe change has landed; specifically: FlutterDesktopEngineProcessMessages. Related: https://github.com/flutter/flutter/issues/93537 --- ci/licenses_golden/licenses_flutter | 1 + shell/platform/common/BUILD.gn | 1 + shell/platform/common/public/flutter_macros.h | 24 +++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 shell/platform/common/public/flutter_macros.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 8386fee41b039..aa5c6a0a1cf96 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1675,6 +1675,7 @@ FILE: ../../../flutter/shell/platform/common/path_utils.h FILE: ../../../flutter/shell/platform/common/path_utils_unittests.cc FILE: ../../../flutter/shell/platform/common/platform_provided_menu.h FILE: ../../../flutter/shell/platform/common/public/flutter_export.h +FILE: ../../../flutter/shell/platform/common/public/flutter_macros.h FILE: ../../../flutter/shell/platform/common/public/flutter_messenger.h FILE: ../../../flutter/shell/platform/common/public/flutter_plugin_registrar.h FILE: ../../../flutter/shell/platform/common/public/flutter_texture_registrar.h diff --git a/shell/platform/common/BUILD.gn b/shell/platform/common/BUILD.gn index 24d450cdb9497..571ee50765d17 100644 --- a/shell/platform/common/BUILD.gn +++ b/shell/platform/common/BUILD.gn @@ -11,6 +11,7 @@ config("desktop_library_implementation") { _public_headers = [ "public/flutter_export.h", + "public/flutter_macros.h", "public/flutter_messenger.h", "public/flutter_plugin_registrar.h", "public/flutter_texture_registrar.h", diff --git a/shell/platform/common/public/flutter_macros.h b/shell/platform/common/public/flutter_macros.h new file mode 100644 index 0000000000000..7b60cb488b0b2 --- /dev/null +++ b/shell/platform/common/public/flutter_macros.h @@ -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 FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_MACROS_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_MACROS_H_ + +#ifdef FLUTTER_DESKTOP_LIBRARY + +// Do not add deprecation annotations when building the library. +#define FLUTTER_DEPRECATED(message) + +#else // FLUTTER_DESKTOP_LIBRARY + +// Add deprecation warning for users of the library. +#ifdef _WIN32 +#define FLUTTER_DEPRECATED(message) __declspec(deprecated(message)) +#else +#define FLUTTER_DEPRECATED(message) __attribute__((deprecated(message))) +#endif + +#endif // FLUTTER_DESKTOP_LIBRARY + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_MACROS_H_ From 27caca415fede0c594d7d3103834e6ddd5cdf6ff Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 12:25:31 -0400 Subject: [PATCH 232/558] Roll Fuchsia Linux SDK from bmiwbb8nY... to OkIFye3iR... (#35307) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c4eecb747b0aa..c3c92f28b5d88 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'bmiwbb8nYGWtGgvKF-P7XNZMltfRfn8QQXo3X7L8jyMC' + 'version': 'OkIFye3iRfA9DknTFPlAZ-xJdNubmiaj1DOQgJqxRPAC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index ecf8aaf0c1e6b..18a777b923b07 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: ea9f0b6644c911e1260accd81c02b537 +Signature: a318ffc376bb966a95c05568cf493f5b UNUSED LICENSES: @@ -3690,6 +3690,7 @@ FILE: ../../../fuchsia/sdk/linux/pkg/fit/include/lib/fit/inline_any.h FILE: ../../../fuchsia/sdk/linux/pkg/fit/include/lib/fit/inline_any_internal.h FILE: ../../../fuchsia/sdk/linux/pkg/inspect/client.shard.cml FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/linkage.h +FILE: ../../../fuchsia/sdk/linux/pkg/stdcompat/include/lib/stdcompat/internal/variant.h FILE: ../../../fuchsia/sdk/linux/pkg/sys/component/realm_builder_absolute.shard.cml FILE: ../../../fuchsia/sdk/linux/pkg/sys/component/realm_builder_base.shard.cml FILE: ../../../fuchsia/sdk/linux/pkg/sys_component_cpp_testing/internal/convert.cc From a705c0cc2d585773c413ae2756c784dfb5fb6ff6 Mon Sep 17 00:00:00 2001 From: Bernardo Eilert Trevisan <43152751+betrevisan@users.noreply.github.com> Date: Wed, 10 Aug 2022 09:47:17 -0700 Subject: [PATCH 233/558] [Impeller] Color matrix color filter implementation. (#35284) --- ci/licenses_golden/licenses_flutter | 4 + .../display_list/display_list_dispatcher.cc | 19 ++- impeller/entity/BUILD.gn | 4 + impeller/entity/contents/content_context.cc | 2 + impeller/entity/contents/content_context.h | 14 ++- .../filters/color_matrix_filter_contents.cc | 88 ++++++++++++++ .../filters/color_matrix_filter_contents.h | 38 ++++++ .../contents/filters/filter_contents.cc | 10 ++ .../entity/contents/filters/filter_contents.h | 9 ++ impeller/entity/entity_unittests.cc | 108 ++++++++++++++++++ .../shaders/color_matrix_color_filter.frag | 48 ++++++++ .../shaders/color_matrix_color_filter.vert | 15 +++ 12 files changed, 357 insertions(+), 2 deletions(-) create mode 100644 impeller/entity/contents/filters/color_matrix_filter_contents.cc create mode 100644 impeller/entity/contents/filters/color_matrix_filter_contents.h create mode 100644 impeller/entity/shaders/color_matrix_color_filter.frag create mode 100644 impeller/entity/shaders/color_matrix_color_filter.vert diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index aa5c6a0a1cf96..1fe4c9d032452 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -556,6 +556,8 @@ FILE: ../../../flutter/impeller/entity/contents/filters/blend_filter_contents.cc FILE: ../../../flutter/impeller/entity/contents/filters/blend_filter_contents.h FILE: ../../../flutter/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc FILE: ../../../flutter/impeller/entity/contents/filters/border_mask_blur_filter_contents.h +FILE: ../../../flutter/impeller/entity/contents/filters/color_matrix_filter_contents.cc +FILE: ../../../flutter/impeller/entity/contents/filters/color_matrix_filter_contents.h FILE: ../../../flutter/impeller/entity/contents/filters/filter_contents.cc FILE: ../../../flutter/impeller/entity/contents/filters/filter_contents.h FILE: ../../../flutter/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -623,6 +625,8 @@ FILE: ../../../flutter/impeller/entity/shaders/blending/blend.frag FILE: ../../../flutter/impeller/entity/shaders/blending/blend.vert FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.frag FILE: ../../../flutter/impeller/entity/shaders/border_mask_blur.vert +FILE: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.frag +FILE: ../../../flutter/impeller/entity/shaders/color_matrix_color_filter.vert FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.frag FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.vert FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index a0678a2e8aa42..c14609c731bd5 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -8,6 +8,7 @@ #include #include "display_list/display_list_blend_mode.h" +#include "display_list/display_list_color_filter.h" #include "display_list/display_list_path_effect.h" #include "display_list/display_list_tile_mode.h" #include "flutter/fml/logging.h" @@ -15,6 +16,7 @@ #include "impeller/display_list/display_list_image_impeller.h" #include "impeller/display_list/nine_patch_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" #include "impeller/entity/contents/radial_gradient_contents.h" #include "impeller/entity/contents/solid_stroke_contents.h" @@ -330,10 +332,25 @@ void DisplayListDispatcher::setColorFilter( }; return; } - case flutter::DlColorFilterType::kMatrix: + case flutter::DlColorFilterType::kMatrix: { + const flutter::DlMatrixColorFilter* dl_matrix = filter->asMatrix(); + impeller::FilterContents::ColorMatrix color_matrix; + dl_matrix->get_matrix(color_matrix.array); + paint_.color_filter = [color_matrix](FilterInput::Ref input) { + return FilterContents::MakeColorMatrix({input}, color_matrix); + }; + return; + } case flutter::DlColorFilterType::kSrgbToLinearGamma: + FML_LOG(ERROR) << "requested DlColorFilterType::kSrgbToLinearGamma"; + UNIMPLEMENTED; + break; case flutter::DlColorFilterType::kLinearToSrgbGamma: + FML_LOG(ERROR) << "requested DlColorFilterType::kLinearToSrgbGamma"; + UNIMPLEMENTED; + break; case flutter::DlColorFilterType::kUnknown: + FML_LOG(ERROR) << "requested DlColorFilterType::kUnknown"; UNIMPLEMENTED; break; } diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 014d11484b232..aa1adbe76730b 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -30,6 +30,8 @@ impeller_shaders("entity_shaders") { "shaders/blending/blend.vert", "shaders/border_mask_blur.frag", "shaders/border_mask_blur.vert", + "shaders/color_matrix_color_filter.frag", + "shaders/color_matrix_color_filter.vert", "shaders/gaussian_blur.frag", "shaders/gaussian_blur.vert", "shaders/glyph_atlas.frag", @@ -67,6 +69,8 @@ impeller_component("entity") { "contents/filters/blend_filter_contents.h", "contents/filters/border_mask_blur_filter_contents.cc", "contents/filters/border_mask_blur_filter_contents.h", + "contents/filters/color_matrix_filter_contents.cc", + "contents/filters/color_matrix_filter_contents.h", "contents/filters/filter_contents.cc", "contents/filters/filter_contents.h", "contents/filters/gaussian_blur_filter_contents.cc", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 2cc6218e08277..f63342cc6aee4 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -195,6 +195,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); border_mask_blur_pipelines_[{}] = CreateDefaultPipeline(*context_); + color_matrix_color_filter_pipelines_[{}] = + CreateDefaultPipeline(*context_); solid_stroke_pipelines_[{}] = CreateDefaultPipeline(*context_); glyph_atlas_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index d31eb9435d8ea..6ab014470ae83 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -33,6 +33,8 @@ #include "impeller/entity/blend.vert.h" #include "impeller/entity/border_mask_blur.frag.h" #include "impeller/entity/border_mask_blur.vert.h" +#include "impeller/entity/color_matrix_color_filter.frag.h" +#include "impeller/entity/color_matrix_color_filter.vert.h" #include "impeller/entity/entity.h" #include "impeller/entity/gaussian_blur.frag.h" #include "impeller/entity/gaussian_blur.vert.h" @@ -106,6 +108,9 @@ using GaussianBlurPipeline = PipelineT; using BorderMaskBlurPipeline = PipelineT; +using ColorMatrixColorFilterPipeline = + PipelineT; using SolidStrokePipeline = PipelineT; using GlyphAtlasPipeline = @@ -145,7 +150,7 @@ struct ContentContextOptions { class ContentContext { public: - ContentContext(std::shared_ptr context); + explicit ContentContext(std::shared_ptr context); ~ContentContext(); @@ -194,6 +199,11 @@ class ContentContext { return GetPipeline(border_mask_blur_pipelines_, opts); } + std::shared_ptr GetColorMatrixColorFilterPipeline( + ContentContextOptions opts) const { + return GetPipeline(color_matrix_color_filter_pipelines_, opts); + } + std::shared_ptr GetSolidStrokePipeline( ContentContextOptions opts) const { return GetPipeline(solid_stroke_pipelines_, opts); @@ -325,6 +335,8 @@ class ContentContext { mutable Variants texture_pipelines_; mutable Variants gaussian_blur_pipelines_; mutable Variants border_mask_blur_pipelines_; + mutable Variants + color_matrix_color_filter_pipelines_; mutable Variants solid_stroke_pipelines_; mutable Variants clip_pipelines_; mutable Variants glyph_atlas_pipelines_; diff --git a/impeller/entity/contents/filters/color_matrix_filter_contents.cc b/impeller/entity/contents/filters/color_matrix_filter_contents.cc new file mode 100644 index 0000000000000..0d93195d64a75 --- /dev/null +++ b/impeller/entity/contents/filters/color_matrix_filter_contents.cc @@ -0,0 +1,88 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/entity/contents/filters/color_matrix_filter_contents.h" + +#include + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/geometry/point.h" +#include "impeller/geometry/vector.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/sampler_library.h" + +namespace impeller { + +ColorMatrixFilterContents::ColorMatrixFilterContents() = default; + +ColorMatrixFilterContents::~ColorMatrixFilterContents() = default; + +void ColorMatrixFilterContents::SetMatrix(const ColorMatrix& matrix) { + matrix_ = matrix; +} + +bool ColorMatrixFilterContents::RenderFilter(const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass, + const Rect& coverage) const { + if (inputs.empty()) { + return true; + } + + using VS = ColorMatrixColorFilterPipeline::VertexShader; + using FS = ColorMatrixColorFilterPipeline::FragmentShader; + + auto input_snapshot = inputs[0]->GetSnapshot(renderer, entity); + if (!input_snapshot.has_value()) { + return true; + } + + Command cmd; + cmd.label = "Color Matrix Filter"; + + auto options = OptionsFromPass(pass); + options.blend_mode = Entity::BlendMode::kSource; + cmd.pipeline = renderer.GetColorMatrixColorFilterPipeline(options); + + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0, 0)}, + {Point(1, 0)}, + {Point(1, 1)}, + {Point(0, 0)}, + {Point(1, 1)}, + {Point(0, 1)}, + }); + auto& host_buffer = pass.GetTransientsBuffer(); + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + cmd.BindVertices(vtx_buffer); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); + + FS::FragInfo frag_info; + const float* matrix = matrix_.array; + frag_info.color_v = Vector4(matrix[4], matrix[9], matrix[14], matrix[19]); + // clang-format off + frag_info.color_m = + Matrix( + matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3], + matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8], + matrix[10], matrix[11], matrix[12], matrix[13], + matrix[15], matrix[16], matrix[17], matrix[18] + ); + // clang-format on + + auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); + FS::BindInputTexture(cmd, input_snapshot->texture, sampler); + FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + + return pass.AddCommand(std::move(cmd)); +} + +} // namespace impeller diff --git a/impeller/entity/contents/filters/color_matrix_filter_contents.h b/impeller/entity/contents/filters/color_matrix_filter_contents.h new file mode 100644 index 0000000000000..e3cdfdcd62773 --- /dev/null +++ b/impeller/entity/contents/filters/color_matrix_filter_contents.h @@ -0,0 +1,38 @@ +// 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/entity/contents/filters/filter_contents.h" +#include "impeller/entity/contents/filters/inputs/filter_input.h" + +namespace impeller { + +// Look at example at: https://github.com/flutter/impeller/pull/132 + +class ColorMatrixFilterContents final : public FilterContents { + public: + ColorMatrixFilterContents(); + + ~ColorMatrixFilterContents() override; + + void SetMatrix(const ColorMatrix& matrix); + + private: + // |FilterContents| + bool RenderFilter(const FilterInput::Vector& input_textures, + const ContentContext& renderer, + const Entity& entity, + RenderPass& pass, + const Rect& coverage) const override; + + ColorMatrix matrix_; + + FML_DISALLOW_COPY_AND_ASSIGN(ColorMatrixFilterContents); +}; + +} // namespace impeller diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index af42a5cca3826..b600f40dbecbd 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -16,6 +16,7 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/filters/blend_filter_contents.h" #include "impeller/entity/contents/filters/border_mask_blur_filter_contents.h" +#include "impeller/entity/contents/filters/color_matrix_filter_contents.h" #include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/entity/contents/texture_contents.h" @@ -112,6 +113,15 @@ std::shared_ptr FilterContents::MakeBorderMaskBlur( return filter; } +std::shared_ptr FilterContents::MakeColorMatrix( + FilterInput::Ref input, + const ColorMatrix& matrix) { + auto filter = std::make_shared(); + filter->SetInputs({input}); + filter->SetMatrix(matrix); + return filter; +} + FilterContents::FilterContents() = default; FilterContents::~FilterContents() = default; diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 84134060e18b5..06a5e6d4ccce9 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -31,6 +31,11 @@ class FilterContents : public Contents { kInner, }; + // Domain is kRGBA, we may decide to support more color modes later. + struct ColorMatrix { + float array[20]; + }; + static std::shared_ptr MakeBlend( Entity::BlendMode blend_mode, FilterInput::Vector inputs, @@ -57,6 +62,10 @@ class FilterContents : public Contents { Sigma sigma_y, BlurStyle blur_style = BlurStyle::kNormal); + static std::shared_ptr MakeColorMatrix( + FilterInput::Ref input, + const ColorMatrix& matrix); + FilterContents(); ~FilterContents() override; diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 2e28a2f0d18a2..a10da41ce5c17 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -1415,5 +1415,113 @@ TEST_P(EntityTest, RRectShadowTest) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(EntityTest, ColorMatrixFilterCoverageIsCorrect) { + // Set up a simple color background. + auto fill = std::make_shared(); + fill->SetPath( + PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath()); + fill->SetColor(Color::Coral()); + + // Set the color matrix filter. + FilterContents::ColorMatrix matrix = { + 1, 1, 1, 1, 1, // + 1, 1, 1, 1, 1, // + 1, 1, 1, 1, 1, // + 1, 1, 1, 1, 1, // + }; + + auto filter = + FilterContents::MakeColorMatrix(FilterInput::Make(fill), matrix); + + Entity e; + e.SetTransformation(Matrix()); + + // Confirm that the actual filter coverage matches the expected coverage. + auto actual = filter->GetCoverage(e); + auto expected = Rect::MakeXYWH(0, 0, 300, 400); + + ASSERT_TRUE(actual.has_value()); + ASSERT_RECT_NEAR(actual.value(), expected); +} + +TEST_P(EntityTest, ColorMatrixFilter) { + auto image = CreateTextureForFixture("boston.jpg"); + ASSERT_TRUE(image); + + auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { + // Set the color matrix filter. + FilterContents::ColorMatrix matrix = { + 1, 0, 0, 0, 0, // + 0, 3, 0, 0, 0, // + 0, 0, 1, 0, 0, // + 0, 0, 0, 1, 0, // + }; + + auto filter = + FilterContents::MakeColorMatrix(FilterInput::Make(image), matrix); + + // Define the entity with the color matrix filter. + Entity entity; + entity.SetTransformation(Matrix::MakeScale(GetContentScale()) * + Matrix::MakeTranslation({500, 300}) * + Matrix::MakeScale(Vector2{0.5, 0.5})); + entity.SetContents(filter); + return entity.Render(context, pass); + }; + + // Should output the boston image with a green filter. + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + +TEST_P(EntityTest, ColorMatrixFilterEditable) { + auto bay_bridge = CreateTextureForFixture("bay_bridge.jpg"); + ASSERT_TRUE(bay_bridge); + + bool first_frame = true; + auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { + // If this is the first frame, set the ImGui's initial size and postion. + if (first_frame) { + first_frame = false; + ImGui::SetNextWindowSize({500, 150}); + ImGui::SetNextWindowPos({260, 600}); + } + + // UI state. + static FilterContents::ColorMatrix color_matrix = { + 1, 0, 0, 0, 0, // + 0, 3, 0, 0, 0, // + 0, 0, 1, 0, 0, // + 0, 0, 0, 1, 0, // + }; + + // Define the ImGui + ImGui::Begin("Color Matrix"); + std::string label = "##1"; + label.c_str(); + for (int i = 0; i < 20; i += 5) { + ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, + &(color_matrix.array[i]), 5, NULL, NULL, "%.2f", 0); + label[2]++; + } + ImGui::End(); + + // Set the color matrix filter. + auto filter = FilterContents::MakeColorMatrix(FilterInput::Make(bay_bridge), + color_matrix); + + // Define the entity with the color matrix filter. + Entity entity; + entity.SetTransformation(Matrix::MakeScale(GetContentScale()) * + Matrix::MakeTranslation({250, 200}) * + Matrix::MakeScale(Vector2{0.5, 0.5})); + entity.SetContents(filter); + entity.Render(context, pass); + + return true; + }; + + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/shaders/color_matrix_color_filter.frag b/impeller/entity/shaders/color_matrix_color_filter.frag new file mode 100644 index 0000000000000..08adb27b6647c --- /dev/null +++ b/impeller/entity/shaders/color_matrix_color_filter.frag @@ -0,0 +1,48 @@ +// 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 + +// 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. +// +// 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: +// +// [ a, b, c, d, e, +// f, g, h, i, j, +// k, l, m, n, o, +// p, q, r, s, t ] +// +// When applied to a color [R, G, B, A], the resulting color is computed as: +// +// R’ = a*R + b*G + c*B + d*A + e; +// G’ = f*R + g*G + h*B + i*A + j; +// 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. + +uniform FragInfo { + mat4 color_m; + vec4 color_v; +} frag_info; + +uniform sampler2D input_texture; + +in vec2 v_position; +out vec4 frag_color; + +void main() { + vec4 input_color = texture(input_texture, v_position); + + // unpremultiply first, as filter inputs are premultiplied. + vec4 color = IPUnpremultiply(input_color); + + color = frag_info.color_m * color + frag_info.color_v; + + // 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 new file mode 100644 index 0000000000000..b741b2744ec60 --- /dev/null +++ b/impeller/entity/shaders/color_matrix_color_filter.vert @@ -0,0 +1,15 @@ +// 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. + +uniform FrameInfo { + mat4 mvp; +} frame_info; + +in vec2 position; +out vec2 v_position; + +void main() { + v_position = position; + gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); +} From 04f5392801c5e920553458c88a9f936bf96ce7ae Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 13:00:45 -0400 Subject: [PATCH 234/558] Roll Skia from e83282daf351 to 0490292655c4 (2 revisions) (#35308) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 35 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/DEPS b/DEPS index c3c92f28b5d88..96442faa00c7f 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': 'e83282daf351a63ec7be825c9cf1a2dba7cf87e0', + 'skia_revision': '0490292655c4b4b35804584341a39c9bbf004616', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index cd803966fba82..5ead88bc84807 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 195e72115fb2a826b1b42c28c9af880f +Signature: e23229ed8802ab9bb0a54880345f2bc4 UNUSED LICENSES: @@ -1310,7 +1310,6 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/mtl/BUILD.bazel FILE: ../../../third_party/skia/src/gpu/ganesh/ops/BUILD.bazel FILE: ../../../third_party/skia/src/gpu/ganesh/tessellate/BUILD.bazel FILE: ../../../third_party/skia/src/gpu/ganesh/text/BUILD.bazel -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/BUILD.bazel FILE: ../../../third_party/skia/src/gpu/ganesh/vk/BUILD.bazel FILE: ../../../third_party/skia/src/gpu/tessellate/BUILD.bazel FILE: ../../../third_party/skia/src/gpu/vk/BUILD.bazel @@ -1560,6 +1559,7 @@ FILE: ../../../third_party/skia/src/effects/SkColorMatrix.cpp FILE: ../../../third_party/skia/src/effects/SkColorMatrixFilter.cpp FILE: ../../../third_party/skia/src/effects/SkLayerDrawLooper.cpp FILE: ../../../third_party/skia/src/effects/SkTableMaskFilter.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/Device.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrAttachment.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrAttachment.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrGpu.h @@ -1571,6 +1571,10 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/GrRenderTarget.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrStencilSettings.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrTexture.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrTexture.h +FILE: ../../../third_party/skia/src/gpu/ganesh/PathRenderer.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/PathRenderer.h +FILE: ../../../third_party/skia/src/gpu/ganesh/PathRendererChain.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/PathRendererChain.h FILE: ../../../third_party/skia/src/gpu/ganesh/geometry/GrPathUtils.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/geometry/GrPathUtils.h FILE: ../../../third_party/skia/src/gpu/ganesh/gl/GrGLAttachment.cpp @@ -1596,11 +1600,6 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/ops/AAHairLinePathRenderer.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/ops/AAHairLinePathRenderer.h FILE: ../../../third_party/skia/src/gpu/ganesh/ops/DefaultPathRenderer.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/ops/DefaultPathRenderer.h -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/Device.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/PathRenderer.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/PathRenderer.h -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/PathRendererChain.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/PathRendererChain.h FILE: ../../../third_party/skia/src/gpu/gl/GrGLDefines.h FILE: ../../../third_party/skia/src/pdf/SkPDFDevice.cpp FILE: ../../../third_party/skia/src/pdf/SkPDFDevice.h @@ -2958,6 +2957,7 @@ FILE: ../../../third_party/skia/src/core/SkYUVPlanesCache.h FILE: ../../../third_party/skia/src/effects/SkTableColorFilter.cpp FILE: ../../../third_party/skia/src/effects/imagefilters/SkImageImageFilter.cpp FILE: ../../../third_party/skia/src/gpu/Blend.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/Device_drawTexture.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrAutoLocaleSetter.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrBlurUtils.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrBlurUtils.h @@ -2985,6 +2985,8 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/GrTTopoSort.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrTestUtils.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrTestUtils.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrXferProcessor.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/SurfaceDrawContext.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/SurfaceDrawContext.h FILE: ../../../third_party/skia/src/gpu/ganesh/effects/GrBlendFragmentProcessor.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/effects/GrBlendFragmentProcessor.h FILE: ../../../third_party/skia/src/gpu/ganesh/effects/GrCustomXfermode.cpp @@ -3024,9 +3026,6 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/ops/LatticeOp.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/ops/LatticeOp.h FILE: ../../../third_party/skia/src/gpu/ganesh/ops/TriangulatingPathRenderer.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/ops/TriangulatingPathRenderer.h -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/Device_drawTexture.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/SurfaceDrawContext.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/SurfaceDrawContext_v1.h FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkCaps.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkCaps.h FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkCommandBuffer.cpp @@ -3882,6 +3881,7 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/GrSurfaceProxyPriv.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrTextureProxyCacheAccess.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrTextureProxyPriv.h FILE: ../../../third_party/skia/src/gpu/ganesh/SkGr.h +FILE: ../../../third_party/skia/src/gpu/ganesh/StencilClip.h FILE: ../../../third_party/skia/src/gpu/ganesh/effects/GrAtlasedShaderHelpers.h FILE: ../../../third_party/skia/src/gpu/ganesh/effects/GrTextureEffect.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/effects/GrTextureEffect.h @@ -3914,7 +3914,6 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelper.h FILE: ../../../third_party/skia/src/gpu/ganesh/ops/TextureOp.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/ops/TextureOp.h -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/StencilClip.h FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkSemaphore.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkSemaphore.h FILE: ../../../third_party/skia/src/opts/SkUtils_opts.h @@ -4042,6 +4041,8 @@ FILE: ../../../third_party/skia/src/core/SkRuntimeEffectPriv.h FILE: ../../../third_party/skia/src/core/SkVM_fwd.h FILE: ../../../third_party/skia/src/core/SkYUVAInfo.cpp FILE: ../../../third_party/skia/src/core/SkYUVAPixmaps.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/ClipStack.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/ClipStack.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrBackendSemaphore.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrBackendSurfaceMutableState.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrBackendSurfaceMutableStateImpl.h @@ -4061,6 +4062,10 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/GrUniformDataManager.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrUniformDataManager.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrUtil.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrYUVABackendTextures.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/StencilMaskHelper.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/StencilMaskHelper.h +FILE: ../../../third_party/skia/src/gpu/ganesh/SurfaceFillContext_v1.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/SurfaceFillContext_v1.h FILE: ../../../third_party/skia/src/gpu/ganesh/d3d/GrD3DAMDMemoryAllocator.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/d3d/GrD3DAMDMemoryAllocator.h FILE: ../../../third_party/skia/src/gpu/ganesh/d3d/GrD3DAttachment.cpp @@ -4114,12 +4119,6 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/geometry/GrShape.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/geometry/GrShape.h FILE: ../../../third_party/skia/src/gpu/ganesh/gl/webgl/GrGLMakeNativeInterface_webgl.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/glsl/GrGLSLUniformHandler.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/ClipStack.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/ClipStack.h -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/StencilMaskHelper.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/StencilMaskHelper.h -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/SurfaceFillContext_v1.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/SurfaceFillContext_v1.h FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkMSAALoadManager.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkMSAALoadManager.h FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkManagedResource.h @@ -7057,6 +7056,7 @@ FILE: ../../../third_party/skia/src/gpu/BufferWriter.h FILE: ../../../third_party/skia/src/gpu/GrRectanizer.h FILE: ../../../third_party/skia/src/gpu/Rectanizer.h FILE: ../../../third_party/skia/src/gpu/RectanizerPow2.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/Device_v1.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrBufferAllocPool.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrBufferAllocPool.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrClip.h @@ -7065,7 +7065,6 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/GrFixedClip.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrGpu.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/SkGr.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/geometry/GrRect.h -FILE: ../../../third_party/skia/src/gpu/ganesh/v1/Device_v1.h FILE: ../../../third_party/skia/src/ports/SkDebug_win.cpp FILE: ../../../third_party/skia/src/text/gpu/Glyph.h ---------------------------------------------------------------------------------------------------- From 6192818802e735f0a36e51119ff7f4dc75356cef Mon Sep 17 00:00:00 2001 From: Casey Hillers Date: Wed, 10 Aug 2022 10:26:12 -0700 Subject: [PATCH 235/558] =?UTF-8?q?Revert=20"Roll=20Dart=20SDK=20from=20f0?= =?UTF-8?q?6ac8474569=20to=20c0767c028f74=20(1=20revision)=20=E2=80=A6=20(?= =?UTF-8?q?#35309)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 96442faa00c7f..606f516b731f6 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '8a0afacdbf9a40320efceb46854b15710173b92f', + 'dart_revision': 'f06ac84745697b1c231bcd37f094b3848bda289e', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 3a8d6323bdb69..23716ae65f297 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: aa78447681930556c7b1cc3f63ea8d2e +Signature: 2ec0b95d585df1f2e202fdf2c17389d5 UNUSED LICENSES: From c3c7e33c69f0edb35c5589f7a5b8c34f1ebda967 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Wed, 10 Aug 2022 10:31:03 -0700 Subject: [PATCH 236/558] Support custom entrypoints in public Windows API (#35285) This adds a dart_entrypoint field to FlutterDesktopEngineProperties in the public C Windows API, which mirrors that in the embedder API. When a null or empty entrypoint is specified, a default entrypoint of 'main' is assumed. Otherwise, the app is launched at the top-level function specified, which must be annotated with @pragma('vm:entry-point') in the Dart source. This change is backward-compatible for existing users of the Windows C API and the C++ client wrapper API. To avoid breaking backward compatibility, this patch preserves the entry_point parameter to FlutterDesktopEngineRun in the public Windows C API as well as in the FlutterEngine::Run method in the C++ client wrapper API. The entrypoint can be specified in either the engine properties struct or via the parameter, but if conflicting non-empty values are specified, the engine launch will intentionally fail with an error message. This change has no effect on existing Flutter Windows desktop apps and no migration is required, because our app templates never specify a custom entrypoint, nor was the option to specify one via the old method particularly feasible, because the FlutterViewController class constructor immediately invokes FlutterViewControllerCreate which immediately launches the engine passed to it with a null entrypoint argument, so long as the engine is not already running. However, running the engine without a view controller previously resulted in errors due to failure to create a rendering surface. This is a followup patch to https://github.com/flutter/engine/pull/35273 which added support for running Dart fixture tests with a live Windows embedder engine. Fixes: https://github.com/flutter/flutter/issues/93537 Related: https://github.com/flutter/flutter/issues/87299 --- ...ility_bridge_delegate_windows_unittests.cc | 2 +- .../windows/client_wrapper/flutter_engine.cc | 5 ++ .../flutter_engine_unittests.cc | 17 ++++++ .../include/flutter/dart_project.h | 16 ++++++ .../include/flutter/flutter_engine.h | 6 ++- shell/platform/windows/fixtures/main.dart | 7 ++- .../windows/flutter_project_bundle.cc | 4 ++ .../platform/windows/flutter_project_bundle.h | 6 +++ shell/platform/windows/flutter_windows.cc | 4 +- .../windows/flutter_windows_engine.cc | 29 ++++++++-- .../platform/windows/flutter_windows_engine.h | 19 +++++-- .../flutter_windows_engine_unittests.cc | 6 +-- .../windows/flutter_windows_unittests.cc | 53 ++++++++++++++++++- .../windows/flutter_windows_view_unittests.cc | 2 +- shell/platform/windows/keyboard_unittests.cc | 2 +- .../platform/windows/public/flutter_windows.h | 22 ++++++-- .../testing/windows_test_config_builder.cc | 22 +++++--- .../testing/windows_test_config_builder.h | 15 ++++-- 18 files changed, 205 insertions(+), 32 deletions(-) diff --git a/shell/platform/windows/accessibility_bridge_delegate_windows_unittests.cc b/shell/platform/windows/accessibility_bridge_delegate_windows_unittests.cc index 27d2fedce3b85..5db7fc4c7de38 100644 --- a/shell/platform/windows/accessibility_bridge_delegate_windows_unittests.cc +++ b/shell/platform/windows/accessibility_bridge_delegate_windows_unittests.cc @@ -86,7 +86,7 @@ std::unique_ptr GetTestEngine() { MockEmbedderApiForKeyboard(modifier, std::make_shared()); - engine->RunWithEntrypoint(nullptr); + engine->Run(); return engine; } diff --git a/shell/platform/windows/client_wrapper/flutter_engine.cc b/shell/platform/windows/client_wrapper/flutter_engine.cc index e9130805c824f..f35c20cd9e5a2 100644 --- a/shell/platform/windows/client_wrapper/flutter_engine.cc +++ b/shell/platform/windows/client_wrapper/flutter_engine.cc @@ -16,6 +16,7 @@ FlutterEngine::FlutterEngine(const DartProject& project) { c_engine_properties.assets_path = project.assets_path().c_str(); c_engine_properties.icu_data_path = project.icu_data_path().c_str(); c_engine_properties.aot_library_path = project.aot_library_path().c_str(); + c_engine_properties.dart_entrypoint = project.dart_entrypoint().c_str(); const std::vector& entrypoint_args = project.dart_entrypoint_arguments(); @@ -40,6 +41,10 @@ FlutterEngine::~FlutterEngine() { ShutDown(); } +bool FlutterEngine::Run() { + return Run(nullptr); +} + bool FlutterEngine::Run(const char* entry_point) { if (!engine_) { std::cerr << "Cannot run an engine that failed creation." << std::endl; diff --git a/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc b/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc index e52fb336a3373..6f09bb960aac5 100644 --- a/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc +++ b/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc @@ -86,6 +86,23 @@ TEST(FlutterEngineTest, CreateDestroy) { EXPECT_EQ(test_api->destroy_called(), true); } +TEST(FlutterEngineTest, CreateDestroyWithCustomEntrypoint) { + testing::ScopedStubFlutterWindowsApi scoped_api_stub( + std::make_unique()); + auto test_api = static_cast(scoped_api_stub.stub()); + { + DartProject project(L"fake/project/path"); + project.set_dart_entrypoint("customEntrypoint"); + FlutterEngine engine(project); + engine.Run(); + EXPECT_EQ(test_api->create_called(), true); + EXPECT_EQ(test_api->run_called(), true); + EXPECT_EQ(test_api->destroy_called(), false); + } + // Destroying should implicitly shut down if it hasn't been done manually. + EXPECT_EQ(test_api->destroy_called(), true); +} + TEST(FlutterEngineTest, ExplicitShutDown) { testing::ScopedStubFlutterWindowsApi scoped_api_stub( std::make_unique()); diff --git a/shell/platform/windows/client_wrapper/include/flutter/dart_project.h b/shell/platform/windows/client_wrapper/include/flutter/dart_project.h index cbc07ff502359..903cfc45e9299 100644 --- a/shell/platform/windows/client_wrapper/include/flutter/dart_project.h +++ b/shell/platform/windows/client_wrapper/include/flutter/dart_project.h @@ -45,6 +45,20 @@ class DartProject { ~DartProject() = default; + // Sets the Dart entrypoint to the specified value. + // + // If not set, the default entrypoint (main) is used. Custom Dart entrypoints + // must be decorated with `@pragma('vm:entry-point')`. + void set_dart_entrypoint(const std::string& entrypoint) { + if (entrypoint.empty()) { + return; + } + dart_entrypoint_ = entrypoint; + } + + // Returns the Dart entrypoint. + const std::string& dart_entrypoint() const { return dart_entrypoint_; } + // Sets the command line arguments that should be passed to the Dart // entrypoint. void set_dart_entrypoint_arguments(std::vector arguments) { @@ -77,6 +91,8 @@ class DartProject { // The path to the AOT library. This will always return a path, but non-AOT // builds will not be expected to actually have a library at that path. std::wstring aot_library_path_; + // The Dart entrypoint to launch. + std::string dart_entrypoint_; // The list of arguments to pass through to the Dart entrypoint. std::vector dart_entrypoint_arguments_; }; diff --git a/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h b/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h index 688361740ebc8..897fccfe0eb94 100644 --- a/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h +++ b/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h @@ -35,13 +35,17 @@ class FlutterEngine : public PluginRegistry { FlutterEngine(FlutterEngine const&) = delete; FlutterEngine& operator=(FlutterEngine const&) = delete; + // Starts running the engine at the entrypoint function specified in the + // DartProject used to configure the engine, or main() by default. + bool Run(); + // Starts running the engine, with an optional entry point. // // If provided, entry_point must be the name of a top-level function from the // same Dart library that contains the app's main() function, and must be // decorated with `@pragma(vm:entry-point)` to ensure the method is not // tree-shaken by the Dart compiler. If not provided, defaults to main(). - bool Run(const char* entry_point = nullptr); + bool Run(const char* entry_point); // Terminates the running engine. void ShutDown(); diff --git a/shell/platform/windows/fixtures/main.dart b/shell/platform/windows/fixtures/main.dart index 6d207279d54ee..219c83e8eb6d5 100644 --- a/shell/platform/windows/fixtures/main.dart +++ b/shell/platform/windows/fixtures/main.dart @@ -3,5 +3,10 @@ // found in the LICENSE file. void main() { - print('Hello windows engine test!'); + print('Hello windows engine test main!'); +} + +@pragma('vm:entry-point') +void customEntrypoint() { + print('Hello windows engine test customEntrypoint!'); } diff --git a/shell/platform/windows/flutter_project_bundle.cc b/shell/platform/windows/flutter_project_bundle.cc index d01ef65a17815..90b2d782d7d7e 100644 --- a/shell/platform/windows/flutter_project_bundle.cc +++ b/shell/platform/windows/flutter_project_bundle.cc @@ -20,6 +20,10 @@ FlutterProjectBundle::FlutterProjectBundle( aot_library_path_ = std::filesystem::path(properties.aot_library_path); } + if (properties.dart_entrypoint && properties.dart_entrypoint[0] != '\0') { + dart_entrypoint_ = properties.dart_entrypoint; + } + for (int i = 0; i < properties.dart_entrypoint_argc; i++) { dart_entrypoint_arguments_.push_back( std::string(properties.dart_entrypoint_argv[i])); diff --git a/shell/platform/windows/flutter_project_bundle.h b/shell/platform/windows/flutter_project_bundle.h index 3cb5d3ca61622..09770b5c094fc 100644 --- a/shell/platform/windows/flutter_project_bundle.h +++ b/shell/platform/windows/flutter_project_bundle.h @@ -50,6 +50,9 @@ class FlutterProjectBundle { // Logs and returns nullptr on failure. UniqueAotDataPtr LoadAotData(const FlutterEngineProcTable& engine_procs); + // Returns the Dart entrypoint. + const std::string& dart_entrypoint() const { return dart_entrypoint_; } + // Returns the command line arguments to be passed through to the Dart // entrypoint. const std::vector& dart_entrypoint_arguments() const { @@ -63,6 +66,9 @@ class FlutterProjectBundle { // Path to the AOT library file, if any. std::filesystem::path aot_library_path_; + // The Dart entrypoint to launch. + std::string dart_entrypoint_; + // Dart entrypoint arguments. std::vector dart_entrypoint_arguments_; diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc index 9e07ed003b648..87c6c8bd55df4 100644 --- a/shell/platform/windows/flutter_windows.cc +++ b/shell/platform/windows/flutter_windows.cc @@ -78,7 +78,7 @@ FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate( std::unique_ptr(EngineFromHandle(engine))); state->view->CreateRenderSurface(); if (!state->view->GetEngine()->running()) { - if (!state->view->GetEngine()->RunWithEntrypoint(nullptr)) { + if (!state->view->GetEngine()->Run()) { return nullptr; } } @@ -144,7 +144,7 @@ bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine_ref) { bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, const char* entry_point) { - return EngineFromHandle(engine)->RunWithEntrypoint(entry_point); + return EngineFromHandle(engine)->Run(entry_point); } uint64_t FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine) { diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index a1edfee1c46f3..a0358bb6090d8 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -200,7 +200,11 @@ void FlutterWindowsEngine::SetSwitches( project_->SetSwitches(switches); } -bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { +bool FlutterWindowsEngine::Run() { + return Run(""); +} + +bool FlutterWindowsEngine::Run(std::string_view entrypoint) { if (!project_->HasValidPaths()) { std::cerr << "Missing or unresolvable paths to assets." << std::endl; return false; @@ -259,6 +263,26 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { args.icu_data_path = icu_path_string.c_str(); args.command_line_argc = static_cast(argv.size()); args.command_line_argv = argv.empty() ? nullptr : argv.data(); + + // Fail if conflicting non-default entrypoints are specified in the method + // argument and the project. + // + // TODO(cbracken): https://github.com/flutter/flutter/issues/109285 + // The entrypoint method parameter should eventually be removed from this + // method and only the entrypoint specified in project_ should be used. + if (!project_->dart_entrypoint().empty() && !entrypoint.empty() && + project_->dart_entrypoint() != entrypoint) { + std::cerr << "Conflicting entrypoints were specified in " + "FlutterDesktopEngineProperties.dart_entrypoint and " + "FlutterDesktopEngineRun(engine, entry_point). " + << std::endl; + return false; + } + if (!entrypoint.empty()) { + args.custom_dart_entrypoint = entrypoint.data(); + } else if (!project_->dart_entrypoint().empty()) { + args.custom_dart_entrypoint = project_->dart_entrypoint().c_str(); + } args.dart_entrypoint_argc = static_cast(entrypoint_argv.size()); args.dart_entrypoint_argv = entrypoint_argv.empty() ? nullptr : entrypoint_argv.data(); @@ -301,9 +325,6 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { if (aot_data_) { args.aot_data = aot_data_.get(); } - if (entrypoint) { - args.custom_dart_entrypoint = entrypoint; - } FlutterRendererConfig renderer_config = surface_manager_ ? GetOpenGLRendererConfig() diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index 71233c318524c..1512870a4e710 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include "flutter/shell/platform/common/accessibility_bridge.h" @@ -72,11 +74,22 @@ class FlutterWindowsEngine { FlutterWindowsEngine(FlutterWindowsEngine const&) = delete; FlutterWindowsEngine& operator=(FlutterWindowsEngine const&) = delete; - // Starts running the engine with the given entrypoint. If null, defaults to - // main(). + // Starts running the entrypoint function specifed in the project bundle. If + // unspecified, defaults to main(). // // Returns false if the engine couldn't be started. - bool RunWithEntrypoint(const char* entrypoint); + bool Run(); + + // Starts running the engine with the given entrypoint. If the empty string + // is specified, defaults to the entrypoint function specified in the project + // bundle, or main() if both are unspecified. + // + // Returns false if the engine couldn't be started or if conflicting, + // non-default values are passed here and in the project bundle.. + // + // DEPRECATED: Prefer setting the entrypoint in the FlutterProjectBundle + // passed to the constructor and calling the no-parameter overload. + bool Run(std::string_view entrypoint); // Returns true if the engine is currently running. bool running() { return engine_ != nullptr; } diff --git a/shell/platform/windows/flutter_windows_engine_unittests.cc b/shell/platform/windows/flutter_windows_engine_unittests.cc index fad87e75e1846..191740f213ebd 100644 --- a/shell/platform/windows/flutter_windows_engine_unittests.cc +++ b/shell/platform/windows/flutter_windows_engine_unittests.cc @@ -129,7 +129,7 @@ TEST(FlutterWindowsEngine, RunDoesExpectedInitialization) { // Set the AngleSurfaceManager to !nullptr to test ANGLE rendering. modifier.SetSurfaceManager(reinterpret_cast(1)); - engine->RunWithEntrypoint(nullptr); + engine->Run(); EXPECT_TRUE(run_called); EXPECT_TRUE(update_locales_called); @@ -206,7 +206,7 @@ TEST(FlutterWindowsEngine, RunWithoutANGLEUsesSoftware) { // Set the AngleSurfaceManager to nullptr to test software fallback path. modifier.SetSurfaceManager(nullptr); - engine->RunWithEntrypoint(nullptr); + engine->Run(); EXPECT_TRUE(run_called); @@ -351,7 +351,7 @@ TEST(FlutterWindowsEngine, AddPluginRegistrarDestructionCallback) { MockEmbedderApiForKeyboard(modifier, std::make_shared()); - engine->RunWithEntrypoint(nullptr); + engine->Run(); // Verify that destruction handlers don't overwrite each other. int result1 = 0; diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index 7b21046eac897..00520426c1897 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -30,7 +30,7 @@ TEST(WindowsNoFixtureTest, GetTextureRegistrar) { TEST_F(WindowsTest, LaunchMain) { auto& context = GetContext(); WindowsConfigBuilder builder(context); - ViewControllerPtr controller{builder.LaunchEngine()}; + ViewControllerPtr controller{builder.Run()}; ASSERT_NE(controller, nullptr); // Run for 1 second, then shut down. @@ -41,5 +41,56 @@ TEST_F(WindowsTest, LaunchMain) { std::this_thread::sleep_for(std::chrono::seconds(1)); } +TEST_F(WindowsTest, LaunchCustomEntrypoint) { + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + builder.SetDartEntrypoint("customEntrypoint"); + ViewControllerPtr controller{builder.Run()}; + ASSERT_NE(controller, nullptr); + + // Run for 1 second, then shut down. + // + // TODO(cbracken): Support registring a native function we can use to + // determine that execution has made it to a specific point in the Dart + // code. https://github.com/flutter/flutter/issues/109242 + std::this_thread::sleep_for(std::chrono::seconds(1)); +} + +// Verify that engine launches with the custom entrypoint specified in the +// FlutterDesktopEngineRun parameter when no entrypoint is specified in +// FlutterDesktopEngineProperties.dart_entrypoint. +// +// TODO(cbracken): https://github.com/flutter/flutter/issues/109285 +TEST_F(WindowsTest, LaunchCustomEntrypointInEngineRunInvocation) { + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + EnginePtr engine{builder.InitializeEngine()}; + ASSERT_NE(engine, nullptr); + + ASSERT_TRUE(FlutterDesktopEngineRun(engine.get(), "customEntrypoint")); + + // Run for 1 second, then shut down. + // + // TODO(cbracken): Support registring a native function we can use to + // determine that execution has made it to a specific point in the Dart + // code. https://github.com/flutter/flutter/issues/109242 + std::this_thread::sleep_for(std::chrono::seconds(1)); +} + +// Verify that engine fails to launch when a conflicting entrypoint in +// FlutterDesktopEngineProperties.dart_entrypoint and the +// FlutterDesktopEngineRun parameter. +// +// TODO(cbracken): https://github.com/flutter/flutter/issues/109285 +TEST_F(WindowsTest, LaunchConflictingCustomEntrypoints) { + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + builder.SetDartEntrypoint("customEntrypoint"); + EnginePtr engine{builder.InitializeEngine()}; + ASSERT_NE(engine, nullptr); + + ASSERT_FALSE(FlutterDesktopEngineRun(engine.get(), "conflictingEntrypoint")); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc index cf823c6357718..9513322daa2b7 100644 --- a/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/shell/platform/windows/flutter_windows_view_unittests.cc @@ -90,7 +90,7 @@ std::unique_ptr GetTestEngine() { MockEmbedderApiForKeyboard(modifier, key_response_controller); - engine->RunWithEntrypoint(nullptr); + engine->Run(); return engine; } diff --git a/shell/platform/windows/keyboard_unittests.cc b/shell/platform/windows/keyboard_unittests.cc index f532c1a92af85..4ce5ba4724e06 100644 --- a/shell/platform/windows/keyboard_unittests.cc +++ b/shell/platform/windows/keyboard_unittests.cc @@ -524,7 +524,7 @@ class KeyboardTester { MockEmbedderApiForKeyboard(modifier, key_response_controller); - engine->RunWithEntrypoint(nullptr); + engine->Run(); return engine; } diff --git a/shell/platform/windows/public/flutter_windows.h b/shell/platform/windows/public/flutter_windows.h index b5d2738778e5a..ca1655f1e9f40 100644 --- a/shell/platform/windows/public/flutter_windows.h +++ b/shell/platform/windows/public/flutter_windows.h @@ -47,6 +47,14 @@ typedef struct { // it will be ignored in that case. const wchar_t* aot_library_path; + // The name of the top-level Dart entrypoint function. If null or the empty + // string, 'main' is assumed. If a custom entrypoint is used, this parameter + // must specifiy the name of a top-level function in the same Dart library as + // the app's main() function. Custom entrypoint functions must be decorated + // with `@pragma('vm:entry-point')` to ensure the method is not tree-shaken + // by the Dart compiler. + const char* dart_entrypoint; + // Number of elements in the array passed in as dart_entrypoint_argv. int dart_entrypoint_argc; @@ -129,13 +137,19 @@ FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopEngineCreate( // |engine| is no longer valid after this call. FLUTTER_EXPORT bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine); -// Starts running the given engine instance and optional entry point in the Dart -// project. If the entry point is null, defaults to main(). +// Starts running the given engine instance. +// +// The entry_point parameter is deprecated but preserved for +// backward-compatibility. If desired, a custom Dart entrypoint function can be +// set in the dart_entrypoint field of the FlutterDesktopEngineProperties +// struct passed to FlutterDesktopEngineCreate. // -// If provided, entry_point must be the name of a top-level function from the +// If sprecified, entry_point must be the name of a top-level function from the // same Dart library that contains the app's main() function, and must be // decorated with `@pragma(vm:entry-point)` to ensure the method is not -// tree-shaken by the Dart compiler. +// tree-shaken by the Dart compiler. If conflicting non-null values are passed +// to this function and via the FlutterDesktopEngineProperties struct, the run +// will fail. // // Returns false if running the engine failed. FLUTTER_EXPORT bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, diff --git a/shell/platform/windows/testing/windows_test_config_builder.cc b/shell/platform/windows/testing/windows_test_config_builder.cc index 69843ea5bb061..c3c2d0ecf9680 100644 --- a/shell/platform/windows/testing/windows_test_config_builder.cc +++ b/shell/platform/windows/testing/windows_test_config_builder.cc @@ -22,6 +22,13 @@ WindowsConfigBuilder::WindowsConfigBuilder(WindowsTestContext& context) WindowsConfigBuilder::~WindowsConfigBuilder() = default; +void WindowsConfigBuilder::SetDartEntrypoint(std::string_view entrypoint) { + if (entrypoint.empty()) { + return; + } + dart_entrypoint_ = entrypoint; +} + void WindowsConfigBuilder::AddDartEntrypointArgument(std::string_view arg) { if (arg.empty()) { return; @@ -36,6 +43,9 @@ FlutterDesktopEngineProperties WindowsConfigBuilder::GetEngineProperties() engine_properties.assets_path = context_.GetAssetsPath().c_str(); engine_properties.icu_data_path = context_.GetIcuDataPath().c_str(); + // Set Dart entrypoint. + engine_properties.dart_entrypoint = dart_entrypoint_.c_str(); + // Set Dart entrypoint argc, argv. std::vector dart_args; dart_args.reserve(dart_entrypoint_arguments_.size()); @@ -55,7 +65,12 @@ FlutterDesktopEngineProperties WindowsConfigBuilder::GetEngineProperties() return engine_properties; } -ViewControllerPtr WindowsConfigBuilder::LaunchEngine() const { +EnginePtr WindowsConfigBuilder::InitializeEngine() const { + FlutterDesktopEngineProperties engine_properties = GetEngineProperties(); + return EnginePtr(FlutterDesktopEngineCreate(&engine_properties)); +} + +ViewControllerPtr WindowsConfigBuilder::Run() const { InitializeCOM(); EnginePtr engine = InitializeEngine(); @@ -78,10 +93,5 @@ void WindowsConfigBuilder::InitializeCOM() const { FML_CHECK(SUCCEEDED(::CoInitializeEx(nullptr, COINIT_MULTITHREADED))); } -EnginePtr WindowsConfigBuilder::InitializeEngine() const { - FlutterDesktopEngineProperties engine_properties = GetEngineProperties(); - return EnginePtr(FlutterDesktopEngineCreate(&engine_properties)); -} - } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/testing/windows_test_config_builder.h b/shell/platform/windows/testing/windows_test_config_builder.h index 0a1bfb400002e..33b2660b2f147 100644 --- a/shell/platform/windows/testing/windows_test_config_builder.h +++ b/shell/platform/windows/testing/windows_test_config_builder.h @@ -52,22 +52,29 @@ class WindowsConfigBuilder { // Returns the desktop engine properties configured for this test. FlutterDesktopEngineProperties GetEngineProperties() const; + // Sets the Dart entrypoint to the specified value. + // + // If not set, the default entrypoint (main) is used. Custom Dart entrypoints + // must be decorated with `@pragma('vm:entry-point')`. + void SetDartEntrypoint(std::string_view entrypoint); + // Adds an argument to the Dart entrypoint arguments List. void AddDartEntrypointArgument(std::string_view arg); + // Returns a configured and initialized engine. + EnginePtr InitializeEngine() const; + // Returns a configured and initialized view controller running the default // Dart entrypoint. - ViewControllerPtr LaunchEngine() const; + ViewControllerPtr Run() const; private: // Initialize COM, so that it is available for use in the library and/or // plugins. void InitializeCOM() const; - // Returns a configured and initialized engine. - EnginePtr InitializeEngine() const; - WindowsTestContext& context_; + std::string dart_entrypoint_; std::vector dart_entrypoint_arguments_; FML_DISALLOW_COPY_AND_ASSIGN(WindowsConfigBuilder); From 63bbf74c15782ffbf529ba84058145cf0de85e10 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 14:11:34 -0400 Subject: [PATCH 237/558] Roll Skia from 0490292655c4 to 0f1018456d33 (4 revisions) (#35311) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 606f516b731f6..bee31fcd29a09 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': '0490292655c4b4b35804584341a39c9bbf004616', + 'skia_revision': '0f1018456d335d24375c9064eb3ada87d02f0606', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 5ead88bc84807..fe9dc6f0842f4 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e23229ed8802ab9bb0a54880345f2bc4 +Signature: b006115088897beb72d248dfde7c0897 UNUSED LICENSES: From 98c0699c50e782ec68e569721ef4bde89c566ada Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Wed, 10 Aug 2022 11:40:11 -0700 Subject: [PATCH 238/558] [Windows] Replace memset with C++ alternatives (#35312) Eliminate a few uses of memset in the code, replacing them with C++ alternatives, like using initialiser list syntax and std::array + fill. This avoids some double-hardcoding of array length in the code. --- shell/platform/windows/flutter_window.cc | 3 +-- .../windows/flutter_windows_unittests.cc | 4 +-- shell/platform/windows/window_unittests.cc | 27 ++++++++++--------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/shell/platform/windows/flutter_window.cc b/shell/platform/windows/flutter_window.cc index a4c66be29db8c..c25f433d9317f 100644 --- a/shell/platform/windows/flutter_window.cc +++ b/shell/platform/windows/flutter_window.cc @@ -250,8 +250,7 @@ bool FlutterWindow::OnBitmapSurfaceUpdated(const void* allocation, size_t row_bytes, size_t height) { HDC dc = ::GetDC(GetWindowHandle()); - BITMAPINFO bmi; - memset(&bmi, 0, sizeof(bmi)); + BITMAPINFO bmi = {}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = row_bytes / 4; bmi.bmiHeader.biHeight = -height; diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index 00520426c1897..ff3d00d0e6fb1 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -4,7 +4,6 @@ #include "flutter/shell/platform/windows/public/flutter_windows.h" -#include #include #include "flutter/shell/platform/windows/testing/windows_test.h" @@ -16,8 +15,7 @@ namespace flutter { namespace testing { TEST(WindowsNoFixtureTest, GetTextureRegistrar) { - FlutterDesktopEngineProperties properties; - memset(&properties, 0, sizeof(FlutterDesktopEngineProperties)); + FlutterDesktopEngineProperties properties = {}; properties.assets_path = L""; properties.icu_data_path = L"icudtl.dat"; auto engine = FlutterDesktopEngineCreate(&properties); diff --git a/shell/platform/windows/window_unittests.cc b/shell/platform/windows/window_unittests.cc index 182dc0918d804..22750e2755a90 100644 --- a/shell/platform/windows/window_unittests.cc +++ b/shell/platform/windows/window_unittests.cc @@ -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 + #include "flutter/shell/platform/windows/testing/mock_text_input_manager.h" #include "flutter/shell/platform/windows/testing/mock_window.h" #include "gtest/gtest.h" @@ -207,19 +209,19 @@ TEST(MockWindow, KeyDownPrintable) { .Times(1) .WillOnce(respond_false); EXPECT_CALL(window, OnText(_)).Times(1); - Win32Message messages[] = {{WM_KEYDOWN, 65, lparam, kWmResultDontCheck}, - {WM_CHAR, 65, lparam, kWmResultDontCheck}}; - window.InjectMessageList(2, messages); + std::array messages = { + Win32Message{WM_KEYDOWN, 65, lparam, kWmResultDontCheck}, + Win32Message{WM_CHAR, 65, lparam, kWmResultDontCheck}}; + window.InjectMessageList(2, messages.data()); } TEST(MockWindow, KeyDownWithCtrl) { MockWindow window; // Simulate CONTROL pressed - BYTE keyboard_state[256]; - memset(keyboard_state, 0, 256); + std::array keyboard_state; keyboard_state[VK_CONTROL] = -1; - SetKeyboardState(keyboard_state); + SetKeyboardState(keyboard_state.data()); LPARAM lparam = CreateKeyEventLparam(30, false, false); @@ -230,8 +232,8 @@ TEST(MockWindow, KeyDownWithCtrl) { window.InjectWindowMessage(WM_KEYDOWN, 65, lparam); - memset(keyboard_state, 0, 256); - SetKeyboardState(keyboard_state); + keyboard_state.fill(0); + SetKeyboardState(keyboard_state.data()); } TEST(MockWindow, KeyDownWithCtrlToggled) { @@ -244,10 +246,9 @@ TEST(MockWindow, KeyDownWithCtrlToggled) { }; // Simulate CONTROL toggled - BYTE keyboard_state[256]; - memset(keyboard_state, 0, 256); + std::array keyboard_state; keyboard_state[VK_CONTROL] = 1; - SetKeyboardState(keyboard_state); + SetKeyboardState(keyboard_state.data()); LPARAM lparam = CreateKeyEventLparam(30, false, false); @@ -261,8 +262,8 @@ TEST(MockWindow, KeyDownWithCtrlToggled) { {WM_CHAR, 65, lparam, kWmResultDontCheck}}; window.InjectMessageList(2, messages); - memset(keyboard_state, 0, 256); - SetKeyboardState(keyboard_state); + keyboard_state.fill(0); + SetKeyboardState(keyboard_state.data()); } TEST(MockWindow, Paint) { From 7b6c20674d11109d7a2e9579ce948e08f6d8a317 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 15:44:11 -0400 Subject: [PATCH 239/558] Roll Skia from 0f1018456d33 to 36f230673448 (1 revision) (#35316) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index bee31fcd29a09..bb3f79e01f001 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': '0f1018456d335d24375c9064eb3ada87d02f0606', + 'skia_revision': '36f2306734483b705ebeaa4738e237082c3f7510', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index fe9dc6f0842f4..2c8b880c49816 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b006115088897beb72d248dfde7c0897 +Signature: e8697617ddc437f5451dad50cd4746c4 UNUSED LICENSES: From d8169a4b1d4f400b8986cc2fc84dafec92ead71b Mon Sep 17 00:00:00 2001 From: Shivesh Ganju Date: Wed, 10 Aug 2022 16:43:59 -0400 Subject: [PATCH 240/558] [fuchsia][scenic] Reset the state of a PointerInjectorEndpoint on (#35241) channel closure. This CL resets the state including cleaning up the buffers whenever a fuchsia.ui.pointerinjector.Device channel closes due to some error. Test: flutter_runner_tests --- .../flutter/pointer_injector_delegate.cc | 6 ++ .../flutter/pointer_injector_delegate.h | 12 +++- .../pointer_injector_delegate_unittest.cc | 66 +++++++++++++++++++ .../tests/fakes/mock_injector_registry.h | 2 + 4 files changed, 85 insertions(+), 1 deletion(-) diff --git a/shell/platform/fuchsia/flutter/pointer_injector_delegate.cc b/shell/platform/fuchsia/flutter/pointer_injector_delegate.cc index 0119f28e8a2b0..0c682bef6ff6b 100644 --- a/shell/platform/fuchsia/flutter/pointer_injector_delegate.cc +++ b/shell/platform/fuchsia/flutter/pointer_injector_delegate.cc @@ -305,4 +305,10 @@ void PointerInjectorDelegate::PointerInjectorEndpoint::RegisterInjector( registered_ = true; } +void PointerInjectorDelegate::PointerInjectorEndpoint::Reset() { + injection_in_flight_ = false; + registered_ = false; + injector_events_ = {}; +} + } // namespace flutter_runner diff --git a/shell/platform/fuchsia/flutter/pointer_injector_delegate.h b/shell/platform/fuchsia/flutter/pointer_injector_delegate.h index 7c041fa346a1a..00063c1af32e5 100644 --- a/shell/platform/fuchsia/flutter/pointer_injector_delegate.h +++ b/shell/platform/fuchsia/flutter/pointer_injector_delegate.h @@ -106,7 +106,11 @@ class PointerInjectorDelegate { if (!weak) { return; } - weak->registered_ = false; + + // Clear all the stale pointer events in |injector_events_| and + // reset the state of |weak| so that any future calls do not inject + // any stale pointer events. + weak->Reset(); }); } @@ -129,6 +133,12 @@ class PointerInjectorDelegate { void EnqueueEvent(fuchsia::ui::pointerinjector::Event event); + // Resets |registered_|, |injection_in_flight_| and |injector_events_| so + // that |device_| can be re-registered and future calls to + // |fuchsia.ui.pointerinjector.Device.Inject| do not include any stale + // pointer events. + void Reset(); + // Set to true if there is a |fuchsia.ui.pointerinjector.Device.Inject| call // in progress. If true, the |fuchsia.ui.pointerinjector.Event| is buffered // in |injector_events_|. diff --git a/shell/platform/fuchsia/flutter/pointer_injector_delegate_unittest.cc b/shell/platform/fuchsia/flutter/pointer_injector_delegate_unittest.cc index 1005671e39225..cee930a428f35 100644 --- a/shell/platform/fuchsia/flutter/pointer_injector_delegate_unittest.cc +++ b/shell/platform/fuchsia/flutter/pointer_injector_delegate_unittest.cc @@ -681,6 +681,72 @@ TEST_P(PointerInjectorDelegateTest, ViewsGetPointerEventsInFIFO) { } } +TEST_P(PointerInjectorDelegateTest, DeviceRetriesRegisterWhenClosed) { + const uint64_t view_id = 1; + const int pointer_id = 1; + auto view_ref_pair = scenic::ViewRefPair::New(); + + auto response = FakePlatformMessageResponse::Create(); + auto response_2 = FakePlatformMessageResponse::Create(); + + std::optional view_ref_clone; + std::optional view_ref_clone_2; + + // Create the view. + if (!is_flatland_) { + CreateView(view_id); + fuv_ViewRef temp_ref; + fuv_ViewRef temp_ref_2; + fidl::Clone(view_ref_pair.view_ref, &temp_ref); + fidl::Clone(view_ref_pair.view_ref, &temp_ref_2); + view_ref_clone = std::move(temp_ref); + view_ref_clone_2 = std::move(temp_ref_2); + } else { + fuv_ViewRef view_ref; + fidl::Clone(view_ref_pair.view_ref, &view_ref); + CreateView(view_id, std::move(view_ref)); + } + + EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage( + PlatformMessageBuilder() + .SetViewId(view_id) + .SetPointerId(pointer_id) + .SetViewRefMaybe(std::move(view_ref_clone)) + .Build(), + response)); + + response->ExpectCompleted("[0]"); + + // The mock Pointerinjector registry server receives a pointer event from + // |f.u.p.Device.Inject| call for the view. + RunLoopUntil([this] { return registry_->num_events_received() == 1; }); + + // The mock Pointerinjector registry server receives a + // |f.u.p.Registry.Register| call for the view. + ASSERT_TRUE(registry_->num_register_calls() == 1); + + // Close the device channel. + registry_->ClearBindings(); + RunLoopUntilIdle(); + + EXPECT_TRUE(pointer_injector_delegate_->HandlePlatformMessage( + PlatformMessageBuilder() + .SetViewId(view_id) + .SetPointerId(pointer_id) + .SetViewRefMaybe(std::move(view_ref_clone_2)) + .Build(), + response_2)); + + response_2->ExpectCompleted("[0]"); + + // The mock Pointerinjector registry server receives a pointer event from + // |f.u.p.Device.Inject| call for the view. + RunLoopUntil([this] { return registry_->num_events_received() == 2; }); + + // The device tries to register again as the channel got closed. + ASSERT_TRUE(registry_->num_register_calls() == 2); +} + INSTANTIATE_TEST_SUITE_P(PointerInjectorDelegateParameterizedTest, PointerInjectorDelegateTest, ::testing::Bool()); diff --git a/shell/platform/fuchsia/flutter/tests/fakes/mock_injector_registry.h b/shell/platform/fuchsia/flutter/tests/fakes/mock_injector_registry.h index 467cd9da43d12..cd7d14b7f7d90 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/mock_injector_registry.h +++ b/shell/platform/fuchsia/flutter/tests/fakes/mock_injector_registry.h @@ -51,6 +51,8 @@ class MockInjectorRegistry : public fuchsia::ui::pointerinjector::Registry, callback(); } + void ClearBindings() { bindings_.clear(); } + // Returns the |fuchsia::ui::pointerinjector::Config| received in the last // |Register(...)| call. const fuchsia::ui::pointerinjector::Config& config() const { return config_; } From 3ec9f21b22e3ce7fcc6cd32b1876f193c4a5bf3a Mon Sep 17 00:00:00 2001 From: Javon Thomas <89162381+JTKryptic@users.noreply.github.com> Date: Wed, 10 Aug 2022 14:36:39 -0700 Subject: [PATCH 241/558] Pushing BackdropFilter Mutator (#34355) --- flow/embedded_views.h | 17 ++++++ flow/layers/backdrop_filter_layer.cc | 3 + flow/layers/platform_view_layer.cc | 1 + flow/mutators_stack_unittests.cc | 27 +++++++++ .../shell_test_external_view_embedder.cc | 36 +++++++++++- .../shell_test_external_view_embedder.h | 22 ++++++- shell/common/shell_unittests.cc | 58 ++++++++++++++++++- .../framework/Source/FlutterPlatformViews.mm | 9 +++ .../Source/FlutterPlatformViews_Internal.h | 9 +++ .../darwin/ios/ios_external_view_embedder.h | 7 +++ .../darwin/ios/ios_external_view_embedder.mm | 11 ++++ 11 files changed, 195 insertions(+), 5 deletions(-) diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 011c20ff3dd87..6a678978f2c85 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -247,6 +247,11 @@ class EmbeddedViewParams { // Clippings are ignored. const SkRect& finalBoundingRect() const { return final_bounding_rect_; } + // Pushes the stored DlImageFilter object to the mutators stack. + void PushImageFilter(std::shared_ptr filter) { + mutators_stack_.PushBackdropFilter(filter); + } + // Whether the embedder should construct DisplayList objects to hold the // rendering commands for each between-view slice of the layer tree. bool display_list_enabled() const { return display_list_enabled_; } @@ -437,6 +442,18 @@ class ExternalViewEmbedder { // 'EndFrame', otherwise returns false. bool GetUsedThisFrame() const { return used_this_frame_; } + // Pushes the platform view id of a visited platform view to a list of + // visited platform views. + virtual void PushVisitedPlatformView(int64_t view_id) {} + + // Pushes a DlImageFilter object to each platform view within a list of + // visited platform views. + // + // See also: |PushVisitedPlatformView| for pushing platform view ids to the + // visited platform views list. + virtual void PushFilterToVisitedPlatformViews( + std::shared_ptr filter) {} + private: bool used_this_frame_ = false; diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 8b77c77d954ef..eb85e73b6a199 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -43,6 +43,9 @@ void BackdropFilterLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context, true, bool(filter_)); + if (context->view_embedder != nullptr) { + context->view_embedder->PushFilterToVisitedPlatformViews(filter_); + } SkRect child_paint_bounds = SkRect::MakeEmpty(); PrerollChildren(context, matrix, &child_paint_bounds); child_paint_bounds.join(context->cull_rect); diff --git a/flow/layers/platform_view_layer.cc b/flow/layers/platform_view_layer.cc index 8a46cbbce127c..a86886fb1b04f 100644 --- a/flow/layers/platform_view_layer.cc +++ b/flow/layers/platform_view_layer.cc @@ -29,6 +29,7 @@ void PlatformViewLayer::Preroll(PrerollContext* context, context->display_list_enabled); context->view_embedder->PrerollCompositeEmbeddedView(view_id_, std::move(params)); + context->view_embedder->PushVisitedPlatformView(view_id_); } void PlatformViewLayer::Paint(PaintContext& context) const { diff --git a/flow/mutators_stack_unittests.cc b/flow/mutators_stack_unittests.cc index a460125ef9627..c93838cfa68bf 100644 --- a/flow/mutators_stack_unittests.cc +++ b/flow/mutators_stack_unittests.cc @@ -163,6 +163,8 @@ TEST(MutatorsStack, Equality) { stack.PushClipPath(path); int alpha = 240; stack.PushOpacity(alpha); + auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + stack.PushBackdropFilter(filter); MutatorsStack stackOther; SkMatrix matrixOther = SkMatrix::Scale(1, 1); @@ -175,6 +177,9 @@ TEST(MutatorsStack, Equality) { stackOther.PushClipPath(otherPath); int otherAlpha = 240; stackOther.PushOpacity(otherAlpha); + auto otherFilter = + std::make_shared(5, 5, DlTileMode::kClamp); + stackOther.PushBackdropFilter(otherFilter); ASSERT_TRUE(stack == stackOther); } @@ -204,6 +209,11 @@ TEST(Mutator, Initialization) { int alpha = 240; Mutator mutator5 = Mutator(alpha); ASSERT_TRUE(mutator5.GetType() == MutatorType::kOpacity); + + auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + Mutator mutator6 = Mutator(filter); + ASSERT_TRUE(mutator6.GetType() == MutatorType::kBackdropFilter); + ASSERT_TRUE(mutator6.GetFilter() == *filter); } TEST(Mutator, CopyConstructor) { @@ -232,6 +242,11 @@ TEST(Mutator, CopyConstructor) { Mutator mutator5 = Mutator(alpha); Mutator copy5 = Mutator(mutator5); ASSERT_TRUE(mutator5 == copy5); + + auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + Mutator mutator6 = Mutator(filter); + Mutator copy6 = Mutator(mutator6); + ASSERT_TRUE(mutator6 == copy6); } TEST(Mutator, Equality) { @@ -260,6 +275,11 @@ TEST(Mutator, Equality) { Mutator mutator5 = Mutator(alpha); Mutator otherMutator5 = Mutator(alpha); ASSERT_TRUE(mutator5 == otherMutator5); + + auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + Mutator mutator6 = Mutator(filter); + Mutator otherMutator6 = Mutator(filter); + ASSERT_TRUE(mutator6 == otherMutator6); } TEST(Mutator, UnEquality) { @@ -275,6 +295,13 @@ TEST(Mutator, UnEquality) { Mutator mutator2 = Mutator(alpha); Mutator otherMutator2 = Mutator(alpha2); ASSERT_TRUE(mutator2 != otherMutator2); + + auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + auto filter2 = + std::make_shared(10, 10, DlTileMode::kClamp); + Mutator mutator3 = Mutator(filter); + Mutator otherMutator3 = Mutator(filter2); + ASSERT_TRUE(mutator3 != otherMutator3); } } // namespace testing diff --git a/shell/common/shell_test_external_view_embedder.cc b/shell/common/shell_test_external_view_embedder.cc index b0f28ff1f08b9..14482ba260c6b 100644 --- a/shell/common/shell_test_external_view_embedder.cc +++ b/shell/common/shell_test_external_view_embedder.cc @@ -28,6 +28,14 @@ SkISize ShellTestExternalViewEmbedder::GetLastSubmittedFrameSize() { return last_submitted_frame_size_; } +std::vector ShellTestExternalViewEmbedder::GetVisitedPlatformViews() { + return visited_platform_views_; +} + +MutatorsStack ShellTestExternalViewEmbedder::GetStack(int64_t view_id) { + return mutators_stacks_[view_id]; +} + // |ExternalViewEmbedder| void ShellTestExternalViewEmbedder::CancelFrame() {} @@ -41,7 +49,16 @@ void ShellTestExternalViewEmbedder::BeginFrame( // |ExternalViewEmbedder| void ShellTestExternalViewEmbedder::PrerollCompositeEmbeddedView( int view_id, - std::unique_ptr params) {} + std::unique_ptr params) { + SkRect view_bounds = SkRect::Make(frame_size_); + std::unique_ptr view; + if (params->display_list_enabled()) { + view = std::make_unique(view_bounds); + } else { + view = std::make_unique(view_bounds); + } + slices_.insert_or_assign(view_id, std::move(view)); +} // |ExternalViewEmbedder| PostPrerollResult ShellTestExternalViewEmbedder::PostPrerollAction( @@ -56,9 +73,24 @@ std::vector ShellTestExternalViewEmbedder::GetCurrentCanvases() { } // |ExternalViewEmbedder| +void ShellTestExternalViewEmbedder::PushVisitedPlatformView(int64_t view_id) { + visited_platform_views_.push_back(view_id); +} + +// |ExternalViewEmbedder| +void ShellTestExternalViewEmbedder::PushFilterToVisitedPlatformViews( + std::shared_ptr filter) { + for (int64_t id : visited_platform_views_) { + EmbeddedViewParams params = current_composition_params_[id]; + params.PushImageFilter(filter); + current_composition_params_[id] = params; + mutators_stacks_[id] = params.mutatorsStack(); + } +} + EmbedderPaintContext ShellTestExternalViewEmbedder::CompositeEmbeddedView( int view_id) { - return {nullptr, nullptr}; + return {slices_[view_id]->canvas(), slices_[view_id]->builder()}; } // |ExternalViewEmbedder| diff --git a/shell/common/shell_test_external_view_embedder.h b/shell/common/shell_test_external_view_embedder.h index f958f6199e694..86c051e5c5963 100644 --- a/shell/common/shell_test_external_view_embedder.h +++ b/shell/common/shell_test_external_view_embedder.h @@ -7,6 +7,7 @@ #include "flutter/flow/embedded_views.h" #include "flutter/fml/raster_thread_merger.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" namespace flutter { @@ -32,9 +33,15 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { // the external view embedder. int GetSubmittedFrameCount(); - // Returns the size of last submitted frame surface + // Returns the size of last submitted frame surface. SkISize GetLastSubmittedFrameSize(); + // Returns the mutators stack for the given platform view. + MutatorsStack GetStack(int64_t); + + // Returns the list of visited platform views. + std::vector GetVisitedPlatformViews(); + private: // |ExternalViewEmbedder| void CancelFrame() override; @@ -61,6 +68,13 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| EmbedderPaintContext CompositeEmbeddedView(int view_id) override; + // |ExternalViewEmbedder| + void PushVisitedPlatformView(int64_t view_id) override; + + // |ExternalViewEmbedder| + void PushFilterToVisitedPlatformViews( + std::shared_ptr filter) override; + // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, std::unique_ptr frame) override; @@ -81,7 +95,11 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { PostPrerollResult post_preroll_result_; bool support_thread_merging_; - + SkISize frame_size_; + std::map> slices_; + std::map mutators_stacks_; + std::map current_composition_params_; + std::vector visited_platform_views_; std::atomic submitted_frame_count_; std::atomic last_submitted_frame_size_; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 7bd244d98aba2..124dbf5d45a70 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -13,8 +13,10 @@ #include "assets/directory_asset_bundle.h" #include "common/graphics/persistent_cache.h" +#include "flutter/flow/layers/backdrop_filter_layer.h" #include "flutter/flow/layers/display_list_layer.h" #include "flutter/flow/layers/layer_raster_cache_item.h" +#include "flutter/flow/layers/platform_view_layer.h" #include "flutter/flow/layers/transform_layer.h" #include "flutter/fml/command_line.h" #include "flutter/fml/dart/dart_converter.h" @@ -765,12 +767,66 @@ TEST_F(ShellTest, ExternalEmbedderNoThreadMerger) { PumpOneFrame(shell.get(), 100, 100, builder); end_frame_latch.Wait(); - ASSERT_TRUE(end_frame_called); DestroyShell(std::move(shell)); } +TEST_F(ShellTest, PushBackdropFilterToVisitedPlatformViews) { + auto settings = CreateSettingsForFixture(); + fml::AutoResetWaitableEvent end_frame_latch; + bool end_frame_called = false; + auto end_frame_callback = + [&](bool should_resubmit_frame, + fml::RefPtr raster_thread_merger) { + ASSERT_TRUE(raster_thread_merger.get() == nullptr); + ASSERT_FALSE(should_resubmit_frame); + end_frame_called = true; + end_frame_latch.Signal(); + }; + auto external_view_embedder = std::make_shared( + end_frame_callback, PostPrerollResult::kResubmitFrame, false); + auto shell = CreateShell(std::move(settings), GetTaskRunnersForFixture(), + false, external_view_embedder); + + // Create the surface needed by rasterizer + PlatformViewNotifyCreated(shell.get()); + + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("emptyMain"); + + RunEngine(shell.get(), std::move(configuration)); + + LayerTreeBuilder builder = [&](std::shared_ptr root) { + auto platform_view_layer = std::make_shared( + SkPoint::Make(10, 10), SkSize::Make(10, 10), 50); + root->Add(platform_view_layer); + auto filter = std::make_shared(5, 5, DlTileMode::kClamp); + auto backdrop_filter_layer = + std::make_shared(filter, DlBlendMode::kSrcOver); + root->Add(backdrop_filter_layer); + auto platform_view_layer2 = std::make_shared( + SkPoint::Make(10, 10), SkSize::Make(10, 10), 75); + backdrop_filter_layer->Add(platform_view_layer2); + }; + + PumpOneFrame(shell.get(), 100, 100, builder); + end_frame_latch.Wait(); + ASSERT_EQ(external_view_embedder->GetVisitedPlatformViews().size(), + (const unsigned long)2); + ASSERT_EQ(external_view_embedder->GetVisitedPlatformViews()[0], 50); + ASSERT_EQ(external_view_embedder->GetVisitedPlatformViews()[1], 75); + ASSERT_TRUE(external_view_embedder->GetStack(75).is_empty()); + ASSERT_FALSE(external_view_embedder->GetStack(50).is_empty()); + + auto filter = DlBlurImageFilter(5, 5, DlTileMode::kClamp); + auto mutator = *external_view_embedder->GetStack(50).Begin(); + ASSERT_EQ(mutator->GetType(), MutatorType::kBackdropFilter); + ASSERT_EQ(mutator->GetFilter(), filter); + + DestroyShell(std::move(shell)); +} + // TODO(https://github.com/flutter/flutter/issues/59816): Enable on fuchsia. TEST_F(ShellTest, #if defined(OS_FUCHSIA) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index d37d1edd5e1c7..2406365cc0322 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -318,6 +318,15 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { } } +void FlutterPlatformViewsController::PushFilterToVisitedPlatformViews( + std::shared_ptr filter) { + for (int64_t id : visited_platform_views_) { + EmbeddedViewParams params = current_composition_params_[id]; + params.PushImageFilter(filter); + current_composition_params_[id] = params; + } +} + void FlutterPlatformViewsController::PrerollCompositeEmbeddedView( int view_id, std::unique_ptr params) { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 3c7a252ada303..8d41b7629c8dd 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -184,6 +184,12 @@ class FlutterPlatformViewsController { // responder. Returns -1 if no such platform view is found. long FindFirstResponderPlatformViewId(); + // Pushes backdrop filter mutation to the mutator stack of each visited platform view. + void PushFilterToVisitedPlatformViews(std::shared_ptr filter); + + // Pushes the view id of a visted platform view to the list of visied platform views. + void PushVisitedPlatformView(int64_t view_id) { visited_platform_views_.push_back(view_id); } + private: static const size_t kMaxLayerAllocations = 2; @@ -291,6 +297,9 @@ class FlutterPlatformViewsController { // The last ID in this vector belond to the that is composited on top of all others. std::vector composition_order_; + // A vector of visited platform view IDs. + std::vector visited_platform_views_; + // The latest composition order that was presented in Present(). std::vector active_composition_order_; diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.h b/shell/platform/darwin/ios/ios_external_view_embedder.h index 54170d5a1c5b8..296930d745f6e 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.h +++ b/shell/platform/darwin/ios/ios_external_view_embedder.h @@ -64,6 +64,13 @@ class IOSExternalViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| bool SupportsDynamicThreadMerging() override; + // |ExternalViewEmbedder| + void PushFilterToVisitedPlatformViews( + std::shared_ptr filter) override; + + // |ExternalViewEmbedder| + void PushVisitedPlatformView(int64_t view_id) override; + FML_DISALLOW_COPY_AND_ASSIGN(IOSExternalViewEmbedder); }; diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.mm b/shell/platform/darwin/ios/ios_external_view_embedder.mm index f82a98f91d429..392c3ba8d6105 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -92,4 +92,15 @@ return true; } +// |ExternalViewEmbedder| +void IOSExternalViewEmbedder::PushFilterToVisitedPlatformViews( + std::shared_ptr filter) { + platform_views_controller_->PushFilterToVisitedPlatformViews(filter); +} + +// |ExternalViewEmbedder| +void IOSExternalViewEmbedder::PushVisitedPlatformView(int64_t view_id) { + platform_views_controller_->PushVisitedPlatformView(view_id); +} + } // namespace flutter From a5abd389e4f4eb95afb676fa6e3d6654b8c35e29 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 17:41:22 -0400 Subject: [PATCH 242/558] Roll Skia from 36f230673448 to 44a17e13fc9b (1 revision) (#35319) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index bb3f79e01f001..058038aa8798a 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': '36f2306734483b705ebeaa4738e237082c3f7510', + 'skia_revision': '44a17e13fc9b689726a31e658d54f35d29f0cb57', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 2c8b880c49816..32d210c30f448 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e8697617ddc437f5451dad50cd4746c4 +Signature: ad7e949b2daca3990cd746f968eb2a13 UNUSED LICENSES: From 697d6eeb35167a4be4faec2b2439f4e6b56369a3 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Wed, 10 Aug 2022 16:00:22 -0700 Subject: [PATCH 243/558] "Reland" "Updates objectc script to accept relative paths."" (#35314) --- tools/gen_objcdoc.sh | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/tools/gen_objcdoc.sh b/tools/gen_objcdoc.sh index dd0583b939231..7f7d65d4f4bd6 100755 --- a/tools/gen_objcdoc.sh +++ b/tools/gen_objcdoc.sh @@ -7,27 +7,29 @@ set -e +if [[ $# -eq 0 ]]; then + echo "Error: Argument specifying output directory required." + exit 1 +fi + +# Move to the flutter checkout +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +pushd "$SCRIPT_DIR/../../flutter" + FLUTTER_UMBRELLA_HEADER=$(find ../out -maxdepth 4 -type f -name Flutter.h | grep 'ios_' | head -n 1) if [[ ! -f "$FLUTTER_UMBRELLA_HEADER" ]] then echo "Error: This script must be run at the root of the Flutter source tree with at least one built Flutter.framework in ../out/ios*/Flutter.framework." + echo "Running from: $(pwd)" exit 1 fi - -# If the script is running from within LUCI we use the LUCI_WORKDIR, if not we force the caller of the script -# to pass an output directory as the first parameter. -OUTPUT_DIR="" - -if [[ -z "$LUCI_CI" ]]; then - if [[ $# -eq 0 ]]; then - echo "Error: Argument specifying output directory required." - exit 1 - else - OUTPUT_DIR="$1" - fi -else - OUTPUT_DIR="$LUCI_WORKDIR/objectc_docs" +OUTPUT_DIR="$1/objectc_docs" +ZIP_DESTINATION="$1" +if [ "${OUTPUT_DIR:0:1}" != "/" ] +then + ZIP_DESTINATION="$SCRIPT_DIR/../../$1" + OUTPUT_DIR="$ZIP_DESTINATION/objectc_docs" fi # If GEM_HOME is set, prefer using its copy of jazzy. @@ -83,3 +85,8 @@ if [[ $EXPECTED_CLASSES != $ACTUAL_CLASSES ]]; then diff <(echo "$EXPECTED_CLASSES") <(echo "$ACTUAL_CLASSES") exit -1 fi + +# Create the final zip file. +pushd $OUTPUT_DIR +zip -r "$ZIP_DESTINATION/ios-objcdoc.zip" . +popd From 35463ebefd6b03d9fecc8517c4dc670d539adf8a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 19:03:05 -0400 Subject: [PATCH 244/558] Roll Skia from 44a17e13fc9b to 4b3a5cc3181c (1 revision) (#35321) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 058038aa8798a..c7a5505e3b426 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': '44a17e13fc9b689726a31e658d54f35d29f0cb57', + 'skia_revision': '4b3a5cc3181cfc6e3ec41cca8c72e421f9e2bf53', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 32d210c30f448..a03174580493c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: ad7e949b2daca3990cd746f968eb2a13 +Signature: fc556fca4e315aada2562cc8a7bd94d7 UNUSED LICENSES: From c9b219f867eac355f5aac35b3b8b8071801c5379 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Wed, 10 Aug 2022 16:25:10 -0700 Subject: [PATCH 245/558] [Impeller] [vulkan] Setup surface producer, and wireup swapchain sync objects (#35322) --- ci/licenses_golden/licenses_flutter | 2 + .../backend/vulkan/playground_impl_vk.cc | 4 +- .../backend/vulkan/playground_impl_vk.h | 3 +- impeller/renderer/backend/vulkan/BUILD.gn | 2 + .../renderer/backend/vulkan/context_vk.cc | 40 ++++- impeller/renderer/backend/vulkan/context_vk.h | 7 +- impeller/renderer/backend/vulkan/formats_vk.h | 28 +++ .../backend/vulkan/surface_producer_vk.cc | 161 ++++++++++++++++++ .../backend/vulkan/surface_producer_vk.h | 51 ++++++ .../renderer/backend/vulkan/surface_vk.cc | 57 ++++++- impeller/renderer/backend/vulkan/surface_vk.h | 18 +- .../renderer/backend/vulkan/swapchain_vk.cc | 36 +++- .../renderer/backend/vulkan/swapchain_vk.h | 16 +- impeller/renderer/surface.h | 2 +- 14 files changed, 402 insertions(+), 25 deletions(-) create mode 100644 impeller/renderer/backend/vulkan/surface_producer_vk.cc create mode 100644 impeller/renderer/backend/vulkan/surface_producer_vk.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 1fe4c9d032452..16eb68bdb0a72 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -799,6 +799,8 @@ FILE: ../../../flutter/impeller/renderer/backend/vulkan/shader_function_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/shader_function_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/shader_library_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/shader_library_vk.h +FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_producer_vk.cc +FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_producer_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_vk.cc FILE: ../../../flutter/impeller/renderer/backend/vulkan/surface_vk.h FILE: ../../../flutter/impeller/renderer/backend/vulkan/swapchain_details_vk.cc diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index ad67592a6d23a..958f5f2531e19 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -85,11 +85,9 @@ PlaygroundImplVK::PlaygroundImplVK() void PlaygroundImplVK::SetupSwapchain() { ContextVK* context_vk = reinterpret_cast(context_.get()); auto window = reinterpret_cast(handle_.get()); - ::glfwCreateWindowSurface(context_vk->GetInstance(), window, nullptr, &surface_); - - swapchain_ = context_vk->CreateSwapchain(surface_); + context_vk->SetupSwapchain(surface_); } PlaygroundImplVK::~PlaygroundImplVK() = default; diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.h b/impeller/playground/backend/vulkan/playground_impl_vk.h index 55dd7f72a13b8..693bc387636e3 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.h +++ b/impeller/playground/backend/vulkan/playground_impl_vk.h @@ -27,9 +27,8 @@ class PlaygroundImplVK final : public PlaygroundImpl { using UniqueHandle = std::unique_ptr; UniqueHandle handle_; - // surface and swapchain + // surface VkSurfaceKHR surface_; - std::unique_ptr swapchain_; // |PlaygroundImpl| std::shared_ptr GetContext() const override; diff --git a/impeller/renderer/backend/vulkan/BUILD.gn b/impeller/renderer/backend/vulkan/BUILD.gn index 78c9d5c66874f..8657983329ebb 100644 --- a/impeller/renderer/backend/vulkan/BUILD.gn +++ b/impeller/renderer/backend/vulkan/BUILD.gn @@ -36,6 +36,8 @@ impeller_component("vulkan") { "shader_function_vk.h", "shader_library_vk.cc", "shader_library_vk.h", + "surface_producer_vk.cc", + "surface_producer_vk.h", "surface_vk.cc", "surface_vk.h", "swapchain_details_vk.cc", diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 563f812322f13..52329dd833071 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -14,8 +14,10 @@ #include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/allocator_vk.h" #include "impeller/renderer/backend/vulkan/capabilities_vk.h" +#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 "vulkan/vulkan.hpp" VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE @@ -137,6 +139,23 @@ static std::optional PickQueue(const vk::PhysicalDevice& device, return std::nullopt; } +static std::optional PickPresentQueue(const vk::PhysicalDevice& device, + vk::SurfaceKHR surface) { + const auto families = device.getQueueFamilyProperties(); + for (size_t i = 0u; i < families.size(); i++) { + auto res = device.getSurfaceSupportKHR(i, surface); + if (res.result != vk::Result::eSuccess) { + continue; + } + vk::Bool32 present_supported = res.value; + if (present_supported) { + return QueueVK{.family = i, .index = 0}; + } + } + VALIDATION_LOG << "No present queue found."; + return std::nullopt; +} + std::shared_ptr ContextVK::Create( PFN_vkGetInstanceProcAddr proc_address_callback, const std::vector>& shader_libraries_data, @@ -436,14 +455,27 @@ vk::Instance ContextVK::GetInstance() const { return *instance_; } -std::unique_ptr ContextVK::CreateSwapchain( - vk::SurfaceKHR surface) const { +void ContextVK::SetupSwapchain(vk::SurfaceKHR surface) { + auto present_queue_out = PickPresentQueue(physical_device_, surface); + if (!present_queue_out.has_value()) { + return; + } + present_queue_ = + device_->getQueue(present_queue_out->family, present_queue_out->index); + auto swapchain_details = SwapchainDetailsVK::Create(physical_device_, surface); if (!swapchain_details) { - return nullptr; + return; } - return SwapchainVK::Create(*device_, surface, *swapchain_details); + swapchain_ = SwapchainVK::Create(*device_, surface, *swapchain_details); + + surface_producer_ = SurfaceProducerVK::Create({ + .device = *device_, + .graphics_queue = graphics_queue_, + .present_queue = present_queue_, + .swapchain = swapchain_.get(), + }); } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 7284008ccbea6..a83bd2d0a14b7 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -14,6 +14,7 @@ #include "impeller/renderer/backend/vulkan/pipeline_library_vk.h" #include "impeller/renderer/backend/vulkan/sampler_library_vk.h" #include "impeller/renderer/backend/vulkan/shader_library_vk.h" +#include "impeller/renderer/backend/vulkan/surface_producer_vk.h" #include "impeller/renderer/backend/vulkan/swapchain_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/context.h" @@ -58,8 +59,7 @@ class ContextVK final : public Context, public BackendCast { vk::Instance GetInstance() const; - std::unique_ptr CreateSwapchain( - vk::SurfaceKHR surface) const; + void SetupSwapchain(vk::SurfaceKHR surface); private: std::shared_ptr worker_task_runner_; @@ -74,7 +74,10 @@ class ContextVK final : public Context, public BackendCast { vk::Queue graphics_queue_; vk::Queue compute_queue_; vk::Queue transfer_queue_; + vk::Queue present_queue_; + std::unique_ptr swapchain_; std::unique_ptr graphics_command_pool_; + std::unique_ptr surface_producer_; bool is_valid_ = false; ContextVK( diff --git a/impeller/renderer/backend/vulkan/formats_vk.h b/impeller/renderer/backend/vulkan/formats_vk.h index dede9aa884b82..90b7724b2450d 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -151,6 +151,34 @@ constexpr vk::Format ToVKImageFormat(PixelFormat format) { } } +constexpr PixelFormat ToPixelFormat(vk::Format format) { + switch (format) { + case vk::Format::eUndefined: + return PixelFormat::kUnknown; + + case vk::Format::eA8B8G8R8UnormPack32: + return PixelFormat::kA8UNormInt; + + case vk::Format::eR8G8B8A8Unorm: + return PixelFormat::kR8G8B8A8UNormInt; + + case vk::Format::eR8G8B8A8Srgb: + return PixelFormat::kR8G8B8A8UNormIntSRGB; + + case vk::Format::eB8G8R8A8Unorm: + return PixelFormat::kB8G8R8A8UNormInt; + + case vk::Format::eB8G8R8A8Srgb: + return PixelFormat::kB8G8R8A8UNormIntSRGB; + + case vk::Format::eS8Uint: + return PixelFormat::kS8UInt; + + default: + return PixelFormat::kUnknown; + } +} + constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count) { switch (sample_count) { case SampleCount::kCount1: diff --git a/impeller/renderer/backend/vulkan/surface_producer_vk.cc b/impeller/renderer/backend/vulkan/surface_producer_vk.cc new file mode 100644 index 0000000000000..d43d9dee66faa --- /dev/null +++ b/impeller/renderer/backend/vulkan/surface_producer_vk.cc @@ -0,0 +1,161 @@ +// 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/renderer/backend/vulkan/surface_producer_vk.h" + +#include + +#include "fml/logging.h" +#include "impeller/renderer/backend/vulkan/surface_vk.h" + +namespace impeller { + +std::unique_ptr SurfaceProducerVK::Create( + const SurfaceProducerCreateInfoVK& create_info) { + auto surface_producer = std::make_unique(create_info); + if (!surface_producer->SetupSyncObjects()) { + FML_LOG(ERROR) << "Failed to setup sync objects."; + return nullptr; + } + + return surface_producer; +} + +SurfaceProducerVK::SurfaceProducerVK( + const SurfaceProducerCreateInfoVK& create_info) + : create_info_(create_info) {} + +SurfaceProducerVK::~SurfaceProducerVK() = default; + +std::unique_ptr SurfaceProducerVK::AcquireSurface( + vk::CommandBuffer command_buffer) { + auto fence_wait_res = create_info_.device.waitForFences({*in_flight_fence_}, + VK_TRUE, UINT64_MAX); + if (fence_wait_res != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to wait for fence: " + << vk::to_string(fence_wait_res); + return nullptr; + } + + auto fence_reset_res = create_info_.device.resetFences({*in_flight_fence_}); + if (fence_reset_res != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to reset fence: " + << vk::to_string(fence_reset_res); + return nullptr; + } + + uint32_t image_index; + auto acuire_image_res = create_info_.device.acquireNextImageKHR( + create_info_.swapchain->GetSwapchain(), UINT64_MAX, + *image_available_semaphore_, {}, &image_index); + if (acuire_image_res != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to acquire next image: " + << vk::to_string(acuire_image_res); + return nullptr; + } + + SurfaceVK::SwapCallback swap_callback = [this, image_index, + command_buffer]() { + if (!Submit(command_buffer)) { + return false; + } + return Present(image_index); + }; + + return SurfaceVK::WrapSwapchainImage( + create_info_.swapchain->GetSwapchainImage(image_index), + std::move(swap_callback)); +} + +bool SurfaceProducerVK::SetupSyncObjects() { + vk::SemaphoreCreateInfo semaphore_create_info; + + { + auto image_avail_res = + create_info_.device.createSemaphoreUnique(semaphore_create_info); + if (image_avail_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to create image available semaphore: " + << vk::to_string(image_avail_res.result); + return false; + } + image_available_semaphore_ = std::move(image_avail_res.value); + } + + { + auto render_finished_res = + create_info_.device.createSemaphoreUnique(semaphore_create_info); + if (render_finished_res.result != vk::Result::eSuccess) { + FML_LOG(ERROR) << "Failed to create render finished semaphore: " + << vk::to_string(render_finished_res.result); + return false; + } + render_finished_semaphore_ = std::move(render_finished_res.value); + } + + vk::FenceCreateInfo fence_create_info; + fence_create_info.flags = vk::FenceCreateFlagBits::eSignaled; + { + auto fence_res = create_info_.device.createFenceUnique(fence_create_info); + if (fence_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to create fence: " + << vk::to_string(fence_res.result); + return false; + } + in_flight_fence_ = std::move(fence_res.value); + } + + return true; +} + +bool SurfaceProducerVK::Submit(vk::CommandBuffer buffer) { + vk::SubmitInfo submit_info; + std::array wait_stages = { + vk::PipelineStageFlagBits::eColorAttachmentOutput}; + submit_info.setWaitDstStageMask(wait_stages); + + std::array wait_semaphores = {*image_available_semaphore_}; + submit_info.setWaitSemaphores(wait_semaphores); + + std::array signal_semaphores = { + *render_finished_semaphore_}; + submit_info.setSignalSemaphores(signal_semaphores); + + std::array command_buffers = {buffer}; + submit_info.setCommandBuffers(command_buffers); + + auto graphics_submit_res = + create_info_.graphics_queue.submit({submit_info}, *in_flight_fence_); + if (graphics_submit_res != vk::Result::eSuccess) { + FML_LOG(ERROR) << "Failed to submit graphics queue: " + << vk::to_string(graphics_submit_res); + return false; + } + + return true; +} + +bool SurfaceProducerVK::Present(uint32_t image_index) { + vk::PresentInfoKHR present_info; + + std::array signal_semaphores = { + *render_finished_semaphore_}; + present_info.setWaitSemaphores(signal_semaphores); + + std::array swapchains = { + create_info_.swapchain->GetSwapchain()}; + present_info.setSwapchains(swapchains); + + std::array image_indices = {image_index}; + present_info.setImageIndices(image_indices); + + auto present_res = create_info_.present_queue.presentKHR(present_info); + if (present_res != vk::Result::eSuccess) { + FML_LOG(ERROR) << "Failed to present: " << vk::to_string(present_res); + return false; + } + + return true; +} + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/surface_producer_vk.h b/impeller/renderer/backend/vulkan/surface_producer_vk.h new file mode 100644 index 0000000000000..96ae70d17adb1 --- /dev/null +++ b/impeller/renderer/backend/vulkan/surface_producer_vk.h @@ -0,0 +1,51 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include + +#include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/swapchain_vk.h" +#include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/surface.h" + +namespace impeller { + +struct SurfaceProducerCreateInfoVK { + vk::Device device; + vk::Queue graphics_queue; + vk::Queue present_queue; + SwapchainVK* swapchain; +}; + +class SurfaceProducerVK { + public: + static std::unique_ptr Create( + const SurfaceProducerCreateInfoVK& create_info); + + explicit SurfaceProducerVK(const SurfaceProducerCreateInfoVK& create_info); + + ~SurfaceProducerVK(); + + std::unique_ptr AcquireSurface(vk::CommandBuffer command_buffer); + + private: + bool SetupSyncObjects(); + + bool Submit(vk::CommandBuffer buffer); + + bool Present(uint32_t image_index); + + const SurfaceProducerCreateInfoVK create_info_; + + // sync objects + vk::UniqueSemaphore image_available_semaphore_; + vk::UniqueSemaphore render_finished_semaphore_; + vk::UniqueFence in_flight_fence_; + + FML_DISALLOW_COPY_AND_ASSIGN(SurfaceProducerVK); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/surface_vk.cc index 1b737032463fa..b3c766d36dc3d 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_vk.cc @@ -5,7 +5,62 @@ #include "impeller/renderer/backend/vulkan/surface_vk.h" namespace impeller { +std::unique_ptr SurfaceVK::WrapSwapchainImage( + SwapchainImageVK* swapchain_image, + SwapCallback swap_callback) { + if (!swapchain_image) { + return nullptr; + } -// + TextureDescriptor color0_tex; + color0_tex.type = TextureType::kTexture2D; + color0_tex.format = swapchain_image->GetPixelFormat(); + color0_tex.size = swapchain_image->GetSize(); + color0_tex.usage = static_cast(TextureUsage::kRenderTarget); + color0_tex.sample_count = SampleCount::kCount1; + + ColorAttachment color0; + // TODO (kaushikiska): this needs to be fixed. + // color0.texture = std::make_shared( + // gl_context.GetReactor(), std::move(color0_tex), + // TextureGLES::IsWrapped::kWrapped); + color0.clear_color = Color::DarkSlateGray(); + color0.load_action = LoadAction::kClear; + color0.store_action = StoreAction::kStore; + + TextureDescriptor stencil0_tex; + stencil0_tex.type = TextureType::kTexture2D; + stencil0_tex.format = swapchain_image->GetPixelFormat(); + stencil0_tex.size = swapchain_image->GetSize(); + stencil0_tex.usage = + static_cast(TextureUsage::kRenderTarget); + stencil0_tex.sample_count = SampleCount::kCount1; + + StencilAttachment stencil0; + stencil0.clear_stencil = 0; + // TODO (kaushikiska): this needs to be fixed. + // stencil0.texture = std::make_shared( + // gl_context.GetReactor(), std::move(stencil0_tex), + // TextureGLES::IsWrapped::kWrapped); + stencil0.load_action = LoadAction::kClear; + stencil0.store_action = StoreAction::kDontCare; + + RenderTarget render_target_desc; + render_target_desc.SetColorAttachment(color0, 0u); + + return std::unique_ptr(new SurfaceVK(std::move(render_target_desc), + swapchain_image, + std::move(swap_callback))); +} + +SurfaceVK::SurfaceVK(RenderTarget target, + SwapchainImageVK* swapchain_image, + SwapCallback swap_callback) {} + +SurfaceVK::~SurfaceVK() = default; + +bool SurfaceVK::Present() const { + return swap_callback_ ? swap_callback_() : false; +} } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/surface_vk.h b/impeller/renderer/backend/vulkan/surface_vk.h index c9d7e1b69202c..2e9403dd0cb73 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.h +++ b/impeller/renderer/backend/vulkan/surface_vk.h @@ -4,19 +4,33 @@ #pragma once +#include + #include "flutter/fml/macros.h" -#include "impeller/renderer/context.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain_vk.h" #include "impeller/renderer/surface.h" namespace impeller { class SurfaceVK final : public Surface { public: + using SwapCallback = std::function; + + static std::unique_ptr WrapSwapchainImage( + SwapchainImageVK* swapchain_image, + SwapCallback swap_callback); + + SurfaceVK(RenderTarget target, + SwapchainImageVK* swapchain_image, + SwapCallback swap_callback); + // |Surface| ~SurfaceVK() override; private: - SurfaceVK(RenderTarget target); + const SwapchainImageVK* swapchain_image_; + SwapCallback swap_callback_; // |Surface| bool Present() const override; diff --git a/impeller/renderer/backend/vulkan/swapchain_vk.cc b/impeller/renderer/backend/vulkan/swapchain_vk.cc index 62b455a928fa8..b57cfee1ec906 100644 --- a/impeller/renderer/backend/vulkan/swapchain_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_vk.cc @@ -6,6 +6,7 @@ #include "fml/logging.h" #include "impeller/base/validation.h" +#include "impeller/renderer/backend/vulkan/formats_vk.h" namespace impeller { @@ -47,9 +48,9 @@ std::unique_ptr SwapchainVK::Create(vk::Device device, return nullptr; } - auto swapchain = std::make_unique(std::move(swapchain_res.value), - surface_format.format, extent); - if (!swapchain->CreateSwapchainImages(device)) { + auto swapchain = std::make_unique( + device, std::move(swapchain_res.value), surface_format.format, extent); + if (!swapchain->CreateSwapchainImages()) { VALIDATION_LOG << "Failed to create swapchain images."; return nullptr; } @@ -57,9 +58,9 @@ std::unique_ptr SwapchainVK::Create(vk::Device device, return swapchain; } -bool SwapchainVK::CreateSwapchainImages(vk::Device device) { +bool SwapchainVK::CreateSwapchainImages() { FML_DCHECK(swapchain_images_.empty()) << "Swapchain images already created"; - auto res = device.getSwapchainImagesKHR(*swapchain_); + auto res = device_.getSwapchainImagesKHR(*swapchain_); if (res.result != vk::Result::eSuccess) { FML_CHECK(false) << "Failed to get swapchain images: " << vk::to_string(res.result); @@ -86,7 +87,7 @@ bool SwapchainVK::CreateSwapchainImages(vk::Device device) { create_info.subresourceRange.baseArrayLayer = 0; create_info.subresourceRange.layerCount = 1; - auto img_view_res = device.createImageViewUnique(create_info); + auto img_view_res = device_.createImageViewUnique(create_info); if (img_view_res.result != vk::Result::eSuccess) { VALIDATION_LOG << "Failed to create image view: " << vk::to_string(img_view_res.result); @@ -100,10 +101,12 @@ bool SwapchainVK::CreateSwapchainImages(vk::Device device) { return true; } -SwapchainVK::SwapchainVK(vk::UniqueSwapchainKHR swapchain, +SwapchainVK::SwapchainVK(vk::Device device, + vk::UniqueSwapchainKHR swapchain, vk::Format image_format, vk::Extent2D extent) - : swapchain_(std::move(swapchain)), + : device_(device), + swapchain_(std::move(swapchain)), image_format_(image_format), extent_(extent) {} @@ -118,6 +121,23 @@ SwapchainImageVK::SwapchainImageVK(vk::Image image, image_format_(image_format), extent_(extent) {} +vk::SwapchainKHR SwapchainVK::GetSwapchain() const { + return *swapchain_; +} + +SwapchainImageVK* SwapchainVK::GetSwapchainImage(uint32_t image_index) const { + FML_DCHECK(image_index < swapchain_images_.size()); + return swapchain_images_[image_index].get(); +} + +PixelFormat SwapchainImageVK::GetPixelFormat() const { + return ToPixelFormat(image_format_); +} + +ISize SwapchainImageVK::GetSize() const { + return ISize(extent_.width, extent_.height); +} + SwapchainImageVK::~SwapchainImageVK() = default; } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain_vk.h b/impeller/renderer/backend/vulkan/swapchain_vk.h index ad585c3b0c4dd..265eaf9fde5c1 100644 --- a/impeller/renderer/backend/vulkan/swapchain_vk.h +++ b/impeller/renderer/backend/vulkan/swapchain_vk.h @@ -7,7 +7,9 @@ #include #include "flutter/fml/macros.h" +#include "impeller/geometry/size.h" #include "impeller/renderer/backend/vulkan/swapchain_details_vk.h" +#include "impeller/renderer/surface.h" namespace impeller { @@ -20,6 +22,10 @@ class SwapchainImageVK { ~SwapchainImageVK(); + PixelFormat GetPixelFormat() const; + + ISize GetSize() const; + private: vk::Image image_; vk::UniqueImageView image_view_; @@ -35,15 +41,21 @@ class SwapchainVK { vk::SurfaceKHR surface, SwapchainDetailsVK& details); - SwapchainVK(vk::UniqueSwapchainKHR swapchain, + SwapchainVK(vk::Device device, + vk::UniqueSwapchainKHR swapchain, vk::Format image_format, vk::Extent2D extent); ~SwapchainVK(); + vk::SwapchainKHR GetSwapchain() const; + + SwapchainImageVK* GetSwapchainImage(uint32_t image_index) const; + private: - bool CreateSwapchainImages(vk::Device device); + bool CreateSwapchainImages(); + vk::Device device_; vk::UniqueSwapchainKHR swapchain_; vk::Format image_format_; vk::Extent2D extent_; diff --git a/impeller/renderer/surface.h b/impeller/renderer/surface.h index 0ab7e53fc2c90..2a9377c5aa668 100644 --- a/impeller/renderer/surface.h +++ b/impeller/renderer/surface.h @@ -18,7 +18,7 @@ class Surface { public: Surface(); - Surface(RenderTarget target_desc); + explicit Surface(RenderTarget target_desc); virtual ~Surface(); From cb67d7c2384c356ea4868226a2a89455a37c98ec Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 10 Aug 2022 20:12:04 -0400 Subject: [PATCH 246/558] Roll Skia from 4b3a5cc3181c to 2db645fcdde2 (2 revisions) (#35326) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c7a5505e3b426..ca9c30f8eab4d 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': '4b3a5cc3181cfc6e3ec41cca8c72e421f9e2bf53', + 'skia_revision': '2db645fcdde2580151a67f9041fa21e3043af3fc', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index a03174580493c..baf8120f3db20 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: fc556fca4e315aada2562cc8a7bd94d7 +Signature: fd68dd0696863f802b91c31104b1d647 UNUSED LICENSES: From bc24be3d7d3d2c03d39ad3f98f4cc2bdd7973cda Mon Sep 17 00:00:00 2001 From: godofredoc Date: Wed, 10 Aug 2022 17:30:06 -0700 Subject: [PATCH 247/558] Add global generator processing for mac_ios builds. (#35328) --- ci/builders/mac_ios_engine.json | 55 ++++++++++++++++++------- ci/builders/mac_ios_engine_profile.json | 32 +++++++++++++- 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/ci/builders/mac_ios_engine.json b/ci/builders/mac_ios_engine.json index 21c700836ba70..b3907394140dc 100644 --- a/ci/builders/mac_ios_engine.json +++ b/ci/builders/mac_ios_engine.json @@ -48,8 +48,7 @@ "archives": [ { "base_path": "out/ios_debug/zip_archives/", - "include_paths": [ - ], + "include_paths": [], "name": "ios_debug" } ], @@ -64,23 +63,51 @@ "--runtime-mode", "debug" ], - "generators": { - "tasks": [ - { - "name": "BuildObjcDoc", - "scripts": [ - "flutter/tools/gen_objcdoc.sh" - ] - } - ] - }, "name": "ios_debug", "ninja": { "config": "ios_debug", - "targets": [] + "targets": [ + "flutter/shell/platform/darwin/ios:flutter_framework" + ] }, "tests": [] } ], - "tests": [] + "tests": [], + "generators": { + "tasks": [ + { + "name": "Debug-FlutterMacOS.framework", + "parameters": [ + "--dst", + "out/debug", + "--arm64-out-dir", + "out/ios_debug", + "--simulator-x64-out-dir", + "out/ios_debug_sim", + "--simulator-arm64-out-dir", + "out/ios_debug_sim_arm64" + ], + "script": "flutter/sky/tools/create_full_ios_framework.py", + "language": "python" + }, + { + "name": "obj-c-doc", + "parameters": [ + "out/debug" + ], + "script": "flutter/tools/gen_objcdoc.sh" + } + ] + }, + "archives": [ + { + "source": "out/debug/artifacts.zip", + "destination": "ios/artifacts.zip" + }, + { + "source": "out/debug/ios-objcdoc.zip", + "destination": "ios-objcdoc.zip" + } + ] } diff --git a/ci/builders/mac_ios_engine_profile.json b/ci/builders/mac_ios_engine_profile.json index 530ab2f4ef7a2..591dfc153ef08 100644 --- a/ci/builders/mac_ios_engine_profile.json +++ b/ci/builders/mac_ios_engine_profile.json @@ -61,10 +61,38 @@ "name": "ios_profile", "ninja": { "config": "ios_profile", - "targets": [] + "targets": [ + "flutter/shell/platform/darwin/ios:flutter_framework", + "flutter/lib/snapshot:generate_snapshot_bin" + ] }, "tests": [] } ], - "tests": [] + "tests": [], + "generators": { + "tasks": [ + { + "name": "Profile-FlutterMacOS.framework", + "parameters": [ + "--dst", + "out/profile", + "--arm64-out-dir", + "out/ios_profile", + "--simulator-x64-out-dir", + "out/ios_debug_sim", + "--simulator-arm64-out-dir", + "out/ios_debug_sim_arm64" + ], + "script": "flutter/sky/tools/create_full_ios_framework.py", + "language": "python" + } + ] + }, + "archives": [ + { + "source": "out/profile/artifacts.zip", + "destination": "ios-profile/artifacts.zip" + } + ] } From 1b3b3edac1b01a59519690c86647c70a67c4d90b Mon Sep 17 00:00:00 2001 From: godofredoc Date: Wed, 10 Aug 2022 17:30:26 -0700 Subject: [PATCH 248/558] Add support for relative paths in mac os gen_snapshot. (#35324) --- sky/tools/create_macos_gen_snapshots.py | 28 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/sky/tools/create_macos_gen_snapshots.py b/sky/tools/create_macos_gen_snapshots.py index 1ecb61d433db3..952c7a9493802 100755 --- a/sky/tools/create_macos_gen_snapshots.py +++ b/sky/tools/create_macos_gen_snapshots.py @@ -9,6 +9,10 @@ import sys import os +buildroot_dir = os.path.abspath( + os.path.join(os.path.realpath(__file__), '..', '..', '..', '..') +) + def main(): parser = argparse.ArgumentParser( @@ -19,25 +23,29 @@ def main(): parser.add_argument('--clang-dir', type=str, default='clang_x64') parser.add_argument('--x64-out-dir', type=str) parser.add_argument('--arm64-out-dir', type=str) - parser.add_argument('--armv7-out-dir', type=str) args = parser.parse_args() + dst = ( + args.dst + if os.path.isabs(args.dst) else os.path.join(buildroot_dir, args.dst) + ) + if args.x64_out_dir: - generate_gen_snapshot( - args.x64_out_dir, os.path.join(args.dst, 'gen_snapshot_x64') + x64_out_dir = ( + args.x64_out_dir if os.path.isabs(args.x64_out_dir) else + os.path.join(buildroot_dir, args.x64_out_dir) ) + generate_gen_snapshot(x64_out_dir, os.path.join(dst, 'gen_snapshot_x64')) if args.arm64_out_dir: - generate_gen_snapshot( - os.path.join(args.arm64_out_dir, args.clang_dir), - os.path.join(args.dst, 'gen_snapshot_arm64') + arm64_out_dir = ( + args.arm64_out_dir if os.path.isabs(args.arm64_out_dir) else + os.path.join(buildroot_dir, args.arm64_out_dir) ) - - if args.armv7_out_dir: generate_gen_snapshot( - os.path.join(args.armv7_out_dir, args.clang_dir), - os.path.join(args.dst, 'gen_snapshot_armv7') + os.path.join(arm64_out_dir, args.clang_dir), + os.path.join(dst, 'gen_snapshot_arm64') ) From c9a31b7ea4fe96ee1dafd18499724216e9eba0a3 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Wed, 10 Aug 2022 19:59:28 -0700 Subject: [PATCH 249/558] Revert "Add support for relative paths in mac os gen_snapshot." (#35331) --- sky/tools/create_macos_gen_snapshots.py | 28 +++++++++---------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/sky/tools/create_macos_gen_snapshots.py b/sky/tools/create_macos_gen_snapshots.py index 952c7a9493802..1ecb61d433db3 100755 --- a/sky/tools/create_macos_gen_snapshots.py +++ b/sky/tools/create_macos_gen_snapshots.py @@ -9,10 +9,6 @@ import sys import os -buildroot_dir = os.path.abspath( - os.path.join(os.path.realpath(__file__), '..', '..', '..', '..') -) - def main(): parser = argparse.ArgumentParser( @@ -23,29 +19,25 @@ def main(): parser.add_argument('--clang-dir', type=str, default='clang_x64') parser.add_argument('--x64-out-dir', type=str) parser.add_argument('--arm64-out-dir', type=str) + parser.add_argument('--armv7-out-dir', type=str) args = parser.parse_args() - dst = ( - args.dst - if os.path.isabs(args.dst) else os.path.join(buildroot_dir, args.dst) - ) - if args.x64_out_dir: - x64_out_dir = ( - args.x64_out_dir if os.path.isabs(args.x64_out_dir) else - os.path.join(buildroot_dir, args.x64_out_dir) + generate_gen_snapshot( + args.x64_out_dir, os.path.join(args.dst, 'gen_snapshot_x64') ) - generate_gen_snapshot(x64_out_dir, os.path.join(dst, 'gen_snapshot_x64')) if args.arm64_out_dir: - arm64_out_dir = ( - args.arm64_out_dir if os.path.isabs(args.arm64_out_dir) else - os.path.join(buildroot_dir, args.arm64_out_dir) + generate_gen_snapshot( + os.path.join(args.arm64_out_dir, args.clang_dir), + os.path.join(args.dst, 'gen_snapshot_arm64') ) + + if args.armv7_out_dir: generate_gen_snapshot( - os.path.join(arm64_out_dir, args.clang_dir), - os.path.join(dst, 'gen_snapshot_arm64') + os.path.join(args.armv7_out_dir, args.clang_dir), + os.path.join(args.dst, 'gen_snapshot_armv7') ) From 5f92d3668c7a172be23df13eebd24ab7e7df29ee Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 00:36:34 -0400 Subject: [PATCH 250/558] Roll Fuchsia Mac SDK from tdJUKQ0dM... to VVKF4KTZT... (#35333) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index ca9c30f8eab4d..e08bd3ffc5531 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'tdJUKQ0dMvgPqjPx8hyE1L3hARwGJOd9RV3zp-j66hgC' + 'version': 'VVKF4KTZTkLEmNkj8KxgiSVL-TBtsbB5pWa_ee3AovEC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 1655d74d5e195f28f8d692ee3b7562c79c812277 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Wed, 10 Aug 2022 22:40:07 -0700 Subject: [PATCH 251/558] Reland Add support for relative paths in mac os gen_snapshot. (#35332) --- sky/tools/create_macos_gen_snapshots.py | 31 ++++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/sky/tools/create_macos_gen_snapshots.py b/sky/tools/create_macos_gen_snapshots.py index 1ecb61d433db3..e76c43282ca3c 100755 --- a/sky/tools/create_macos_gen_snapshots.py +++ b/sky/tools/create_macos_gen_snapshots.py @@ -9,6 +9,10 @@ import sys import os +buildroot_dir = os.path.abspath( + os.path.join(os.path.realpath(__file__), '..', '..', '..', '..') +) + def main(): parser = argparse.ArgumentParser( @@ -23,21 +27,36 @@ def main(): args = parser.parse_args() + dst = ( + args.dst + if os.path.isabs(args.dst) else os.path.join(buildroot_dir, args.dst) + ) + if args.x64_out_dir: - generate_gen_snapshot( - args.x64_out_dir, os.path.join(args.dst, 'gen_snapshot_x64') + x64_out_dir = ( + args.x64_out_dir if os.path.isabs(args.x64_out_dir) else + os.path.join(buildroot_dir, args.x64_out_dir) ) + generate_gen_snapshot(x64_out_dir, os.path.join(dst, 'gen_snapshot_x64')) if args.arm64_out_dir: + arm64_out_dir = ( + args.arm64_out_dir if os.path.isabs(args.arm64_out_dir) else + os.path.join(buildroot_dir, args.arm64_out_dir) + ) generate_gen_snapshot( - os.path.join(args.arm64_out_dir, args.clang_dir), - os.path.join(args.dst, 'gen_snapshot_arm64') + os.path.join(arm64_out_dir, args.clang_dir), + os.path.join(dst, 'gen_snapshot_arm64') ) if args.armv7_out_dir: + armv7_out_dir = ( + args.armv7_out_dir if os.path.isabs(args.armv7_out_dir) else + os.path.join(buildroot_dir, args.armv7_out_dir) + ) generate_gen_snapshot( - os.path.join(args.armv7_out_dir, args.clang_dir), - os.path.join(args.dst, 'gen_snapshot_armv7') + os.path.join(armv7_out_dir, args.clang_dir), + os.path.join(dst, 'gen_snapshot_armv7') ) From 463b7695963a2b0abedf3beb800ccf9e3e602a57 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 02:04:36 -0400 Subject: [PATCH 252/558] Roll Skia from 2db645fcdde2 to 8caa45760bb7 (1 revision) (#35335) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e08bd3ffc5531..8071648540209 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': '2db645fcdde2580151a67f9041fa21e3043af3fc', + 'skia_revision': '8caa45760bb755978f1b8be5cb5ab11440631d92', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index baf8120f3db20..be756a7290972 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: fd68dd0696863f802b91c31104b1d647 +Signature: 24f87351754fbe4ea9439a61f7c79002 UNUSED LICENSES: From d343bca6f600d3b5fe07a2ddbd0e352170ae11e7 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 03:14:12 -0400 Subject: [PATCH 253/558] Roll Skia from 8caa45760bb7 to 41cb8f2f9d12 (2 revisions) (#35337) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 8071648540209..bafa57c817200 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': '8caa45760bb755978f1b8be5cb5ab11440631d92', + 'skia_revision': '41cb8f2f9d128a67e2782dfb89732477a223cff9', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index be756a7290972..630568f0d86fe 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 24f87351754fbe4ea9439a61f7c79002 +Signature: f364b1245968c49ae838fc2876eedd02 UNUSED LICENSES: @@ -5584,6 +5584,8 @@ FILE: ../../../third_party/skia/src/gpu/graphite/AttachmentTypes.h FILE: ../../../third_party/skia/src/gpu/graphite/ClipStack.cpp FILE: ../../../third_party/skia/src/gpu/graphite/ClipStack_graphite.h FILE: ../../../third_party/skia/src/gpu/graphite/CommandTypes.h +FILE: ../../../third_party/skia/src/gpu/graphite/ComputePassTask.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/ComputePassTask.h FILE: ../../../third_party/skia/src/gpu/graphite/ComputePipeline.cpp FILE: ../../../third_party/skia/src/gpu/graphite/ComputePipeline.h FILE: ../../../third_party/skia/src/gpu/graphite/ComputePipelineDesc.h From f2fce029698f68f5b382ea8abbc36b4ceb7145ed Mon Sep 17 00:00:00 2001 From: JsouLiang Date: Thu, 11 Aug 2022 15:44:51 +0800 Subject: [PATCH 254/558] Create DlLocalMatrixImageFilter (#34878) --- display_list/display_list_builder.cc | 1 + display_list/display_list_image_filter.cc | 25 ++++ display_list/display_list_image_filter.h | 111 ++++++++++++++++++ .../display_list_image_filter_unittests.cc | 87 ++++++++++++++ .../display_list/display_list_dispatcher.cc | 1 + 5 files changed, 225 insertions(+) diff --git a/display_list/display_list_builder.cc b/display_list/display_list_builder.cc index 970e019ff56bf..a4741ad24c470 100644 --- a/display_list/display_list_builder.cc +++ b/display_list/display_list_builder.cc @@ -225,6 +225,7 @@ void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) { break; } case DlImageFilterType::kComposeFilter: + case DlImageFilterType::kLocalMatrixFilter: case DlImageFilterType::kColorFilter: { Push(0, 0, filter); break; diff --git a/display_list/display_list_image_filter.cc b/display_list/display_list_image_filter.cc index f9eb71d35cca1..cae1321ffda34 100644 --- a/display_list/display_list_image_filter.cc +++ b/display_list/display_list_image_filter.cc @@ -27,6 +27,31 @@ std::shared_ptr DlImageFilter::From( return std::make_shared(sk_ref_sp(sk_filter)); } +std::shared_ptr DlImageFilter::makeWithLocalMatrix( + const SkMatrix& matrix) { + if (matrix.isIdentity()) { + return shared(); + } + // Matrix + switch (this->matrix_capability()) { + case MatrixCapability::kTranslate: { + if (!matrix.isTranslate()) { + // Nothing we can do at this point + return nullptr; + } + } + case MatrixCapability::kScaleTranslate: { + if (!matrix.isScaleTranslate()) { + // Nothing we can do at this point + return nullptr; + } + } + default: + break; + } + return std::make_shared(matrix, shared()); +} + SkRect* DlComposeImageFilter::map_local_bounds(const SkRect& input_bounds, SkRect& output_bounds) const { SkRect cur_bounds = input_bounds; diff --git a/display_list/display_list_image_filter.h b/display_list/display_list_image_filter.h index 5cc789e337795..4a0063b8b48cb 100644 --- a/display_list/display_list_image_filter.h +++ b/display_list/display_list_image_filter.h @@ -34,6 +34,7 @@ enum class DlImageFilterType { kMatrix, kComposeFilter, kColorFilter, + kLocalMatrixFilter, kUnknown }; @@ -41,12 +42,19 @@ class DlBlurImageFilter; class DlDilateImageFilter; class DlErodeImageFilter; class DlMatrixImageFilter; +class DlLocalMatrixImageFilter; class DlComposeImageFilter; class DlColorFilterImageFilter; class DlImageFilter : public DlAttribute { public: + enum class MatrixCapability { + kTranslate, + kScaleTranslate, + kComplex, + }; + // Return a shared_ptr holding a DlImageFilter representing the indicated // Skia SkImageFilter pointer. // @@ -82,6 +90,13 @@ class DlImageFilter // type of ImageFilter, otherwise return nullptr. virtual const DlMatrixImageFilter* asMatrix() const { return nullptr; } + virtual const DlLocalMatrixImageFilter* asLocalMatrix() const { + return nullptr; + } + + virtual std::shared_ptr makeWithLocalMatrix( + const SkMatrix& matrix); + // Return a DlComposeImageFilter pointer to this object iff it is a Compose // type of ImageFilter, otherwise return nullptr. virtual const DlComposeImageFilter* asCompose() const { return nullptr; } @@ -137,6 +152,10 @@ class DlImageFilter const SkMatrix& ctm, SkIRect& input_bounds) const = 0; + virtual MatrixCapability matrix_capability() const { + return MatrixCapability::kScaleTranslate; + } + protected: static SkVector map_vectors_affine(const SkMatrix& ctm, SkScalar x, @@ -534,6 +553,10 @@ class DlComposeImageFilter final : public DlImageFilter { inner_->skia_object()); } + MatrixCapability matrix_capability() const override { + return std::min(outer_->matrix_capability(), inner_->matrix_capability()); + } + protected: bool equals_(const DlImageFilter& other) const override { FML_DCHECK(other.type() == DlImageFilterType::kComposeFilter); @@ -606,6 +629,15 @@ class DlColorFilterImageFilter final : public DlImageFilter { return SkImageFilters::ColorFilter(color_filter_->skia_object(), nullptr); } + MatrixCapability matrix_capability() const override { + return MatrixCapability::kComplex; + } + + std::shared_ptr makeWithLocalMatrix( + const SkMatrix& matrix) override { + return shared(); + } + protected: bool equals_(const DlImageFilter& other) const override { FML_DCHECK(other.type() == DlImageFilterType::kColorFilter); @@ -617,6 +649,85 @@ class DlColorFilterImageFilter final : public DlImageFilter { std::shared_ptr color_filter_; }; +class DlLocalMatrixImageFilter final : public DlImageFilter { + public: + explicit DlLocalMatrixImageFilter(const SkMatrix& matrix, + std::shared_ptr filter) + : matrix_(matrix), image_filter_(filter) {} + explicit DlLocalMatrixImageFilter(const DlLocalMatrixImageFilter* filter) + : DlLocalMatrixImageFilter(filter->matrix_, filter->image_filter_) {} + DlLocalMatrixImageFilter(const DlLocalMatrixImageFilter& filter) + : DlLocalMatrixImageFilter(&filter) {} + std::shared_ptr shared() const override { + return std::make_shared(this); + } + + DlImageFilterType type() const override { + return DlImageFilterType::kLocalMatrixFilter; + } + size_t size() const override { return sizeof(*this); } + + const SkMatrix& matrix() const { return matrix_; } + + const DlLocalMatrixImageFilter* asLocalMatrix() const override { + return this; + } + + bool modifies_transparent_black() const override { + if (!image_filter_) { + return false; + } + return image_filter_->modifies_transparent_black(); + } + + SkRect* map_local_bounds(const SkRect& input_bounds, + SkRect& output_bounds) const override { + if (!image_filter_) { + return nullptr; + } + return image_filter_->map_local_bounds(input_bounds, output_bounds); + } + + SkIRect* map_device_bounds(const SkIRect& input_bounds, + const SkMatrix& ctm, + SkIRect& output_bounds) const override { + if (!image_filter_) { + return nullptr; + } + return image_filter_->map_device_bounds( + input_bounds, SkMatrix::Concat(ctm, matrix_), output_bounds); + } + + SkIRect* get_input_device_bounds(const SkIRect& output_bounds, + const SkMatrix& ctm, + SkIRect& input_bounds) const override { + if (!image_filter_) { + return nullptr; + } + return image_filter_->get_input_device_bounds( + output_bounds, SkMatrix::Concat(ctm, matrix_), input_bounds); + } + + sk_sp skia_object() const override { + if (!image_filter_) { + return nullptr; + } + return image_filter_->skia_object()->makeWithLocalMatrix(matrix_); + } + + protected: + bool equals_(const DlImageFilter& other) const override { + FML_DCHECK(other.type() == DlImageFilterType::kMatrix); + auto that = static_cast(&other); + return (matrix_ == that->matrix_ && + Equals(image_filter_, that->image_filter_)); + } + + private: + SkMatrix matrix_; + std::shared_ptr image_filter_; +}; + // A wrapper class for a Skia ImageFilter of unknown type. The above 4 types // are the only types that can be constructed by Flutter using the // ui.ImageFilter class so this class should be rarely used. The main use diff --git a/display_list/display_list_image_filter_unittests.cc b/display_list/display_list_image_filter_unittests.cc index 346a2f7ff56e3..f3f2507cf3b82 100644 --- a/display_list/display_list_image_filter_unittests.cc +++ b/display_list/display_list_image_filter_unittests.cc @@ -3,10 +3,14 @@ // found in the LICENSE file. #include "flutter/display_list/display_list_attributes_testing.h" +#include "flutter/display_list/display_list_blend_mode.h" #include "flutter/display_list/display_list_builder.h" +#include "flutter/display_list/display_list_color.h" +#include "flutter/display_list/display_list_color_filter.h" #include "flutter/display_list/display_list_comparable.h" #include "flutter/display_list/display_list_image_filter.h" #include "flutter/display_list/display_list_sampling_options.h" +#include "flutter/display_list/display_list_tile_mode.h" #include "flutter/display_list/types.h" #include "gtest/gtest.h" @@ -759,6 +763,89 @@ TEST(DisplayListImageFilter, UnknownContents) { ASSERT_EQ(filter.skia_object().get(), sk_filter.get()); } +TEST(DisplayListImageFilter, LocalImageFilterBounds) { + auto filter_matrix = SkMatrix::MakeAll(2.0, 0.0, 10, // + 0.5, 3.0, 15, // + 0.0, 0.0, 1); + std::vector> sk_filters{ + SkImageFilters::Blur(5.0, 6.0, SkTileMode::kRepeat, nullptr), + SkImageFilters::ColorFilter( + SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcOver), nullptr), + SkImageFilters::Dilate(5.0, 10.0, nullptr), + SkImageFilters::MatrixTransform(filter_matrix, + ToSk(DlImageSampling::kLinear), nullptr), + SkImageFilters::Compose( + SkImageFilters::Blur(5.0, 6.0, SkTileMode::kRepeat, nullptr), + SkImageFilters::ColorFilter( + SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcOver), + nullptr))}; + + DlBlendColorFilter dl_color_filter(DlColor::kRed(), DlBlendMode::kSrcOver); + std::vector> dl_filters{ + std::make_shared(5.0, 6.0, DlTileMode::kRepeat), + std::make_shared(dl_color_filter.shared()), + std::make_shared(5, 10), + std::make_shared(filter_matrix, + DlImageSampling::kLinear), + std::make_shared( + std::make_shared(5.0, 6.0, DlTileMode::kRepeat), + std::make_shared( + dl_color_filter.shared()))}; + + auto persp = SkMatrix::I(); + persp.setPerspY(0.001); + std::vector matrices = { + SkMatrix::Translate(10.0, 10.0), + SkMatrix::Scale(2.0, 2.0).preTranslate(10.0, 10.0), + SkMatrix::RotateDeg(45).preTranslate(5.0, 5.0), persp}; + std::vector bounds_matrices{SkMatrix::Translate(5.0, 10.0), + SkMatrix::Scale(2.0, 2.0)}; + + for (unsigned i = 0; i < sk_filters.size(); i++) { + for (unsigned j = 0; j < matrices.size(); j++) { + for (unsigned k = 0; k < bounds_matrices.size(); k++) { + auto& m = matrices[j]; + auto& bounds_matrix = bounds_matrices[k]; + auto sk_local_filter = sk_filters[i]->makeWithLocalMatrix(m); + auto dl_local_filter = dl_filters[i]->makeWithLocalMatrix(m); + if (!sk_local_filter || !dl_local_filter) { + ASSERT_TRUE(!sk_local_filter); + ASSERT_TRUE(!dl_local_filter); + continue; + } + { + auto inputBounds = SkIRect::MakeLTRB(20, 20, 80, 80); + SkIRect sk_rect, dl_rect; + sk_rect = sk_local_filter->filterBounds( + inputBounds, bounds_matrix, + SkImageFilter::MapDirection::kForward_MapDirection); + dl_local_filter->map_device_bounds(inputBounds, bounds_matrix, + dl_rect); + ASSERT_EQ(sk_rect, dl_rect); + } + { + // Test for: Know the outset bounds to get the inset bounds + // Skia have some bounds calculate error of DilateFilter and + // MatrixFilter + // Skia issue: https://bugs.chromium.org/p/skia/issues/detail?id=13444 + // flutter issue: https://github.com/flutter/flutter/issues/108693 + if (i == 2 || i == 3) { + continue; + } + auto outsetBounds = SkIRect::MakeLTRB(20, 20, 80, 80); + SkIRect sk_rect, dl_rect; + sk_rect = sk_local_filter->filterBounds( + outsetBounds, bounds_matrix, + SkImageFilter::MapDirection::kReverse_MapDirection); + dl_local_filter->get_input_device_bounds(outsetBounds, bounds_matrix, + dl_rect); + ASSERT_EQ(sk_rect, dl_rect); + } + } + } + } +} + TEST(DisplayListImageFilter, UnknownEquals) { sk_sp sk_filter = SkImageFilters::Blur(5.0, 6.0, SkTileMode::kRepeat, nullptr); diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index c14609c731bd5..5525e23de08d7 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -441,6 +441,7 @@ static std::optional ToImageFilterProc( case flutter::DlImageFilterType::kDilate: case flutter::DlImageFilterType::kErode: case flutter::DlImageFilterType::kMatrix: + case flutter::DlImageFilterType::kLocalMatrixFilter: case flutter::DlImageFilterType::kComposeFilter: case flutter::DlImageFilterType::kColorFilter: case flutter::DlImageFilterType::kUnknown: From ac81750a6c615711880875199b3b5bb9b0062577 Mon Sep 17 00:00:00 2001 From: JsouLiang Date: Thu, 11 Aug 2022 15:48:40 +0800 Subject: [PATCH 255/558] optimize out unnecessary save restore pairs (#34967) * drafting the solution to optimize out unnecessary save restore pairs * remove unnecessary save/restore pairs * delete the calculator change; * fix some logic; Add some testcases * Add test for set DlPaint * update test cases * Prune TranslateTriggersDeferredSave unittest --- display_list/display_list_builder.cc | 28 +- display_list/display_list_builder.h | 4 + display_list/display_list_unittests.cc | 549 +++++++++++++++++++++++++ 3 files changed, 579 insertions(+), 2 deletions(-) diff --git a/display_list/display_list_builder.cc b/display_list/display_list_builder.cc index a4741ad24c470..4b7c1c0e81c97 100644 --- a/display_list/display_list_builder.cc +++ b/display_list/display_list_builder.cc @@ -4,6 +4,7 @@ #include "flutter/display_list/display_list_builder.h" +#include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_blend_mode.h" #include "flutter/display_list/display_list_ops.h" @@ -414,19 +415,29 @@ void DisplayListBuilder::setAttributesFromPaint( } } +void DisplayListBuilder::checkForDeferredSave() { + if (current_layer_->has_deferred_save_op_) { + Push(0, 1); + current_layer_->has_deferred_save_op_ = false; + } +} + void DisplayListBuilder::save() { - Push(0, 1); layer_stack_.emplace_back(current_layer_); current_layer_ = &layer_stack_.back(); + current_layer_->has_deferred_save_op_ = true; } + void DisplayListBuilder::restore() { if (layer_stack_.size() > 1) { + if (!current_layer_->has_deferred_save_op_) { + Push(0, 1); + } // Grab the current layer info before we push the restore // on the stack. LayerInfo layer_info = layer_stack_.back(); layer_stack_.pop_back(); current_layer_ = &layer_stack_.back(); - Push(0, 1); if (layer_info.has_layer) { if (layer_info.is_group_opacity_compatible()) { // We are now going to go back and modify the matching saveLayer @@ -505,6 +516,7 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds, void DisplayListBuilder::translate(SkScalar tx, SkScalar ty) { if (SkScalarIsFinite(tx) && SkScalarIsFinite(ty) && (tx != 0.0 || ty != 0.0)) { + checkForDeferredSave(); Push(0, 1, tx, ty); current_layer_->matrix.preTranslate(tx, ty); } @@ -512,12 +524,14 @@ void DisplayListBuilder::translate(SkScalar tx, SkScalar ty) { void DisplayListBuilder::scale(SkScalar sx, SkScalar sy) { if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) && (sx != 1.0 || sy != 1.0)) { + checkForDeferredSave(); Push(0, 1, sx, sy); current_layer_->matrix.preScale(sx, sy); } } void DisplayListBuilder::rotate(SkScalar degrees) { if (SkScalarMod(degrees, 360.0) != 0.0) { + checkForDeferredSave(); Push(0, 1, degrees); current_layer_->matrix.preConcat(SkMatrix::RotateDeg(degrees)); } @@ -525,6 +539,7 @@ void DisplayListBuilder::rotate(SkScalar degrees) { void DisplayListBuilder::skew(SkScalar sx, SkScalar sy) { if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) && (sx != 0.0 || sy != 0.0)) { + checkForDeferredSave(); Push(0, 1, sx, sy); current_layer_->matrix.preConcat(SkMatrix::Skew(sx, sy)); } @@ -541,6 +556,7 @@ void DisplayListBuilder::transform2DAffine( SkScalarsAreFinite(mxt, myt) && !(mxx == 1 && mxy == 0 && mxt == 0 && myx == 0 && myy == 1 && myt == 0)) { + checkForDeferredSave(); Push(0, 1, mxx, mxy, mxt, myx, myy, myt); @@ -566,6 +582,7 @@ void DisplayListBuilder::transformFullPerspective( SkScalarsAreFinite(myx, myy) && SkScalarsAreFinite(myz, myt) && SkScalarsAreFinite(mzx, mzy) && SkScalarsAreFinite(mzz, mzt) && SkScalarsAreFinite(mwx, mwy) && SkScalarsAreFinite(mwz, mwt)) { + checkForDeferredSave(); Push(0, 1, mxx, mxy, mxz, mxt, myx, myy, myz, myt, @@ -579,6 +596,7 @@ void DisplayListBuilder::transformFullPerspective( } // clang-format on void DisplayListBuilder::transformReset() { + checkForDeferredSave(); Push(0, 0); current_layer_->matrix.setIdentity(); } @@ -600,6 +618,10 @@ void DisplayListBuilder::transform(const SkM44* m44) { void DisplayListBuilder::clipRect(const SkRect& rect, SkClipOp clip_op, bool is_aa) { + if (!rect.isFinite()) { + return; + } + checkForDeferredSave(); switch (clip_op) { case SkClipOp::kIntersect: Push(0, 1, rect, is_aa); @@ -616,6 +638,7 @@ void DisplayListBuilder::clipRRect(const SkRRect& rrect, if (rrect.isRect()) { clipRect(rrect.rect(), clip_op, is_aa); } else { + checkForDeferredSave(); switch (clip_op) { case SkClipOp::kIntersect: Push(0, 1, rrect, is_aa); @@ -647,6 +670,7 @@ void DisplayListBuilder::clipPath(const SkPath& path, return; } } + checkForDeferredSave(); switch (clip_op) { case SkClipOp::kIntersect: Push(0, 1, path, is_aa); diff --git a/display_list/display_list_builder.h b/display_list/display_list_builder.h index ce785c594b7ad..759b7280ed0f1 100644 --- a/display_list/display_list_builder.h +++ b/display_list/display_list_builder.h @@ -343,6 +343,8 @@ class DisplayListBuilder final : public virtual Dispatcher, sk_sp Build(); private: + void checkForDeferredSave(); + SkAutoTMalloc storage_; size_t used_ = 0; size_t allocated_ = 0; @@ -397,6 +399,8 @@ class DisplayListBuilder final : public virtual Dispatcher, // This offset is only valid if |has_layer| is true. size_t save_layer_offset; + bool has_deferred_save_op_ = false; + bool has_layer; bool cannot_inherit_opacity; bool has_compatible_op; diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index ea8dfc0cbee44..62155636c23de 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -3,14 +3,19 @@ // found in the LICENSE file. #include +#include +#include +#include #include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_blend_mode.h" #include "flutter/display_list/display_list_builder.h" #include "flutter/display_list/display_list_canvas_recorder.h" +#include "flutter/display_list/display_list_paint.h" #include "flutter/display_list/display_list_rtree.h" #include "flutter/display_list/display_list_test_utils.h" #include "flutter/display_list/display_list_utils.h" +#include "flutter/fml/logging.h" #include "flutter/fml/math.h" #include "flutter/testing/display_list_testing.h" #include "flutter/testing/testing.h" @@ -1644,6 +1649,550 @@ TEST(DisplayList, RTreeOfSaveLayerFilterScene) { test_rtree(rtree, {19, 19, 51, 51}, rects, {0, 1}); } +TEST(DisplayList, RemoveUnnecessarySaveRestorePairs) { + { + DisplayListBuilder builder; + builder.drawRect({10, 10, 20, 20}); + builder.save(); // This save op is unnecessary + builder.drawRect({50, 50, 60, 60}); + builder.restore(); + + DisplayListBuilder builder2; + builder2.drawRect({10, 10, 20, 20}); + builder2.drawRect({50, 50, 60, 60}); + ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), builder2.Build())); + } + + { + DisplayListBuilder builder; + builder.drawRect({10, 10, 20, 20}); + builder.save(); + builder.translate(1.0, 1.0); + { + builder.save(); // unnecessary + builder.drawRect({50, 50, 60, 60}); + builder.restore(); + } + + builder.restore(); + + DisplayListBuilder builder2; + builder2.drawRect({10, 10, 20, 20}); + builder2.save(); + builder2.translate(1.0, 1.0); + { builder2.drawRect({50, 50, 60, 60}); } + builder2.restore(); + ASSERT_TRUE(DisplayListsEQ_Verbose(builder.Build(), builder2.Build())); + } +} + +TEST(DisplayList, CollapseMultipleNestedSaveRestore) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.save(); + builder1.translate(10, 10); + builder1.scale(2, 2); + builder1.clipRect({10, 10, 20, 20}, SkClipOp::kIntersect, false); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.restore(); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.translate(10, 10); + builder2.scale(2, 2); + builder2.clipRect({10, 10, 20, 20}, SkClipOp::kIntersect, false); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, CollapseNestedSaveAndSaveLayerRestore) { + DisplayListBuilder builder1; + builder1.save(); + builder1.saveLayer(nullptr, false); + builder1.drawRect({0, 0, 100, 100}); + builder1.scale(2, 2); + builder1.restore(); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.saveLayer(nullptr, false); + builder2.drawRect({0, 0, 100, 100}); + builder2.scale(2, 2); + builder2.restore(); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, RemoveUnnecessarySaveRestorePairsInSetPaint) { + SkRect build_bounds = SkRect::MakeLTRB(-100, -100, 200, 200); + SkRect rect = SkRect::MakeLTRB(30, 30, 70, 70); + // clang-format off + const float alpha_matrix[] = { + 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, + }; + // clang-format on + DlMatrixColorFilter alpha_color_filter(alpha_matrix); + // Making sure hiding a problematic ColorFilter as an ImageFilter + // will generate the same behavior as setting it as a ColorFilter + + DlColorFilterImageFilter color_filter_image_filter(alpha_color_filter); + { + DisplayListBuilder builder(build_bounds); + builder.save(); + DlPaint paint; + paint.setImageFilter(&color_filter_image_filter); + builder.drawRect(rect, paint); + builder.restore(); + sk_sp display_list1 = builder.Build(); + + DisplayListBuilder builder2(build_bounds); + DlPaint paint2; + paint2.setImageFilter(&color_filter_image_filter); + builder2.drawRect(rect, paint2); + sk_sp display_list2 = builder2.Build(); + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); + } + + { + DisplayListBuilder builder(build_bounds); + builder.save(); + builder.saveLayer(&build_bounds, true); + DlPaint paint; + paint.setImageFilter(&color_filter_image_filter); + builder.drawRect(rect, paint); + builder.restore(); + builder.restore(); + sk_sp display_list1 = builder.Build(); + + DisplayListBuilder builder2(build_bounds); + builder2.saveLayer(&build_bounds, true); + DlPaint paint2; + paint2.setImageFilter(&color_filter_image_filter); + builder2.drawRect(rect, paint2); + builder2.restore(); + sk_sp display_list2 = builder2.Build(); + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); + } +} + +TEST(DisplayList, TransformTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.transform(SkM44::Translate(10, 100)); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.transform(SkM44::Translate(10, 100)); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.transform(SkM44::Translate(10, 100)); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + builder2.save(); + builder2.transform(SkM44::Translate(10, 100)); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, Transform2DTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.transform2DAffine(0, 1, 12, 1, 0, 33); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.transform2DAffine(0, 1, 12, 1, 0, 33); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, TransformPerspectiveTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.transformFullPerspective(0, 1, 0, 12, 1, 0, 0, 33, 3, 2, 5, 29, 0, 0, + 0, 12); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.transformFullPerspective(0, 1, 0, 12, 1, 0, 0, 33, 3, 2, 5, 29, 0, 0, + 0, 12); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, ResetTransformTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.transformReset(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.transformReset(); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, SkewTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.skew(10, 10); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.skew(10, 10); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, TranslateTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.translate(10, 10); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.translate(10, 10); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, ScaleTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.scale(0.5, 0.5); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.scale(0.5, 0.5); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, ClipRectTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.clipRect(SkRect::MakeLTRB(0, 0, 100, 100), SkClipOp::kIntersect, + true); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.transform(SkM44()); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.clipRect(SkRect::MakeLTRB(0, 0, 100, 100), SkClipOp::kIntersect, + true); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + builder2.transform(SkM44()); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, ClipRRectTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.clipRRect(kTestRRect, SkClipOp::kIntersect, true); + + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.transform(SkM44()); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.clipRRect(kTestRRect, SkClipOp::kIntersect, true); + + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + builder2.transform(SkM44()); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, ClipPathTriggersDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.clipPath(kTestPath1, SkClipOp::kIntersect, true); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.transform(SkM44()); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.clipPath(kTestPath1, SkClipOp::kIntersect, true); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + builder2.transform(SkM44()); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, NOPTranslateDoesNotTriggerDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.translate(0, 0); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.drawRect({0, 0, 100, 100}); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, NOPScaleDoesNotTriggerDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.scale(1.0, 1.0); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.drawRect({0, 0, 100, 100}); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, NOPRotationDoesNotTriggerDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.rotate(360); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.drawRect({0, 0, 100, 100}); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, NOPSkewDoesNotTriggerDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.skew(0, 0); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.drawRect({0, 0, 100, 100}); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, NOPTransformDoesNotTriggerDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.transform(SkM44()); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.transform(SkM44()); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.drawRect({0, 0, 100, 100}); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, NOPTransform2DDoesNotTriggerDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.transform2DAffine(1, 0, 0, 0, 1, 0); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.drawRect({0, 0, 100, 100}); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + +TEST(DisplayList, NOPTransformFullPerspectiveDoesNotTriggerDeferredSave) { + { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.transformFullPerspective(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 1); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.drawRect({0, 0, 100, 100}); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); + } + + { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.transformFullPerspective(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 1); + builder1.transformReset(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.save(); + builder2.transformReset(); + builder2.drawRect({0, 0, 100, 100}); + builder2.restore(); + builder2.drawRect({0, 0, 100, 100}); + + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); + } +} + +TEST(DisplayList, NOPClipDoesNotTriggerDeferredSave) { + DisplayListBuilder builder1; + builder1.save(); + builder1.save(); + builder1.clipRect(SkRect::MakeLTRB(0, SK_ScalarNaN, SK_ScalarNaN, 0), + SkClipOp::kIntersect, true); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + builder1.drawRect({0, 0, 100, 100}); + builder1.restore(); + auto display_list1 = builder1.Build(); + + DisplayListBuilder builder2; + builder2.drawRect({0, 0, 100, 100}); + builder2.drawRect({0, 0, 100, 100}); + auto display_list2 = builder2.Build(); + + ASSERT_TRUE(DisplayListsEQ_Verbose(display_list1, display_list2)); +} + TEST(DisplayList, RTreeOfClippedSaveLayerFilterScene) { DisplayListBuilder builder; // blur filter with sigma=1 expands by 30 on all sides From f94d613b38d0c3851dd2a4a57fa9e9fc0e96eeb0 Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Thu, 11 Aug 2022 18:14:17 +0800 Subject: [PATCH 256/558] [impeller] Add 'ColorSourceProc' for creating color source contents (#35299) --- impeller/aiks/aiks_unittests.cc | 75 +++++++++++++------ impeller/aiks/paint.cc | 6 +- impeller/aiks/paint.h | 3 +- .../display_list/display_list_dispatcher.cc | 58 ++++++++------ 4 files changed, 97 insertions(+), 45 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index d4fbf8c6361aa..5fc29d01bb740 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -214,13 +214,16 @@ TEST_P(AiksTest, CanRenderLinearGradient) { for (int i = 0; i < 4; i++) { canvas.Save(); canvas.Translate(offsets[i]); - auto contents = std::make_shared(); - contents->SetEndPoints({0, 0}, {100, 100}); - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - contents->SetColors(std::move(colors)); - contents->SetTileMode(tile_modes[i]); - paint.contents = contents; + Entity::TileMode tile_mode = tile_modes[i]; + paint.color_source = [tile_mode]() { + auto contents = std::make_shared(); + contents->SetEndPoints({0, 0}, {100, 100}); + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; + contents->SetColors(std::move(colors)); + contents->SetTileMode(tile_mode); + return contents; + }; canvas.DrawRect({0, 0, 200, 200}, paint); canvas.Restore(); } @@ -238,13 +241,16 @@ TEST_P(AiksTest, CanRenderRadialGradient) { for (int i = 0; i < 4; i++) { canvas.Save(); canvas.Translate(offsets[i]); - auto contents = std::make_shared(); - contents->SetCenterAndRadius({50, 50}, 50); - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - contents->SetColors(std::move(colors)); - contents->SetTileMode(tile_modes[i]); - paint.contents = contents; + Entity::TileMode tile_mode = tile_modes[i]; + paint.color_source = [tile_mode]() { + auto contents = std::make_shared(); + contents->SetCenterAndRadius({50, 50}, 50); + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; + contents->SetColors(std::move(colors)); + contents->SetTileMode(tile_mode); + return contents; + }; canvas.DrawRect({0, 0, 200, 200}, paint); canvas.Restore(); } @@ -263,13 +269,16 @@ TEST_P(AiksTest, CanRenderSweepGradient) { for (int i = 0; i < 4; i++) { canvas.Save(); canvas.Translate(offsets[i]); - auto contents = std::make_shared(); - contents->SetCenterAndAngles({50, 50}, Degrees(45), Degrees(135)); - std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, - Color{0.1294, 0.5882, 0.9529, 1.0}}; - contents->SetColors(std::move(colors)); - contents->SetTileMode(tile_modes[i]); - paint.contents = contents; + Entity::TileMode tile_mode = tile_modes[i]; + paint.color_source = [tile_mode]() { + auto contents = std::make_shared(); + contents->SetCenterAndAngles({50, 50}, Degrees(45), Degrees(135)); + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; + contents->SetColors(std::move(colors)); + contents->SetTileMode(tile_mode); + return contents; + }; canvas.DrawRect({0, 0, 200, 200}, paint); canvas.Restore(); } @@ -277,6 +286,30 @@ TEST_P(AiksTest, CanRenderSweepGradient) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, CanRenderDifferentShapesWithSameColorSource) { + Canvas canvas; + Paint paint; + paint.color_source = []() { + auto contents = std::make_shared(); + contents->SetEndPoints({0, 0}, {100, 100}); + std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, + Color{0.1294, 0.5882, 0.9529, 1.0}}; + contents->SetColors(std::move(colors)); + contents->SetTileMode(Entity::TileMode::kRepeat); + return contents; + }; + canvas.Save(); + canvas.Translate({100, 100, 0}); + canvas.DrawRect({0, 0, 200, 200}, paint); + canvas.Restore(); + + canvas.Save(); + canvas.Translate({100, 400, 0}); + canvas.DrawCircle({100, 100}, 100, paint); + canvas.Restore(); + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + TEST_P(AiksTest, BlendModeShouldCoverWholeScreen) { Canvas canvas; Paint paint; diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 2d49996f3c485..0a6704de9147f 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -10,7 +10,9 @@ namespace impeller { std::shared_ptr Paint::CreateContentsForEntity(Path path, bool cover) const { - if (contents) { + if (color_source.has_value()) { + auto& source = color_source.value(); + auto contents = source(); contents->SetPath(std::move(path)); return contents; } @@ -41,7 +43,7 @@ std::shared_ptr Paint::CreateContentsForEntity(Path path, std::shared_ptr Paint::WithFilters( std::shared_ptr input, std::optional is_solid_color) const { - bool is_solid_color_val = is_solid_color.value_or(!contents); + bool is_solid_color_val = is_solid_color.value_or(!color_source); if (mask_blur_descriptor.has_value()) { input = mask_blur_descriptor->CreateMaskBlur(FilterInput::Make(input), diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index 8a70d3428ed15..b150c868e3b7e 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -25,6 +25,7 @@ struct Paint { using MaskFilterProc = std::function(FilterInput::Ref, bool is_solid_color)>; + using ColorSourceProc = std::function()>; enum class Style { kFill, @@ -40,7 +41,7 @@ struct Paint { }; Color color = Color::Black(); - std::shared_ptr contents; + std::optional color_source; Scalar stroke_width = 0.0; SolidStrokeContents::Cap stroke_cap = SolidStrokeContents::Cap::kButt; diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 5525e23de08d7..e8dd2f38fc0ba 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -239,14 +239,14 @@ static std::vector ToRSXForms(const SkRSXform xform[], int count) { void DisplayListDispatcher::setColorSource( const flutter::DlColorSource* source) { if (!source) { - paint_.contents = nullptr; + paint_.color_source = std::nullopt; return; } switch (source->type()) { case flutter::DlColorSourceType::kColor: { const flutter::DlColorColorSource* color = source->asColor(); - paint_.contents = nullptr; + paint_.color_source = std::nullopt; setColor(color->color()); FML_DCHECK(color); return; @@ -255,49 +255,65 @@ void DisplayListDispatcher::setColorSource( const flutter::DlLinearGradientColorSource* linear = source->asLinearGradient(); FML_DCHECK(linear); - auto contents = std::make_shared(); - contents->SetEndPoints(ToPoint(linear->start_point()), - ToPoint(linear->end_point())); + auto start_point = ToPoint(linear->start_point()); + auto end_point = ToPoint(linear->end_point()); std::vector colors; for (auto i = 0; i < linear->stop_count(); i++) { colors.emplace_back(ToColor(linear->colors()[i])); } - contents->SetColors(std::move(colors)); - contents->SetTileMode(ToTileMode(linear->tile_mode())); - paint_.contents = std::move(contents); + auto tile_mode = ToTileMode(linear->tile_mode()); + paint_.color_source = [start_point, end_point, colors = std::move(colors), + tile_mode]() { + auto contents = std::make_shared(); + contents->SetEndPoints(start_point, end_point); + contents->SetColors(std::move(colors)); + contents->SetTileMode(tile_mode); + return contents; + }; return; } case flutter::DlColorSourceType::kRadialGradient: { const flutter::DlRadialGradientColorSource* radialGradient = source->asRadialGradient(); FML_DCHECK(radialGradient); - auto contents = std::make_shared(); - contents->SetCenterAndRadius(ToPoint(radialGradient->center()), - radialGradient->radius()); + auto center = ToPoint(radialGradient->center()); + auto radius = radialGradient->radius(); std::vector colors; for (auto i = 0; i < radialGradient->stop_count(); i++) { colors.emplace_back(ToColor(radialGradient->colors()[i])); } - contents->SetColors(std::move(colors)); - contents->SetTileMode(ToTileMode(radialGradient->tile_mode())); - paint_.contents = std::move(contents); + auto tile_mode = ToTileMode(radialGradient->tile_mode()); + paint_.color_source = [center, radius, colors = std::move(colors), + tile_mode]() { + auto contents = std::make_shared(); + contents->SetCenterAndRadius(center, radius), + contents->SetColors(std::move(colors)); + contents->SetTileMode(tile_mode); + return contents; + }; return; } case flutter::DlColorSourceType::kSweepGradient: { const flutter::DlSweepGradientColorSource* sweepGradient = source->asSweepGradient(); FML_DCHECK(sweepGradient); - auto contents = std::make_shared(); - contents->SetCenterAndAngles(ToPoint(sweepGradient->center()), - Degrees(sweepGradient->start()), - Degrees(sweepGradient->end())); + + auto center = ToPoint(sweepGradient->center()); + auto start_angle = Degrees(sweepGradient->start()); + auto end_angle = Degrees(sweepGradient->end()); std::vector colors; for (auto i = 0; i < sweepGradient->stop_count(); i++) { colors.emplace_back(ToColor(sweepGradient->colors()[i])); } - contents->SetColors(std::move(colors)); - contents->SetTileMode(ToTileMode(sweepGradient->tile_mode())); - paint_.contents = std::move(contents); + auto tile_mode = ToTileMode(sweepGradient->tile_mode()); + paint_.color_source = [center, start_angle, end_angle, + colors = std::move(colors), tile_mode]() { + auto contents = std::make_shared(); + contents->SetCenterAndAngles(center, start_angle, end_angle); + contents->SetColors(std::move(colors)); + contents->SetTileMode(tile_mode); + return contents; + }; return; } case flutter::DlColorSourceType::kImage: From 5b1cb0cfc83cfeca5294358ae9bebf7ffff418c2 Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Thu, 11 Aug 2022 21:18:16 +0800 Subject: [PATCH 257/558] [Impeller] Implement tiled texture contents for image color source (#35264) --- ci/licenses_golden/licenses_flutter | 4 + impeller/aiks/aiks_unittests.cc | 78 ++++++++++++ .../compiler/shader_lib/impeller/texture.glsl | 26 ++-- .../display_list/display_list_dispatcher.cc | 102 ++++++++------- impeller/entity/BUILD.gn | 4 + impeller/entity/contents/content_context.cc | 2 + impeller/entity/contents/content_context.h | 10 ++ .../entity/contents/tiled_texture_contents.cc | 118 ++++++++++++++++++ .../entity/contents/tiled_texture_contents.h | 51 ++++++++ .../entity/shaders/tiled_texture_fill.frag | 29 +++++ .../entity/shaders/tiled_texture_fill.vert | 18 +++ 11 files changed, 393 insertions(+), 49 deletions(-) create mode 100644 impeller/entity/contents/tiled_texture_contents.cc create mode 100644 impeller/entity/contents/tiled_texture_contents.h create mode 100644 impeller/entity/shaders/tiled_texture_fill.frag create mode 100644 impeller/entity/shaders/tiled_texture_fill.vert diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 16eb68bdb0a72..450968be91055 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -589,6 +589,8 @@ FILE: ../../../flutter/impeller/entity/contents/text_contents.cc FILE: ../../../flutter/impeller/entity/contents/text_contents.h FILE: ../../../flutter/impeller/entity/contents/texture_contents.cc FILE: ../../../flutter/impeller/entity/contents/texture_contents.h +FILE: ../../../flutter/impeller/entity/contents/tiled_texture_contents.cc +FILE: ../../../flutter/impeller/entity/contents/tiled_texture_contents.h FILE: ../../../flutter/impeller/entity/contents/vertices_contents.cc FILE: ../../../flutter/impeller/entity/contents/vertices_contents.h FILE: ../../../flutter/impeller/entity/entity.cc @@ -645,6 +647,8 @@ FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.vert 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 +FILE: ../../../flutter/impeller/entity/shaders/tiled_texture_fill.vert FILE: ../../../flutter/impeller/entity/shaders/vertices.frag FILE: ../../../flutter/impeller/entity/shaders/vertices.vert FILE: ../../../flutter/impeller/geometry/color.cc diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 5fc29d01bb740..55a8c32993fd7 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -10,10 +10,12 @@ #include "impeller/aiks/aiks_playground.h" #include "impeller/aiks/canvas.h" #include "impeller/aiks/image.h" +#include "impeller/entity/contents/tiled_texture_contents.h" #include "impeller/geometry/color.h" #include "impeller/geometry/geometry_unittests.h" #include "impeller/geometry/path_builder.h" #include "impeller/playground/widgets.h" +#include "impeller/renderer/command_buffer.h" #include "impeller/renderer/snapshot.h" #include "impeller/typographer/backends/skia/text_frame_skia.h" #include "impeller/typographer/backends/skia/text_render_context_skia.h" @@ -70,6 +72,82 @@ TEST_P(AiksTest, CanRenderImage) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +bool GenerateMipmap(std::shared_ptr context, + std::shared_ptr texture, + std::string label) { + auto buffer = context->CreateCommandBuffer(); + if (!buffer) { + return false; + } + auto pass = buffer->CreateBlitPass(); + if (!pass) { + return false; + } + pass->GenerateMipmap(texture, label); + pass->EncodeCommands(context->GetResourceAllocator()); + return true; +} + +TEST_P(AiksTest, CanRenderTiledTexture) { + auto context = GetContext(); + ASSERT_TRUE(context); + bool first_frame = true; + auto texture = CreateTextureForFixture("table_mountain_nx.png"); + auto callback = [&](AiksContext& renderer, RenderTarget& render_target) { + if (first_frame) { + first_frame = false; + GenerateMipmap(context, texture, "table_mountain_nx"); + ImGui::SetNextWindowSize({480, 100}); + ImGui::SetNextWindowPos({100, 550}); + } + + const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; + const Entity::TileMode tile_modes[] = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + const char* mip_filter_names[] = {"None", "Nearest", "Linear"}; + const MipFilter mip_filters[] = {MipFilter::kNone, MipFilter::kNearest, + MipFilter::kLinear}; + const char* min_mag_filter_names[] = {"Nearest", "Linear"}; + const MinMagFilter min_mag_filters[] = {MinMagFilter::kNearest, + MinMagFilter::kLinear}; + static int selected_x_tile_mode = 0; + static int selected_y_tile_mode = 0; + static int selected_mip_filter = 0; + static int selected_min_mag_filter = 0; + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::Combo("X tile mode", &selected_x_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); + ImGui::Combo("Y tile mode", &selected_y_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); + ImGui::Combo("Mip filter", &selected_mip_filter, mip_filter_names, + sizeof(mip_filter_names) / sizeof(char*)); + ImGui::Combo("Min Mag filter", &selected_min_mag_filter, + min_mag_filter_names, + sizeof(min_mag_filter_names) / sizeof(char*)); + ImGui::End(); + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + auto x_tile_mode = tile_modes[selected_x_tile_mode]; + auto y_tile_mode = tile_modes[selected_y_tile_mode]; + SamplerDescriptor descriptor; + descriptor.mip_filter = mip_filters[selected_mip_filter]; + descriptor.min_filter = min_mag_filters[selected_min_mag_filter]; + descriptor.mag_filter = min_mag_filters[selected_min_mag_filter]; + paint.color_source = [texture, x_tile_mode, y_tile_mode, descriptor]() { + auto contents = std::make_shared(); + contents->SetTexture(texture); + contents->SetTileModes(x_tile_mode, y_tile_mode); + contents->SetSamplerDescriptor(descriptor); + return contents; + }; + canvas.DrawRect({0, 0, 600, 600}, paint); + return renderer.Render(canvas.EndRecordingAsPicture(), render_target); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + TEST_P(AiksTest, CanRenderImageRect) { Canvas canvas; Paint paint; diff --git a/impeller/compiler/shader_lib/impeller/texture.glsl b/impeller/compiler/shader_lib/impeller/texture.glsl index 714e92ca81445..633af1cd2819a 100644 --- a/impeller/compiler/shader_lib/impeller/texture.glsl +++ b/impeller/compiler/shader_lib/impeller/texture.glsl @@ -48,9 +48,9 @@ float IPFloatTile(float t, float tile_mode) { /// Remap a vec2 using a tiling mode. /// /// Runs each component of the vec2 through `IPFloatTile`. -vec2 IPVec2Tile(vec2 coords, float tile_mode) { - return vec2(IPFloatTile(coords.x, tile_mode), - IPFloatTile(coords.y, tile_mode)); +vec2 IPVec2Tile(vec2 coords, float x_tile_mode, float y_tile_mode) { + return vec2(IPFloatTile(coords.x, x_tile_mode), + IPFloatTile(coords.y, y_tile_mode)); } /// Sample a texture, emulating a specific tile mode. @@ -60,13 +60,25 @@ vec2 IPVec2Tile(vec2 coords, float tile_mode) { vec4 IPSampleWithTileMode(sampler2D tex, vec2 coords, float y_coord_scale, - float tile_mode) { - if (tile_mode == kTileModeDecal && - (coords.x < 0 || coords.y < 0 || coords.x >= 1 || coords.y >= 1)) { + float x_tile_mode, + float y_tile_mode) { + if (x_tile_mode == kTileModeDecal && (coords.x < 0 || coords.x >= 1) || + y_tile_mode == kTileModeDecal && (coords.y < 0 || coords.y >= 1)) { return vec4(0); } - return IPSample(tex, IPVec2Tile(coords, 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. +/// +/// This is useful for Impeller graphics backend that don't have native support +/// for Decal. +vec4 IPSampleWithTileMode(sampler2D tex, + vec2 coords, + float y_coord_scale, + float tile_mode) { + return IPSampleWithTileMode(tex, coords, y_coord_scale, tile_mode, tile_mode); } #endif diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index e8dd2f38fc0ba..4ec8572f770b4 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -21,6 +21,7 @@ #include "impeller/entity/contents/radial_gradient_contents.h" #include "impeller/entity/contents/solid_stroke_contents.h" #include "impeller/entity/contents/sweep_gradient_contents.h" +#include "impeller/entity/contents/tiled_texture_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/path.h" #include "impeller/geometry/path_builder.h" @@ -118,6 +119,47 @@ static Entity::TileMode ToTileMode(flutter::DlTileMode tile_mode) { } } +static impeller::SamplerDescriptor ToSamplerDescriptor( + const flutter::DlImageSampling options) { + impeller::SamplerDescriptor desc; + switch (options) { + case flutter::DlImageSampling::kNearestNeighbor: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kNearest; + desc.label = "Nearest Sampler"; + break; + case flutter::DlImageSampling::kLinear: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; + desc.label = "Linear Sampler"; + break; + case flutter::DlImageSampling::kMipmapLinear: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; + desc.mip_filter = impeller::MipFilter::kLinear; + desc.label = "Mipmap Linear Sampler"; + break; + default: + break; + } + return desc; +} + +static impeller::SamplerDescriptor ToSamplerDescriptor( + const flutter::DlFilterMode options) { + impeller::SamplerDescriptor desc; + switch (options) { + case flutter::DlFilterMode::kNearest: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kNearest; + desc.label = "Nearest Sampler"; + break; + case flutter::DlFilterMode::kLinear: + desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; + desc.label = "Linear Sampler"; + break; + default: + break; + } + return desc; +} + // |flutter::Dispatcher| void DisplayListDispatcher::setAntiAlias(bool aa) { // Nothing to do because AA is implicit. @@ -316,7 +358,24 @@ void DisplayListDispatcher::setColorSource( }; return; } - case flutter::DlColorSourceType::kImage: + case flutter::DlColorSourceType::kImage: { + const flutter::DlImageColorSource* image_color_source = source->asImage(); + FML_DCHECK(image_color_source && + image_color_source->image()->impeller_texture()); + auto texture = image_color_source->image()->impeller_texture(); + auto x_tile_mode = ToTileMode(image_color_source->horizontal_tile_mode()); + auto y_tile_mode = ToTileMode(image_color_source->vertical_tile_mode()); + auto desc = ToSamplerDescriptor(image_color_source->sampling()); + paint_.color_source = [texture, x_tile_mode, y_tile_mode, desc]() { + auto contents = std::make_shared(); + contents->SetTexture(texture); + contents->SetTileModes(x_tile_mode, y_tile_mode); + contents->SetSamplerDescriptor(desc); + // TODO(109384) Support 'matrix' parameter for all color sources. + return contents; + }; + return; + } case flutter::DlColorSourceType::kConicalGradient: case flutter::DlColorSourceType::kUnknown: UNIMPLEMENTED; @@ -908,47 +967,6 @@ void DisplayListDispatcher::drawImage(const sk_sp image, ); } -static impeller::SamplerDescriptor ToSamplerDescriptor( - const flutter::DlImageSampling options) { - impeller::SamplerDescriptor desc; - switch (options) { - case flutter::DlImageSampling::kNearestNeighbor: - desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kNearest; - desc.label = "Nearest Sampler"; - break; - case flutter::DlImageSampling::kLinear: - desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; - desc.label = "Linear Sampler"; - break; - case flutter::DlImageSampling::kMipmapLinear: - desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; - desc.mip_filter = impeller::MipFilter::kLinear; - desc.label = "Mipmap Linear Sampler"; - break; - default: - break; - } - return desc; -} - -static impeller::SamplerDescriptor ToSamplerDescriptor( - const flutter::DlFilterMode options) { - impeller::SamplerDescriptor desc; - switch (options) { - case flutter::DlFilterMode::kNearest: - desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kNearest; - desc.label = "Nearest Sampler"; - break; - case flutter::DlFilterMode::kLinear: - desc.min_filter = desc.mag_filter = impeller::MinMagFilter::kLinear; - desc.label = "Linear Sampler"; - break; - default: - break; - } - return desc; -} - // |flutter::Dispatcher| void DisplayListDispatcher::drawImageRect( const sk_sp image, diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index aa1adbe76730b..cce9b2e138370 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -50,6 +50,8 @@ impeller_shaders("entity_shaders") { "shaders/sweep_gradient_fill.vert", "shaders/texture_fill.frag", "shaders/texture_fill.vert", + "shaders/tiled_texture_fill.frag", + "shaders/tiled_texture_fill.vert", "shaders/vertices.frag", "shaders/vertices.vert", ] @@ -101,6 +103,8 @@ impeller_component("entity") { "contents/text_contents.h", "contents/texture_contents.cc", "contents/texture_contents.h", + "contents/tiled_texture_contents.cc", + "contents/tiled_texture_contents.h", "contents/vertices_contents.cc", "contents/vertices_contents.h", "entity.cc", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index f63342cc6aee4..f0aacb04c32c8 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -191,6 +191,8 @@ ContentContext::ContentContext(std::shared_ptr context) blend_softlight_pipelines_[{}] = CreateDefaultPipeline(*context_); texture_pipelines_[{}] = CreateDefaultPipeline(*context_); + tiled_texture_pipelines_[{}] = + CreateDefaultPipeline(*context_); gaussian_blur_pipelines_[{}] = CreateDefaultPipeline(*context_); border_mask_blur_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 6ab014470ae83..98b50420c9d71 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -54,6 +54,8 @@ #include "impeller/entity/sweep_gradient_fill.vert.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" +#include "impeller/entity/tiled_texture_fill.frag.h" +#include "impeller/entity/tiled_texture_fill.vert.h" #include "impeller/entity/vertices.frag.h" #include "impeller/entity/vertices.vert.h" #include "impeller/renderer/formats.h" @@ -104,6 +106,8 @@ using BlendSoftLightPipeline = PipelineT; using TexturePipeline = PipelineT; +using TiledTexturePipeline = + PipelineT; using GaussianBlurPipeline = PipelineT; using BorderMaskBlurPipeline = @@ -189,6 +193,11 @@ class ContentContext { return GetPipeline(texture_pipelines_, opts); } + std::shared_ptr GetTiledTexturePipeline( + ContentContextOptions opts) const { + return GetPipeline(tiled_texture_pipelines_, opts); + } + std::shared_ptr GetGaussianBlurPipeline( ContentContextOptions opts) const { return GetPipeline(gaussian_blur_pipelines_, opts); @@ -333,6 +342,7 @@ class ContentContext { mutable Variants rrect_blur_pipelines_; mutable Variants texture_blend_pipelines_; mutable Variants texture_pipelines_; + mutable Variants tiled_texture_pipelines_; mutable Variants gaussian_blur_pipelines_; mutable Variants border_mask_blur_pipelines_; mutable Variants diff --git a/impeller/entity/contents/tiled_texture_contents.cc b/impeller/entity/contents/tiled_texture_contents.cc new file mode 100644 index 0000000000000..c3b6521ca97fe --- /dev/null +++ b/impeller/entity/contents/tiled_texture_contents.cc @@ -0,0 +1,118 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/entity/contents/tiled_texture_contents.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/tiled_texture_fill.frag.h" +#include "impeller/entity/tiled_texture_fill.vert.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/sampler_library.h" +#include "impeller/tessellator/tessellator.h" + +namespace impeller { + +TiledTextureContents::TiledTextureContents() = default; + +TiledTextureContents::~TiledTextureContents() = default; + +void TiledTextureContents::SetPath(Path path) { + path_ = std::move(path); +} + +void TiledTextureContents::SetTexture(std::shared_ptr texture) { + texture_ = std::move(texture); +} + +void TiledTextureContents::SetTileModes(Entity::TileMode x_tile_mode, + Entity::TileMode y_tile_mode) { + x_tile_mode_ = x_tile_mode; + y_tile_mode_ = y_tile_mode; +} + +void TiledTextureContents::SetSamplerDescriptor(SamplerDescriptor desc) { + sampler_descriptor_ = std::move(desc); +} + +std::optional TiledTextureContents::GetCoverage( + const Entity& entity) const { + return path_.GetTransformedBoundingBox(entity.GetTransformation()); +}; + +bool TiledTextureContents::Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const { + if (texture_ == nullptr) { + return true; + } + + using VS = TiledTextureFillVertexShader; + using FS = TiledTextureFillFragmentShader; + + const auto coverage_rect = path_.GetBoundingBox(); + + if (!coverage_rect.has_value()) { + return true; + } + + if (coverage_rect->size.IsEmpty()) { + return true; + } + + const auto texture_size = texture_->GetSize(); + if (texture_size.IsEmpty()) { + return true; + } + + VertexBufferBuilder vertex_builder; + { + const auto tess_result = + Tessellator{}.Tessellate(path_.GetFillType(), path_.CreatePolyline(), + [&vertex_builder, &texture_size](Point vtx) { + VS::PerVertexData data; + data.position = vtx; + data.texture_coords = vtx / texture_size; + vertex_builder.AppendVertex(data); + }); + + if (tess_result == Tessellator::Result::kInputError) { + return true; + } + if (tess_result == Tessellator::Result::kTessellationError) { + return false; + } + } + + if (!vertex_builder.HasVertices()) { + return true; + } + + auto& host_buffer = pass.GetTransientsBuffer(); + + VS::VertInfo vert_info; + vert_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + entity.GetTransformation(); + + FS::FragInfo frag_info; + frag_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); + frag_info.x_tile_mode = static_cast(x_tile_mode_); + frag_info.y_tile_mode = static_cast(y_tile_mode_); + + Command cmd; + cmd.label = "TiledTextureFill"; + cmd.pipeline = + renderer.GetTiledTexturePipeline(OptionsFromPassAndEntity(pass, entity)); + cmd.stencil_reference = entity.GetStencilDepth(); + cmd.BindVertices(vertex_builder.CreateVertexBuffer(host_buffer)); + VS::BindVertInfo(cmd, host_buffer.EmplaceUniform(vert_info)); + FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + FS::BindTextureSampler(cmd, texture_, + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + sampler_descriptor_)); + pass.AddCommand(std::move(cmd)); + + return true; +} + +} // namespace impeller diff --git a/impeller/entity/contents/tiled_texture_contents.h b/impeller/entity/contents/tiled_texture_contents.h new file mode 100644 index 0000000000000..378ff9051eb34 --- /dev/null +++ b/impeller/entity/contents/tiled_texture_contents.h @@ -0,0 +1,51 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#pragma once + +#include +#include +#include + +#include "flutter/fml/macros.h" +#include "impeller/entity/contents/path_contents.h" +#include "impeller/entity/entity.h" +#include "impeller/geometry/path.h" +#include "impeller/renderer/sampler_descriptor.h" + +namespace impeller { + +class TiledTextureContents final : public PathContents { + public: + TiledTextureContents(); + + ~TiledTextureContents() override; + + void SetPath(Path path) override; + + // |Contents| + std::optional GetCoverage(const Entity& entity) const override; + + // |Contents| + bool Render(const ContentContext& renderer, + const Entity& entity, + RenderPass& pass) const override; + + void SetTexture(std::shared_ptr texture); + + void SetTileModes(Entity::TileMode x_tile_mode, Entity::TileMode y_tile_mode); + + void SetSamplerDescriptor(SamplerDescriptor desc); + + private: + Path path_; + std::shared_ptr texture_; + SamplerDescriptor sampler_descriptor_ = {}; + Entity::TileMode x_tile_mode_; + Entity::TileMode y_tile_mode_; + + FML_DISALLOW_COPY_AND_ASSIGN(TiledTextureContents); +}; + +} // namespace impeller diff --git a/impeller/entity/shaders/tiled_texture_fill.frag b/impeller/entity/shaders/tiled_texture_fill.frag new file mode 100644 index 0000000000000..1c0c0411414b0 --- /dev/null +++ b/impeller/entity/shaders/tiled_texture_fill.frag @@ -0,0 +1,29 @@ +// 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 + +uniform sampler2D texture_sampler; + +uniform FragInfo { + float texture_sampler_y_coord_scale; + float x_tile_mode; + float y_tile_mode; +} +frag_info; + +in vec2 v_texture_coords; + +out vec4 frag_color; + +void main() { + frag_color = + IPSampleWithTileMode( + texture_sampler, // sampler + v_texture_coords, // texture coordinates + 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 + ); +} diff --git a/impeller/entity/shaders/tiled_texture_fill.vert b/impeller/entity/shaders/tiled_texture_fill.vert new file mode 100644 index 0000000000000..c8abc9aaabbce --- /dev/null +++ b/impeller/entity/shaders/tiled_texture_fill.vert @@ -0,0 +1,18 @@ +// 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. + +uniform VertInfo { + mat4 mvp; +} +vert_info; + +in vec2 position; +in vec2 texture_coords; + +out vec2 v_texture_coords; + +void main() { + gl_Position = vert_info.mvp * vec4(position, 0.0, 1.0); + v_texture_coords = texture_coords; +} From 12df8b7075fc25928c40904e7f753fae3f76bfa9 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 09:41:43 -0400 Subject: [PATCH 258/558] Roll Skia from 41cb8f2f9d12 to 85412c2ca484 (1 revision) (#35339) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index bafa57c817200..9b42632190dce 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': '41cb8f2f9d128a67e2782dfb89732477a223cff9', + 'skia_revision': '85412c2ca48464637972c8d0a0886cc9d90391bd', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 630568f0d86fe..4279fb3c3ee0b 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: f364b1245968c49ae838fc2876eedd02 +Signature: c82dad930a30e40d0453dc6cba5ae803 UNUSED LICENSES: From cf8d7c01d66d77b88c02f9c6786ccb0e58ba0592 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 10:51:49 -0400 Subject: [PATCH 259/558] Roll Skia from 85412c2ca484 to 431cf68b785c (2 revisions) (#35340) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 9b42632190dce..e69383cac9c32 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': '85412c2ca48464637972c8d0a0886cc9d90391bd', + 'skia_revision': '431cf68b785cf529bd106844970b3f5023098c88', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 4279fb3c3ee0b..2aa93c86bd6b3 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: c82dad930a30e40d0453dc6cba5ae803 +Signature: d828f8212753d4439e4c38dc1084c40a UNUSED LICENSES: From 492cf91f28541be014be308c1e385d5da3cb9f30 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 11:59:46 -0400 Subject: [PATCH 260/558] Roll Skia from 431cf68b785c to 7acdbfc5ae97 (2 revisions) (#35341) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e69383cac9c32..97b90b627566c 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': '431cf68b785cf529bd106844970b3f5023098c88', + 'skia_revision': '7acdbfc5ae97776c6f2502cfd4949bef67feae42', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 2aa93c86bd6b3..8ecc90fef40d4 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d828f8212753d4439e4c38dc1084c40a +Signature: 7ba3b625555454cc5bcc6e22c0324174 UNUSED LICENSES: From 7261384fc04e352570e4619426195de6d025a54f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 13:17:21 -0400 Subject: [PATCH 261/558] Roll Skia from 7acdbfc5ae97 to ebdd78b09827 (5 revisions) (#35342) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 26 +------------------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/DEPS b/DEPS index 97b90b627566c..5eafe6dca6ad5 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': '7acdbfc5ae97776c6f2502cfd4949bef67feae42', + 'skia_revision': 'ebdd78b098271de2462ef0a2c24a7b8eacc2d349', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 8ecc90fef40d4..f5533e38d6c7c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 7ba3b625555454cc5bcc6e22c0324174 +Signature: 0437b7e931559ee10817f7b792fd9c98 UNUSED LICENSES: @@ -802,7 +802,6 @@ FILE: ../../../third_party/skia/go.sum FILE: ../../../third_party/skia/go_repositories.bzl FILE: ../../../third_party/skia/include/BUILD.bazel FILE: ../../../third_party/skia/include/android/BUILD.bazel -FILE: ../../../third_party/skia/include/c/BUILD.bazel FILE: ../../../third_party/skia/include/codec/BUILD.bazel FILE: ../../../third_party/skia/include/config/BUILD.bazel FILE: ../../../third_party/skia/include/core/BUILD.bazel @@ -1281,7 +1280,6 @@ FILE: ../../../third_party/skia/specs/web-img-decode/proposed/impl/impl.js FILE: ../../../third_party/skia/specs/web-img-decode/proposed/index.html FILE: ../../../third_party/skia/src/BUILD.bazel FILE: ../../../third_party/skia/src/android/BUILD.bazel -FILE: ../../../third_party/skia/src/c/BUILD.bazel FILE: ../../../third_party/skia/src/codec/BUILD.bazel FILE: ../../../third_party/skia/src/core/BUILD.bazel FILE: ../../../third_party/skia/src/core/SkOrderedReadBuffer.h @@ -1692,8 +1690,6 @@ FILE: ../../../third_party/skia/dm/DMJsonWriter.h FILE: ../../../third_party/skia/gm/aaa.cpp FILE: ../../../third_party/skia/gm/beziers.cpp FILE: ../../../third_party/skia/gm/blurcircles.cpp -FILE: ../../../third_party/skia/gm/cgm.c -FILE: ../../../third_party/skia/gm/cgms.cpp FILE: ../../../third_party/skia/gm/clipdrawdraw.cpp FILE: ../../../third_party/skia/gm/coloremoji_blendmodes.cpp FILE: ../../../third_party/skia/gm/colorfilters.cpp @@ -1729,17 +1725,6 @@ FILE: ../../../third_party/skia/gm/textblobshader.cpp FILE: ../../../third_party/skia/gm/tiledscaledbitmap.cpp FILE: ../../../third_party/skia/gm/variedtext.cpp FILE: ../../../third_party/skia/gm/yuvtorgbsubset.cpp -FILE: ../../../third_party/skia/include/c/sk_canvas.h -FILE: ../../../third_party/skia/include/c/sk_data.h -FILE: ../../../third_party/skia/include/c/sk_image.h -FILE: ../../../third_party/skia/include/c/sk_maskfilter.h -FILE: ../../../third_party/skia/include/c/sk_matrix.h -FILE: ../../../third_party/skia/include/c/sk_paint.h -FILE: ../../../third_party/skia/include/c/sk_path.h -FILE: ../../../third_party/skia/include/c/sk_picture.h -FILE: ../../../third_party/skia/include/c/sk_shader.h -FILE: ../../../third_party/skia/include/c/sk_surface.h -FILE: ../../../third_party/skia/include/c/sk_types.h FILE: ../../../third_party/skia/include/core/SkBBHFactory.h FILE: ../../../third_party/skia/include/core/SkBlurTypes.h FILE: ../../../third_party/skia/include/core/SkDrawable.h @@ -1752,7 +1737,6 @@ FILE: ../../../third_party/skia/include/ports/SkFontMgr_indirect.h FILE: ../../../third_party/skia/include/ports/SkRemotableFontMgr.h FILE: ../../../third_party/skia/include/private/SkHalf.h FILE: ../../../third_party/skia/samplecode/SampleRectanizer.cpp -FILE: ../../../third_party/skia/src/c/sk_surface.cpp FILE: ../../../third_party/skia/src/core/SkBBHFactory.cpp FILE: ../../../third_party/skia/src/core/SkBitmapCache.cpp FILE: ../../../third_party/skia/src/core/SkBitmapCache.h @@ -2798,7 +2782,6 @@ FILE: ../../../third_party/skia/client_utils/android/BitmapRegionDecoder.h FILE: ../../../third_party/skia/client_utils/android/BitmapRegionDecoderPriv.h FILE: ../../../third_party/skia/dm/DMSrcSink.cpp FILE: ../../../third_party/skia/dm/DMSrcSink.h -FILE: ../../../third_party/skia/experimental/c-api-example/skia-c-example.c FILE: ../../../third_party/skia/experimental/tools/coreGraphicsPdf2png.cpp FILE: ../../../third_party/skia/gm/aaxfermodes.cpp FILE: ../../../third_party/skia/gm/addarc.cpp @@ -2881,9 +2864,6 @@ FILE: ../../../third_party/skia/samplecode/SampleAnimatedText.cpp FILE: ../../../third_party/skia/samplecode/SampleAtlas.cpp FILE: ../../../third_party/skia/samplecode/SampleShip.cpp FILE: ../../../third_party/skia/samplecode/SampleXfer.cpp -FILE: ../../../third_party/skia/src/c/sk_c_from_to.h -FILE: ../../../third_party/skia/src/c/sk_paint.cpp -FILE: ../../../third_party/skia/src/c/sk_types_priv.h FILE: ../../../third_party/skia/src/codec/SkAndroidCodec.cpp FILE: ../../../third_party/skia/src/codec/SkAndroidCodecAdapter.cpp FILE: ../../../third_party/skia/src/codec/SkAndroidCodecAdapter.h @@ -3495,8 +3475,6 @@ FILE: ../../../third_party/skia/gm/trickycubicstrokes.cpp FILE: ../../../third_party/skia/gm/unpremul.cpp FILE: ../../../third_party/skia/gm/wacky_yuv_formats.cpp FILE: ../../../third_party/skia/include/android/SkAnimatedImage.h -FILE: ../../../third_party/skia/include/c/sk_colorspace.h -FILE: ../../../third_party/skia/include/c/sk_imageinfo.h FILE: ../../../third_party/skia/include/core/SkCanvasVirtualEnforcer.h FILE: ../../../third_party/skia/include/core/SkContourMeasure.h FILE: ../../../third_party/skia/include/core/SkCoverageMode.h @@ -3559,7 +3537,6 @@ FILE: ../../../third_party/skia/samplecode/SampleCusp.cpp FILE: ../../../third_party/skia/samplecode/SampleFlutterAnimate.cpp FILE: ../../../third_party/skia/samplecode/SampleGlyphTransform.cpp FILE: ../../../third_party/skia/src/android/SkAnimatedImage.cpp -FILE: ../../../third_party/skia/src/c/sk_imageinfo.cpp FILE: ../../../third_party/skia/src/codec/SkEncodedInfo.cpp FILE: ../../../third_party/skia/src/codec/SkParseEncodedOrigin.cpp FILE: ../../../third_party/skia/src/codec/SkWuffsCodec.cpp @@ -3827,7 +3804,6 @@ FILE: ../../../third_party/skia/samplecode/SampleShadowReference.cpp FILE: ../../../third_party/skia/samplecode/SampleShadowUtils.cpp FILE: ../../../third_party/skia/samplecode/SampleStrokeVerb.cpp FILE: ../../../third_party/skia/src/android/SkAndroidFrameworkUtils.cpp -FILE: ../../../third_party/skia/src/c/sk_effects.cpp FILE: ../../../third_party/skia/src/codec/SkBmpBaseCodec.cpp FILE: ../../../third_party/skia/src/codec/SkBmpBaseCodec.h FILE: ../../../third_party/skia/src/codec/SkFrameHolder.h From dbe17d75f70effce13f63ac6e2ad160365e12616 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 13:29:49 -0400 Subject: [PATCH 262/558] Roll Fuchsia Mac SDK from VVKF4KTZT... to QWFPHejM3... (#35344) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 5eafe6dca6ad5..e543c184de542 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'VVKF4KTZTkLEmNkj8KxgiSVL-TBtsbB5pWa_ee3AovEC' + 'version': 'QWFPHejM3XUHdRt0mm8agNq7weRw5hSVM4AEoJhrWgEC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 02cbee29fa0e24bb2a41a6c980b528eec8af76c5 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 13:48:56 -0400 Subject: [PATCH 263/558] Roll Dart SDK from f06ac8474569 to 38bfbc6df9a5 (8 revisions) (#35345) --- DEPS | 8 ++++---- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DEPS b/DEPS index e543c184de542..62e1c329a607a 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'f06ac84745697b1c231bcd37f094b3848bda289e', + 'dart_revision': '38bfbc6df9a529472d78fbc31a71043bd2b0c8fb', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -200,10 +200,10 @@ deps = { Var('dart_git') + '/csslib.git@ba2eb2d80530eedefadaade338a09c2dd60410f3', 'src/third_party/dart/third_party/pkg/dart_style': - Var('dart_git') + '/dart_style.git@d7b73536a8079331c888b7da539b80e6825270ea', + Var('dart_git') + '/dart_style.git@49bc3ff32b5578b6e19f8fd376d668130941ee29', 'src/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@f419695f57c580f30ea142a0f6e13a9e0001b342', + Var('dart_git') + '/dartdoc.git@8ee30225e2d89d6044dc48965c9ce1ec1c406cb9', 'src/third_party/dart/third_party/pkg/ffi': Var('dart_git') + '/ffi.git@18b2b549d55009ff594600b04705ff6161681e07', @@ -233,7 +233,7 @@ deps = { Var('dart_git') + '/json_rpc_2.git@805e6536dd961d66f6b8cd46d8f3e61774f957c9', 'src/third_party/dart/third_party/pkg/linter': - Var('dart_git') + '/linter.git@075a3b6abf54b38c295690ec8e043607654f2da3', + Var('dart_git') + '/linter.git@a97919a064cc4b3b6923a18cdb47a3779a31bc7b', 'src/third_party/dart/third_party/pkg/logging': Var('dart_git') + '/logging.git@d10e24844c2e01d3f6d2b5a1a2bb8717359c6a87', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 23716ae65f297..4147009db4e97 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 2ec0b95d585df1f2e202fdf2c17389d5 +Signature: f88fb225a5be5fb8fa3f200c1d1e1c62 UNUSED LICENSES: From 40e0335755c93a3558e5a74ff8930a7130c0c108 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 14:06:41 -0400 Subject: [PATCH 264/558] Roll Dart SDK from f06ac8474569 to 38bfbc6df9a5 (8 revisions) (#35347) From dc3f179eabf5da97f6d42b3f4af4474f1fce0ccb Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 11 Aug 2022 11:26:16 -0700 Subject: [PATCH 265/558] add missing break statements in makeWithLocalMatrix (#35346) --- display_list/display_list_image_filter.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/display_list/display_list_image_filter.cc b/display_list/display_list_image_filter.cc index cae1321ffda34..8d4a98fb89e6a 100644 --- a/display_list/display_list_image_filter.cc +++ b/display_list/display_list_image_filter.cc @@ -39,12 +39,14 @@ std::shared_ptr DlImageFilter::makeWithLocalMatrix( // Nothing we can do at this point return nullptr; } + break; } case MatrixCapability::kScaleTranslate: { if (!matrix.isScaleTranslate()) { // Nothing we can do at this point return nullptr; } + break; } default: break; From 0201218ed11f24086477d9f12abaacce259b4063 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 14:27:05 -0400 Subject: [PATCH 266/558] Roll Skia from ebdd78b09827 to a6569df91245 (2 revisions) (#35348) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 62e1c329a607a..083ff300eee75 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': 'ebdd78b098271de2462ef0a2c24a7b8eacc2d349', + 'skia_revision': 'a6569df912456dfe258b108eda71472dcc34f4bd', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f5533e38d6c7c..f1285d985eb61 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 0437b7e931559ee10817f7b792fd9c98 +Signature: b63b86c4bab674a31ae8fd5f6bbce1c3 UNUSED LICENSES: From 18a29008261409363dc03944526e71c47b7ee8c6 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Thu, 11 Aug 2022 11:28:37 -0700 Subject: [PATCH 267/558] [Impeller] Get rid of redundant viewport and scissor bindings. (#35330) --- .../renderer/backend/metal/render_pass_mtl.mm | 58 ++++++++++++------- impeller/renderer/formats.h | 8 +++ 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 5f38a6215774b..90f074e682bd0 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -299,6 +299,36 @@ bool SetSampler(ShaderStage stage, return false; } + void SetViewport(const Viewport& viewport) { + if (viewport_.has_value() && viewport_.value() == viewport) { + return; + } + [encoder_ setViewport:MTLViewport{ + .originX = viewport.rect.origin.x, + .originY = viewport.rect.origin.y, + .width = viewport.rect.size.width, + .height = viewport.rect.size.height, + .znear = viewport.depth_range.z_near, + .zfar = viewport.depth_range.z_far, + }]; + viewport_ = viewport; + } + + void SetScissor(const IRect& scissor) { + if (scissor_.has_value() && scissor_.value() == scissor) { + return; + } + [encoder_ + setScissorRect:MTLScissorRect{ + .x = static_cast(scissor.origin.x), + .y = static_cast(scissor.origin.y), + .width = static_cast(scissor.size.width), + .height = + static_cast(scissor.size.height), + }]; + scissor_ = scissor; + } + private: struct BufferOffsetPair { id buffer = nullptr; @@ -314,6 +344,8 @@ bool SetSampler(ShaderStage stage, std::map buffers_; std::map textures_; std::map samplers_; + std::optional viewport_; + std::optional scissor_; }; static bool Bind(PassBindingsCache& pass, @@ -423,6 +455,11 @@ static bool Bind(PassBindingsCache& pass, PipelineMTL::Cast(*command.pipeline).GetMTLRenderPipelineState()); pass_bindings.SetDepthStencilState( PipelineMTL::Cast(*command.pipeline).GetMTLDepthStencilState()); + pass_bindings.SetViewport(command.viewport.value_or( + {.rect = Rect::MakeSize(GetRenderTargetSize())})); + pass_bindings.SetScissor( + command.scissor.value_or(IRect::MakeSize(GetRenderTargetSize()))); + [encoder setFrontFacingWinding:pipeline_desc.GetWindingOrder() == WindingOrder::kClockwise ? MTLWindingClockwise @@ -430,27 +467,6 @@ static bool Bind(PassBindingsCache& pass, [encoder setCullMode:ToMTLCullMode(pipeline_desc.GetCullMode())]; [encoder setStencilReferenceValue:command.stencil_reference]; - auto v = command.viewport.value_or( - {.rect = Rect::MakeSize(GetRenderTargetSize())}); - MTLViewport viewport = { - .originX = v.rect.origin.x, - .originY = v.rect.origin.y, - .width = v.rect.size.width, - .height = v.rect.size.height, - .znear = v.depth_range.z_near, - .zfar = v.depth_range.z_far, - }; - [encoder setViewport:viewport]; - - auto s = command.scissor.value_or(IRect::MakeSize(GetRenderTargetSize())); - MTLScissorRect scissor = { - .x = static_cast(s.origin.x), - .y = static_cast(s.origin.y), - .width = static_cast(s.size.width), - .height = static_cast(s.size.height), - }; - [encoder setScissorRect:scissor]; - if (!bind_stage_resources(command.vertex_bindings, ShaderStage::kVertex)) { return false; } diff --git a/impeller/renderer/formats.h b/impeller/renderer/formats.h index ebf318f42ca26..65509c6a3ae15 100644 --- a/impeller/renderer/formats.h +++ b/impeller/renderer/formats.h @@ -184,11 +184,19 @@ enum class PrimitiveType { struct DepthRange { Scalar z_near = 0.0; Scalar z_far = 1.0; + + constexpr bool operator==(const DepthRange& other) const { + return z_near == other.z_near && z_far == other.z_far; + } }; struct Viewport { Rect rect; DepthRange depth_range; + + constexpr bool operator==(const Viewport& other) const { + return rect == other.rect && depth_range == other.depth_range; + } }; enum class MinMagFilter { From 7509b07411528688f3848c625d1afb9113823e92 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 16:04:04 -0400 Subject: [PATCH 268/558] Roll Skia from a6569df91245 to f2ac3b9728f7 (1 revision) (#35349) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 083ff300eee75..6baf781687695 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': 'a6569df912456dfe258b108eda71472dcc34f4bd', + 'skia_revision': 'f2ac3b9728f770efb53c34aeca7da6527d36f311', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 53bbdd64769268dd416f603e8d0cae955bc002ef Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Thu, 11 Aug 2022 14:04:31 -0700 Subject: [PATCH 269/558] Add doc comments to WindowsTestContext (#35350) Adds missing doc comments to WindowsTestContext. Issue: https://github.com/flutter/flutter/issues/87299 --- shell/platform/windows/testing/windows_test_context.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/platform/windows/testing/windows_test_context.h b/shell/platform/windows/testing/windows_test_context.h index bdc6fcc22a2de..30673f1ca5d3e 100644 --- a/shell/platform/windows/testing/windows_test_context.h +++ b/shell/platform/windows/testing/windows_test_context.h @@ -23,8 +23,10 @@ class WindowsTestContext { explicit WindowsTestContext(std::string_view assets_path = ""); virtual ~WindowsTestContext(); + // Returns the path to assets required by the Flutter runtime. const std::wstring& GetAssetsPath() const; + // Returns the path to the ICU library data file. const std::wstring& GetIcuDataPath() const; private: From 66871eeef992c86500efa6c1582dbf1e4135fee6 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 17:11:51 -0400 Subject: [PATCH 270/558] Roll Skia from f2ac3b9728f7 to 683a7ce89257 (4 revisions) (#35351) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6baf781687695..b2eaf7ce3e7d8 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': 'f2ac3b9728f770efb53c34aeca7da6527d36f311', + 'skia_revision': '683a7ce892579bafe85b881100f21ecc4e8c8ba6', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f1285d985eb61..9b5730f006c70 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b63b86c4bab674a31ae8fd5f6bbce1c3 +Signature: f09a7634433d451c5b2cb06fa47af0d8 UNUSED LICENSES: From b80a11d888d02f2fc5ccd76fc48520fc4448b061 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 11 Aug 2022 14:49:47 -0700 Subject: [PATCH 271/558] [Impeller] Render axis-aligned Caps for zero length lines in Impeller (#35298) --- .../display_list/display_list_dispatcher.cc | 28 +++++++++--------- .../display_list/display_list_unittests.cc | 29 +++++++++++++++++-- .../entity/contents/solid_stroke_contents.cc | 17 +++++++---- impeller/geometry/path.cc | 2 +- impeller/geometry/point.h | 2 +- 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 4ec8572f770b4..68739c5b98af2 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -888,7 +888,6 @@ void DisplayListDispatcher::drawArc(const SkRect& oval_bounds, void DisplayListDispatcher::drawPoints(SkCanvas::PointMode mode, uint32_t count, const SkPoint points[]) { - // auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); Paint paint = paint_; paint.style = Paint::Style::kStroke; switch (mode) { @@ -897,29 +896,28 @@ void DisplayListDispatcher::drawPoints(SkCanvas::PointMode mode, paint.stroke_cap = SolidStrokeContents::Cap::kSquare; } for (uint32_t i = 0; i < count; i++) { - SkPoint p0 = points[i]; - // kEhCloseEnough works around a bug where Impeller does not draw - // anything for zero-length lines. - // See: https://github.com/flutter/flutter/issues/109077 - SkPoint p1 = points[i] + SkPoint{kEhCloseEnough, 0.0}; - auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); + Point p0 = ToPoint(points[i]); + auto path = PathBuilder{}.AddLine(p0, p0).TakePath(); canvas_.DrawPath(std::move(path), paint); } break; case SkCanvas::kLines_PointMode: for (uint32_t i = 1; i < count; i += 2) { - SkPoint p0 = points[i - 1]; - SkPoint p1 = points[i]; - auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); + Point p0 = ToPoint(points[i - 1]); + Point p1 = ToPoint(points[i]); + auto path = PathBuilder{}.AddLine(p0, p1).TakePath(); canvas_.DrawPath(std::move(path), paint); } break; case SkCanvas::kPolygon_PointMode: - for (uint32_t i = 1; i < count; i++) { - SkPoint p0 = points[i - 1]; - SkPoint p1 = points[i]; - auto path = PathBuilder{}.AddLine(ToPoint(p0), ToPoint(p1)).TakePath(); - canvas_.DrawPath(std::move(path), paint); + if (count > 1) { + Point p0 = ToPoint(points[0]); + for (uint32_t i = 1; i < count; i++) { + Point p1 = ToPoint(points[i]); + auto path = PathBuilder{}.AddLine(p0, p1).TakePath(); + canvas_.DrawPath(std::move(path), paint); + p0 = p1; + } } break; } diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index 18bd21af98479..08e4bb352d2af 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -451,11 +451,13 @@ TEST_P(DisplayListTest, CanDrawPoints) { flutter::DlStrokeCap::kRound, flutter::DlStrokeCap::kSquare, }; - flutter::DlPaint paint = flutter::DlPaint().setStrokeWidth(20); + flutter::DlPaint paint = + flutter::DlPaint() // + .setColor(flutter::DlColor::kYellow().withAlpha(127)) // + .setStrokeWidth(20); builder.translate(50, 50); for (auto cap : caps) { paint.setStrokeCap(cap); - paint.setColor(flutter::DlColor::kYellow().withAlpha(127)); builder.save(); builder.drawPoints(SkCanvas::kPoints_PointMode, 7, points, paint); builder.translate(150, 0); @@ -468,5 +470,28 @@ TEST_P(DisplayListTest, CanDrawPoints) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(DisplayListTest, CanDrawZeroLengthLine) { + flutter::DisplayListBuilder builder; + std::vector caps = { + flutter::DlStrokeCap::kButt, + flutter::DlStrokeCap::kRound, + flutter::DlStrokeCap::kSquare, + }; + flutter::DlPaint paint = + flutter::DlPaint() // + .setColor(flutter::DlColor::kYellow().withAlpha(127)) // + .setDrawStyle(flutter::DlDrawStyle::kStroke) // + .setStrokeCap(flutter::DlStrokeCap::kButt) // + .setStrokeWidth(20); + SkPath path = SkPath().addPoly({{150, 50}, {150, 50}}, false); + for (auto cap : caps) { + paint.setStrokeCap(cap); + builder.drawLine({50, 50}, {50, 50}, paint); + builder.drawPath(path, paint); + builder.translate(0, 150); + } + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/contents/solid_stroke_contents.cc b/impeller/entity/contents/solid_stroke_contents.cc index c332b966c5b51..326b90f342805 100644 --- a/impeller/entity/contents/solid_stroke_contents.cc +++ b/impeller/entity/contents/solid_stroke_contents.cc @@ -72,10 +72,6 @@ static VertexBuffer CreateSolidStrokeVertices( VertexBufferBuilder vtx_builder; auto polyline = path.CreatePolyline(); - if (polyline.points.size() < 2) { - return {}; // Nothing to render. - } - VS::PerVertexData vtx; // Normal state. @@ -95,8 +91,17 @@ static VertexBuffer CreateSolidStrokeVertices( std::tie(contour_start_point_i, contour_end_point_i) = polyline.GetContourPointBounds(contour_i); - if (contour_end_point_i - contour_start_point_i < 2) { - continue; // This contour has no renderable content. + switch (contour_end_point_i - contour_start_point_i) { + case 1: { + Point p = polyline.points[contour_start_point_i]; + cap_proc(vtx_builder, p, {-1, 0}, smoothing); + cap_proc(vtx_builder, p, {1, 0}, smoothing); + continue; + } + case 0: + continue; // This contour has no renderable content. + default: + break; } // The first point's normal is always the same as diff --git a/impeller/geometry/path.cc b/impeller/geometry/path.cc index 69b1cd46a4927..72e9488e4f057 100644 --- a/impeller/geometry/path.cc +++ b/impeller/geometry/path.cc @@ -237,7 +237,7 @@ Path::Polyline Path::CreatePolyline( for (const auto& point : collection) { if (previous_contour_point.has_value() && previous_contour_point.value() == point) { - // Slip over duplicate points in the same contour. + // Skip over duplicate points in the same contour. continue; } previous_contour_point = point; diff --git a/impeller/geometry/point.h b/impeller/geometry/point.h index 7b511ed9d64a6..5fd01ea9a2812 100644 --- a/impeller/geometry/point.h +++ b/impeller/geometry/point.h @@ -189,7 +189,7 @@ struct TPoint { constexpr TPoint Normalize() const { const auto length = GetLength(); if (length == 0) { - return {}; + return {1, 0}; } return {x / length, y / length}; } From d28282730dac29c5039afc0cbf23f45802688f20 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Thu, 11 Aug 2022 14:50:10 -0700 Subject: [PATCH 272/558] [Impeller] Passes and command buffers hold weak handles to the context. (#35352) This makes the submission simpler as the allocators can be acquired from the pass itself. Also makes command buffer submission go through a common method that performs error checking before dispatch to the backend. --- impeller/entity/contents/content_context.cc | 2 +- impeller/entity/entity_pass.cc | 3 +-- impeller/entity/inline_pass_context.cc | 2 +- impeller/playground/playground.cc | 4 ++-- .../backend/gles/command_buffer_gles.cc | 15 ++++++--------- .../renderer/backend/gles/command_buffer_gles.h | 5 +++-- impeller/renderer/backend/gles/context_gles.cc | 3 ++- .../renderer/backend/gles/render_pass_gles.cc | 16 +++++++++------- .../renderer/backend/gles/render_pass_gles.h | 7 ++++--- .../renderer/backend/metal/command_buffer_mtl.h | 7 +++---- .../backend/metal/command_buffer_mtl.mm | 17 +++++------------ impeller/renderer/backend/metal/context_mtl.mm | 3 ++- .../renderer/backend/metal/render_pass_mtl.h | 7 ++++--- .../renderer/backend/metal/render_pass_mtl.mm | 11 ++++++----- .../backend/vulkan/command_buffer_vk.cc | 5 +++-- .../renderer/backend/vulkan/command_buffer_vk.h | 4 ++-- .../renderer/backend/vulkan/render_pass_vk.h | 3 +-- impeller/renderer/command_buffer.cc | 16 +++++++++++++++- impeller/renderer/command_buffer.h | 8 ++++++-- impeller/renderer/context.h | 2 +- impeller/renderer/render_pass.cc | 15 +++++++++++++-- impeller/renderer/render_pass.h | 10 +++++----- impeller/renderer/renderer.cc | 5 ++++- impeller/renderer/renderer_unittests.cc | 6 +++--- 24 files changed, 102 insertions(+), 74 deletions(-) diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index f0aacb04c32c8..3ab9ec79738ba 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -263,7 +263,7 @@ std::shared_ptr ContentContext::MakeSubpass( return nullptr; } - if (!sub_renderpass->EncodeCommands(context->GetResourceAllocator())) { + if (!sub_renderpass->EncodeCommands()) { return nullptr; } diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index cec25f034b407..9d957c3686554 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -173,8 +173,7 @@ bool EntityPass::Render(ContentContext& renderer, entity.Render(renderer, *render_pass); } - if (!render_pass->EncodeCommands( - renderer.GetContext()->GetResourceAllocator())) { + if (!render_pass->EncodeCommands()) { return false; } if (!command_buffer->SubmitCommands()) { diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc index 393cc1fa649d2..fa0f38135e86f 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -37,7 +37,7 @@ bool InlinePassContext::EndPass() { return true; } - if (!pass_->EncodeCommands(context_->GetResourceAllocator())) { + if (!pass_->EncodeCommands()) { return false; } diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index c91f8df98b1b0..ab0457cee5a88 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -244,7 +244,7 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) { ImGui_ImplImpeller_RenderDrawData(ImGui::GetDrawData(), *pass); - pass->EncodeCommands(renderer->GetContext()->GetResourceAllocator()); + pass->EncodeCommands(); if (!buffer->SubmitCommands()) { return false; } @@ -284,7 +284,7 @@ bool Playground::OpenPlaygroundHere(SinglePassCallback pass_callback) { return false; } - pass->EncodeCommands(context->GetResourceAllocator()); + pass->EncodeCommands(); if (!buffer->SubmitCommands()) { return false; } diff --git a/impeller/renderer/backend/gles/command_buffer_gles.cc b/impeller/renderer/backend/gles/command_buffer_gles.cc index 7bb99354c079c..f6452528995c5 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.cc +++ b/impeller/renderer/backend/gles/command_buffer_gles.cc @@ -10,8 +10,10 @@ namespace impeller { -CommandBufferGLES::CommandBufferGLES(ReactorGLES::Ref reactor) - : reactor_(std::move(reactor)), +CommandBufferGLES::CommandBufferGLES(std::weak_ptr context, + ReactorGLES::Ref reactor) + : CommandBuffer(std::move(context)), + reactor_(std::move(reactor)), is_valid_(reactor_ && reactor_->IsValid()) {} CommandBufferGLES::~CommandBufferGLES() = default; @@ -27,13 +29,8 @@ bool CommandBufferGLES::IsValid() const { } // |CommandBuffer| -bool CommandBufferGLES::SubmitCommands(CompletionCallback callback) { - if (!IsValid()) { - return false; - } - +bool CommandBufferGLES::OnSubmitCommands(CompletionCallback callback) { const auto result = reactor_->React(); - if (callback) { callback(result ? CommandBuffer::Status::kCompleted : CommandBuffer::Status::kError); @@ -48,7 +45,7 @@ std::shared_ptr CommandBufferGLES::OnCreateRenderPass( return nullptr; } auto pass = std::shared_ptr( - new RenderPassGLES(std::move(target), reactor_)); + new RenderPassGLES(context_, std::move(target), reactor_)); if (!pass->IsValid()) { return nullptr; } diff --git a/impeller/renderer/backend/gles/command_buffer_gles.h b/impeller/renderer/backend/gles/command_buffer_gles.h index 22b26464379d7..a83bab052c03d 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.h +++ b/impeller/renderer/backend/gles/command_buffer_gles.h @@ -22,7 +22,8 @@ class CommandBufferGLES final : public CommandBuffer { ReactorGLES::Ref reactor_; bool is_valid_ = false; - CommandBufferGLES(ReactorGLES::Ref reactor); + CommandBufferGLES(std::weak_ptr context, + ReactorGLES::Ref reactor); // |CommandBuffer| void SetLabel(const std::string& label) const override; @@ -31,7 +32,7 @@ class CommandBufferGLES final : public CommandBuffer { bool IsValid() const override; // |CommandBuffer| - bool SubmitCommands(CompletionCallback callback) override; + bool OnSubmitCommands(CompletionCallback callback) override; // |CommandBuffer| std::shared_ptr OnCreateRenderPass( diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index 28f8d8418ca2d..a7522b412d7bf 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -103,7 +103,8 @@ std::shared_ptr ContextGLES::GetPipelineLibrary() const { } std::shared_ptr ContextGLES::CreateCommandBuffer() const { - return std::shared_ptr(new CommandBufferGLES(reactor_)); + return std::shared_ptr( + new CommandBufferGLES(weak_from_this(), reactor_)); } // |Context| diff --git a/impeller/renderer/backend/gles/render_pass_gles.cc b/impeller/renderer/backend/gles/render_pass_gles.cc index 3dae613f4ad31..3e96e82c054b1 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/impeller/renderer/backend/gles/render_pass_gles.cc @@ -16,8 +16,10 @@ namespace impeller { -RenderPassGLES::RenderPassGLES(RenderTarget target, ReactorGLES::Ref reactor) - : RenderPass(std::move(target)), +RenderPassGLES::RenderPassGLES(std::weak_ptr context, + RenderTarget target, + ReactorGLES::Ref reactor) + : RenderPass(std::move(context), std::move(target)), reactor_(std::move(reactor)), is_valid_(reactor_ && reactor_->IsValid()) {} @@ -455,8 +457,7 @@ struct RenderPassData { } // |RenderPass| -bool RenderPassGLES::EncodeCommands( - const std::shared_ptr& transients_allocator) const { +bool RenderPassGLES::OnEncodeCommands(const Context& context) const { if (!IsValid()) { return false; } @@ -507,10 +508,11 @@ bool RenderPassGLES::EncodeCommands( CanDiscardAttachmentWhenDone(stencil0->store_action); } - return reactor_->AddOperation([pass_data, transients_allocator, + return reactor_->AddOperation([pass_data, + allocator = context.GetResourceAllocator(), commands = commands_](const auto& reactor) { - auto result = EncodeCommandsInReactor(*pass_data, transients_allocator, - reactor, commands); + auto result = + EncodeCommandsInReactor(*pass_data, allocator, reactor, commands); FML_CHECK(result) << "Must be able to encode GL commands without error."; }); } diff --git a/impeller/renderer/backend/gles/render_pass_gles.h b/impeller/renderer/backend/gles/render_pass_gles.h index 7f66f036dc77a..7ffc5202a2cad 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.h +++ b/impeller/renderer/backend/gles/render_pass_gles.h @@ -22,7 +22,9 @@ class RenderPassGLES final : public RenderPass { std::string label_; bool is_valid_ = false; - RenderPassGLES(RenderTarget target, ReactorGLES::Ref reactor); + RenderPassGLES(std::weak_ptr context, + RenderTarget target, + ReactorGLES::Ref reactor); // |RenderPass| bool IsValid() const override; @@ -31,8 +33,7 @@ class RenderPassGLES final : public RenderPass { void OnSetLabel(std::string label) override; // |RenderPass| - bool EncodeCommands( - const std::shared_ptr& transients_allocator) const override; + bool OnEncodeCommands(const Context& context) const override; FML_DISALLOW_COPY_AND_ASSIGN(RenderPassGLES); }; diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.h b/impeller/renderer/backend/metal/command_buffer_mtl.h index 6c038d675376a..e4e09609657a8 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.h +++ b/impeller/renderer/backend/metal/command_buffer_mtl.h @@ -13,8 +13,6 @@ namespace impeller { class CommandBufferMTL final : public CommandBuffer { public: - CommandBufferMTL(); - // |CommandBuffer| ~CommandBufferMTL() override; @@ -23,7 +21,8 @@ class CommandBufferMTL final : public CommandBuffer { id buffer_ = nullptr; - CommandBufferMTL(id queue); + CommandBufferMTL(const std::weak_ptr context, + id queue); // |CommandBuffer| void SetLabel(const std::string& label) const override; @@ -32,7 +31,7 @@ class CommandBufferMTL final : public CommandBuffer { bool IsValid() const override; // |CommandBuffer| - bool SubmitCommands(CompletionCallback callback) override; + bool OnSubmitCommands(CompletionCallback callback) override; // |CommandBuffer| std::shared_ptr OnCreateRenderPass( diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.mm b/impeller/renderer/backend/metal/command_buffer_mtl.mm index 90bcbf1cf9256..babafbdf0c75f 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/command_buffer_mtl.mm @@ -137,8 +137,9 @@ static void LogMTLCommandBufferErrorIfPresent(id buffer) { return [queue commandBuffer]; } -CommandBufferMTL::CommandBufferMTL(id queue) - : buffer_(CreateCommandBuffer(queue)) {} +CommandBufferMTL::CommandBufferMTL(const std::weak_ptr context, + id queue) + : CommandBuffer(std::move(context)), buffer_(CreateCommandBuffer(queue)) {} CommandBufferMTL::~CommandBufferMTL() = default; @@ -166,15 +167,7 @@ static void LogMTLCommandBufferErrorIfPresent(id buffer) { return CommandBufferMTL::Status::kError; } -bool CommandBufferMTL::SubmitCommands(CompletionCallback callback) { - if (!IsValid()) { - // Already committed or was never valid. Either way, this is caller error. - if (callback) { - callback(Status::kError); - } - return false; - } - +bool CommandBufferMTL::OnSubmitCommands(CompletionCallback callback) { if (callback) { [buffer_ addCompletedHandler:^(id buffer) { LogMTLCommandBufferErrorIfPresent(buffer); @@ -195,7 +188,7 @@ static void LogMTLCommandBufferErrorIfPresent(id buffer) { } auto pass = std::shared_ptr( - new RenderPassMTL(buffer_, std::move(target))); + new RenderPassMTL(context_, std::move(target), buffer_)); if (!pass->IsValid()) { return nullptr; } diff --git a/impeller/renderer/backend/metal/context_mtl.mm b/impeller/renderer/backend/metal/context_mtl.mm index 726d56d904802..c19f3888e6d18 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -193,7 +193,8 @@ return nullptr; } - auto buffer = std::shared_ptr(new CommandBufferMTL(queue)); + auto buffer = std::shared_ptr( + new CommandBufferMTL(weak_from_this(), queue)); if (!buffer->IsValid()) { return nullptr; } diff --git a/impeller/renderer/backend/metal/render_pass_mtl.h b/impeller/renderer/backend/metal/render_pass_mtl.h index 8458a96c8aa83..fd9d4bd80b46d 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.h +++ b/impeller/renderer/backend/metal/render_pass_mtl.h @@ -25,7 +25,9 @@ class RenderPassMTL final : public RenderPass { std::string label_; bool is_valid_ = false; - RenderPassMTL(id buffer, RenderTarget target); + RenderPassMTL(std::weak_ptr context, + RenderTarget target, + id buffer); // |RenderPass| bool IsValid() const override; @@ -34,8 +36,7 @@ class RenderPassMTL final : public RenderPass { void OnSetLabel(std::string label) override; // |RenderPass| - bool EncodeCommands( - const std::shared_ptr& transients_allocator) const override; + bool OnEncodeCommands(const Context& context) const override; bool EncodeCommands(const std::shared_ptr& transients_allocator, id pass) const; diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 90f074e682bd0..8827498924559 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -128,8 +128,10 @@ static bool ConfigureStencilAttachment( return result; } -RenderPassMTL::RenderPassMTL(id buffer, RenderTarget target) - : RenderPass(std::move(target)), +RenderPassMTL::RenderPassMTL(std::weak_ptr context, + RenderTarget target, + id buffer) + : RenderPass(std::move(context), std::move(target)), buffer_(buffer), desc_(ToMTLRenderPassDescriptor(GetRenderTarget())) { if (!buffer_ || !desc_ || !render_target_.IsValid()) { @@ -151,8 +153,7 @@ static bool ConfigureStencilAttachment( label_ = std::move(label); } -bool RenderPassMTL::EncodeCommands( - const std::shared_ptr& transients_allocator) const { +bool RenderPassMTL::OnEncodeCommands(const Context& context) const { TRACE_EVENT0("impeller", "RenderPassMTL::EncodeCommands"); if (!IsValid()) { return false; @@ -173,7 +174,7 @@ static bool ConfigureStencilAttachment( fml::ScopedCleanupClosure auto_end( [render_command_encoder]() { [render_command_encoder endEncoding]; }); - return EncodeCommands(transients_allocator, render_command_encoder); + return EncodeCommands(context.GetResourceAllocator(), render_command_encoder); } //----------------------------------------------------------------------------- diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.cc b/impeller/renderer/backend/vulkan/command_buffer_vk.cc index 0a33906c1f2de..e560ba9e652c8 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.cc @@ -9,7 +9,8 @@ namespace impeller { -CommandBufferVK::CommandBufferVK() = default; +CommandBufferVK::CommandBufferVK(std::weak_ptr context) + : CommandBuffer(std::move(context)) {} CommandBufferVK::~CommandBufferVK() = default; @@ -21,7 +22,7 @@ bool CommandBufferVK::IsValid() const { FML_UNREACHABLE(); } -bool CommandBufferVK::SubmitCommands(CompletionCallback callback) { +bool CommandBufferVK::OnSubmitCommands(CompletionCallback callback) { FML_UNREACHABLE(); } diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.h b/impeller/renderer/backend/vulkan/command_buffer_vk.h index cb166f8689ecb..a4525382fc9a5 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.h @@ -17,7 +17,7 @@ class CommandBufferVK final : public CommandBuffer { private: friend class ContextMTL; - CommandBufferVK(); + explicit CommandBufferVK(std::weak_ptr context); // |CommandBuffer| void SetLabel(const std::string& label) const override; @@ -26,7 +26,7 @@ class CommandBufferVK final : public CommandBuffer { bool IsValid() const override; // |CommandBuffer| - bool SubmitCommands(CompletionCallback callback) override; + bool OnSubmitCommands(CompletionCallback callback) override; // |CommandBuffer| std::shared_ptr OnCreateRenderPass( diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index afb942f798024..42cec8935329d 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -27,8 +27,7 @@ class RenderPassVK final : public RenderPass { void OnSetLabel(std::string label) override; // |RenderPass| - bool EncodeCommands( - const std::shared_ptr& transients_allocator) const override; + bool OnEncodeCommands(const Context& context) const override; FML_DISALLOW_COPY_AND_ASSIGN(RenderPassVK); }; diff --git a/impeller/renderer/command_buffer.cc b/impeller/renderer/command_buffer.cc index 75ff9e700f78a..6429afaf3131a 100644 --- a/impeller/renderer/command_buffer.cc +++ b/impeller/renderer/command_buffer.cc @@ -4,15 +4,29 @@ #include "impeller/renderer/command_buffer.h" +#include "flutter/fml/trace_event.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" namespace impeller { -CommandBuffer::CommandBuffer() = default; +CommandBuffer::CommandBuffer(std::weak_ptr context) + : context_(std::move(context)) {} CommandBuffer::~CommandBuffer() = default; +bool CommandBuffer::SubmitCommands(CompletionCallback callback) { + TRACE_EVENT0("impeller", "CommandBuffer::SubmitCommands"); + if (!IsValid()) { + // Already committed or was never valid. Either way, this is caller error. + if (callback) { + callback(Status::kError); + } + return false; + } + return OnSubmitCommands(callback); +} + bool CommandBuffer::SubmitCommands() { return SubmitCommands(nullptr); } diff --git a/impeller/renderer/command_buffer.h b/impeller/renderer/command_buffer.h index 92328a0ae3197..28158e15561ad 100644 --- a/impeller/renderer/command_buffer.h +++ b/impeller/renderer/command_buffer.h @@ -59,7 +59,7 @@ class CommandBuffer { /// /// @param[in] callback The completion callback. /// - [[nodiscard]] virtual bool SubmitCommands(CompletionCallback callback) = 0; + [[nodiscard]] bool SubmitCommands(CompletionCallback callback); [[nodiscard]] bool SubmitCommands(); @@ -82,13 +82,17 @@ class CommandBuffer { std::shared_ptr CreateBlitPass() const; protected: - CommandBuffer(); + std::weak_ptr context_; + + explicit CommandBuffer(std::weak_ptr context); virtual std::shared_ptr OnCreateRenderPass( RenderTarget render_target) const = 0; virtual std::shared_ptr OnCreateBlitPass() const = 0; + [[nodiscard]] virtual bool OnSubmitCommands(CompletionCallback callback) = 0; + private: FML_DISALLOW_COPY_AND_ASSIGN(CommandBuffer); }; diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index db31bcf5236b8..dad614f5051eb 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -17,7 +17,7 @@ class CommandBuffer; class PipelineLibrary; class Allocator; -class Context { +class Context : public std::enable_shared_from_this { public: virtual ~Context(); diff --git a/impeller/renderer/render_pass.cc b/impeller/renderer/render_pass.cc index f3db163cb1994..ba084ff442b33 100644 --- a/impeller/renderer/render_pass.cc +++ b/impeller/renderer/render_pass.cc @@ -6,8 +6,10 @@ namespace impeller { -RenderPass::RenderPass(RenderTarget target) - : render_target_(std::move(target)), +RenderPass::RenderPass(std::weak_ptr context, + RenderTarget target) + : context_(std::move(context)), + render_target_(std::move(target)), transients_buffer_(HostBuffer::Create()) {} RenderPass::~RenderPass() = default; @@ -63,4 +65,13 @@ bool RenderPass::AddCommand(Command command) { return true; } +bool RenderPass::EncodeCommands() const { + auto context = context_.lock(); + // The context could have been collected in the meantime. + if (!context) { + return false; + } + return OnEncodeCommands(*context); +} + } // namespace impeller diff --git a/impeller/renderer/render_pass.h b/impeller/renderer/render_pass.h index e026dc69fd223..4386d5c9e00b0 100644 --- a/impeller/renderer/render_pass.h +++ b/impeller/renderer/render_pass.h @@ -51,23 +51,23 @@ class RenderPass { //---------------------------------------------------------------------------- /// @brief Encode the recorded commands to the underlying command buffer. /// - /// @param transients_allocator The transients allocator. - /// /// @return If the commands were encoded to the underlying command /// buffer. /// - virtual bool EncodeCommands( - const std::shared_ptr& transients_allocator) const = 0; + bool EncodeCommands() const; protected: + const std::weak_ptr context_; const RenderTarget render_target_; std::shared_ptr transients_buffer_; std::vector commands_; - RenderPass(RenderTarget target); + RenderPass(std::weak_ptr context, RenderTarget target); virtual void OnSetLabel(std::string label) = 0; + virtual bool OnEncodeCommands(const Context& context) const = 0; + private: FML_DISALLOW_COPY_AND_ASSIGN(RenderPass); }; diff --git a/impeller/renderer/renderer.cc b/impeller/renderer/renderer.cc index 9fd707a7eaaf0..c4c431c9ed8a8 100644 --- a/impeller/renderer/renderer.cc +++ b/impeller/renderer/renderer.cc @@ -53,8 +53,11 @@ bool Renderer::Render(std::unique_ptr surface, return false; } + const auto present_result = surface->Present(); + frames_in_flight_sema_->Signal(); - return surface->Present(); + + return present_result; } std::shared_ptr Renderer::GetContext() const { diff --git a/impeller/renderer/renderer_unittests.cc b/impeller/renderer/renderer_unittests.cc index 25160b94c5398..17f64e6f506f8 100644 --- a/impeller/renderer/renderer_unittests.cc +++ b/impeller/renderer/renderer_unittests.cc @@ -378,7 +378,7 @@ TEST_P(RendererTest, CanRenderToTexture) { VS::BindUniformBuffer( cmd, r2t_pass->GetTransientsBuffer().EmplaceUniform(uniforms)); ASSERT_TRUE(r2t_pass->AddCommand(std::move(cmd))); - ASSERT_TRUE(r2t_pass->EncodeCommands(context->GetResourceAllocator())); + ASSERT_TRUE(r2t_pass->EncodeCommands()); } #if IMPELLER_ENABLE_METAL @@ -543,7 +543,7 @@ TEST_P(RendererTest, CanBlitTextureToTexture) { pass->AddCommand(std::move(cmd)); } - pass->EncodeCommands(context->GetResourceAllocator()); + pass->EncodeCommands(); } if (!buffer->SubmitCommands()) { @@ -664,7 +664,7 @@ TEST_P(RendererTest, CanGenerateMipmaps) { pass->AddCommand(std::move(cmd)); } - pass->EncodeCommands(context->GetResourceAllocator()); + pass->EncodeCommands(); } if (!buffer->SubmitCommands()) { From d42fa7a8044b64de1f5cf754fb24a073f1488839 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 17:50:35 -0400 Subject: [PATCH 273/558] Roll Dart SDK from 38bfbc6df9a5 to 36c21217228c (1 revision) (#35353) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index b2eaf7ce3e7d8..5c3718d1f86d4 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '38bfbc6df9a529472d78fbc31a71043bd2b0c8fb', + 'dart_revision': '36c21217228c78dc1e0f2d1eb2d1c3df376698ec', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 27985b7c8a1696f95c6053de3c4e30365e2128f5 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Thu, 11 Aug 2022 18:02:22 -0400 Subject: [PATCH 274/558] Remove fx_logger_config_t.console_fd (#35302) This was deprecated in https://fxrev.dev/708606. --- fml/logging_unittests.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/fml/logging_unittests.cc b/fml/logging_unittests.cc index 1f6b0f9b83c4e..a64d33e52f3fb 100644 --- a/fml/logging_unittests.cc +++ b/fml/logging_unittests.cc @@ -55,7 +55,6 @@ class LoggingSocketTest : public ::testing::Test { fx_logger_config_t config = { .min_severity = FX_LOG_INFO, - .console_fd = -1, .log_sink_socket = local.release(), .tags = nullptr, .num_tags = 0, From fc9d0206db86a0cc6e8940b54d227ead7ebbc445 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 18:22:04 -0400 Subject: [PATCH 275/558] Roll Skia from 683a7ce89257 to 6e743daaf5cd (2 revisions) (#35354) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DEPS b/DEPS index 5c3718d1f86d4..8b12896699f0f 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': '683a7ce892579bafe85b881100f21ecc4e8c8ba6', + 'skia_revision': '6e743daaf5cdd5c6f9be73b7696dfbc46123e6e0', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 9b5730f006c70..34f8d92d4707a 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: f09a7634433d451c5b2cb06fa47af0d8 +Signature: 5a5c8c6ce3e85881d892e5772a48ffa9 UNUSED LICENSES: @@ -2596,8 +2596,6 @@ FILE: ../../../third_party/skia/src/gpu/graphite/DrawPass.h FILE: ../../../third_party/skia/src/gpu/graphite/DrawTypes.h FILE: ../../../third_party/skia/src/gpu/graphite/DrawWriter.cpp FILE: ../../../third_party/skia/src/gpu/graphite/DrawWriter.h -FILE: ../../../third_party/skia/src/gpu/graphite/Gpu.cpp -FILE: ../../../third_party/skia/src/gpu/graphite/Gpu.h FILE: ../../../third_party/skia/src/gpu/graphite/GpuWorkSubmission.h FILE: ../../../third_party/skia/src/gpu/graphite/GraphicsPipeline.cpp FILE: ../../../third_party/skia/src/gpu/graphite/GraphicsPipeline.h @@ -2614,6 +2612,8 @@ FILE: ../../../third_party/skia/src/gpu/graphite/Renderer.h FILE: ../../../third_party/skia/src/gpu/graphite/ResourceProvider.cpp FILE: ../../../third_party/skia/src/gpu/graphite/ResourceProvider.h FILE: ../../../third_party/skia/src/gpu/graphite/ResourceTypes.h +FILE: ../../../third_party/skia/src/gpu/graphite/SharedContext.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/SharedContext.h FILE: ../../../third_party/skia/src/gpu/graphite/SkStuff.cpp FILE: ../../../third_party/skia/src/gpu/graphite/Surface_Graphite.cpp FILE: ../../../third_party/skia/src/gpu/graphite/Surface_Graphite.h @@ -2640,12 +2640,12 @@ FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlCaps.h FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlCaps.mm FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlCommandBuffer.h FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlCommandBuffer.mm -FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlGpu.h -FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlGpu.mm FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlGraphicsPipeline.h FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlGraphicsPipeline.mm FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlResourceProvider.h FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlResourceProvider.mm +FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlSharedContext.h +FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlSharedContext.mm FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlTexture.h FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlTexture.mm FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlTypesPriv.mm From dd393ffbe237633b697b3668dd314dcde420964b Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Thu, 11 Aug 2022 16:15:04 -0700 Subject: [PATCH 276/558] [Impeller] Add implementations for concurrent work-queues. (#35355) --- ci/licenses_golden/licenses_flutter | 6 +++ impeller/base/BUILD.gn | 11 +++++ .../base/platform/darwin/work_queue_darwin.cc | 38 +++++++++++++++++ .../base/platform/darwin/work_queue_darwin.h | 36 ++++++++++++++++ impeller/base/work_queue.cc | 13 ++++++ impeller/base/work_queue.h | 27 ++++++++++++ impeller/base/work_queue_common.cc | 25 +++++++++++ impeller/base/work_queue_common.h | 33 +++++++++++++++ .../renderer/backend/gles/context_gles.cc | 22 +++++++++- impeller/renderer/backend/gles/context_gles.h | 4 ++ impeller/renderer/backend/metal/context_mtl.h | 4 ++ .../renderer/backend/metal/context_mtl.mm | 41 +++++++++++++++---- .../renderer/backend/vulkan/context_vk.cc | 14 +++++++ impeller/renderer/backend/vulkan/context_vk.h | 4 ++ impeller/renderer/context.h | 3 ++ 15 files changed, 271 insertions(+), 10 deletions(-) create mode 100644 impeller/base/platform/darwin/work_queue_darwin.cc create mode 100644 impeller/base/platform/darwin/work_queue_darwin.h create mode 100644 impeller/base/work_queue.cc create mode 100644 impeller/base/work_queue.h create mode 100644 impeller/base/work_queue_common.cc create mode 100644 impeller/base/work_queue_common.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 450968be91055..a051333848cc4 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -450,6 +450,8 @@ FILE: ../../../flutter/impeller/base/base_unittests.cc FILE: ../../../flutter/impeller/base/comparable.cc FILE: ../../../flutter/impeller/base/comparable.h FILE: ../../../flutter/impeller/base/config.h +FILE: ../../../flutter/impeller/base/platform/darwin/work_queue_darwin.cc +FILE: ../../../flutter/impeller/base/platform/darwin/work_queue_darwin.h FILE: ../../../flutter/impeller/base/promise.cc FILE: ../../../flutter/impeller/base/promise.h FILE: ../../../flutter/impeller/base/strings.cc @@ -462,6 +464,10 @@ FILE: ../../../flutter/impeller/base/validation.cc FILE: ../../../flutter/impeller/base/validation.h FILE: ../../../flutter/impeller/base/version.cc FILE: ../../../flutter/impeller/base/version.h +FILE: ../../../flutter/impeller/base/work_queue.cc +FILE: ../../../flutter/impeller/base/work_queue.h +FILE: ../../../flutter/impeller/base/work_queue_common.cc +FILE: ../../../flutter/impeller/base/work_queue_common.h FILE: ../../../flutter/impeller/blobcat/blob.cc FILE: ../../../flutter/impeller/blobcat/blob.h FILE: ../../../flutter/impeller/blobcat/blob_library.cc diff --git a/impeller/base/BUILD.gn b/impeller/base/BUILD.gn index 577d34d78f2b7..4edd4e1a154f9 100644 --- a/impeller/base/BUILD.gn +++ b/impeller/base/BUILD.gn @@ -24,8 +24,19 @@ impeller_component("base") { "validation.h", "version.cc", "version.h", + "work_queue.cc", + "work_queue.h", + "work_queue_common.cc", + "work_queue_common.h", ] + if (is_ios || is_mac) { + sources += [ + "platform/darwin/work_queue_darwin.cc", + "platform/darwin/work_queue_darwin.h", + ] + } + deps = [ "//flutter/fml" ] } diff --git a/impeller/base/platform/darwin/work_queue_darwin.cc b/impeller/base/platform/darwin/work_queue_darwin.cc new file mode 100644 index 0000000000000..6ac76520530ed --- /dev/null +++ b/impeller/base/platform/darwin/work_queue_darwin.cc @@ -0,0 +1,38 @@ +// 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/base/platform/darwin/work_queue_darwin.h" + +namespace impeller { + +std::shared_ptr WorkQueueDarwin::Create() { + auto queue = std::shared_ptr(new WorkQueueDarwin()); + if (!queue->IsValid()) { + return nullptr; + } + return queue; +} + +WorkQueueDarwin::WorkQueueDarwin() + : queue_(::dispatch_queue_create( + "io.flutter.impeller.wq", + ::dispatch_queue_attr_make_with_qos_class( + DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL, + QOS_CLASS_USER_INITIATED, + -1))) {} + +WorkQueueDarwin::~WorkQueueDarwin() = default; + +bool WorkQueueDarwin::IsValid() const { + return queue_ != NULL; +} + +// |WorkQueue| +void WorkQueueDarwin::PostTask(fml::closure task) { + dispatch_async(queue_, ^() { + task(); + }); +} + +} // namespace impeller diff --git a/impeller/base/platform/darwin/work_queue_darwin.h b/impeller/base/platform/darwin/work_queue_darwin.h new file mode 100644 index 0000000000000..c82aca9eb285f --- /dev/null +++ b/impeller/base/platform/darwin/work_queue_darwin.h @@ -0,0 +1,36 @@ +// 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/fml/macros.h" +#include "impeller/base/work_queue.h" + +namespace impeller { + +class WorkQueueDarwin final : public WorkQueue { + public: + static std::shared_ptr Create(); + + // |WorkQueue| + ~WorkQueueDarwin(); + + bool IsValid() const; + + private: + dispatch_queue_t queue_ = NULL; + + WorkQueueDarwin(); + + // |WorkQueue| + void PostTask(fml::closure task) override; + + FML_DISALLOW_COPY_AND_ASSIGN(WorkQueueDarwin); +}; + +} // namespace impeller diff --git a/impeller/base/work_queue.cc b/impeller/base/work_queue.cc new file mode 100644 index 0000000000000..f4a375496207a --- /dev/null +++ b/impeller/base/work_queue.cc @@ -0,0 +1,13 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/impeller/base/work_queue.h" + +namespace impeller { + +WorkQueue::WorkQueue() = default; + +WorkQueue::~WorkQueue() = default; + +} // namespace impeller diff --git a/impeller/base/work_queue.h b/impeller/base/work_queue.h new file mode 100644 index 0000000000000..afd31c7acd53c --- /dev/null +++ b/impeller/base/work_queue.h @@ -0,0 +1,27 @@ +// 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 "flutter/fml/closure.h" +#include "flutter/fml/macros.h" + +namespace impeller { + +class WorkQueue : public std::enable_shared_from_this { + public: + virtual ~WorkQueue(); + + virtual void PostTask(fml::closure task) = 0; + + protected: + WorkQueue(); + + private: + FML_DISALLOW_COPY_AND_ASSIGN(WorkQueue); +}; + +} // namespace impeller diff --git a/impeller/base/work_queue_common.cc b/impeller/base/work_queue_common.cc new file mode 100644 index 0000000000000..9a1f0620148ec --- /dev/null +++ b/impeller/base/work_queue_common.cc @@ -0,0 +1,25 @@ +// 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/base/work_queue_common.h" + +namespace impeller { + +std::shared_ptr WorkQueueCommon::Create() { + return std::shared_ptr(new WorkQueueCommon()); +} + +WorkQueueCommon::WorkQueueCommon() + : loop_(fml::ConcurrentMessageLoop::Create(2u)) {} + +WorkQueueCommon::~WorkQueueCommon() { + loop_->Terminate(); +} + +// |WorkQueue| +void WorkQueueCommon::PostTask(fml::closure task) { + loop_->GetTaskRunner()->PostTask(std::move(task)); +} + +} // namespace impeller diff --git a/impeller/base/work_queue_common.h b/impeller/base/work_queue_common.h new file mode 100644 index 0000000000000..952f6ecbadacd --- /dev/null +++ b/impeller/base/work_queue_common.h @@ -0,0 +1,33 @@ +// 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 "flutter/fml/concurrent_message_loop.h" +#include "flutter/fml/macros.h" +#include "impeller/base/work_queue.h" + +namespace impeller { + +class WorkQueueCommon : public WorkQueue { + public: + static std::shared_ptr Create(); + + // |WorkQueue| + ~WorkQueueCommon(); + + private: + std::shared_ptr loop_; + + WorkQueueCommon(); + + // |WorkQueue| + void PostTask(fml::closure task) override; + + FML_DISALLOW_COPY_AND_ASSIGN(WorkQueueCommon); +}; + +} // namespace impeller diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index a7522b412d7bf..7ff2339498613 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -6,6 +6,7 @@ #include "impeller/base/config.h" #include "impeller/base/validation.h" +#include "impeller/base/work_queue_common.h" namespace impeller { @@ -52,12 +53,21 @@ ContextGLES::ContextGLES( } } - // Create the sampler library + // Create the sampler library. { sampler_library_ = std::shared_ptr(new SamplerLibraryGLES()); } + // Create the work queue. + { + work_queue_ = WorkQueueCommon::Create(); + if (!work_queue_) { + VALIDATION_LOG << "Could not create work queue."; + return; + } + } + is_valid_ = true; } @@ -86,27 +96,37 @@ bool ContextGLES::IsValid() const { return is_valid_; } +// |Context| std::shared_ptr ContextGLES::GetResourceAllocator() const { return resource_allocator_; } +// |Context| std::shared_ptr ContextGLES::GetShaderLibrary() const { return shader_library_; } +// |Context| std::shared_ptr ContextGLES::GetSamplerLibrary() const { return sampler_library_; } +// |Context| std::shared_ptr ContextGLES::GetPipelineLibrary() const { return pipeline_library_; } +// |Context| std::shared_ptr ContextGLES::CreateCommandBuffer() const { return std::shared_ptr( new CommandBufferGLES(weak_from_this(), reactor_)); } +// |Context| +std::shared_ptr ContextGLES::GetWorkQueue() const { + return work_queue_; +} + // |Context| bool ContextGLES::HasThreadingRestrictions() const { return true; diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index f96efd2098760..7c7246dc796b6 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -38,6 +38,7 @@ class ContextGLES final : public Context, std::shared_ptr shader_library_; std::shared_ptr pipeline_library_; std::shared_ptr sampler_library_; + std::shared_ptr work_queue_; std::shared_ptr resource_allocator_; bool is_valid_ = false; @@ -62,6 +63,9 @@ class ContextGLES final : public Context, // |Context| std::shared_ptr CreateCommandBuffer() const override; + // |Context| + std::shared_ptr GetWorkQueue() const override; + // |Context| bool HasThreadingRestrictions() const override; diff --git a/impeller/renderer/backend/metal/context_mtl.h b/impeller/renderer/backend/metal/context_mtl.h index a08a9b252071c..45368a26ac737 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -42,6 +42,7 @@ class ContextMTL final : public Context, std::shared_ptr pipeline_library_; std::shared_ptr sampler_library_; std::shared_ptr resource_allocator_; + std::shared_ptr work_queue_; bool is_valid_ = false; ContextMTL(id device, NSArray>* shader_libraries); @@ -64,6 +65,9 @@ class ContextMTL final : public Context, // |Context| std::shared_ptr CreateCommandBuffer() const override; + // |Context| + std::shared_ptr GetWorkQueue() 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 c19f3888e6d18..b3a8d7ea5c805 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -9,6 +9,7 @@ #include "flutter/fml/file.h" #include "flutter/fml/logging.h" #include "flutter/fml/paths.h" +#include "impeller/base/platform/darwin/work_queue_darwin.h" #include "impeller/renderer/backend/metal/sampler_library_mtl.h" #include "impeller/renderer/sampler_descriptor.h" @@ -40,31 +41,43 @@ shader_library_ = std::move(library); } - // Setup command queues. - command_queue_ = device_.newCommandQueue; - - if (!command_queue_) { - return; + // Setup command queue. + { + command_queue_ = device_.newCommandQueue; + if (!command_queue_) { + VALIDATION_LOG << "Could not setup the command queue."; + return; + } + command_queue_.label = @"Impeller Command Queue"; } - command_queue_.label = @"Impeller Command Queue"; - // Setup the pipeline library. - { // + { pipeline_library_ = std::shared_ptr(new PipelineLibraryMTL(device_)); } // Setup the sampler library. - { // + { sampler_library_ = std::shared_ptr(new SamplerLibraryMTL(device_)); } + // Setup the resource allocator. { resource_allocator_ = std::shared_ptr( new AllocatorMTL(device_, "Impeller Permanents Allocator")); if (!resource_allocator_) { + VALIDATION_LOG << "Could not setup the resource allocator."; + return; + } + } + + // Setup the work queue. + { + work_queue_ = WorkQueueDarwin::Create(); + if (!work_queue_) { + VALIDATION_LOG << "Could not setup the work queue."; return; } } @@ -167,26 +180,36 @@ ContextMTL::~ContextMTL() = default; +// |Context| bool ContextMTL::IsValid() const { return is_valid_; } +// |Context| std::shared_ptr ContextMTL::GetShaderLibrary() const { return shader_library_; } +// |Context| std::shared_ptr ContextMTL::GetPipelineLibrary() const { return pipeline_library_; } +// |Context| std::shared_ptr ContextMTL::GetSamplerLibrary() const { return sampler_library_; } +// |Context| std::shared_ptr ContextMTL::CreateCommandBuffer() const { return CreateCommandBufferInQueue(command_queue_); } +// |Context| +std::shared_ptr ContextMTL::GetWorkQueue() const { + return work_queue_; +} + std::shared_ptr ContextMTL::CreateCommandBufferInQueue( id queue) const { if (!IsValid()) { diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 52329dd833071..27a15e293222e 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -12,6 +12,7 @@ #include "flutter/fml/build_config.h" #include "flutter/fml/trace_event.h" #include "impeller/base/validation.h" +#include "impeller/base/work_queue_common.h" #include "impeller/renderer/backend/vulkan/allocator_vk.h" #include "impeller/renderer/backend/vulkan/capabilities_vk.h" #include "impeller/renderer/backend/vulkan/surface_producer_vk.h" @@ -407,6 +408,13 @@ ContextVK::ContextVK( return; } + auto work_queue = WorkQueueCommon::Create(); + + if (!work_queue) { + VALIDATION_LOG << "Could not create workqueue."; + return; + } + instance_ = std::move(instance.value); debug_messenger_ = std::move(debug_messenger); device_ = std::move(device.value); @@ -414,6 +422,7 @@ ContextVK::ContextVK( shader_library_ = std::move(shader_library); sampler_library_ = std::move(sampler_library); pipeline_library_ = std::move(pipeline_library); + work_queue_ = std::move(work_queue); graphics_queue_ = device_->getQueue(graphics_queue->family, graphics_queue->index); compute_queue_ = @@ -447,6 +456,11 @@ std::shared_ptr ContextVK::GetPipelineLibrary() const { return pipeline_library_; } +// |Context| +std::shared_ptr ContextVK::GetWorkQueue() const { + return work_queue_; +} + std::shared_ptr ContextVK::CreateCommandBuffer() const { FML_UNREACHABLE(); } diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index a83bd2d0a14b7..eadc810d44d36 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -78,6 +78,7 @@ class ContextVK final : public Context, public BackendCast { std::unique_ptr swapchain_; std::unique_ptr graphics_command_pool_; std::unique_ptr surface_producer_; + std::shared_ptr work_queue_; bool is_valid_ = false; ContextVK( @@ -102,6 +103,9 @@ class ContextVK final : public Context, public BackendCast { // |Context| std::shared_ptr CreateCommandBuffer() const override; + // |Context| + std::shared_ptr GetWorkQueue() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextVK); }; diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index dad614f5051eb..7f13fce9ac684 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -16,6 +16,7 @@ class SamplerLibrary; class CommandBuffer; class PipelineLibrary; class Allocator; +class WorkQueue; class Context : public std::enable_shared_from_this { public: @@ -36,6 +37,8 @@ class Context : public std::enable_shared_from_this { virtual std::shared_ptr CreateCommandBuffer() const = 0; + virtual std::shared_ptr GetWorkQueue() const = 0; + virtual bool HasThreadingRestrictions() const; protected: From 733c8bda3a3ff26e41ce14ec8d44ac172e4f4603 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 19:33:23 -0400 Subject: [PATCH 277/558] Roll Skia from 6e743daaf5cd to 3901abed0034 (2 revisions) (#35358) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 8b12896699f0f..d33dd0b990398 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': '6e743daaf5cdd5c6f9be73b7696dfbc46123e6e0', + 'skia_revision': '3901abed003450c20001e6b7538408e484ed7aa9', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 34f8d92d4707a..9c9a037c80130 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 5a5c8c6ce3e85881d892e5772a48ffa9 +Signature: de88b55052fef995d37493e6a9c75de1 UNUSED LICENSES: @@ -2058,7 +2058,6 @@ FILE: ../../../third_party/skia/src/core/SkLRUCache.h FILE: ../../../third_party/skia/src/core/SkLeanWindows.h FILE: ../../../third_party/skia/src/core/SkMSAN.h FILE: ../../../third_party/skia/src/core/SkMatrixPriv.h -FILE: ../../../third_party/skia/src/core/SkModeColorFilter.h FILE: ../../../third_party/skia/src/core/SkOverdrawCanvas.cpp FILE: ../../../third_party/skia/src/core/SkPathMeasurePriv.h FILE: ../../../third_party/skia/src/core/SkRasterPipeline.cpp From 2230e89d76361e37b22fe5200232be3bf6ab8293 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 11 Aug 2022 16:55:51 -0700 Subject: [PATCH 278/558] Use kPremul_SkAlphaType in Picture.toImageSync (#35336) --- lib/ui/painting/picture.cc | 2 +- testing/dart/canvas_test.dart | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index dd64f1b2d7696..4d5411d1830f6 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -68,7 +68,7 @@ void Picture::RasterizeToImageSync(sk_sp display_list, auto image = CanvasImage::Create(); const SkImageInfo image_info = SkImageInfo::Make( - width, height, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType); + width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType); auto dl_image = DlDeferredImageGPU::Make( image_info, std::move(display_list), std::move(snapshot_delegate), std::move(raster_task_runner), std::move(unref_queue)); diff --git a/testing/dart/canvas_test.dart b/testing/dart/canvas_test.dart index d220aff07535f..e9dc8b1337d51 100644 --- a/testing/dart/canvas_test.dart +++ b/testing/dart/canvas_test.dart @@ -505,6 +505,39 @@ void main() { expect(data.buffer.asUint8List()[3], 0xFF); }); + test('toImage and toImageSync have identical contents', () async { + // Note: on linux this stil seems to be different. + // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/108835 + if (Platform.isLinux) { + return; + } + + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.drawRect( + const Rect.fromLTWH(20, 20, 100, 100), + Paint()..color = const Color(0xA0FF6D00), + ); + final Picture picture = recorder.endRecording(); + final Image toImageImage = await picture.toImage(200, 200); + final Image toImageSyncImage = picture.toImageSync(200, 200); + + // To trigger observable difference in alpha, draw image + // on a second canvas. + Future drawOnCanvas(Image image) async { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.drawPaint(Paint()..color = const Color(0x4FFFFFFF)); + canvas.drawImage(image, Offset.zero, Paint()); + final Image resultImage = await recorder.endRecording().toImage(200, 200); + return (await resultImage.toByteData())!; + } + + final ByteData dataSync = await drawOnCanvas(toImageImage); + final ByteData data = await drawOnCanvas(toImageSyncImage); + expect(data, listEquals(dataSync)); + }); + test('Canvas.drawParagraph throws when Paragraph.layout was not called', () async { // Regression test for https://github.com/flutter/flutter/issues/97172 bool assertsEnabled = false; @@ -896,3 +929,12 @@ void main() { expect(canvas.getDestinationClipBounds(), initialDestinationBounds); }); } + +Matcher listEquals(ByteData expected) => (dynamic v) { + Expect.type(v); + final ByteData value = v as ByteData; + expect(value.lengthInBytes, expected.lengthInBytes); + for (int i = 0; i < value.lengthInBytes; i++) { + expect(value.getUint8(i), expected.getUint8(i)); + } +}; From feed7e3cf52529dc1bf65b45339a79188193be3e Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Thu, 11 Aug 2022 17:03:04 -0700 Subject: [PATCH 279/558] [Impeller] [vulkan] reland binding offset for vulkan (#35356) --- impeller/compiler/code_gen_template.h | 2 -- impeller/compiler/compiler.cc | 17 +++++++++++++++++ impeller/compiler/compiler.h | 2 ++ impeller/compiler/compiler_test.cc | 7 +++++++ impeller/compiler/compiler_test.h | 3 +++ impeller/compiler/compiler_unittests.cc | 25 +++++++++++++++++++++++++ impeller/fixtures/BUILD.gn | 1 + impeller/fixtures/sample.frag | 14 ++++++++++++++ impeller/renderer/pipeline_builder.h | 9 +++++++++ 9 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 impeller/fixtures/sample.frag diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index 7769f02779524..58b9b0a7b9464 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -152,7 +152,6 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} // =========================================================================== // Metadata for Vulkan ======================================================= // =========================================================================== -{% if length(buffers)+length(sampled_images) > 0 %} static constexpr std::array kDescriptorSetLayouts{ {% for buffer in buffers %} DescriptorSetLayout{ @@ -171,7 +170,6 @@ std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} }, {% endfor %} }; -{% endif %} }; // struct {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index 795f9962a7479..b650556ccccbb 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -14,10 +14,15 @@ #include "impeller/compiler/compiler_backend.h" #include "impeller/compiler/includer.h" #include "impeller/compiler/logger.h" +#include "impeller/compiler/types.h" namespace impeller { namespace compiler { +const uint32_t kFragBindingBase = 128; +const size_t kNumUniformKinds = + int(shaderc_uniform_kind::shaderc_uniform_kind_buffer) + 1; + static CompilerBackend CreateMSLCompiler(const spirv_cross::ParsedIR& ir, const SourceOptions& source_options) { auto sl_compiler = std::make_shared(ir); @@ -223,6 +228,15 @@ static void SetLimitations(shaderc::CompileOptions& compiler_opts) { } } +void Compiler::SetBindingBase(shaderc::CompileOptions& compiler_opts) const { + for (size_t uniform_kind = 0; uniform_kind < kNumUniformKinds; + uniform_kind++) { + compiler_opts.SetBindingBaseForStage( + ToShaderCShaderKind(SourceType::kFragmentShader), + static_cast(uniform_kind), kFragBindingBase); + } +} + Compiler::Compiler(const fml::Mapping& source_mapping, SourceOptions source_options, Reflector::Options reflector_options) @@ -333,6 +347,9 @@ Compiler::Compiler(const fml::Mapping& source_mapping, } spirv_options.SetAutoBindUniforms(true); +#ifdef IMPELLER_ENABLE_VULKAN + SetBindingBase(spirv_options); +#endif spirv_options.SetAutoMapLocations(true); std::vector included_file_names; diff --git a/impeller/compiler/compiler.h b/impeller/compiler/compiler.h index 9dd3d901c3dde..379f610fd2286 100644 --- a/impeller/compiler/compiler.h +++ b/impeller/compiler/compiler.h @@ -57,6 +57,8 @@ class Compiler { std::string GetDependencyNames(std::string separator) const; + void SetBindingBase(shaderc::CompileOptions& compiler_opts) const; + FML_DISALLOW_COPY_AND_ASSIGN(Compiler); }; diff --git a/impeller/compiler/compiler_test.cc b/impeller/compiler/compiler_test.cc index 79285051f1f81..1e7efe0f1f883 100644 --- a/impeller/compiler/compiler_test.cc +++ b/impeller/compiler/compiler_test.cc @@ -89,6 +89,13 @@ bool CompilerTest::ValidateDepfileEscaped(const char* fixture_name) const { return true; } +std::unique_ptr CompilerTest::GetReflectionJson( + const char* fixture_name) const { + auto filename = ReflectionJSONName(fixture_name); + auto fd = fml::OpenFileReadOnly(intermediates_directory_, filename.c_str()); + return fml::FileMapping::CreateReadOnly(fd); +} + bool CompilerTest::CanCompileAndReflect(const char* fixture_name, SourceType source_type) const { auto fixture = flutter::testing::OpenFixtureAsMapping(fixture_name); diff --git a/impeller/compiler/compiler_test.h b/impeller/compiler/compiler_test.h index be9504de15dac..d9dfdba92856f 100644 --- a/impeller/compiler/compiler_test.h +++ b/impeller/compiler/compiler_test.h @@ -21,6 +21,9 @@ class CompilerTest : public ::testing::TestWithParam { ~CompilerTest(); + std::unique_ptr GetReflectionJson( + const char* fixture_name) const; + bool CanCompileAndReflect( const char* fixture_name, SourceType source_type = SourceType::kUnknown) const; diff --git a/impeller/compiler/compiler_unittests.cc b/impeller/compiler/compiler_unittests.cc index 68084d62d35ca..9c69da2bae1af 100644 --- a/impeller/compiler/compiler_unittests.cc +++ b/impeller/compiler/compiler_unittests.cc @@ -70,6 +70,31 @@ TEST_P(CompilerTest, ShaderWithSpecialCharactersHasEscapedDepfile) { ASSERT_TRUE(ValidateDepfileEscaped("sa\%m#ple.vert")); } +TEST_P(CompilerTest, BindingBaseForFragShader) { + if (GetParam() == TargetPlatform::kFlutterSPIRV) { + // This is a failure of reflection which this target doesn't perform. + GTEST_SKIP(); + } + +#ifndef IMPELLER_ENABLE_VULKAN + GTEST_SKIP(); +#endif + + ASSERT_TRUE(CanCompileAndReflect("sample.vert", SourceType::kVertexShader)); + ASSERT_TRUE(CanCompileAndReflect("sample.frag", SourceType::kFragmentShader)); + + auto get_binding = [&](const char* fixture) -> uint32_t { + auto json_fd = GetReflectionJson(fixture); + nlohmann::json shader_json = nlohmann::json::parse(json_fd->GetMapping()); + return shader_json["buffers"][0]["binding"].get(); + }; + + auto vert_uniform_binding = get_binding("sample.vert"); + auto frag_uniform_binding = get_binding("sample.frag"); + + ASSERT_GT(frag_uniform_binding, vert_uniform_binding); +} + #define INSTANTIATE_TARGET_PLATFORM_TEST_SUITE_P(suite_name) \ INSTANTIATE_TEST_SUITE_P( \ suite_name, CompilerTest, \ diff --git a/impeller/fixtures/BUILD.gn b/impeller/fixtures/BUILD.gn index 88a828942649a..0c6a3ae73c04d 100644 --- a/impeller/fixtures/BUILD.gn +++ b/impeller/fixtures/BUILD.gn @@ -44,6 +44,7 @@ test_fixtures("file_fixtures") { "kalimba.jpg", "resources_limit.vert", "sample.comp", + "sample.frag", "sample.tesc", "sample.tese", "sample.vert", diff --git a/impeller/fixtures/sample.frag b/impeller/fixtures/sample.frag new file mode 100644 index 0000000000000..5d9c83604dd68 --- /dev/null +++ b/impeller/fixtures/sample.frag @@ -0,0 +1,14 @@ +// 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. + +uniform FragInfo { + vec4 color; +} +frag_info; + +out vec4 frag_color; + +void main() { + frag_color = frag_info.color; +} diff --git a/impeller/renderer/pipeline_builder.h b/impeller/renderer/pipeline_builder.h index 92def4e50b7ea..e583b88300c8b 100644 --- a/impeller/renderer/pipeline_builder.h +++ b/impeller/renderer/pipeline_builder.h @@ -100,6 +100,15 @@ struct PipelineBuilder { << VertexShader::kLabel << "'."; return false; } + + if (!vertex_descriptor->SetDescriptorSetLayouts( + FragmentShader::kDescriptorSetLayouts)) { + VALIDATION_LOG << "Cound not configure vertex descriptor set layout for" + " pipeline named '" + << VertexShader::kLabel << "'."; + return false; + } + desc.SetVertexDescriptor(std::move(vertex_descriptor)); } From 3747cf318c58b3e6c97d5690e4c8fffd70d33e21 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Thu, 11 Aug 2022 17:17:38 -0700 Subject: [PATCH 280/558] [Windows] Support native functions in test fixtures (#35357) Adds the ability to register native functions for use in test fixtures. This allows registering native C++ functions that can be invoked from Dart code to perform the following common actions: * Signal a waiting latch in the C++ part of the test. * Pass data back to the C++ part of the test. * Allow the C++ part of the test to pass data to the test. Fixes: https://github.com/flutter/flutter/issues/109242 Fixes: https://github.com/flutter/flutter/issues/87299 --- shell/platform/windows/BUILD.gn | 2 + shell/platform/windows/fixtures/main.dart | 27 ++++- .../windows/flutter_windows_engine.cc | 6 ++ .../platform/windows/flutter_windows_engine.h | 17 +++ .../windows/flutter_windows_unittests.cc | 101 ++++++++++++++---- .../testing/windows_test_config_builder.cc | 7 ++ .../windows/testing/windows_test_context.cc | 24 ++++- .../windows/testing/windows_test_context.h | 17 +++ 8 files changed, 177 insertions(+), 24 deletions(-) diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index d2df59b2cf740..194e17f1f1e6d 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -225,6 +225,8 @@ executable("flutter_windows_unittests") { "//flutter/shell/platform/embedder:embedder_as_internal_library", "//flutter/shell/platform/embedder:embedder_test_utils", "//flutter/testing", + "//flutter/testing:dart", + "//flutter/third_party/tonic", "//third_party/rapidjson", ] } diff --git a/shell/platform/windows/fixtures/main.dart b/shell/platform/windows/fixtures/main.dart index 219c83e8eb6d5..2799c2f47ecf5 100644 --- a/shell/platform/windows/fixtures/main.dart +++ b/shell/platform/windows/fixtures/main.dart @@ -2,11 +2,34 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Signals a waiting latch in the native test. +void signal() native 'Signal'; + +// Signals a waiting latch in the native test, passing a boolean value. +void signalBoolValue(bool value) native 'SignalBoolValue'; + +// Signals a waiting latch in the native test, which returns a value to the fixture. +bool signalBoolReturn() native 'SignalBoolReturn'; + void main() { - print('Hello windows engine test main!'); } @pragma('vm:entry-point') void customEntrypoint() { - print('Hello windows engine test customEntrypoint!'); +} + +@pragma('vm:entry-point') +void verifyNativeFunction() { + signal(); +} + +@pragma('vm:entry-point') +void verifyNativeFunctionWithParameters() { + signalBoolValue(true); +} + +@pragma('vm:entry-point') +void verifyNativeFunctionWithReturn() { + bool value = signalBoolReturn(); + signalBoolValue(value); } diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index a0358bb6090d8..54d68f232885b 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -319,6 +319,12 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { host->accessibility_bridge_->AddFlutterSemanticsCustomActionUpdate( action); }; + args.root_isolate_create_callback = [](void* user_data) { + auto host = static_cast(user_data); + if (host->root_isolate_create_callback_) { + host->root_isolate_create_callback_(); + } + }; args.custom_task_runners = &custom_task_runners; diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index 1512870a4e710..c3c0d6109d922 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -13,6 +13,7 @@ #include #include +#include "flutter/fml/closure.h" #include "flutter/shell/platform/common/accessibility_bridge.h" #include "flutter/shell/platform/common/client_wrapper/binary_messenger_impl.h" #include "flutter/shell/platform/common/client_wrapper/include/flutter/basic_message_channel.h" @@ -203,6 +204,19 @@ class FlutterWindowsEngine { // Returns the native accessibility node with the given id. gfx::NativeViewAccessible GetNativeAccessibleFromId(AccessibilityNodeId id); + // Register a root isolate create callback. + // + // The root isolate create callback is invoked at creation of the root Dart + // isolate in the app. This may be used to be notified that execution of the + // main Dart entrypoint is about to begin, and is used by test infrastructure + // to register a native function resolver that can register and resolve + // functions marked as native in the Dart code. + // + // This must be called before calling |Run|. + void SetRootIsolateCreateCallback(const fml::closure& callback) { + root_isolate_create_callback_ = callback; + } + private: // Allows swapping out embedder_api_ calls in tests. friend class EngineModifier; @@ -277,6 +291,9 @@ class FlutterWindowsEngine { // The manager for WindowProc delegate registration and callbacks. std::unique_ptr window_proc_delegate_manager_; + + // The root isolate creation callback. + fml::closure root_isolate_create_callback_; }; } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index ff3d00d0e6fb1..4479e4cd02617 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -6,14 +6,19 @@ #include +#include "flutter/fml/synchronization/count_down_latch.h" +#include "flutter/fml/synchronization/waitable_event.h" #include "flutter/shell/platform/windows/testing/windows_test.h" #include "flutter/shell/platform/windows/testing/windows_test_config_builder.h" #include "flutter/shell/platform/windows/testing/windows_test_context.h" #include "gtest/gtest.h" +#include "third_party/tonic/converter/dart_converter.h" namespace flutter { namespace testing { +// Verify that we can fetch a texture registrar. +// Prevent regression: https://github.com/flutter/flutter/issues/86617 TEST(WindowsNoFixtureTest, GetTextureRegistrar) { FlutterDesktopEngineProperties properties = {}; properties.assets_path = L""; @@ -25,33 +30,21 @@ TEST(WindowsNoFixtureTest, GetTextureRegistrar) { FlutterDesktopEngineDestroy(engine); } +// Verify we can successfully launch main(). TEST_F(WindowsTest, LaunchMain) { auto& context = GetContext(); WindowsConfigBuilder builder(context); ViewControllerPtr controller{builder.Run()}; ASSERT_NE(controller, nullptr); - - // Run for 1 second, then shut down. - // - // TODO(cbracken): Support registring a native function we can use to - // determine that execution has made it to a specific point in the Dart - // code. https://github.com/flutter/flutter/issues/109242 - std::this_thread::sleep_for(std::chrono::seconds(1)); } +// Verify we can successfully launch a custom entry point. TEST_F(WindowsTest, LaunchCustomEntrypoint) { auto& context = GetContext(); WindowsConfigBuilder builder(context); builder.SetDartEntrypoint("customEntrypoint"); ViewControllerPtr controller{builder.Run()}; ASSERT_NE(controller, nullptr); - - // Run for 1 second, then shut down. - // - // TODO(cbracken): Support registring a native function we can use to - // determine that execution has made it to a specific point in the Dart - // code. https://github.com/flutter/flutter/issues/109242 - std::this_thread::sleep_for(std::chrono::seconds(1)); } // Verify that engine launches with the custom entrypoint specified in the @@ -66,13 +59,6 @@ TEST_F(WindowsTest, LaunchCustomEntrypointInEngineRunInvocation) { ASSERT_NE(engine, nullptr); ASSERT_TRUE(FlutterDesktopEngineRun(engine.get(), "customEntrypoint")); - - // Run for 1 second, then shut down. - // - // TODO(cbracken): Support registring a native function we can use to - // determine that execution has made it to a specific point in the Dart - // code. https://github.com/flutter/flutter/issues/109242 - std::this_thread::sleep_for(std::chrono::seconds(1)); } // Verify that engine fails to launch when a conflicting entrypoint in @@ -90,5 +76,78 @@ TEST_F(WindowsTest, LaunchConflictingCustomEntrypoints) { ASSERT_FALSE(FlutterDesktopEngineRun(engine.get(), "conflictingEntrypoint")); } +// Verify that native functions can be registered and resolved. +TEST_F(WindowsTest, VerifyNativeFunction) { + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + builder.SetDartEntrypoint("verifyNativeFunction"); + + fml::AutoResetWaitableEvent latch; + auto native_entry = + CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { latch.Signal(); }); + context.AddNativeFunction("Signal", native_entry); + + ViewControllerPtr controller{builder.Run()}; + ASSERT_NE(controller, nullptr); + + // Wait until signal has been called. + latch.Wait(); +} + +// Verify that native functions that pass parameters can be registered and +// resolved. +TEST_F(WindowsTest, VerifyNativeFunctionWithParameters) { + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + builder.SetDartEntrypoint("verifyNativeFunctionWithParameters"); + + bool bool_value = false; + fml::AutoResetWaitableEvent latch; + auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + auto handle = Dart_GetNativeBooleanArgument(args, 0, &bool_value); + ASSERT_FALSE(Dart_IsError(handle)); + latch.Signal(); + }); + context.AddNativeFunction("SignalBoolValue", native_entry); + + ViewControllerPtr controller{builder.Run()}; + ASSERT_NE(controller, nullptr); + + // Wait until signalBoolValue has been called. + latch.Wait(); + EXPECT_TRUE(bool_value); +} + +// Verify that native functions that return values can be registered and +// resolved. +TEST_F(WindowsTest, VerifyNativeFunctionWithReturn) { + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + builder.SetDartEntrypoint("verifyNativeFunctionWithReturn"); + + bool bool_value_to_return = true; + fml::CountDownLatch latch(2); + auto bool_return_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + Dart_SetBooleanReturnValue(args, bool_value_to_return); + latch.CountDown(); + }); + context.AddNativeFunction("SignalBoolReturn", bool_return_entry); + + bool bool_value_passed = false; + auto bool_pass_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + auto handle = Dart_GetNativeBooleanArgument(args, 0, &bool_value_passed); + ASSERT_FALSE(Dart_IsError(handle)); + latch.CountDown(); + }); + context.AddNativeFunction("SignalBoolValue", bool_pass_entry); + + ViewControllerPtr controller{builder.Run()}; + ASSERT_NE(controller, nullptr); + + // Wait until signalBoolReturn and signalBoolValue have been called. + latch.Wait(); + EXPECT_TRUE(bool_value_passed); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/testing/windows_test_config_builder.cc b/shell/platform/windows/testing/windows_test_config_builder.cc index c3c2d0ecf9680..35376e241f062 100644 --- a/shell/platform/windows/testing/windows_test_config_builder.cc +++ b/shell/platform/windows/testing/windows_test_config_builder.cc @@ -11,6 +11,7 @@ #include #include "flutter/fml/logging.h" +#include "flutter/shell/platform/windows/flutter_windows_engine.h" #include "flutter/shell/platform/windows/public/flutter_windows.h" #include "flutter/shell/platform/windows/testing/windows_test_context.h" @@ -78,6 +79,12 @@ ViewControllerPtr WindowsConfigBuilder::Run() const { return {}; } + // Register native functions. + FlutterWindowsEngine* windows_engine = + reinterpret_cast(engine.get()); + windows_engine->SetRootIsolateCreateCallback( + context_.GetRootIsolateCallback()); + int width = 600; int height = 400; ViewControllerPtr controller( diff --git a/shell/platform/windows/testing/windows_test_context.cc b/shell/platform/windows/testing/windows_test_context.cc index 42da7c1651341..87ba928fbbe74 100644 --- a/shell/platform/windows/testing/windows_test_context.cc +++ b/shell/platform/windows/testing/windows_test_context.cc @@ -10,7 +10,16 @@ namespace flutter { namespace testing { WindowsTestContext::WindowsTestContext(std::string_view assets_path) - : assets_path_(fml::Utf8ToWideString(assets_path)) {} + : assets_path_(fml::Utf8ToWideString(assets_path)), + native_resolver_(std::make_shared()) { + isolate_create_callbacks_.push_back( + [weak_resolver = + std::weak_ptr{native_resolver_}]() { + if (auto resolver = weak_resolver.lock()) { + resolver->SetNativeResolverForIsolate(); + } + }); +} WindowsTestContext::~WindowsTestContext() = default; @@ -22,5 +31,18 @@ const std::wstring& WindowsTestContext::GetIcuDataPath() const { return icu_data_path_; } +void WindowsTestContext::AddNativeFunction(std::string_view name, + Dart_NativeFunction function) { + native_resolver_->AddNativeCallback(std::string{name}, function); +} + +fml::closure WindowsTestContext::GetRootIsolateCallback() { + return [this]() { + for (auto closure : this->isolate_create_callbacks_) { + closure(); + } + }; +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/testing/windows_test_context.h b/shell/platform/windows/testing/windows_test_context.h index 30673f1ca5d3e..813aa44126623 100644 --- a/shell/platform/windows/testing/windows_test_context.h +++ b/shell/platform/windows/testing/windows_test_context.h @@ -7,8 +7,11 @@ #include #include +#include +#include "flutter/fml/closure.h" #include "flutter/fml/macros.h" +#include "flutter/testing/test_dart_native_resolver.h" namespace flutter { namespace testing { @@ -29,9 +32,23 @@ class WindowsTestContext { // Returns the path to the ICU library data file. const std::wstring& GetIcuDataPath() const; + // Registers a native function callable from Dart code in test fixtures. In + // the Dart test fixture, the associated function can be declared as: + // + // ReturnType functionName() native 'IdentifyingName'; + // + // where `IdentifyingName` matches the |name| parameter to this method. + void AddNativeFunction(std::string_view name, Dart_NativeFunction function); + + // Returns the root isolate create callback to register with the Flutter + // runtime. + fml::closure GetRootIsolateCallback(); + private: std::wstring assets_path_; std::wstring icu_data_path_ = L"icudtl.dat"; + std::vector isolate_create_callbacks_; + std::shared_ptr native_resolver_; FML_DISALLOW_COPY_AND_ASSIGN(WindowsTestContext); }; From d980252d271a214a50373cd8215c72e22945b521 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Thu, 11 Aug 2022 17:20:05 -0700 Subject: [PATCH 281/558] [Impeller] [vulkan] Add support for wrapped surfaces (#35359) --- .../backend/vulkan/playground_impl_vk.cc | 8 +-- .../backend/vulkan/playground_impl_vk.h | 3 -- .../renderer/backend/vulkan/allocator_vk.cc | 13 ++++- .../renderer/backend/vulkan/context_vk.cc | 24 ++++----- impeller/renderer/backend/vulkan/context_vk.h | 3 +- .../backend/vulkan/surface_producer_vk.cc | 18 +++++-- .../backend/vulkan/surface_producer_vk.h | 6 ++- .../renderer/backend/vulkan/surface_vk.cc | 29 ++++++++--- impeller/renderer/backend/vulkan/surface_vk.h | 1 + .../renderer/backend/vulkan/swapchain_vk.cc | 4 ++ .../renderer/backend/vulkan/swapchain_vk.h | 2 + .../renderer/backend/vulkan/texture_vk.cc | 49 +++++++++++++------ impeller/renderer/backend/vulkan/texture_vk.h | 43 ++++++++++++---- 13 files changed, 144 insertions(+), 59 deletions(-) diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index 958f5f2531e19..f154f5326fd23 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -85,9 +85,11 @@ PlaygroundImplVK::PlaygroundImplVK() void PlaygroundImplVK::SetupSwapchain() { ContextVK* context_vk = reinterpret_cast(context_.get()); auto window = reinterpret_cast(handle_.get()); - ::glfwCreateWindowSurface(context_vk->GetInstance(), window, nullptr, - &surface_); - context_vk->SetupSwapchain(surface_); + vk::Instance instance = context_vk->GetInstance(); + VkSurfaceKHR surface_tmp; + ::glfwCreateWindowSurface(instance, window, nullptr, &surface_tmp); + vk::UniqueSurfaceKHR surface{surface_tmp, instance}; + context_vk->SetupSwapchain(std::move(surface)); } PlaygroundImplVK::~PlaygroundImplVK() = default; diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.h b/impeller/playground/backend/vulkan/playground_impl_vk.h index 693bc387636e3..ec5d6c6421d53 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.h +++ b/impeller/playground/backend/vulkan/playground_impl_vk.h @@ -27,9 +27,6 @@ class PlaygroundImplVK final : public PlaygroundImpl { using UniqueHandle = std::unique_ptr; UniqueHandle handle_; - // surface - VkSurfaceKHR surface_; - // |PlaygroundImpl| std::shared_ptr GetContext() const override; diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index ade9dd215fbf3..0d6304c3eebdb 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -102,8 +102,17 @@ std::shared_ptr AllocatorVK::CreateTexture( return nullptr; } - return std::make_shared(desc, context_, allocator_, img, - allocation, allocation_info); + auto texture_info = std::make_unique(TextureInfoVK{ + .backing_type = TextureBackingTypeVK::kAllocatedTexture, + .allocated_texture = + { + .allocator = &allocator_, + .allocation = allocation, + .allocation_info = allocation_info, + .image = img, + }, + }); + return std::make_shared(desc, &context_, std::move(texture_info)); } // |Allocator| diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 27a15e293222e..6c3c0b3e0eac9 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -469,8 +469,9 @@ vk::Instance ContextVK::GetInstance() const { return *instance_; } -void ContextVK::SetupSwapchain(vk::SurfaceKHR surface) { - auto present_queue_out = PickPresentQueue(physical_device_, surface); +void ContextVK::SetupSwapchain(vk::UniqueSurfaceKHR surface) { + surface_ = std::move(surface); + auto present_queue_out = PickPresentQueue(physical_device_, *surface); if (!present_queue_out.has_value()) { return; } @@ -478,18 +479,19 @@ void ContextVK::SetupSwapchain(vk::SurfaceKHR surface) { device_->getQueue(present_queue_out->family, present_queue_out->index); auto swapchain_details = - SwapchainDetailsVK::Create(physical_device_, surface); + SwapchainDetailsVK::Create(physical_device_, *surface); if (!swapchain_details) { return; } - swapchain_ = SwapchainVK::Create(*device_, surface, *swapchain_details); - - surface_producer_ = SurfaceProducerVK::Create({ - .device = *device_, - .graphics_queue = graphics_queue_, - .present_queue = present_queue_, - .swapchain = swapchain_.get(), - }); + swapchain_ = SwapchainVK::Create(*device_, *surface, *swapchain_details); + auto weak_this = weak_from_this(); + surface_producer_ = SurfaceProducerVK::Create( + weak_this, { + .device = *device_, + .graphics_queue = graphics_queue_, + .present_queue = present_queue_, + .swapchain = swapchain_.get(), + }); } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index eadc810d44d36..1741c6782743f 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -59,7 +59,7 @@ class ContextVK final : public Context, public BackendCast { vk::Instance GetInstance() const; - void SetupSwapchain(vk::SurfaceKHR surface); + void SetupSwapchain(vk::UniqueSurfaceKHR surface); private: std::shared_ptr worker_task_runner_; @@ -75,6 +75,7 @@ class ContextVK final : public Context, public BackendCast { vk::Queue compute_queue_; vk::Queue transfer_queue_; vk::Queue present_queue_; + vk::UniqueSurfaceKHR surface_; std::unique_ptr swapchain_; std::unique_ptr graphics_command_pool_; std::unique_ptr surface_producer_; diff --git a/impeller/renderer/backend/vulkan/surface_producer_vk.cc b/impeller/renderer/backend/vulkan/surface_producer_vk.cc index d43d9dee66faa..d0fad4b56ca94 100644 --- a/impeller/renderer/backend/vulkan/surface_producer_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_producer_vk.cc @@ -12,8 +12,10 @@ namespace impeller { std::unique_ptr SurfaceProducerVK::Create( + std::weak_ptr context, const SurfaceProducerCreateInfoVK& create_info) { - auto surface_producer = std::make_unique(create_info); + auto surface_producer = + std::make_unique(context, create_info); if (!surface_producer->SetupSyncObjects()) { FML_LOG(ERROR) << "Failed to setup sync objects."; return nullptr; @@ -23,8 +25,9 @@ std::unique_ptr SurfaceProducerVK::Create( } SurfaceProducerVK::SurfaceProducerVK( + std::weak_ptr context, const SurfaceProducerCreateInfoVK& create_info) - : create_info_(create_info) {} + : context_(context), create_info_(create_info) {} SurfaceProducerVK::~SurfaceProducerVK() = default; @@ -63,9 +66,14 @@ std::unique_ptr SurfaceProducerVK::AcquireSurface( return Present(image_index); }; - return SurfaceVK::WrapSwapchainImage( - create_info_.swapchain->GetSwapchainImage(image_index), - std::move(swap_callback)); + if (auto context = context_.lock()) { + ContextVK* context_vk = reinterpret_cast(context.get()); + return SurfaceVK::WrapSwapchainImage( + create_info_.swapchain->GetSwapchainImage(image_index), context_vk, + std::move(swap_callback)); + } else { + return nullptr; + } } bool SurfaceProducerVK::SetupSyncObjects() { diff --git a/impeller/renderer/backend/vulkan/surface_producer_vk.h b/impeller/renderer/backend/vulkan/surface_producer_vk.h index 96ae70d17adb1..6d3ed2e116b97 100644 --- a/impeller/renderer/backend/vulkan/surface_producer_vk.h +++ b/impeller/renderer/backend/vulkan/surface_producer_vk.h @@ -23,15 +23,19 @@ struct SurfaceProducerCreateInfoVK { class SurfaceProducerVK { public: static std::unique_ptr Create( + std::weak_ptr context, const SurfaceProducerCreateInfoVK& create_info); - explicit SurfaceProducerVK(const SurfaceProducerCreateInfoVK& create_info); + SurfaceProducerVK(std::weak_ptr context, + const SurfaceProducerCreateInfoVK& create_info); ~SurfaceProducerVK(); std::unique_ptr AcquireSurface(vk::CommandBuffer command_buffer); private: + std::weak_ptr context_; + bool SetupSyncObjects(); bool Submit(vk::CommandBuffer buffer); diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/surface_vk.cc index b3c766d36dc3d..f87a36aeb9ed8 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_vk.cc @@ -4,9 +4,12 @@ #include "impeller/renderer/backend/vulkan/surface_vk.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" + namespace impeller { std::unique_ptr SurfaceVK::WrapSwapchainImage( SwapchainImageVK* swapchain_image, + ContextVK* context, SwapCallback swap_callback) { if (!swapchain_image) { return nullptr; @@ -20,10 +23,15 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( color0_tex.sample_count = SampleCount::kCount1; ColorAttachment color0; - // TODO (kaushikiska): this needs to be fixed. - // color0.texture = std::make_shared( - // gl_context.GetReactor(), std::move(color0_tex), - // TextureGLES::IsWrapped::kWrapped); + auto color_texture_info = std::make_unique(TextureInfoVK{ + .backing_type = TextureBackingTypeVK::kWrappedTexture, + .wrapped_texture = + { + .swapchain_image = swapchain_image, + }, + }); + color0.texture = std::make_shared(std::move(color0_tex), context, + std::move(color_texture_info)); color0.clear_color = Color::DarkSlateGray(); color0.load_action = LoadAction::kClear; color0.store_action = StoreAction::kStore; @@ -38,10 +46,15 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( StencilAttachment stencil0; stencil0.clear_stencil = 0; - // TODO (kaushikiska): this needs to be fixed. - // stencil0.texture = std::make_shared( - // gl_context.GetReactor(), std::move(stencil0_tex), - // TextureGLES::IsWrapped::kWrapped); + auto stencil_texture_info = std::make_unique(TextureInfoVK{ + .backing_type = TextureBackingTypeVK::kWrappedTexture, + .wrapped_texture = + { + .swapchain_image = swapchain_image, + }, + }); + stencil0.texture = std::make_shared( + std::move(stencil0_tex), context, std::move(stencil_texture_info)); stencil0.load_action = LoadAction::kClear; stencil0.store_action = StoreAction::kDontCare; diff --git a/impeller/renderer/backend/vulkan/surface_vk.h b/impeller/renderer/backend/vulkan/surface_vk.h index 2e9403dd0cb73..ac6797e6afa02 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.h +++ b/impeller/renderer/backend/vulkan/surface_vk.h @@ -19,6 +19,7 @@ class SurfaceVK final : public Surface { static std::unique_ptr WrapSwapchainImage( SwapchainImageVK* swapchain_image, + ContextVK* context, SwapCallback swap_callback); SurfaceVK(RenderTarget target, diff --git a/impeller/renderer/backend/vulkan/swapchain_vk.cc b/impeller/renderer/backend/vulkan/swapchain_vk.cc index b57cfee1ec906..df88759c745de 100644 --- a/impeller/renderer/backend/vulkan/swapchain_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain_vk.cc @@ -138,6 +138,10 @@ ISize SwapchainImageVK::GetSize() const { return ISize(extent_.width, extent_.height); } +vk::Image SwapchainImageVK::GetImage() const { + return image_; +} + SwapchainImageVK::~SwapchainImageVK() = default; } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/swapchain_vk.h b/impeller/renderer/backend/vulkan/swapchain_vk.h index 265eaf9fde5c1..c57a8800d073b 100644 --- a/impeller/renderer/backend/vulkan/swapchain_vk.h +++ b/impeller/renderer/backend/vulkan/swapchain_vk.h @@ -26,6 +26,8 @@ class SwapchainImageVK { ISize GetSize() const; + vk::Image GetImage() const; + private: vk::Image image_; vk::UniqueImageView image_view_; diff --git a/impeller/renderer/backend/vulkan/texture_vk.cc b/impeller/renderer/backend/vulkan/texture_vk.cc index 8d4661166769c..9a6950ee7be2b 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_vk.cc @@ -7,32 +7,32 @@ namespace impeller { TextureVK::TextureVK(TextureDescriptor desc, - ContextVK& context, - const VmaAllocator& allocator, - VkImage image, - VmaAllocation allocation, - VmaAllocationInfo allocation_info) + ContextVK* context, + std::unique_ptr texture_info) : Texture(desc), context_(context), - allocator_(allocator), - image_(image), - allocation_(allocation), - allocation_info_(allocation_info) {} + texture_info_(std::move(texture_info)) {} TextureVK::~TextureVK() { - if (image_) { - vmaDestroyImage(allocator_, image_, allocation_); + if (!IsWrapped() && IsValid()) { + const auto& texture = texture_info_->allocated_texture; + vmaDestroyImage(*texture.allocator, texture.image, texture.allocation); } } void TextureVK::SetLabel(std::string_view label) { - context_.SetDebugName(vk::Image{image_}, label); + context_->SetDebugName(GetImage(), label); } bool TextureVK::OnSetContents(const uint8_t* contents, size_t length, size_t slice) { - if (!image_ || !contents) { + if (IsWrapped()) { + FML_LOG(ERROR) << "Cannot set contents of a wrapped texture"; + return false; + } + + if (!IsValid() || !contents) { return false; } @@ -45,7 +45,8 @@ bool TextureVK::OnSetContents(const uint8_t* contents, } // currently we are only supporting 2d textures, no cube textures etc. - memcpy(allocation_info_.pMappedData, contents, length); + auto mapping = texture_info_->allocated_texture.allocation_info.pMappedData; + memcpy(mapping, contents, length); return true; } @@ -58,11 +59,29 @@ bool TextureVK::OnSetContents(std::shared_ptr mapping, } bool TextureVK::IsValid() const { - return image_; + switch (texture_info_->backing_type) { + case TextureBackingTypeVK::kAllocatedTexture: + return texture_info_->allocated_texture.image; + case TextureBackingTypeVK::kWrappedTexture: + return texture_info_->wrapped_texture.swapchain_image; + } } ISize TextureVK::GetSize() const { return GetTextureDescriptor().size; } +bool TextureVK::IsWrapped() const { + return texture_info_->backing_type == TextureBackingTypeVK::kWrappedTexture; +} + +vk::Image TextureVK::GetImage() const { + switch (texture_info_->backing_type) { + case TextureBackingTypeVK::kAllocatedTexture: + return texture_info_->allocated_texture.image; + case TextureBackingTypeVK::kWrappedTexture: + return texture_info_->wrapped_texture.swapchain_image->GetImage(); + } +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/texture_vk.h b/impeller/renderer/backend/vulkan/texture_vk.h index 0bc53f7dc6c2d..e3e667c19564b 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.h +++ b/impeller/renderer/backend/vulkan/texture_vk.h @@ -7,29 +7,52 @@ #include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" #include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/swapchain_vk.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/texture.h" namespace impeller { +enum class TextureBackingTypeVK { + kAllocatedTexture, + kWrappedTexture, +}; + +struct WrappedTextureInfoVK { + SwapchainImageVK* swapchain_image = nullptr; +}; + +struct AllocatedTextureInfoVK { + VmaAllocator* allocator = nullptr; + VmaAllocation allocation = nullptr; + VmaAllocationInfo allocation_info = {}; + VkImage image = nullptr; +}; + +struct TextureInfoVK { + TextureBackingTypeVK backing_type; + union { + WrappedTextureInfoVK wrapped_texture; + AllocatedTextureInfoVK allocated_texture; + }; +}; + class TextureVK final : public Texture, public BackendCast { public: TextureVK(TextureDescriptor desc, - ContextVK& context, - const VmaAllocator& allocator, - VkImage image, - VmaAllocation allocation, - VmaAllocationInfo allocation_info); + ContextVK* context, + std::unique_ptr texture_info); // |Texture| ~TextureVK() override; + bool IsWrapped() const; + private: - ContextVK& context_; - const VmaAllocator& allocator_; - VkImage image_; - VmaAllocation allocation_; - VmaAllocationInfo allocation_info_; + ContextVK* context_; + std::unique_ptr texture_info_; + + vk::Image GetImage() const; // |Texture| void SetLabel(std::string_view label) override; From 1ff6966f08beb499868ed7708a17331a769395f3 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Thu, 11 Aug 2022 17:27:07 -0700 Subject: [PATCH 282/558] [Impeller] Cleanup the build dependency graph. (#35360) --- ci/licenses_golden/licenses_flutter | 1 + impeller/renderer/BUILD.gn | 1 + impeller/renderer/shader_types.h | 18 +++++++ impeller/runtime_stage/BUILD.gn | 2 +- impeller/runtime_stage/runtime_stage.cc | 14 +++--- impeller/runtime_stage/runtime_stage.h | 41 ++------------- .../runtime_stage/runtime_stage_playground.cc | 4 +- .../runtime_stage/runtime_stage_unittests.cc | 9 ++-- impeller/runtime_stage/runtime_types.h | 50 +++++++++++++++++++ 9 files changed, 90 insertions(+), 50 deletions(-) create mode 100644 impeller/runtime_stage/runtime_types.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index a051333848cc4..a4657cb0b7e0f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -898,6 +898,7 @@ FILE: ../../../flutter/impeller/runtime_stage/runtime_stage.h FILE: ../../../flutter/impeller/runtime_stage/runtime_stage_playground.cc FILE: ../../../flutter/impeller/runtime_stage/runtime_stage_playground.h FILE: ../../../flutter/impeller/runtime_stage/runtime_stage_unittests.cc +FILE: ../../../flutter/impeller/runtime_stage/runtime_types.h FILE: ../../../flutter/impeller/tessellator/c/tessellator.cc FILE: ../../../flutter/impeller/tessellator/c/tessellator.h FILE: ../../../flutter/impeller/tessellator/dart/lib/tessellator.dart diff --git a/impeller/renderer/BUILD.gn b/impeller/renderer/BUILD.gn index 460502c838a61..f593a42fd144d 100644 --- a/impeller/renderer/BUILD.gn +++ b/impeller/renderer/BUILD.gn @@ -81,6 +81,7 @@ impeller_component("renderer") { "../base", "../geometry", "../image", + "../runtime_stage", "../tessellator", ] diff --git a/impeller/renderer/shader_types.h b/impeller/renderer/shader_types.h index 7750032b030e9..fe4af812f165a 100644 --- a/impeller/renderer/shader_types.h +++ b/impeller/renderer/shader_types.h @@ -9,7 +9,9 @@ #include #include "flutter/fml/hash_combine.h" +#include "flutter/fml/logging.h" #include "impeller/geometry/matrix.h" +#include "impeller/runtime_stage/runtime_types.h" namespace impeller { @@ -22,6 +24,22 @@ enum class ShaderStage { kCompute, }; +constexpr ShaderStage ToShaderStage(RuntimeShaderStage stage) { + switch (stage) { + case RuntimeShaderStage::kVertex: + return ShaderStage::kVertex; + case RuntimeShaderStage::kFragment: + return ShaderStage::kFragment; + case RuntimeShaderStage::kCompute: + return ShaderStage::kCompute; + case RuntimeShaderStage::kTessellationControl: + return ShaderStage::kTessellationControl; + case RuntimeShaderStage::kTessellationEvaluation: + return ShaderStage::kTessellationEvaluation; + } + FML_UNREACHABLE(); +} + enum class ShaderType { kUnknown, kVoid, diff --git a/impeller/runtime_stage/BUILD.gn b/impeller/runtime_stage/BUILD.gn index e0fe2502263ae..b36a7f9017c88 100644 --- a/impeller/runtime_stage/BUILD.gn +++ b/impeller/runtime_stage/BUILD.gn @@ -20,11 +20,11 @@ impeller_component("runtime_stage") { sources = [ "runtime_stage.cc", "runtime_stage.h", + "runtime_types.h", ] public_deps = [ ":runtime_stage_flatbuffers", "../base", - "../renderer", "//flutter/fml", ] } diff --git a/impeller/runtime_stage/runtime_stage.cc b/impeller/runtime_stage/runtime_stage.cc index 353287d6a0caf..c75f33b425730 100644 --- a/impeller/runtime_stage/runtime_stage.cc +++ b/impeller/runtime_stage/runtime_stage.cc @@ -43,18 +43,18 @@ static RuntimeUniformType ToType(fb::UniformDataType type) { FML_UNREACHABLE(); } -static ShaderStage ToShaderStage(fb::Stage stage) { +static RuntimeShaderStage ToShaderStage(fb::Stage stage) { switch (stage) { case fb::Stage::kVertex: - return ShaderStage::kVertex; + return RuntimeShaderStage::kVertex; case fb::Stage::kFragment: - return ShaderStage::kFragment; + return RuntimeShaderStage::kFragment; case fb::Stage::kCompute: - return ShaderStage::kCompute; + return RuntimeShaderStage::kCompute; case fb::Stage::kTessellationControl: - return ShaderStage::kTessellationControl; + return RuntimeShaderStage::kTessellationControl; case fb::Stage::kTessellationEvaluation: - return ShaderStage::kTessellationEvaluation; + return RuntimeShaderStage::kTessellationEvaluation; } FML_UNREACHABLE(); } @@ -128,7 +128,7 @@ const std::string& RuntimeStage::GetEntrypoint() const { return entrypoint_; } -ShaderStage RuntimeStage::GetShaderStage() const { +RuntimeShaderStage RuntimeStage::GetShaderStage() const { return stage_; } diff --git a/impeller/runtime_stage/runtime_stage.h b/impeller/runtime_stage/runtime_stage.h index 2bbcf83d372fc..fcf5d529d9bf5 100644 --- a/impeller/runtime_stage/runtime_stage.h +++ b/impeller/runtime_stage/runtime_stage.h @@ -9,52 +9,19 @@ #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" -#include "impeller/renderer/shader_function.h" -#include "impeller/renderer/shader_types.h" +#include "impeller/runtime_stage/runtime_types.h" namespace impeller { -enum RuntimeUniformType { - kBoolean, - kSignedByte, - kUnsignedByte, - kSignedShort, - kUnsignedShort, - kSignedInt, - kUnsignedInt, - kSignedInt64, - kUnsignedInt64, - kHalfFloat, - kFloat, - kDouble, - kSampledImage, -}; - -struct RuntimeUniformDimensions { - size_t rows = 0; - size_t cols = 0; -}; - -struct RuntimeUniformDescription { - std::string name; - size_t location = 0u; - RuntimeUniformType type = kFloat; - RuntimeUniformDimensions dimensions; - size_t bit_width; - size_t array_elements; -}; - -size_t SizeOfRuntimeUniformType(RuntimeUniformType type); - class RuntimeStage { public: - RuntimeStage(std::shared_ptr payload); + explicit RuntimeStage(std::shared_ptr payload); ~RuntimeStage(); bool IsValid() const; - ShaderStage GetShaderStage() const; + RuntimeShaderStage GetShaderStage() const; const std::vector& GetUniforms() const; @@ -65,7 +32,7 @@ class RuntimeStage { const std::shared_ptr& GetCodeMapping() const; private: - ShaderStage stage_ = ShaderStage::kUnknown; + RuntimeShaderStage stage_ = RuntimeShaderStage::kVertex; std::shared_ptr payload_; std::string entrypoint_; std::shared_ptr code_mapping_; diff --git a/impeller/runtime_stage/runtime_stage_playground.cc b/impeller/runtime_stage/runtime_stage_playground.cc index af1dc536cf349..096030843315a 100644 --- a/impeller/runtime_stage/runtime_stage_playground.cc +++ b/impeller/runtime_stage/runtime_stage_playground.cc @@ -9,6 +9,7 @@ #include "flutter/fml/make_copyable.h" #include "flutter/testing/testing.h" #include "impeller/renderer/shader_library.h" +#include "impeller/renderer/shader_types.h" namespace impeller { @@ -34,7 +35,8 @@ bool RuntimeStagePlayground::RegisterStage(const RuntimeStage& stage) { auto future = registration.get_future(); auto library = GetContext()->GetShaderLibrary(); GetContext()->GetShaderLibrary()->RegisterFunction( - stage.GetEntrypoint(), stage.GetShaderStage(), stage.GetCodeMapping(), + stage.GetEntrypoint(), ToShaderStage(stage.GetShaderStage()), + stage.GetCodeMapping(), fml::MakeCopyable([reg = std::move(registration)](bool result) mutable { reg.set_value(result); })); diff --git a/impeller/runtime_stage/runtime_stage_unittests.cc b/impeller/runtime_stage/runtime_stage_unittests.cc index 66e3a83da6fb8..108d59d0742e5 100644 --- a/impeller/runtime_stage/runtime_stage_unittests.cc +++ b/impeller/runtime_stage/runtime_stage_unittests.cc @@ -13,6 +13,7 @@ #include "impeller/renderer/pipeline_descriptor.h" #include "impeller/renderer/pipeline_library.h" #include "impeller/renderer/shader_library.h" +#include "impeller/renderer/shader_types.h" #include "impeller/runtime_stage/runtime_stage.h" #include "impeller/runtime_stage/runtime_stage_playground.h" @@ -29,7 +30,7 @@ TEST(RuntimeStageTest, CanReadValidBlob) { ASSERT_GT(fixture->GetSize(), 0u); RuntimeStage stage(std::move(fixture)); ASSERT_TRUE(stage.IsValid()); - ASSERT_EQ(stage.GetShaderStage(), ShaderStage::kFragment); + ASSERT_EQ(stage.GetShaderStage(), RuntimeShaderStage::kFragment); } TEST(RuntimeStageTest, CanRejectInvalidBlob) { @@ -199,9 +200,9 @@ TEST_P(RuntimeStageTest, CanRegisterStage) { auto future = registration.get_future(); auto library = GetContext()->GetShaderLibrary(); library->RegisterFunction( - stage.GetEntrypoint(), // - stage.GetShaderStage(), // - stage.GetCodeMapping(), // + stage.GetEntrypoint(), // + ToShaderStage(stage.GetShaderStage()), // + stage.GetCodeMapping(), // fml::MakeCopyable([reg = std::move(registration)](bool result) mutable { reg.set_value(result); })); diff --git a/impeller/runtime_stage/runtime_types.h b/impeller/runtime_stage/runtime_types.h new file mode 100644 index 0000000000000..7b3f06b0504bf --- /dev/null +++ b/impeller/runtime_stage/runtime_types.h @@ -0,0 +1,50 @@ +// 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 + +namespace impeller { + +enum RuntimeUniformType { + kBoolean, + kSignedByte, + kUnsignedByte, + kSignedShort, + kUnsignedShort, + kSignedInt, + kUnsignedInt, + kSignedInt64, + kUnsignedInt64, + kHalfFloat, + kFloat, + kDouble, + kSampledImage, +}; + +enum class RuntimeShaderStage { + kVertex, + kFragment, + kCompute, + kTessellationControl, + kTessellationEvaluation, +}; + +struct RuntimeUniformDimensions { + size_t rows = 0; + size_t cols = 0; +}; + +struct RuntimeUniformDescription { + std::string name; + size_t location = 0u; + RuntimeUniformType type = RuntimeUniformType::kFloat; + RuntimeUniformDimensions dimensions; + size_t bit_width; + size_t array_elements; +}; + +} // namespace impeller From bcecbae85ba1e29c5257c5e45de1c2f713664183 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Thu, 11 Aug 2022 17:51:11 -0700 Subject: [PATCH 283/558] [Impeller] Trivial nullptr de-reference fix (#35361) --- impeller/entity/entity_pass.cc | 5 +++++ impeller/entity/inline_pass_context.cc | 3 +++ 2 files changed, 8 insertions(+) diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 9d957c3686554..2a317b042fd58 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -365,6 +365,11 @@ bool EntityPass::OnRender(ContentContext& renderer, stencil_depth_floor); auto pass = pass_context.GetRenderPass(pass_depth); + + if (!pass) { + return false; + } + if (!element_entity.ShouldRender(pass->GetRenderTargetSize())) { return true; // Nothing to render. } diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc index fa0f38135e86f..26661e8d8155a 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -4,6 +4,7 @@ #include "impeller/entity/inline_pass_context.h" +#include "impeller/base/validation.h" #include "impeller/renderer/command_buffer.h" namespace impeller { @@ -61,6 +62,7 @@ std::shared_ptr InlinePassContext::GetRenderPass( if (!IsActive()) { command_buffer_ = context_->CreateCommandBuffer(); if (!command_buffer_) { + VALIDATION_LOG << "Could not create command buffer."; return nullptr; } @@ -85,6 +87,7 @@ std::shared_ptr InlinePassContext::GetRenderPass( pass_ = command_buffer_->CreateRenderPass(render_target_); if (!pass_) { + VALIDATION_LOG << "Could not create render pass."; return nullptr; } From adbbadf1770840eef6577824ff5f0b6fb90bf116 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Thu, 11 Aug 2022 18:29:33 -0700 Subject: [PATCH 284/558] [Impeller] [vulkan] Wire descriptor set layouts (#35363) --- impeller/renderer/backend/vulkan/formats_vk.h | 61 +++++++++++++++++++ .../backend/vulkan/pipeline_library_vk.cc | 56 +++++++++++++++-- 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/impeller/renderer/backend/vulkan/formats_vk.h b/impeller/renderer/backend/vulkan/formats_vk.h index 90b7724b2450d..c603dfd222665 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -6,6 +6,7 @@ #include "flutter/fml/macros.h" #include "impeller/renderer/backend/vulkan/vk.h" +#include "impeller/renderer/descriptor_set_layout.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/shader_types.h" @@ -227,4 +228,64 @@ constexpr vk::SamplerAddressMode ToVKSamplerAddressMode( FML_UNREACHABLE(); } +constexpr vk::ShaderStageFlags ToVkShaderStage(ShaderStage stage) { + switch (stage) { + case ShaderStage::kUnknown: + return vk::ShaderStageFlagBits::eAll; + case ShaderStage::kFragment: + return vk::ShaderStageFlagBits::eFragment; + case ShaderStage::kTessellationControl: + return vk::ShaderStageFlagBits::eTessellationControl; + case ShaderStage::kTessellationEvaluation: + return vk::ShaderStageFlagBits::eTessellationEvaluation; + case ShaderStage::kCompute: + return vk::ShaderStageFlagBits::eCompute; + case ShaderStage::kVertex: + return vk::ShaderStageFlagBits::eVertex; + } +} + +constexpr vk::DescriptorSetLayoutBinding ToVKDescriptorSetLayoutBinding( + const DescriptorSetLayout& layout) { + vk::DescriptorSetLayoutBinding binding; + binding.binding = layout.binding; + binding.descriptorCount = layout.descriptor_count; + vk::DescriptorType desc_type = vk::DescriptorType(); + switch (layout.descriptor_type) { + case DescriptorType::kSampledImage: + desc_type = vk::DescriptorType::eCombinedImageSampler; + break; + case DescriptorType::kUniformBuffer: + desc_type = vk::DescriptorType::eUniformBuffer; + break; + } + binding.descriptorType = desc_type; + binding.stageFlags = ToVkShaderStage(layout.shader_stage); + return binding; +} + +constexpr vk::AttachmentLoadOp ToVKAttachmentLoadOp(LoadAction load_action) { + switch (load_action) { + case LoadAction::kLoad: + return vk::AttachmentLoadOp::eLoad; + case LoadAction::kClear: + return vk::AttachmentLoadOp::eClear; + case LoadAction::kDontCare: + return vk::AttachmentLoadOp::eDontCare; + } +} + +constexpr vk::AttachmentStoreOp ToVKAttachmentStoreOp( + StoreAction store_action) { + switch (store_action) { + case StoreAction::kStore: + return vk::AttachmentStoreOp::eStore; + case StoreAction::kDontCare: + return vk::AttachmentStoreOp::eDontCare; + case StoreAction::kMultisampleResolve: + // TODO (kaushikiska): vulkan doesn't support multisample resolve. + return vk::AttachmentStoreOp::eDontCare; + } +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc index b207723825eef..f89d22bfb6884 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -155,7 +155,9 @@ std::optional PipelineLibraryVK::CreateRenderPass( vk::SubpassDescription subpass_info; subpass_info.setPipelineBindPoint(vk::PipelineBindPoint::eGraphics); subpass_info.setColorAttachments(color_attachment_references); - subpass_info.setResolveAttachments(resolve_attachment_references); + if (sample_count != SampleCount::kCount1) { + subpass_info.setResolveAttachments(resolve_attachment_references); + } if (depth_stencil_attachment_reference.has_value()) { subpass_info.setPDepthStencilAttachment( &depth_stencil_attachment_reference.value()); @@ -280,13 +282,58 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( return nullptr; } + // only 1 stream of data is supported for now. + vk::VertexInputBindingDescription binding_description = {}; + binding_description.setBinding(0); + binding_description.setInputRate(vk::VertexInputRate::eVertex); + + std::vector attr_descs; + uint32_t stride = 0; + const auto& stage_inputs = desc.GetVertexDescriptor()->GetStageInputs(); + for (const ShaderStageIOSlot& stage_in : stage_inputs) { + vk::VertexInputAttributeDescription attr_desc; + attr_desc.setBinding(stage_in.binding); + attr_desc.setLocation(stage_in.location); + attr_desc.setFormat(vk::Format::eR8G8B8A8Unorm); + attr_desc.setOffset(stride); + attr_descs.push_back(attr_desc); + stride += stage_in.bit_width * stage_in.vec_size; + } + + binding_description.setStride(stride); + + vk::PipelineVertexInputStateCreateInfo vertex_input_state; + vertex_input_state.setVertexAttributeDescriptions(attr_descs); + vertex_input_state.setVertexBindingDescriptionCount(1); + vertex_input_state.setPVertexBindingDescriptions(&binding_description); + + pipeline_info.setPVertexInputState(&vertex_input_state); + //---------------------------------------------------------------------------- /// Pipeline Layout a.k.a the descriptor sets and uniforms. /// - std::vector descriptor_set_layouts; - // TODO(106377): Wire this up from the C++ generated headers. + std::vector bindings = {}; + + for (auto layout : desc.GetVertexDescriptor()->GetDescriptorSetLayouts()) { + auto vk_desc_layout = ToVKDescriptorSetLayoutBinding(layout); + bindings.push_back(vk_desc_layout); + } + + vk::DescriptorSetLayoutCreateInfo descriptor_set_create; + descriptor_set_create.setBindings(bindings); + + auto descriptor_set_create_res = + device_.createDescriptorSetLayoutUnique(descriptor_set_create); + if (descriptor_set_create_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "unable to create uniform descriptors"; + return nullptr; + } + + vk::UniqueDescriptorSetLayout descriptor_set_layout = + std::move(descriptor_set_create_res.value); + vk::PipelineLayoutCreateInfo pipeline_layout_info; - pipeline_layout_info.setSetLayouts(descriptor_set_layouts); + pipeline_layout_info.setSetLayouts(descriptor_set_layout.get()); auto pipeline_layout = device_.createPipelineLayoutUnique(pipeline_layout_info); if (pipeline_layout.result != vk::Result::eSuccess) { @@ -298,7 +345,6 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( pipeline_info.setLayout(pipeline_layout.value.get()); // TODO(WIP) - // pipeline_info.setPVertexInputState(&vertex_input_state); // pipeline_info.setPDepthStencilState(&depth_stencil_state_); // See the note in the header about why this is a reader lock. From 643742e4fb97900e39b27c704e71bfbab8cce58b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 11 Aug 2022 22:13:21 -0400 Subject: [PATCH 285/558] Roll Dart SDK from 36c21217228c to 48134445a5f2 (1 revision) (#35364) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d33dd0b990398..0c35c83d73115 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '36c21217228c78dc1e0f2d1eb2d1c3df376698ec', + 'dart_revision': '48134445a5f2bba9191a236ee78e540f71c09203', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 4147009db4e97..c223476c4e8b4 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: f88fb225a5be5fb8fa3f200c1d1e1c62 +Signature: d33b5a7c8fe92e053a4549156321fd3b UNUSED LICENSES: From 913f6b23e22942dab45324a0c1e366593613891f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 01:53:37 -0400 Subject: [PATCH 286/558] Roll Skia from 3901abed0034 to bdeedf187ec2 (1 revision) (#35368) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0c35c83d73115..79a383af5b237 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': '3901abed003450c20001e6b7538408e484ed7aa9', + 'skia_revision': 'bdeedf187ec21b71b4f8054d78765596f8780e80', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 9c9a037c80130..c79a85595e3e0 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: de88b55052fef995d37493e6a9c75de1 +Signature: 7158d0263e7698dd299364911c2e30a6 UNUSED LICENSES: From 88380787339cbf04ab3c6ef765465c7c0dbe8763 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 02:24:12 -0400 Subject: [PATCH 287/558] Roll Fuchsia Mac SDK from QWFPHejM3XUHdRt0m... to xp69KGYFKc4vMfCaO... (#35369) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 79a383af5b237..82748ab921824 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'QWFPHejM3XUHdRt0mm8agNq7weRw5hSVM4AEoJhrWgEC' + 'version': 'xp69KGYFKc4vMfCaOZPe5k8T7EnxuUG_jjLNj8D9xnUC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From d35771a75191b916a184959f1bc3e7e1f4909ab1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 02:29:39 -0400 Subject: [PATCH 288/558] Roll Dart SDK from 48134445a5f2 to 71fbf1e98002 (1 revision) (#35370) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 82748ab921824..476ac465a06a5 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '48134445a5f2bba9191a236ee78e540f71c09203', + 'dart_revision': '71fbf1e98002b4311273867049aa2efdff949045', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index c223476c4e8b4..7c754b47679c3 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: d33b5a7c8fe92e053a4549156321fd3b +Signature: 81b8e8aea9318909389fefd25aeb9018 UNUSED LICENSES: From e20ba0df407cd93c746552afc6eecd0eb8b6b37d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 03:03:05 -0400 Subject: [PATCH 289/558] Roll Skia from bdeedf187ec2 to c3108c8b1362 (2 revisions) (#35371) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 476ac465a06a5..e62aed46ed320 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': 'bdeedf187ec21b71b4f8054d78765596f8780e80', + 'skia_revision': 'c3108c8b1362562aeb309e4f864126248aefcfc8', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index c79a85595e3e0..31385df04541e 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 7158d0263e7698dd299364911c2e30a6 +Signature: 29d4f92bcccd0a6e0a12f94346c0ed24 UNUSED LICENSES: From 34933f96b7ea0ce3192f180d8882ec98e06031ff Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 04:13:46 -0400 Subject: [PATCH 290/558] Roll Skia from c3108c8b1362 to b621a886528f (1 revision) (#35372) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e62aed46ed320..f544f276f0423 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': 'c3108c8b1362562aeb309e4f864126248aefcfc8', + 'skia_revision': 'b621a886528f2c81a5b6708182f24f937df955d7', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 31385df04541e..d8d51e8dbe68f 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 29d4f92bcccd0a6e0a12f94346c0ed24 +Signature: f639c71cab37393bf09667ec9290d50d UNUSED LICENSES: From 4f921bbd00933065473ec7447d966d95599e509c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 09:06:13 -0400 Subject: [PATCH 291/558] Roll Skia from b621a886528f to d0b3f6eafe1c (1 revision) (#35374) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index f544f276f0423..dfda9de72dcc9 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': 'b621a886528f2c81a5b6708182f24f937df955d7', + 'skia_revision': 'd0b3f6eafe1c26ebbdcbe276d1c256a899b62931', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index d8d51e8dbe68f..53026c26c598d 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: f639c71cab37393bf09667ec9290d50d +Signature: 189ef4d7eb3b776bfa1d304375c7f184 UNUSED LICENSES: @@ -4039,8 +4039,6 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/GrUtil.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/GrYUVABackendTextures.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/StencilMaskHelper.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/StencilMaskHelper.h -FILE: ../../../third_party/skia/src/gpu/ganesh/SurfaceFillContext_v1.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/SurfaceFillContext_v1.h FILE: ../../../third_party/skia/src/gpu/ganesh/d3d/GrD3DAMDMemoryAllocator.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/d3d/GrD3DAMDMemoryAllocator.h FILE: ../../../third_party/skia/src/gpu/ganesh/d3d/GrD3DAttachment.cpp From f29bc623e68d59e1dfedd701c0ffa07ca728fffd Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 09:41:05 -0400 Subject: [PATCH 292/558] Roll Dart SDK from 71fbf1e98002 to 73b84ba39d98 (1 revision) (#35375) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index dfda9de72dcc9..0e88f38aa4f9b 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '71fbf1e98002b4311273867049aa2efdff949045', + 'dart_revision': '73b84ba39d9875eeb5c201741073e424f51fd56a', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -233,7 +233,7 @@ deps = { Var('dart_git') + '/json_rpc_2.git@805e6536dd961d66f6b8cd46d8f3e61774f957c9', 'src/third_party/dart/third_party/pkg/linter': - Var('dart_git') + '/linter.git@a97919a064cc4b3b6923a18cdb47a3779a31bc7b', + Var('dart_git') + '/linter.git@304042aaa933a02d2581ab9598dd2ddaebdbc803', 'src/third_party/dart/third_party/pkg/logging': Var('dart_git') + '/logging.git@d10e24844c2e01d3f6d2b5a1a2bb8717359c6a87', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 7c754b47679c3..7c24384f15b63 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 81b8e8aea9318909389fefd25aeb9018 +Signature: aa6af9f3f9c51da06dbf3854f112dde0 UNUSED LICENSES: From de118a55ade0577325178c5f2c777f5a51556ab3 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 10:18:05 -0400 Subject: [PATCH 293/558] Roll Skia from d0b3f6eafe1c to 2026231c6abd (1 revision) (#35376) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0e88f38aa4f9b..5b03886efd730 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': 'd0b3f6eafe1c26ebbdcbe276d1c256a899b62931', + 'skia_revision': '2026231c6abda23c51b5d0c6cbcddf56ab0b806c', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 53026c26c598d..6c929f742c9ab 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 189ef4d7eb3b776bfa1d304375c7f184 +Signature: afcbcd3c3430023589bad647c088c33e UNUSED LICENSES: From bd967df679950179028acdc3124ec9fccd47b1c7 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 11:27:15 -0400 Subject: [PATCH 294/558] Roll Skia from 2026231c6abd to 72044d88a240 (1 revision) (#35377) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 5b03886efd730..0e502fe5e2d5a 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': '2026231c6abda23c51b5d0c6cbcddf56ab0b806c', + 'skia_revision': '72044d88a240aeec5139479fefc860a65686dce2', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 6c929f742c9ab..315a3ba7967e0 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: afcbcd3c3430023589bad647c088c33e +Signature: 0336adeae2079d62d1969c61d17ed674 UNUSED LICENSES: From c354e0e04ceabcf91460b48df3d0d80a10a6c415 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 12:52:18 -0400 Subject: [PATCH 295/558] Roll Skia from 72044d88a240 to 579816c289d3 (2 revisions) (#35378) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DEPS b/DEPS index 0e502fe5e2d5a..7a1473728e92f 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': '72044d88a240aeec5139479fefc860a65686dce2', + 'skia_revision': '579816c289d3808a17f66396d23bfbea7c4152b0', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 315a3ba7967e0..b05fcf9339343 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 0336adeae2079d62d1969c61d17ed674 +Signature: 026272190f940e2e22b194aed5a41ecc UNUSED LICENSES: @@ -5603,11 +5603,15 @@ FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlQueueManager.h FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlQueueManager.mm FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlSampler.h FILE: ../../../third_party/skia/src/gpu/graphite/mtl/MtlSampler.mm +FILE: ../../../third_party/skia/src/gpu/graphite/render/BitmapTextRenderStep.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/render/BitmapTextRenderStep.h FILE: ../../../third_party/skia/src/gpu/graphite/render/CoverBoundsRenderStep.cpp FILE: ../../../third_party/skia/src/gpu/graphite/render/CoverBoundsRenderStep.h FILE: ../../../third_party/skia/src/gpu/graphite/render/DynamicInstancesPatchAllocator.h FILE: ../../../third_party/skia/src/gpu/graphite/render/MiddleOutFanRenderStep.cpp FILE: ../../../third_party/skia/src/gpu/graphite/render/MiddleOutFanRenderStep.h +FILE: ../../../third_party/skia/src/gpu/graphite/render/SDFTextRenderStep.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/render/SDFTextRenderStep.h FILE: ../../../third_party/skia/src/gpu/graphite/render/StencilAndCoverDSS.h FILE: ../../../third_party/skia/src/gpu/graphite/render/TessellateCurvesRenderStep.cpp FILE: ../../../third_party/skia/src/gpu/graphite/render/TessellateCurvesRenderStep.h @@ -5615,10 +5619,6 @@ FILE: ../../../third_party/skia/src/gpu/graphite/render/TessellateStrokesRenderS FILE: ../../../third_party/skia/src/gpu/graphite/render/TessellateStrokesRenderStep.h FILE: ../../../third_party/skia/src/gpu/graphite/render/TessellateWedgesRenderStep.cpp FILE: ../../../third_party/skia/src/gpu/graphite/render/TessellateWedgesRenderStep.h -FILE: ../../../third_party/skia/src/gpu/graphite/render/TextDirectRenderStep.cpp -FILE: ../../../third_party/skia/src/gpu/graphite/render/TextDirectRenderStep.h -FILE: ../../../third_party/skia/src/gpu/graphite/render/TextSDFRenderStep.cpp -FILE: ../../../third_party/skia/src/gpu/graphite/render/TextSDFRenderStep.h FILE: ../../../third_party/skia/src/gpu/graphite/render/VerticesRenderStep.cpp FILE: ../../../third_party/skia/src/gpu/graphite/render/VerticesRenderStep.h FILE: ../../../third_party/skia/src/gpu/graphite/text/AtlasManager.cpp From d1b18b5d6811b59b1535c39561923e85126e63ac Mon Sep 17 00:00:00 2001 From: Bernardo Eilert Trevisan <43152751+betrevisan@users.noreply.github.com> Date: Fri, 12 Aug 2022 10:52:54 -0700 Subject: [PATCH 296/558] Enable dirty region management within the Embedder API (#35022) --- shell/common/shell_test_platform_view_gl.cc | 6 +- shell/common/shell_test_platform_view_gl.h | 2 +- shell/gpu/gpu_surface_gl_delegate.h | 26 +- shell/gpu/gpu_surface_gl_impeller.cc | 3 +- shell/gpu/gpu_surface_gl_skia.cc | 22 +- shell/gpu/gpu_surface_gl_skia.h | 4 + .../android/android_surface_gl_impeller.cc | 6 +- .../android/android_surface_gl_impeller.h | 2 +- .../android/android_surface_gl_skia.cc | 8 +- .../android/android_surface_gl_skia.h | 2 +- .../android/surface/android_surface_mock.cc | 6 +- .../android/surface/android_surface_mock.h | 2 +- shell/platform/embedder/embedder.cc | 117 +++++- shell/platform/embedder/embedder.h | 47 ++- .../platform/embedder/embedder_surface_gl.cc | 13 +- shell/platform/embedder/embedder_surface_gl.h | 9 +- .../embedder/tests/embedder_config_builder.cc | 12 +- .../embedder/tests/embedder_config_builder.h | 2 + .../tests/embedder_test_context_gl.cc | 26 +- .../embedder/tests/embedder_test_context_gl.h | 14 +- .../embedder/tests/embedder_unittests_gl.cc | 379 +++++++++++++++++- 21 files changed, 657 insertions(+), 51 deletions(-) diff --git a/shell/common/shell_test_platform_view_gl.cc b/shell/common/shell_test_platform_view_gl.cc index 492354230e8dc..ac68ff3971d0b 100644 --- a/shell/common/shell_test_platform_view_gl.cc +++ b/shell/common/shell_test_platform_view_gl.cc @@ -69,8 +69,10 @@ bool ShellTestPlatformViewGL::GLContextPresent( } // |GPUSurfaceGLDelegate| -intptr_t ShellTestPlatformViewGL::GLContextFBO(GLFrameInfo frame_info) const { - return gl_surface_.GetFramebuffer(frame_info.width, frame_info.height); +GLFBOInfo ShellTestPlatformViewGL::GLContextFBO(GLFrameInfo frame_info) const { + return GLFBOInfo{ + .fbo_id = gl_surface_.GetFramebuffer(frame_info.width, frame_info.height), + }; } // |GPUSurfaceGLDelegate| diff --git a/shell/common/shell_test_platform_view_gl.h b/shell/common/shell_test_platform_view_gl.h index c890c1e0fc6ec..b4afc1266975b 100644 --- a/shell/common/shell_test_platform_view_gl.h +++ b/shell/common/shell_test_platform_view_gl.h @@ -61,7 +61,7 @@ class ShellTestPlatformViewGL : public ShellTestPlatformView, bool GLContextPresent(const GLPresentInfo& present_info) override; // |GPUSurfaceGLDelegate| - intptr_t GLContextFBO(GLFrameInfo frame_info) const override; + GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const override; // |GPUSurfaceGLDelegate| GLProcResolver GetGLProcResolver() const override; diff --git a/shell/gpu/gpu_surface_gl_delegate.h b/shell/gpu/gpu_surface_gl_delegate.h index f9da6a11120fd..d1e31b96559f5 100644 --- a/shell/gpu/gpu_surface_gl_delegate.h +++ b/shell/gpu/gpu_surface_gl_delegate.h @@ -22,17 +22,32 @@ struct GLFrameInfo { uint32_t height; }; +// A structure to represent the frame buffer information which is returned to +// the rendering backend after requesting a frame buffer object. +struct GLFBOInfo { + // The frame buffer's ID. + uint32_t fbo_id; + // This boolean flags whether the returned FBO supports partial repaint. + const bool partial_repaint_enabled; + // The frame buffer's existing damage (i.e. damage since it was last used). + const SkIRect existing_damage; +}; + // Information passed during presentation of a frame. struct GLPresentInfo { uint32_t fbo_id; - // Damage is a hint to compositor telling it which parts of front buffer - // need to be updated - const std::optional& damage; + // The frame damage is a hint to compositor telling it which parts of front + // buffer need to be updated. + const std::optional& frame_damage; // Time at which this frame is scheduled to be presented. This is a hint // that can be passed to the platform to drop queued frames. std::optional presentation_time = std::nullopt; + + // The buffer damage refers to the region that needs to be set as damaged + // within the frame buffer. + const std::optional& buffer_damage; }; class GPUSurfaceGLDelegate { @@ -54,8 +69,9 @@ class GPUSurfaceGLDelegate { // context and not any of the contexts dedicated for IO. virtual bool GLContextPresent(const GLPresentInfo& present_info) = 0; - // The ID of the main window bound framebuffer. Typically FBO0. - virtual intptr_t GLContextFBO(GLFrameInfo frame_info) const = 0; + // The information about the main window bound framebuffer. ID is Typically + // FBO0. + virtual GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const = 0; // The rendering subsystem assumes that the ID of the main window bound // framebuffer remains constant throughout. If this assumption in incorrect, diff --git a/shell/gpu/gpu_surface_gl_impeller.cc b/shell/gpu/gpu_surface_gl_impeller.cc index 24413147274a6..3fc7c441b42bb 100644 --- a/shell/gpu/gpu_surface_gl_impeller.cc +++ b/shell/gpu/gpu_surface_gl_impeller.cc @@ -62,10 +62,11 @@ std::unique_ptr GPUSurfaceGLImpeller::AcquireFrame( if (weak) { GLPresentInfo present_info = { .fbo_id = 0, - .damage = std::nullopt, + .frame_damage = std::nullopt, // TODO (https://github.com/flutter/flutter/issues/105597): wire-up // presentation time to impeller backend. .presentation_time = std::nullopt, + .buffer_damage = std::nullopt, }; delegate->GLContextPresent(present_info); } diff --git a/shell/gpu/gpu_surface_gl_skia.cc b/shell/gpu/gpu_surface_gl_skia.cc index 66bb6636d95d8..eafb6120b3774 100644 --- a/shell/gpu/gpu_surface_gl_skia.cc +++ b/shell/gpu/gpu_surface_gl_skia.cc @@ -181,10 +181,10 @@ bool GPUSurfaceGLSkia::CreateOrUpdateSurfaces(const SkISize& size) { GLFrameInfo frame_info = {static_cast(size.width()), static_cast(size.height())}; - const uint32_t fbo_id = delegate_->GLContextFBO(frame_info); + const GLFBOInfo fbo_info = delegate_->GLContextFBO(frame_info); onscreen_surface = WrapOnscreenSurface(context_.get(), // GL context size, // root surface size - fbo_id // window FBO ID + fbo_info.fbo_id // window FBO ID ); if (onscreen_surface == nullptr) { @@ -195,7 +195,9 @@ bool GPUSurfaceGLSkia::CreateOrUpdateSurfaces(const SkISize& size) { } onscreen_surface_ = std::move(onscreen_surface); - fbo_id_ = fbo_id; + fbo_id_ = fbo_info.fbo_id; + supports_partial_repaint_ = fbo_info.partial_repaint_enabled; + existing_damage_ = fbo_info.existing_damage; return true; } @@ -248,6 +250,9 @@ std::unique_ptr GPUSurfaceGLSkia::AcquireFrame( }; framebuffer_info = delegate_->GLContextFramebufferInfo(); + // Partial repaint is enabled by default + framebuffer_info.supports_partial_repaint = supports_partial_repaint_; + framebuffer_info.existing_damage = existing_damage_; return std::make_unique(surface, std::move(framebuffer_info), submit_callback, std::move(context_switch)); @@ -268,8 +273,9 @@ bool GPUSurfaceGLSkia::PresentSurface(const SurfaceFrame& frame, GLPresentInfo present_info = { .fbo_id = fbo_id_, - .damage = frame.submit_info().frame_damage, + .frame_damage = frame.submit_info().frame_damage, .presentation_time = frame.submit_info().presentation_time, + .buffer_damage = frame.submit_info().buffer_damage, }; if (!delegate_->GLContextPresent(present_info)) { return false; @@ -284,11 +290,11 @@ bool GPUSurfaceGLSkia::PresentSurface(const SurfaceFrame& frame, // The FBO has changed, ask the delegate for the new FBO and do a surface // re-wrap. - const uint32_t fbo_id = delegate_->GLContextFBO(frame_info); + const GLFBOInfo fbo_info = delegate_->GLContextFBO(frame_info); auto new_onscreen_surface = WrapOnscreenSurface(context_.get(), // GL context current_size, // root surface size - fbo_id // window FBO ID + fbo_info.fbo_id // window FBO ID ); if (!new_onscreen_surface) { @@ -296,7 +302,9 @@ bool GPUSurfaceGLSkia::PresentSurface(const SurfaceFrame& frame, } onscreen_surface_ = std::move(new_onscreen_surface); - fbo_id_ = fbo_id; + fbo_id_ = fbo_info.fbo_id; + supports_partial_repaint_ = fbo_info.partial_repaint_enabled; + existing_damage_ = fbo_info.existing_damage; } return true; diff --git a/shell/gpu/gpu_surface_gl_skia.h b/shell/gpu/gpu_surface_gl_skia.h index 90cad241945fd..39f6e3f607dfe 100644 --- a/shell/gpu/gpu_surface_gl_skia.h +++ b/shell/gpu/gpu_surface_gl_skia.h @@ -67,6 +67,8 @@ class GPUSurfaceGLSkia : public Surface { sk_sp onscreen_surface_; /// FBO backing the current `onscreen_surface_`. uint32_t fbo_id_ = 0; + // Private variable used to keep track of the current FBO's existing damage. + SkIRect existing_damage_ = SkIRect::MakeEmpty(); bool context_owner_ = false; // TODO(38466): Refactor GPU surface APIs take into account the fact that an // external view embedder may want to render to the root surface. This is a @@ -74,6 +76,8 @@ class GPUSurfaceGLSkia : public Surface { // external view embedder is present. const bool render_to_surface_ = true; bool valid_ = false; + // Partial repaint is on by default. + bool supports_partial_repaint_ = true; // WeakPtrFactory must be the last member. fml::TaskRunnerAffineWeakPtrFactory weak_factory_; diff --git a/shell/platform/android/android_surface_gl_impeller.cc b/shell/platform/android/android_surface_gl_impeller.cc index 28c1cfe55f19e..635acc77a9502 100644 --- a/shell/platform/android/android_surface_gl_impeller.cc +++ b/shell/platform/android/android_surface_gl_impeller.cc @@ -295,9 +295,11 @@ bool AndroidSurfaceGLImpeller::GLContextPresent( } // |GPUSurfaceGLDelegate| -intptr_t AndroidSurfaceGLImpeller::GLContextFBO(GLFrameInfo frame_info) const { +GLFBOInfo AndroidSurfaceGLImpeller::GLContextFBO(GLFrameInfo frame_info) const { // FBO0 is the default window bound framebuffer in EGL environments. - return 0; + return GLFBOInfo{ + .fbo_id = 0, + }; } // |GPUSurfaceGLDelegate| diff --git a/shell/platform/android/android_surface_gl_impeller.h b/shell/platform/android/android_surface_gl_impeller.h index 8bcf14dbee27b..9d2399868da97 100644 --- a/shell/platform/android/android_surface_gl_impeller.h +++ b/shell/platform/android/android_surface_gl_impeller.h @@ -68,7 +68,7 @@ class AndroidSurfaceGLImpeller final : public GPUSurfaceGLDelegate, bool GLContextPresent(const GLPresentInfo& present_info) override; // |GPUSurfaceGLDelegate| - intptr_t GLContextFBO(GLFrameInfo frame_info) const override; + GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const override; // |GPUSurfaceGLDelegate| sk_sp GetGLInterface() const override; diff --git a/shell/platform/android/android_surface_gl_skia.cc b/shell/platform/android/android_surface_gl_skia.cc index 23242c9b3bad4..50ac30835bb1f 100644 --- a/shell/platform/android/android_surface_gl_skia.cc +++ b/shell/platform/android/android_surface_gl_skia.cc @@ -159,13 +159,15 @@ bool AndroidSurfaceGLSkia::GLContextPresent(const GLPresentInfo& present_info) { if (present_info.presentation_time) { onscreen_surface_->SetPresentationTime(*present_info.presentation_time); } - return onscreen_surface_->SwapBuffers(present_info.damage); + return onscreen_surface_->SwapBuffers(present_info.frame_damage); } -intptr_t AndroidSurfaceGLSkia::GLContextFBO(GLFrameInfo frame_info) const { +GLFBOInfo AndroidSurfaceGLSkia::GLContextFBO(GLFrameInfo frame_info) const { FML_DCHECK(IsValid()); // The default window bound framebuffer on Android. - return 0; + return GLFBOInfo{ + .fbo_id = 0, + }; } // |GPUSurfaceGLDelegate| diff --git a/shell/platform/android/android_surface_gl_skia.h b/shell/platform/android/android_surface_gl_skia.h index 99a910b69b76d..73f36945127f8 100644 --- a/shell/platform/android/android_surface_gl_skia.h +++ b/shell/platform/android/android_surface_gl_skia.h @@ -67,7 +67,7 @@ class AndroidSurfaceGLSkia final : public GPUSurfaceGLDelegate, bool GLContextPresent(const GLPresentInfo& present_info) override; // |GPUSurfaceGLDelegate| - intptr_t GLContextFBO(GLFrameInfo frame_info) const override; + GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const override; // |GPUSurfaceGLDelegate| sk_sp GetGLInterface() const override; diff --git a/shell/platform/android/surface/android_surface_mock.cc b/shell/platform/android/surface/android_surface_mock.cc index c3a9f38fc8f0c..8f718fcae667a 100644 --- a/shell/platform/android/surface/android_surface_mock.cc +++ b/shell/platform/android/surface/android_surface_mock.cc @@ -22,8 +22,10 @@ bool AndroidSurfaceMock::GLContextPresent(const GLPresentInfo& present_info) { return true; } -intptr_t AndroidSurfaceMock::GLContextFBO(GLFrameInfo frame_info) const { - return 0; +GLFBOInfo AndroidSurfaceMock::GLContextFBO(GLFrameInfo frame_info) const { + return GLFBOInfo{ + .fbo_id = 0, + }; } } // namespace flutter diff --git a/shell/platform/android/surface/android_surface_mock.h b/shell/platform/android/surface/android_surface_mock.h index d7363873a9a31..3f326a21920b7 100644 --- a/shell/platform/android/surface/android_surface_mock.h +++ b/shell/platform/android/surface/android_surface_mock.h @@ -51,7 +51,7 @@ class AndroidSurfaceMock final : public GPUSurfaceGLDelegate, bool GLContextPresent(const GLPresentInfo& present_info) override; // |GPUSurfaceGLDelegate| - intptr_t GLContextFBO(GLFrameInfo frame_info) const override; + GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const override; }; } // namespace flutter diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 0868901fce3d6..97fced2ab3001 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -132,6 +132,12 @@ static bool IsOpenGLRendererConfigValid(const FlutterRendererConfig* config) { return false; } + if (!SAFE_EXISTS(open_gl_config, populate_existing_damage)) { + FML_LOG(INFO) << "populate_existing_damage was not defined, disabling " + "partial repaint. If you wish to enable partial repaint, " + "please define this callback."; + } + return true; } @@ -222,7 +228,29 @@ static void* DefaultGLProcResolver(const char* name) { } #endif // FML_OS_LINUX || FML_OS_WIN -static flutter::Shell::CreateCallback +#ifdef SHELL_ENABLE_GL +// Auxiliary function used to translate rectangles of type SkIRect to +// FlutterRect. +static FlutterRect SkIRectToFlutterRect(const SkIRect sk_rect) { + FlutterRect flutter_rect = {static_cast(sk_rect.fLeft), + static_cast(sk_rect.fTop), + static_cast(sk_rect.fRight), + static_cast(sk_rect.fBottom)}; + return flutter_rect; +} + +// Auxiliary function used to translate rectangles of type FlutterRect to +// SkIRect. +static const SkIRect FlutterRectToSkIRect(FlutterRect flutter_rect) { + SkIRect rect = {static_cast(flutter_rect.left), + static_cast(flutter_rect.top), + static_cast(flutter_rect.right), + static_cast(flutter_rect.bottom)}; + return rect; +} +#endif + +static inline flutter::Shell::CreateCallback InferOpenGLPlatformViewCreationCallback( const FlutterRendererConfig* config, void* user_data, @@ -241,15 +269,45 @@ InferOpenGLPlatformViewCreationCallback( auto gl_clear_current = [ptr = config->open_gl.clear_current, user_data]() -> bool { return ptr(user_data); }; - auto gl_present = [present = config->open_gl.present, - present_with_info = config->open_gl.present_with_info, - user_data](uint32_t fbo_id) -> bool { + auto gl_present = + [present = config->open_gl.present, + present_with_info = config->open_gl.present_with_info, + user_data](flutter::GLPresentInfo gl_present_info) -> bool { if (present) { return present(user_data); } else { - FlutterPresentInfo present_info = {}; - present_info.struct_size = sizeof(FlutterPresentInfo); - present_info.fbo_id = fbo_id; + // Format the frame and buffer damages accordingly. Note that, since the + // current compute damage algorithm only returns one rectangle for damage + // we are assuming the number of rectangles provided in frame and buffer + // damage are always 1. Once the function that computes damage implements + // support for multiple damage rectangles, GLPresentInfo should also + // contain the number of damage rectangles. + const size_t num_rects = 1; + + std::array frame_damage_rect = { + SkIRectToFlutterRect(*(gl_present_info.frame_damage))}; + std::array buffer_damage_rect = { + SkIRectToFlutterRect(*(gl_present_info.buffer_damage))}; + + FlutterDamage frame_damage{ + .struct_size = sizeof(FlutterDamage), + .num_rects = frame_damage_rect.size(), + .damage = frame_damage_rect.data(), + }; + FlutterDamage buffer_damage{ + .struct_size = sizeof(FlutterDamage), + .num_rects = buffer_damage_rect.size(), + .damage = buffer_damage_rect.data(), + }; + + // Construct the present information concerning the frame being rendered. + FlutterPresentInfo present_info = { + .struct_size = sizeof(FlutterPresentInfo), + .fbo_id = gl_present_info.fbo_id, + .frame_damage = frame_damage, + .buffer_damage = buffer_damage, + }; + return present_with_info(user_data, &present_info); } }; @@ -269,6 +327,50 @@ InferOpenGLPlatformViewCreationCallback( } }; + auto gl_populate_existing_damage = + [populate_existing_damage = config->open_gl.populate_existing_damage, + user_data](intptr_t id) -> flutter::GLFBOInfo { + // If no populate_existing_damage was provided, disable partial + // repaint. + if (!populate_existing_damage) { + return flutter::GLFBOInfo{ + .fbo_id = static_cast(id), + .partial_repaint_enabled = false, + .existing_damage = SkIRect::MakeEmpty(), + }; + } + + // Given the FBO's ID, get its existing damage. + FlutterDamage existing_damage; + populate_existing_damage(user_data, id, &existing_damage); + + bool partial_repaint_enabled = true; + SkIRect existing_damage_rect; + + // Verify that at least one damage rectangle was provided. + if (existing_damage.num_rects <= 0 || existing_damage.damage == nullptr) { + FML_LOG(INFO) << "No damage was provided. Forcing full repaint."; + existing_damage_rect = SkIRect::MakeEmpty(); + partial_repaint_enabled = false; + } else if (existing_damage.num_rects > 1) { + // Log message notifying users that multi-damage is not yet available in + // case they try to make use of it. + FML_LOG(INFO) << "Damage with multiple rectangles not yet supported. " + "Repainting the whole frame."; + existing_damage_rect = SkIRect::MakeEmpty(); + partial_repaint_enabled = false; + } else { + existing_damage_rect = FlutterRectToSkIRect(*(existing_damage.damage)); + } + + // Pass the information about this FBO to the rendering backend. + return flutter::GLFBOInfo{ + .fbo_id = static_cast(id), + .partial_repaint_enabled = partial_repaint_enabled, + .existing_damage = existing_damage_rect, + }; + }; + const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl; std::function gl_make_resource_current_callback = nullptr; if (SAFE_ACCESS(open_gl_config, make_resource_current, nullptr) != nullptr) { @@ -326,6 +428,7 @@ InferOpenGLPlatformViewCreationCallback( gl_make_resource_current_callback, // gl_make_resource_current_callback gl_surface_transformation_callback, // gl_surface_transformation_callback gl_proc_resolver, // gl_proc_resolver + gl_populate_existing_damage, // gl_populate_existing_damage }; return fml::MakeCopyable( diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 88a3014f0218f..93e92b7d4c6fa 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -433,6 +433,16 @@ typedef struct { FlutterSize lower_left_corner_radius; } FlutterRoundedRect; +/// A structure to represent a damage region. +typedef struct { + /// The size of this struct. Must be sizeof(FlutterDamage). + size_t struct_size; + /// The number of rectangles within the damage region. + size_t num_rects; + /// The actual damage region(s) in question. + FlutterRect* damage; +} FlutterDamage; + /// This information is passed to the embedder when requesting a frame buffer /// object. /// @@ -449,6 +459,13 @@ typedef uint32_t (*UIntFrameInfoCallback)( void* /* user data */, const FlutterFrameInfo* /* frame info */); +/// Callback for when a frame buffer object is requested with necessary +/// information for partial repaint. +typedef void (*FlutterFrameBufferWithDamageCallback)( + void* /* user data */, + const intptr_t /* fbo id */, + FlutterDamage* /* existing damage */); + /// This information is passed to the embedder when a surface is presented. /// /// See: \ref FlutterOpenGLRendererConfig.present_with_info. @@ -457,6 +474,10 @@ typedef struct { size_t struct_size; /// Id of the fbo backing the surface that was presented. uint32_t fbo_id; + /// Damage representing the area that the compositor needs to render. + FlutterDamage frame_damage; + /// Damage used to set the buffer's damage region. + FlutterDamage buffer_damage; } FlutterPresentInfo; /// Callback for when a surface is presented. @@ -471,7 +492,10 @@ typedef struct { BoolCallback clear_current; /// Specifying one (and only one) of `present` or `present_with_info` is /// required. Specifying both is an error and engine initialization will be - /// terminated. The return value indicates success of the present call. + /// terminated. The return value indicates success of the present call. If + /// the intent is to use dirty region management, present_with_info must be + /// defined as present will not succeed in communicating information about + /// damage. BoolCallback present; /// Specifying one (and only one) of the `fbo_callback` or /// `fbo_with_frame_info_callback` is required. Specifying both is an error @@ -520,8 +544,27 @@ typedef struct { /// required. Specifying both is an error and engine initialization will be /// terminated. When using this variant, the embedder is passed a /// `FlutterPresentInfo` struct that the embedder can use to release any - /// resources. The return value indicates success of the present call. + /// resources. The return value indicates success of the present call. This + /// callback is essential for dirty region management. If not defined, all the + /// pixels on the screen will be rendered at every frame (regardless of + /// whether damage is actually being computed or not). This is because the + /// information that is passed along to the callback contains the frame and + /// buffer damage that are essential for dirty region management. BoolPresentInfoCallback present_with_info; + /// Specifying this callback is a requirement for dirty region management. + /// Dirty region management will only render the areas of the screen that have + /// changed in between frames, greatly reducing rendering times and energy + /// consumption. To take advantage of these benefits, it is necessary to + /// define populate_existing_damage as a callback that takes user + /// data, an FBO ID, and an existing damage FlutterDamage. The callback should + /// use the given FBO ID to identify the FBO's exisiting damage (i.e. areas + /// that have changed since the FBO was last used) and use it to populate the + /// given existing damage variable. This callback is dependent on either + /// fbo_callback or fbo_with_frame_info_callback being defined as they are + /// responsible for providing populate_existing_damage with the FBO's + /// ID. Not specifying populate_existing_damage will result in full + /// repaint (i.e. rendering all the pixels on the screen at every frame). + FlutterFrameBufferWithDamageCallback populate_existing_damage; } FlutterOpenGLRendererConfig; /// Alias for id. diff --git a/shell/platform/embedder/embedder_surface_gl.cc b/shell/platform/embedder/embedder_surface_gl.cc index e406ee9ed10fa..88cdb316c5e5b 100644 --- a/shell/platform/embedder/embedder_surface_gl.cc +++ b/shell/platform/embedder/embedder_surface_gl.cc @@ -19,7 +19,8 @@ EmbedderSurfaceGL::EmbedderSurfaceGL( if (!gl_dispatch_table_.gl_make_current_callback || !gl_dispatch_table_.gl_clear_current_callback || !gl_dispatch_table_.gl_present_callback || - !gl_dispatch_table_.gl_fbo_callback) { + !gl_dispatch_table_.gl_fbo_callback || + !gl_dispatch_table_.gl_populate_existing_damage) { return; } @@ -46,12 +47,16 @@ bool EmbedderSurfaceGL::GLContextClearCurrent() { // |GPUSurfaceGLDelegate| bool EmbedderSurfaceGL::GLContextPresent(const GLPresentInfo& present_info) { - return gl_dispatch_table_.gl_present_callback(present_info.fbo_id); + // Pass the present information to the embedder present callback. + return gl_dispatch_table_.gl_present_callback(present_info); } // |GPUSurfaceGLDelegate| -intptr_t EmbedderSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const { - return gl_dispatch_table_.gl_fbo_callback(frame_info); +GLFBOInfo EmbedderSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const { + // Get the FBO ID using the gl_fbo_callback and then get exiting damage by + // passing that ID to the gl_populate_existing_damage. + return gl_dispatch_table_.gl_populate_existing_damage( + gl_dispatch_table_.gl_fbo_callback(frame_info)); } // |GPUSurfaceGLDelegate| diff --git a/shell/platform/embedder/embedder_surface_gl.h b/shell/platform/embedder/embedder_surface_gl.h index c0a2b6a55d98f..583f0f469a0e7 100644 --- a/shell/platform/embedder/embedder_surface_gl.h +++ b/shell/platform/embedder/embedder_surface_gl.h @@ -18,12 +18,13 @@ class EmbedderSurfaceGL final : public EmbedderSurface, struct GLDispatchTable { std::function gl_make_current_callback; // required std::function gl_clear_current_callback; // required - std::function gl_present_callback; // required + std::function gl_present_callback; // required std::function gl_fbo_callback; // required std::function gl_make_resource_current_callback; // optional std::function - gl_surface_transformation_callback; // optional - std::function gl_proc_resolver; // optional + gl_surface_transformation_callback; // optional + std::function gl_proc_resolver; // optional + std::function gl_populate_existing_damage; // required }; EmbedderSurfaceGL( @@ -59,7 +60,7 @@ class EmbedderSurfaceGL final : public EmbedderSurface, bool GLContextPresent(const GLPresentInfo& present_info) override; // |GPUSurfaceGLDelegate| - intptr_t GLContextFBO(GLFrameInfo frame_info) const override; + GLFBOInfo GLContextFBO(GLFrameInfo frame_info) const override; // |GPUSurfaceGLDelegate| bool GLContextFBOResetAfterPresent() const override; diff --git a/shell/platform/embedder/tests/embedder_config_builder.cc b/shell/platform/embedder/tests/embedder_config_builder.cc index 918abff4e261e..58e48c4b594d8 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.cc +++ b/shell/platform/embedder/tests/embedder_config_builder.cc @@ -52,13 +52,14 @@ EmbedderConfigBuilder::EmbedderConfigBuilder( opengl_renderer_config_.present_with_info = [](void* context, const FlutterPresentInfo* present_info) -> bool { return reinterpret_cast(context)->GLPresent( - present_info->fbo_id); + *present_info); }; opengl_renderer_config_.fbo_with_frame_info_callback = [](void* context, const FlutterFrameInfo* frame_info) -> uint32_t { return reinterpret_cast(context)->GLGetFramebuffer( *frame_info); }; + opengl_renderer_config_.populate_existing_damage = nullptr; opengl_renderer_config_.make_resource_current = [](void* context) -> bool { return reinterpret_cast(context) ->GLMakeResourceCurrent(); @@ -160,7 +161,10 @@ void EmbedderConfigBuilder::SetOpenGLPresentCallBack() { FML_CHECK(renderer_config_.type == FlutterRendererType::kOpenGL); renderer_config_.open_gl.present = [](void* context) -> bool { // passing a placeholder fbo_id. - return reinterpret_cast(context)->GLPresent(0); + return reinterpret_cast(context)->GLPresent( + FlutterPresentInfo{ + .fbo_id = 0, + }); }; #endif } @@ -312,6 +316,10 @@ void EmbedderConfigBuilder::SetupVsyncCallback() { }; } +FlutterRendererConfig& EmbedderConfigBuilder::GetRendererConfig() { + return renderer_config_; +} + void EmbedderConfigBuilder::SetRenderTaskRunner( const FlutterTaskRunnerDescription* runner) { if (runner == nullptr) { diff --git a/shell/platform/embedder/tests/embedder_config_builder.h b/shell/platform/embedder/tests/embedder_config_builder.h index 3ce230c0146b8..2727c85fdadbd 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.h +++ b/shell/platform/embedder/tests/embedder_config_builder.h @@ -104,6 +104,8 @@ class EmbedderConfigBuilder { FlutterCompositor& GetCompositor(); + FlutterRendererConfig& GetRendererConfig(); + void SetRenderTargetType( EmbedderTestBackingStoreProducer::RenderTargetType type, FlutterSoftwarePixelFormat software_pixfmt = kNative32); diff --git a/shell/platform/embedder/tests/embedder_test_context_gl.cc b/shell/platform/embedder/tests/embedder_test_context_gl.cc index 9a7bc9bcf1c26..0215999814a0d 100644 --- a/shell/platform/embedder/tests/embedder_test_context_gl.cc +++ b/shell/platform/embedder/tests/embedder_test_context_gl.cc @@ -39,7 +39,7 @@ bool EmbedderTestContextGL::GLClearCurrent() { return gl_surface_->ClearCurrent(); } -bool EmbedderTestContextGL::GLPresent(uint32_t fbo_id) { +bool EmbedderTestContextGL::GLPresent(FlutterPresentInfo present_info) { FML_CHECK(gl_surface_) << "GL surface must be initialized."; gl_surface_present_count_++; @@ -50,7 +50,7 @@ bool EmbedderTestContextGL::GLPresent(uint32_t fbo_id) { } if (callback) { - callback(fbo_id); + callback(present_info); } FireRootSurfacePresentCallbackIfPresent( @@ -64,6 +64,12 @@ void EmbedderTestContextGL::SetGLGetFBOCallback(GLGetFBOCallback callback) { gl_get_fbo_callback_ = callback; } +void EmbedderTestContextGL::SetGLPopulateExistingDamageCallback( + GLPopulateExistingDamageCallback callback) { + std::scoped_lock lock(gl_callback_mutex_); + gl_populate_existing_damage_callback_ = callback; +} + void EmbedderTestContextGL::SetGLPresentCallback(GLPresentCallback callback) { std::scoped_lock lock(gl_callback_mutex_); gl_present_callback_ = callback; @@ -86,6 +92,22 @@ uint32_t EmbedderTestContextGL::GLGetFramebuffer(FlutterFrameInfo frame_info) { return gl_surface_->GetFramebuffer(size.width, size.height); } +void EmbedderTestContextGL::GLPopulateExistingDamage( + const intptr_t id, + FlutterDamage* existing_damage) { + FML_CHECK(gl_surface_) << "GL surface must be initialized."; + + GLPopulateExistingDamageCallback callback; + { + std::scoped_lock lock(gl_callback_mutex_); + callback = gl_populate_existing_damage_callback_; + } + + if (callback) { + callback(id, existing_damage); + } +} + bool EmbedderTestContextGL::GLMakeResourceCurrent() { FML_CHECK(gl_surface_) << "GL surface must be initialized."; return gl_surface_->MakeResourceCurrent(); diff --git a/shell/platform/embedder/tests/embedder_test_context_gl.h b/shell/platform/embedder/tests/embedder_test_context_gl.h index 65e2c34c355c2..9b91ef5868868 100644 --- a/shell/platform/embedder/tests/embedder_test_context_gl.h +++ b/shell/platform/embedder/tests/embedder_test_context_gl.h @@ -14,7 +14,10 @@ namespace testing { class EmbedderTestContextGL : public EmbedderTestContext { public: using GLGetFBOCallback = std::function; - using GLPresentCallback = std::function; + using GLPopulateExistingDamageCallback = + std::function; + using GLPresentCallback = + std::function; explicit EmbedderTestContextGL(std::string assets_path = ""); @@ -38,6 +41,9 @@ class EmbedderTestContextGL : public EmbedderTestContext { /// void SetGLGetFBOCallback(GLGetFBOCallback callback); + void SetGLPopulateExistingDamageCallback( + GLPopulateExistingDamageCallback callback); + uint32_t GetWindowFBOId() const; //---------------------------------------------------------------------------- @@ -53,6 +59,9 @@ class EmbedderTestContextGL : public EmbedderTestContext { /// void SetGLPresentCallback(GLPresentCallback callback); + void GLPopulateExistingDamage(const intptr_t id, + FlutterDamage* existing_damage); + protected: virtual void SetupCompositor() override; @@ -65,6 +74,7 @@ class EmbedderTestContextGL : public EmbedderTestContext { std::mutex gl_callback_mutex_; GLGetFBOCallback gl_get_fbo_callback_; GLPresentCallback gl_present_callback_; + GLPopulateExistingDamageCallback gl_populate_existing_damage_callback_; void SetupSurface(SkISize surface_size) override; @@ -72,7 +82,7 @@ class EmbedderTestContextGL : public EmbedderTestContext { bool GLClearCurrent(); - bool GLPresent(uint32_t fbo_id); + bool GLPresent(FlutterPresentInfo present_info); uint32_t GLGetFramebuffer(FlutterFrameInfo frame_info); diff --git a/shell/platform/embedder/tests/embedder_unittests_gl.cc b/shell/platform/embedder/tests/embedder_unittests_gl.cc index 9174461529058..76cf6102cdf60 100644 --- a/shell/platform/embedder/tests/embedder_unittests_gl.cc +++ b/shell/platform/embedder/tests/embedder_unittests_gl.cc @@ -3106,6 +3106,72 @@ TEST_F(EmbedderTest, MustNotRunWithBothPresentCallbacksSet) { ASSERT_FALSE(engine.is_valid()); } +TEST_F(EmbedderTest, MustStillRunWhenPopulateExistingDamageIsNotProvided) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(1, 1)); + builder.GetRendererConfig().open_gl.populate_existing_damage = nullptr; + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); +} + +TEST_F(EmbedderTest, MustRunWhenPopulateExistingDamageIsProvided) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(1, 1)); + + builder.GetRendererConfig().open_gl.populate_existing_damage = + [](void* context, const intptr_t id, + FlutterDamage* existing_damage) -> void { + return reinterpret_cast(context) + ->GLPopulateExistingDamage(id, existing_damage); + }; + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); +} + +TEST_F(EmbedderTest, MustRunWithPopulateExistingDamageAndFBOCallback) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(1, 1)); + builder.GetRendererConfig().open_gl.fbo_callback = + [](void* context) -> uint32_t { return 0; }; + builder.GetRendererConfig().open_gl.fbo_with_frame_info_callback = nullptr; + builder.GetRendererConfig().open_gl.populate_existing_damage = + [](void* context, const intptr_t id, + FlutterDamage* existing_damage) -> void { + return reinterpret_cast(context) + ->GLPopulateExistingDamage(id, existing_damage); + }; + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); +} + +TEST_F(EmbedderTest, + MustNotRunWhenPopulateExistingDamageButNoOtherFBOCallback) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(1, 1)); + builder.GetRendererConfig().open_gl.fbo_callback = nullptr; + builder.GetRendererConfig().open_gl.fbo_with_frame_info_callback = nullptr; + builder.GetRendererConfig().open_gl.populate_existing_damage = + [](void* context, const intptr_t id, + FlutterDamage* existing_damage) -> void { + return reinterpret_cast(context) + ->GLPopulateExistingDamage(id, existing_damage); + }; + + auto engine = builder.LaunchEngine(); + ASSERT_FALSE(engine.is_valid()); +} + TEST_F(EmbedderTest, PresentInfoContainsValidFBOId) { auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); @@ -3140,8 +3206,8 @@ TEST_F(EmbedderTest, PresentInfoContainsValidFBOId) { const uint32_t window_fbo_id = static_cast(context).GetWindowFBOId(); static_cast(context).SetGLPresentCallback( - [window_fbo_id = window_fbo_id](uint32_t fbo_id) { - ASSERT_EQ(fbo_id, window_fbo_id); + [window_fbo_id = window_fbo_id](FlutterPresentInfo present_info) { + ASSERT_EQ(present_info.fbo_id, window_fbo_id); frame_latch.CountDown(); }); @@ -3149,6 +3215,315 @@ TEST_F(EmbedderTest, PresentInfoContainsValidFBOId) { frame_latch.Wait(); } +TEST_F(EmbedderTest, + PresentInfoReceivesFullDamageWhenExistingDamageIsWholeScreen) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(800, 600)); + builder.SetDartEntrypoint("render_gradient"); + builder.GetRendererConfig().open_gl.populate_existing_damage = + [](void* context, const intptr_t id, + FlutterDamage* existing_damage) -> void { + return reinterpret_cast(context) + ->GLPopulateExistingDamage(id, existing_damage); + }; + + // Return existing damage as the entire screen on purpose. + static_cast(context) + .SetGLPopulateExistingDamageCallback( + [](const intptr_t id, FlutterDamage* existing_damage_ptr) { + const size_t num_rects = 1; + FlutterRect existing_damage_rects[num_rects] = { + FlutterRect{0, 0, 800, 600}}; + existing_damage_ptr->num_rects = num_rects; + existing_damage_ptr->damage = existing_damage_rects; + }); + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + // First frame should be entirely rerendered. + static_cast(context).SetGLPresentCallback( + [](FlutterPresentInfo present_info) { + const size_t num_rects = 1; + ASSERT_EQ(present_info.frame_damage.num_rects, num_rects); + ASSERT_EQ(present_info.frame_damage.damage->left, 0); + ASSERT_EQ(present_info.frame_damage.damage->top, 0); + ASSERT_EQ(present_info.frame_damage.damage->right, 800); + ASSERT_EQ(present_info.frame_damage.damage->bottom, 600); + + ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects); + ASSERT_EQ(present_info.buffer_damage.damage->left, 0); + ASSERT_EQ(present_info.buffer_damage.damage->top, 0); + ASSERT_EQ(present_info.buffer_damage.damage->right, 800); + ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600); + }); + + // Send a window metrics events so frames may be scheduled. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 800; + event.height = 600; + event.pixel_ratio = 1.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); + + // Because it's the same as the first frame, the second frame damage should + // be empty but, because there was a full existing buffer damage, the buffer + // damage should be the entire screen. + static_cast(context).SetGLPresentCallback( + [](FlutterPresentInfo present_info) { + const size_t num_rects = 1; + ASSERT_EQ(present_info.frame_damage.num_rects, num_rects); + ASSERT_EQ(present_info.frame_damage.damage->left, 0); + ASSERT_EQ(present_info.frame_damage.damage->top, 0); + ASSERT_EQ(present_info.frame_damage.damage->right, 0); + ASSERT_EQ(present_info.frame_damage.damage->bottom, 0); + + ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects); + ASSERT_EQ(present_info.buffer_damage.damage->left, 0); + ASSERT_EQ(present_info.buffer_damage.damage->top, 0); + ASSERT_EQ(present_info.buffer_damage.damage->right, 800); + ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600); + }); + + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); +} + +TEST_F(EmbedderTest, PresentInfoReceivesEmptyDamage) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(800, 600)); + builder.SetDartEntrypoint("render_gradient"); + builder.GetRendererConfig().open_gl.populate_existing_damage = + [](void* context, const intptr_t id, + FlutterDamage* existing_damage) -> void { + return reinterpret_cast(context) + ->GLPopulateExistingDamage(id, existing_damage); + }; + + // Return no existing damage on purpose. + static_cast(context) + .SetGLPopulateExistingDamageCallback( + [](const intptr_t id, FlutterDamage* existing_damage_ptr) { + const size_t num_rects = 1; + FlutterRect existing_damage_rects[num_rects] = { + FlutterRect{0, 0, 0, 0}}; + existing_damage_ptr->num_rects = num_rects; + existing_damage_ptr->damage = existing_damage_rects; + }); + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + // First frame should be entirely rerendered. + static_cast(context).SetGLPresentCallback( + [](FlutterPresentInfo present_info) { + const size_t num_rects = 1; + ASSERT_EQ(present_info.frame_damage.num_rects, num_rects); + ASSERT_EQ(present_info.frame_damage.damage->left, 0); + ASSERT_EQ(present_info.frame_damage.damage->top, 0); + ASSERT_EQ(present_info.frame_damage.damage->right, 800); + ASSERT_EQ(present_info.frame_damage.damage->bottom, 600); + + ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects); + ASSERT_EQ(present_info.buffer_damage.damage->left, 0); + ASSERT_EQ(present_info.buffer_damage.damage->top, 0); + ASSERT_EQ(present_info.buffer_damage.damage->right, 800); + ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600); + }); + + // Send a window metrics events so frames may be scheduled. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 800; + event.height = 600; + event.pixel_ratio = 1.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); + + // Because it's the same as the first frame, the second frame should not be + // rerendered assuming there is no existing damage. + static_cast(context).SetGLPresentCallback( + [](FlutterPresentInfo present_info) { + const size_t num_rects = 1; + ASSERT_EQ(present_info.frame_damage.num_rects, num_rects); + ASSERT_EQ(present_info.frame_damage.damage->left, 0); + ASSERT_EQ(present_info.frame_damage.damage->top, 0); + ASSERT_EQ(present_info.frame_damage.damage->right, 0); + ASSERT_EQ(present_info.frame_damage.damage->bottom, 0); + + ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects); + ASSERT_EQ(present_info.buffer_damage.damage->left, 0); + ASSERT_EQ(present_info.buffer_damage.damage->top, 0); + ASSERT_EQ(present_info.buffer_damage.damage->right, 0); + ASSERT_EQ(present_info.buffer_damage.damage->bottom, 0); + }); + + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); +} + +TEST_F(EmbedderTest, PresentInfoReceivesPartialDamage) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(800, 600)); + builder.SetDartEntrypoint("render_gradient"); + builder.GetRendererConfig().open_gl.populate_existing_damage = + [](void* context, const intptr_t id, + FlutterDamage* existing_damage) -> void { + return reinterpret_cast(context) + ->GLPopulateExistingDamage(id, existing_damage); + }; + + // Return existing damage as only part of the screen on purpose. + static_cast(context) + .SetGLPopulateExistingDamageCallback( + [](const intptr_t id, FlutterDamage* existing_damage_ptr) { + const size_t num_rects = 1; + FlutterRect existing_damage_rects[num_rects] = { + FlutterRect{200, 150, 400, 300}}; + existing_damage_ptr->num_rects = num_rects; + existing_damage_ptr->damage = existing_damage_rects; + }); + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + // First frame should be entirely rerendered. + static_cast(context).SetGLPresentCallback( + [](FlutterPresentInfo present_info) { + const size_t num_rects = 1; + ASSERT_EQ(present_info.frame_damage.num_rects, num_rects); + ASSERT_EQ(present_info.frame_damage.damage->left, 0); + ASSERT_EQ(present_info.frame_damage.damage->top, 0); + ASSERT_EQ(present_info.frame_damage.damage->right, 800); + ASSERT_EQ(present_info.frame_damage.damage->bottom, 600); + + ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects); + ASSERT_EQ(present_info.buffer_damage.damage->left, 0); + ASSERT_EQ(present_info.buffer_damage.damage->top, 0); + ASSERT_EQ(present_info.buffer_damage.damage->right, 800); + ASSERT_EQ(present_info.buffer_damage.damage->bottom, 600); + }); + + // Send a window metrics events so frames may be scheduled. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 800; + event.height = 600; + event.pixel_ratio = 1.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); + + // Because it's the same as the first frame, the second frame damage should be + // empty but, because there was a partial existing damage, the buffer damage + // should represent that partial damage area. + static_cast(context).SetGLPresentCallback( + [](FlutterPresentInfo present_info) { + const size_t num_rects = 1; + ASSERT_EQ(present_info.frame_damage.num_rects, num_rects); + ASSERT_EQ(present_info.frame_damage.damage->left, 0); + ASSERT_EQ(present_info.frame_damage.damage->top, 0); + ASSERT_EQ(present_info.frame_damage.damage->right, 0); + ASSERT_EQ(present_info.frame_damage.damage->bottom, 0); + + ASSERT_EQ(present_info.buffer_damage.num_rects, num_rects); + ASSERT_EQ(present_info.buffer_damage.damage->left, 200); + ASSERT_EQ(present_info.buffer_damage.damage->top, 150); + ASSERT_EQ(present_info.buffer_damage.damage->right, 400); + ASSERT_EQ(present_info.buffer_damage.damage->bottom, 300); + }); + + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); +} + +TEST_F(EmbedderTest, PopulateExistingDamageReceivesValidID) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(800, 600)); + builder.SetDartEntrypoint("render_gradient"); + builder.GetRendererConfig().open_gl.populate_existing_damage = + [](void* context, const intptr_t id, + FlutterDamage* existing_damage) -> void { + return reinterpret_cast(context) + ->GLPopulateExistingDamage(id, existing_damage); + }; + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + const uint32_t window_fbo_id = + static_cast(context).GetWindowFBOId(); + static_cast(context) + .SetGLPopulateExistingDamageCallback( + [window_fbo_id = window_fbo_id](intptr_t id, + FlutterDamage* existing_damage) { + ASSERT_EQ(id, window_fbo_id); + }); + + // Send a window metrics events so frames may be scheduled. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 800; + event.height = 600; + event.pixel_ratio = 1.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); +} + +TEST_F(EmbedderTest, PopulateExistingDamageReceivesInvalidID) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(800, 600)); + builder.SetDartEntrypoint("render_gradient"); + builder.GetRendererConfig().open_gl.populate_existing_damage = + [](void* context, const intptr_t id, + FlutterDamage* existing_damage) -> void { + return reinterpret_cast(context) + ->GLPopulateExistingDamage(id, existing_damage); + }; + + // Return a bad FBO ID on purpose. + builder.GetRendererConfig().open_gl.fbo_with_frame_info_callback = + [](void* context, const FlutterFrameInfo* frame_info) -> uint32_t { + return 123; + }; + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + context.AddNativeCallback("SignalNativeTest", + CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + /* Nothing to do. */ + })); + + const uint32_t window_fbo_id = + static_cast(context).GetWindowFBOId(); + static_cast(context) + .SetGLPopulateExistingDamageCallback( + [window_fbo_id = window_fbo_id](intptr_t id, + FlutterDamage* existing_damage) { + ASSERT_NE(id, window_fbo_id); + }); + + // Send a window metrics events so frames may be scheduled. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = 800; + event.height = 600; + event.pixel_ratio = 1.0; + ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event), + kSuccess); +} + TEST_F(EmbedderTest, SetSingleDisplayConfigurationWithDisplayId) { auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); From a2f3bd58ce73815ae73a58dc1e124a4ae56c8ecd Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 14:11:48 -0400 Subject: [PATCH 297/558] Roll Skia from 579816c289d3 to 4c8980366baa (3 revisions) (#35379) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 7a1473728e92f..da62244882aae 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': '579816c289d3808a17f66396d23bfbea7c4152b0', + 'skia_revision': '4c8980366baa0b68c9f1496224531121a74a27c1', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index b05fcf9339343..1b195217671b1 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 026272190f940e2e22b194aed5a41ecc +Signature: e3109ae04a6971b05044adf250ea227c UNUSED LICENSES: From c4909788dcd1bac4ea0b33f2d7ba38a040a2af85 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 15:23:05 -0400 Subject: [PATCH 298/558] Roll Fuchsia Mac SDK from xp69KGYFKc4vMfCaO... to nCfx-rfACtWRHENfE... (#35382) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index da62244882aae..195d1fd2274d1 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'xp69KGYFKc4vMfCaOZPe5k8T7EnxuUG_jjLNj8D9xnUC' + 'version': 'nCfx-rfACtWRHENfEE4Sh08mBCybMk7ViNvRnCn7a6gC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From ca551395d32185bb3917a1bf18b8043c0f411600 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 15:30:17 -0400 Subject: [PATCH 299/558] Roll Skia from 4c8980366baa to fbbbdd228a14 (5 revisions) (#35383) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 195d1fd2274d1..a2e86ffaf3b31 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': '4c8980366baa0b68c9f1496224531121a74a27c1', + 'skia_revision': 'fbbbdd228a14ed046eb51b21bcce4179317c3534', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 1b195217671b1..d29c4640fc455 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e3109ae04a6971b05044adf250ea227c +Signature: 0e32bb42d0ca95516a349df9b19bc236 UNUSED LICENSES: From 7db09053a2fad347bf53c0ffb5c1004b402fc34c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 16:40:43 -0400 Subject: [PATCH 300/558] Roll Skia from fbbbdd228a14 to aa244737b2fd (2 revisions) (#35384) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index a2e86ffaf3b31..e1703be510a3a 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': 'fbbbdd228a14ed046eb51b21bcce4179317c3534', + 'skia_revision': 'aa244737b2fdc7c9f1d7cb6b20c039aa68046768', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index d29c4640fc455..5dbe403eee219 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 0e32bb42d0ca95516a349df9b19bc236 +Signature: 36ff19acd033f54c10835de91c2b4eb4 UNUSED LICENSES: From 45b29a2a4cb62906b93580744b3b1a5ebdc4cdf1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 17:34:04 -0400 Subject: [PATCH 301/558] Roll Dart SDK from 73b84ba39d98 to 29d9805d57e5 (1 revision) (#35385) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e1703be510a3a..84aeec257fdbd 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '73b84ba39d9875eeb5c201741073e424f51fd56a', + 'dart_revision': '29d9805d57e51308d217148bf98d103eea657552', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 0626456bbfb417811e12a779b54898508b578f05 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 17:51:33 -0400 Subject: [PATCH 302/558] Roll Skia from aa244737b2fd to 009ec4385403 (1 revision) (#35386) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 84aeec257fdbd..4d362d1571ce1 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': 'aa244737b2fdc7c9f1d7cb6b20c039aa68046768', + 'skia_revision': '009ec4385403d135e52fc65f3ccde1415f623106', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 5dbe403eee219..d1736b9bdba13 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 36ff19acd033f54c10835de91c2b4eb4 +Signature: 8e8f07251b77c50b2aaaf08b442524e1 UNUSED LICENSES: From fb19700742c3383cb7884514d95085310a009d95 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 19:37:12 -0400 Subject: [PATCH 303/558] Roll Skia from 009ec4385403 to de94ab05da63 (1 revision) (#35387) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 4d362d1571ce1..d2a77ca2d4f30 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': '009ec4385403d135e52fc65f3ccde1415f623106', + 'skia_revision': 'de94ab05da6301bb1fa49b329c12bdf8c413b3bc', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index d1736b9bdba13..328bc0096ad14 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 8e8f07251b77c50b2aaaf08b442524e1 +Signature: dac7e4cca7c97ff1d1d47e0edaa08ef1 UNUSED LICENSES: From 2180e62f6c7e43f1471a1b3bfc5776b47e726728 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 12 Aug 2022 21:31:16 -0400 Subject: [PATCH 304/558] Roll Dart SDK from 29d9805d57e5 to 3bfae4864b82 (1 revision) (#35390) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index d2a77ca2d4f30..0e4bd22abf13b 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '29d9805d57e51308d217148bf98d103eea657552', + 'dart_revision': '3bfae4864b82819cbfa184db1c7996ad4cef91f1', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From cd1a1cb757f595a900e0bc493bcfcb06875592f7 Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Fri, 12 Aug 2022 22:19:39 -0700 Subject: [PATCH 305/558] [Windows] Migrate error logging to FML_LOG (#35367) Migrates error logging from logging directly to stderr to using the FML_LOG macro with a specified log level. No additional tests since there is no semantic change to the logging (FML_LOG simply writes to stderr). --- .../platform/windows/angle_surface_manager.cc | 11 +++-- .../platform/windows/external_texture_d3d.cc | 4 +- .../windows/flutter_project_bundle.cc | 18 ++++---- shell/platform/windows/flutter_window.cc | 4 +- .../windows/flutter_windows_engine.cc | 46 +++++++++---------- .../flutter_windows_texture_registrar.cc | 8 ++-- .../windows/keyboard_key_channel_handler.cc | 5 +- .../platform/windows/keyboard_key_handler.cc | 7 ++- shell/platform/windows/keyboard_manager.cc | 9 ++-- shell/platform/windows/platform_handler.cc | 13 ++++-- shell/platform/windows/task_runner_window.cc | 5 +- 11 files changed, 66 insertions(+), 64 deletions(-) diff --git a/shell/platform/windows/angle_surface_manager.cc b/shell/platform/windows/angle_surface_manager.cc index 8f8daf02ddd54..95eb1d1224873 100644 --- a/shell/platform/windows/angle_surface_manager.cc +++ b/shell/platform/windows/angle_surface_manager.cc @@ -4,15 +4,16 @@ #include "flutter/shell/platform/windows/angle_surface_manager.h" -#include #include +#include "flutter/fml/logging.h" + // Logs an EGL error to stderr. This automatically calls eglGetError() // and logs the error code. static void LogEglError(std::string message) { EGLint error = eglGetError(); - std::cerr << "EGL: " << message << std::endl; - std::cerr << "EGL: eglGetError returned " << error << std::endl; + FML_LOG(ERROR) << "EGL: " << message; + FML_LOG(ERROR) << "EGL: eglGetError returned " << error; } namespace flutter { @@ -245,8 +246,8 @@ void AngleSurfaceManager::ResizeSurface(WindowsRenderTarget* render_target, ClearContext(); DestroySurface(); if (!CreateSurface(render_target, width, height)) { - std::cerr << "AngleSurfaceManager::ResizeSurface failed to create surface" - << std::endl; + FML_LOG(ERROR) + << "AngleSurfaceManager::ResizeSurface failed to create surface"; } } } diff --git a/shell/platform/windows/external_texture_d3d.cc b/shell/platform/windows/external_texture_d3d.cc index dfd4d1979daf4..cd8785d717c67 100644 --- a/shell/platform/windows/external_texture_d3d.cc +++ b/shell/platform/windows/external_texture_d3d.cc @@ -6,8 +6,8 @@ #include #include -#include +#include "flutter/fml/logging.h" #include "flutter/shell/platform/embedder/embedder_struct_macros.h" namespace flutter { @@ -107,7 +107,7 @@ bool ExternalTextureD3d::CreateOrUpdateTexture( if (egl_surface_ == EGL_NO_SURFACE || eglBindTexImage(surface_manager_->egl_display(), egl_surface_, EGL_BACK_BUFFER) == EGL_FALSE) { - std::cerr << "Binding D3D surface failed." << std::endl; + FML_LOG(ERROR) << "Binding D3D surface failed."; } last_surface_handle_ = handle; } diff --git a/shell/platform/windows/flutter_project_bundle.cc b/shell/platform/windows/flutter_project_bundle.cc index 90b2d782d7d7e..df289b526a0f4 100644 --- a/shell/platform/windows/flutter_project_bundle.cc +++ b/shell/platform/windows/flutter_project_bundle.cc @@ -5,8 +5,8 @@ #include "flutter/shell/platform/windows/flutter_project_bundle.h" #include -#include +#include "flutter/fml/logging.h" #include "flutter/shell/platform/common/engine_switches.h" // nogncheck #include "flutter/shell/platform/common/path_utils.h" @@ -34,9 +34,8 @@ FlutterProjectBundle::FlutterProjectBundle( (!aot_library_path_.empty() && aot_library_path_.is_relative())) { std::filesystem::path executable_location = GetExecutableDirectory(); if (executable_location.empty()) { - std::cerr - << "Unable to find executable location to resolve resource paths." - << std::endl; + FML_LOG(ERROR) + << "Unable to find executable location to resolve resource paths."; assets_path_ = std::filesystem::path(); icu_path_ = std::filesystem::path(); } else { @@ -59,14 +58,13 @@ bool FlutterProjectBundle::HasValidPaths() { UniqueAotDataPtr FlutterProjectBundle::LoadAotData( const FlutterEngineProcTable& engine_procs) { if (aot_library_path_.empty()) { - std::cerr - << "Attempted to load AOT data, but no aot_library_path was provided." - << std::endl; + FML_LOG(ERROR) + << "Attempted to load AOT data, but no aot_library_path was provided."; return UniqueAotDataPtr(nullptr, nullptr); } if (!std::filesystem::exists(aot_library_path_)) { - std::cerr << "Can't load AOT data from " << aot_library_path_.u8string() - << "; no such file." << std::endl; + FML_LOG(ERROR) << "Can't load AOT data from " + << aot_library_path_.u8string() << "; no such file."; return UniqueAotDataPtr(nullptr, nullptr); } std::string path_string = aot_library_path_.u8string(); @@ -76,7 +74,7 @@ UniqueAotDataPtr FlutterProjectBundle::LoadAotData( FlutterEngineAOTData data = nullptr; auto result = engine_procs.CreateAOTData(&source, &data); if (result != kSuccess) { - std::cerr << "Failed to load AOT data from: " << path_string << std::endl; + FML_LOG(ERROR) << "Failed to load AOT data from: " << path_string; return UniqueAotDataPtr(nullptr, nullptr); } return UniqueAotDataPtr(data, engine_procs.CollectAOTData); diff --git a/shell/platform/windows/flutter_window.cc b/shell/platform/windows/flutter_window.cc index c25f433d9317f..67926e0a8ed37 100644 --- a/shell/platform/windows/flutter_window.cc +++ b/shell/platform/windows/flutter_window.cc @@ -8,6 +8,8 @@ #include #include +#include "flutter/fml/logging.h" + namespace flutter { namespace { @@ -121,7 +123,7 @@ static uint64_t ConvertWinButtonToFlutterButton(UINT button) { case XBUTTON2: return kFlutterPointerButtonMouseForward; } - std::cerr << "Mouse button not recognized: " << button << std::endl; + FML_LOG(WARNING) << "Mouse button not recognized: " << button; return 0; } diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 54d68f232885b..972b9bb94b254 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -10,6 +10,7 @@ #include #include +#include "flutter/fml/logging.h" #include "flutter/fml/platform/win/wstring_conversion.h" #include "flutter/shell/platform/common/client_wrapper/binary_messenger_impl.h" #include "flutter/shell/platform/common/path_utils.h" @@ -156,17 +157,18 @@ FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project) embedder_api_.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&embedder_api_); - task_runner_ = std::make_unique( - embedder_api_.GetCurrentTime, [this](const auto* task) { - if (!engine_) { - std::cerr << "Cannot post an engine task when engine is not running." - << std::endl; - return; - } - if (embedder_api_.RunTask(engine_, task) != kSuccess) { - std::cerr << "Failed to post an engine task." << std::endl; - } - }); + task_runner_ = + std::make_unique( + embedder_api_.GetCurrentTime, [this](const auto* task) { + if (!engine_) { + FML_LOG(ERROR) + << "Cannot post an engine task when engine is not running."; + return; + } + if (embedder_api_.RunTask(engine_, task) != kSuccess) { + FML_LOG(ERROR) << "Failed to post an engine task."; + } + }); // Set up the legacy structs backing the API handles. messenger_ = std::make_unique(); @@ -206,7 +208,7 @@ bool FlutterWindowsEngine::Run() { bool FlutterWindowsEngine::Run(std::string_view entrypoint) { if (!project_->HasValidPaths()) { - std::cerr << "Missing or unresolvable paths to assets." << std::endl; + FML_LOG(ERROR) << "Missing or unresolvable paths to assets."; return false; } std::string assets_path_string = project_->assets_path().u8string(); @@ -214,7 +216,7 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { if (embedder_api_.RunsAOTCompiledDartCode()) { aot_data_ = project_->LoadAotData(embedder_api_); if (!aot_data_) { - std::cerr << "Unable to start engine without AOT data." << std::endl; + FML_LOG(ERROR) << "Unable to start engine without AOT data."; return false; } } @@ -272,10 +274,9 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { // method and only the entrypoint specified in project_ should be used. if (!project_->dart_entrypoint().empty() && !entrypoint.empty() && project_->dart_entrypoint() != entrypoint) { - std::cerr << "Conflicting entrypoints were specified in " - "FlutterDesktopEngineProperties.dart_entrypoint and " - "FlutterDesktopEngineRun(engine, entry_point). " - << std::endl; + FML_LOG(ERROR) << "Conflicting entrypoints were specified in " + "FlutterDesktopEngineProperties.dart_entrypoint and " + "FlutterDesktopEngineRun(engine, entry_point). "; return false; } if (!entrypoint.empty()) { @@ -339,8 +340,7 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { auto result = embedder_api_.Run(FLUTTER_ENGINE_VERSION, &renderer_config, &args, this, &engine_); if (result != kSuccess || engine_ == nullptr) { - std::cerr << "Failed to start Flutter engine: error " << result - << std::endl; + FML_LOG(ERROR) << "Failed to start Flutter engine: error " << result; return false; } @@ -454,7 +454,7 @@ bool FlutterWindowsEngine::SendPlatformMessage( embedder_api_.PlatformMessageCreateResponseHandle( engine_, reply, user_data, &response_handle); if (result != kSuccess) { - std::cout << "Failed to create response handle\n"; + FML_LOG(ERROR) << "Failed to create response handle"; return false; } } @@ -486,9 +486,9 @@ void FlutterWindowsEngine::SendPlatformMessageResponse( void FlutterWindowsEngine::HandlePlatformMessage( const FlutterPlatformMessage* engine_message) { if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { - std::cerr << "Invalid message size received. Expected: " - << sizeof(FlutterPlatformMessage) << " but received " - << engine_message->struct_size << std::endl; + FML_LOG(ERROR) << "Invalid message size received. Expected: " + << sizeof(FlutterPlatformMessage) << " but received " + << engine_message->struct_size; return; } diff --git a/shell/platform/windows/flutter_windows_texture_registrar.cc b/shell/platform/windows/flutter_windows_texture_registrar.cc index 9e3b3bd0f77a5..0abc73b75afe3 100644 --- a/shell/platform/windows/flutter_windows_texture_registrar.cc +++ b/shell/platform/windows/flutter_windows_texture_registrar.cc @@ -4,9 +4,9 @@ #include "flutter/shell/platform/windows/flutter_windows_texture_registrar.h" -#include #include +#include "flutter/fml/logging.h" #include "flutter/shell/platform/embedder/embedder_struct_macros.h" #include "flutter/shell/platform/windows/external_texture_d3d.h" #include "flutter/shell/platform/windows/external_texture_pixelbuffer.h" @@ -31,7 +31,7 @@ int64_t FlutterWindowsTextureRegistrar::RegisterTexture( if (texture_info->type == kFlutterDesktopPixelBufferTexture) { if (!texture_info->pixel_buffer_config.callback) { - std::cerr << "Invalid pixel buffer texture callback." << std::endl; + FML_LOG(ERROR) << "Invalid pixel buffer texture callback."; return kInvalidTexture; } @@ -47,7 +47,7 @@ int64_t FlutterWindowsTextureRegistrar::RegisterTexture( surface_type == kFlutterDesktopGpuSurfaceTypeD3d11Texture2D) { auto callback = SAFE_ACCESS(gpu_surface_config, callback, nullptr); if (!callback) { - std::cerr << "Invalid GPU surface descriptor callback." << std::endl; + FML_LOG(ERROR) << "Invalid GPU surface descriptor callback."; return kInvalidTexture; } @@ -58,7 +58,7 @@ int64_t FlutterWindowsTextureRegistrar::RegisterTexture( } } - std::cerr << "Attempted to register texture of unsupport type." << std::endl; + FML_LOG(ERROR) << "Attempted to register texture of unsupport type."; return kInvalidTexture; } diff --git a/shell/platform/windows/keyboard_key_channel_handler.cc b/shell/platform/windows/keyboard_key_channel_handler.cc index 0359903b9e07f..94041cdb15d1f 100644 --- a/shell/platform/windows/keyboard_key_channel_handler.cc +++ b/shell/platform/windows/keyboard_key_channel_handler.cc @@ -6,8 +6,7 @@ #include -#include - +#include "flutter/fml/logging.h" #include "flutter/shell/platform/common/json_message_codec.h" #include "flutter/shell/platform/windows/keyboard_utils.h" @@ -139,7 +138,7 @@ void KeyboardKeyChannelHandler::KeyboardHook( event.AddMember(kTypeKey, kKeyUp, allocator); break; default: - std::cerr << "Unknown key event action: " << action << std::endl; + FML_LOG(WARNING) << "Unknown key event action: " << action; callback(false); return; } diff --git a/shell/platform/windows/keyboard_key_handler.cc b/shell/platform/windows/keyboard_key_handler.cc index d31aee1c28d7f..718c6f2afbcca 100644 --- a/shell/platform/windows/keyboard_key_handler.cc +++ b/shell/platform/windows/keyboard_key_handler.cc @@ -6,8 +6,7 @@ #include -#include - +#include "flutter/fml/logging.h" #include "flutter/shell/platform/windows/keyboard_utils.h" namespace flutter { @@ -48,10 +47,10 @@ void KeyboardKeyHandler::KeyboardHook(int key, incoming->callback = std::move(callback); if (pending_responds_.size() > kMaxPendingEvents) { - std::cerr + FML_LOG(ERROR) << "There are " << pending_responds_.size() << " keyboard events that have not yet received a response from the " - << "framework. Are responses being sent?" << std::endl; + << "framework. Are responses being sent?"; } pending_responds_.push_back(std::move(incoming)); diff --git a/shell/platform/windows/keyboard_manager.cc b/shell/platform/windows/keyboard_manager.cc index 5bd25a636699f..d8891a5a9c996 100644 --- a/shell/platform/windows/keyboard_manager.cc +++ b/shell/platform/windows/keyboard_manager.cc @@ -3,10 +3,10 @@ // found in the LICENSE file. #include -#include #include #include +#include "flutter/fml/logging.h" #include "flutter/shell/platform/windows/keyboard_manager.h" #include "flutter/shell/platform/windows/keyboard_utils.h" @@ -120,15 +120,14 @@ void KeyboardManager::RedispatchEvent(std::unique_ptr event) { UINT result = window_delegate_->Win32DispatchMessage( message.action, message.wparam, message.lparam); if (result != 0) { - std::cerr << "Unable to synthesize event for keyboard event." - << std::endl; + FML_LOG(ERROR) << "Unable to synthesize event for keyboard event."; } } if (pending_redispatches_.size() > kMaxPendingEvents) { - std::cerr + FML_LOG(ERROR) << "There are " << pending_redispatches_.size() << " keyboard events that have not yet received a response from the " - << "framework. Are responses being sent?" << std::endl; + << "framework. Are responses being sent?"; } } diff --git a/shell/platform/windows/platform_handler.cc b/shell/platform/windows/platform_handler.cc index d1ab70090ed5b..c73677da1b1f8 100644 --- a/shell/platform/windows/platform_handler.cc +++ b/shell/platform/windows/platform_handler.cc @@ -7,9 +7,9 @@ #include #include -#include #include +#include "flutter/fml/logging.h" #include "flutter/fml/platform/win/wstring_conversion.h" #include "flutter/shell/platform/common/json_method_codec.h" #include "flutter/shell/platform/windows/flutter_windows_view.h" @@ -41,14 +41,16 @@ class ScopedGlobalMemory { ScopedGlobalMemory(unsigned int flags, size_t bytes) { memory_ = ::GlobalAlloc(flags, bytes); if (!memory_) { - std::cerr << "Unable to allocate global memory: " << ::GetLastError(); + FML_LOG(ERROR) << "Unable to allocate global memory: " + << ::GetLastError(); } } ~ScopedGlobalMemory() { if (memory_) { if (::GlobalFree(memory_) != nullptr) { - std::cerr << "Failed to free global allocation: " << ::GetLastError(); + FML_LOG(ERROR) << "Failed to free global allocation: " + << ::GetLastError(); } } } @@ -79,7 +81,7 @@ class ScopedGlobalLock { if (memory) { locked_memory_ = ::GlobalLock(memory); if (!locked_memory_) { - std::cerr << "Unable to acquire global lock: " << ::GetLastError(); + FML_LOG(ERROR) << "Unable to acquire global lock: " << ::GetLastError(); } } } @@ -89,7 +91,8 @@ class ScopedGlobalLock { if (!::GlobalUnlock(source_)) { DWORD error = ::GetLastError(); if (error != NO_ERROR) { - std::cerr << "Unable to release global lock: " << ::GetLastError(); + FML_LOG(ERROR) << "Unable to release global lock: " + << ::GetLastError(); } } } diff --git a/shell/platform/windows/task_runner_window.cc b/shell/platform/windows/task_runner_window.cc index ccdf4b570ac13..5aa21da9dc67b 100644 --- a/shell/platform/windows/task_runner_window.cc +++ b/shell/platform/windows/task_runner_window.cc @@ -5,7 +5,8 @@ #include "flutter/shell/platform/windows/task_runner_window.h" #include -#include + +#include "flutter/fml/logging.h" namespace flutter { @@ -52,7 +53,7 @@ std::shared_ptr TaskRunnerWindow::GetSharedInstance() { void TaskRunnerWindow::WakeUp() { if (!PostMessage(window_handle_, WM_NULL, 0, 0)) { - std::cerr << "Failed to post message to main thread." << std::endl; + FML_LOG(ERROR) << "Failed to post message to main thread."; } } From 5cc5c5f04f0a6e2525746268fb2dd8d588072711 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 13 Aug 2022 02:04:05 -0400 Subject: [PATCH 306/558] Roll Dart SDK from 3bfae4864b82 to bc96e1681db3 (1 revision) (#35391) --- DEPS | 10 +++++----- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DEPS b/DEPS index 0e4bd22abf13b..d918435119371 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '3bfae4864b82819cbfa184db1c7996ad4cef91f1', + 'dart_revision': 'bc96e1681db3741789d0baf4bd05f357c7afa9bb', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -46,11 +46,11 @@ vars = { 'dart_clock_rev': '2507a228773c5e877fc9e3330080b234aad965c0', 'dart_collection_rev': '414ffa1bc8ba18bd608bbf916d95715311d89ac1', 'dart_devtools_rev': 'd131d19091f6b89ac89486bd92440a25a523e8b0', - 'dart_protobuf_rev': '6f5360ba1d6c4605049fa3574357dab7c8d38400', + 'dart_protobuf_rev': '7edcdde795cd63f147d4b3c9c054d6bcd8b0ead2', 'dart_pub_rev': 'ac7db6c07318efa4a8712110275eaf70f96a6d00', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': 'e00c0ea769e32821d91c0880da8eb736839a6e6d', - 'dart_webdev_rev': '490d6a06f7ed75654bcfd5a0e8351f8a0f59df1c', + 'dart_webdev_rev': '8afdb97e783b32f78cb59bd83161f9ab62b2c7f7', 'dart_webkit_inspection_protocol_rev': '57522d6b29d94903b765c757079d906555d5a171', 'dart_yaml_edit_rev': '01589b3ce447b03aed991db49f1ec6445ad5476d', 'dart_zlib_rev': '27c2f474b71d0d20764f86f60ef8b00da1a16cda', @@ -203,7 +203,7 @@ deps = { Var('dart_git') + '/dart_style.git@49bc3ff32b5578b6e19f8fd376d668130941ee29', 'src/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@8ee30225e2d89d6044dc48965c9ce1ec1c406cb9', + Var('dart_git') + '/dartdoc.git@446e0fd1f26b47d2b0b48505f3ed8c9f48d22f57', 'src/third_party/dart/third_party/pkg/ffi': Var('dart_git') + '/ffi.git@18b2b549d55009ff594600b04705ff6161681e07', @@ -221,7 +221,7 @@ deps = { Var('dart_git') + '/html.git@8243e967caad9932c13971af3b2a7c8f028383d5', 'src/third_party/dart/third_party/pkg/http': - Var('dart_git') + '/http.git@45f91f23847d51df53bb704bd25a7f64fb117081', + Var('dart_git') + '/http.git@c440755e7c101abf153b52755545f21698e9da63', 'src/third_party/dart/third_party/pkg/http_multi_server': Var('dart_git') + '/http_multi_server.git@20bf079c8955d1250a45afb9cb096472a724a551', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 7c24384f15b63..b2071236864bc 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: aa6af9f3f9c51da06dbf3854f112dde0 +Signature: c143e3ea1bdd8ab9276906301751724b UNUSED LICENSES: From b88c04b9e3d64ac3768a87e7377929c01d3be7b3 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 13 Aug 2022 03:46:08 -0400 Subject: [PATCH 307/558] Roll Skia from de94ab05da63 to a36d00818f3d (1 revision) (#35392) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d918435119371..fb12eab092b93 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': 'de94ab05da6301bb1fa49b329c12bdf8c413b3bc', + 'skia_revision': 'a36d00818f3daa1410cc4a4162153b5eab76d9f3', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 328bc0096ad14..fe9de256f7483 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: dac7e4cca7c97ff1d1d47e0edaa08ef1 +Signature: 54b0bb352069bc17360b6e136b5352ad UNUSED LICENSES: From 18dca3de7496563a57c8b25487c1d869f5b1c950 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 13 Aug 2022 04:20:09 -0400 Subject: [PATCH 308/558] Roll Fuchsia Mac SDK from nCfx-rfACtWRHENfE... to Hnz_UoVKLOuTrxp_X... (#35393) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index fb12eab092b93..8e44338b74661 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'nCfx-rfACtWRHENfEE4Sh08mBCybMk7ViNvRnCn7a6gC' + 'version': 'Hnz_UoVKLOuTrxp_XFUOEksXp7SJnq5mJnHBnNXZz9oC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 83771593cb551bf1da890bc3e5977db0409d9422 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 13 Aug 2022 17:14:22 -0400 Subject: [PATCH 309/558] Roll Fuchsia Mac SDK from Hnz_UoVKLOuTrxp_X... to 4hPJa443oXXdJyx52... (#35395) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 8e44338b74661..bd415bd45ab0f 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'Hnz_UoVKLOuTrxp_XFUOEksXp7SJnq5mJnHBnNXZz9oC' + 'version': '4hPJa443oXXdJyx52NolaaDFOSWe4T34exkoBwefls4C' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From f49a617535af12dbdd83b3c648726f6a41a68b6d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 14 Aug 2022 06:32:34 -0400 Subject: [PATCH 310/558] Roll Fuchsia Mac SDK from 4hPJa443oXXdJyx52... to ZoZVdTL7kJ13TVSo9... (#35396) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index bd415bd45ab0f..55133ade96298 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': '4hPJa443oXXdJyx52NolaaDFOSWe4T34exkoBwefls4C' + 'version': 'ZoZVdTL7kJ13TVSo9tEwdHNZbkLmghInNFLpmwu-g9AC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From cc9f4c63b7e509c1f0adb65227af2a57ae93a100 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 14 Aug 2022 19:23:05 -0400 Subject: [PATCH 311/558] Roll Fuchsia Mac SDK from ZoZVdTL7kJ13TVSo9... to 8JM9sWJEq4xWtq2LS... (#35397) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 55133ade96298..e92d7750d9617 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'ZoZVdTL7kJ13TVSo9tEwdHNZbkLmghInNFLpmwu-g9AC' + 'version': '8JM9sWJEq4xWtq2LSNMqLhYoiq0MCZWRq23SJBeAPSgC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 4656c2f46cad633ac3fb93db1fa612de4bc67749 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 01:53:58 -0400 Subject: [PATCH 312/558] Roll Skia from a36d00818f3d to 6064203b019b (1 revision) (#35398) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e92d7750d9617..66e926f676130 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': 'a36d00818f3daa1410cc4a4162153b5eab76d9f3', + 'skia_revision': '6064203b019b6fa3163e0f6af663ad5677071953', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index fe9de256f7483..f6d4460e68d02 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 54b0bb352069bc17360b6e136b5352ad +Signature: ac9d5ca2a5a3c425f381e1c424ee8bf6 UNUSED LICENSES: From 16fb19e72f883c43e04136fafabf7466bad0cf1f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 03:13:05 -0400 Subject: [PATCH 313/558] Roll Skia from 6064203b019b to d8a4a8a96695 (2 revisions) (#35399) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 66e926f676130..e84a60b237a0b 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': '6064203b019b6fa3163e0f6af663ad5677071953', + 'skia_revision': 'd8a4a8a966952e9326973f05b69e0c26ff679d5c', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f6d4460e68d02..dfeb9827b871c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: ac9d5ca2a5a3c425f381e1c424ee8bf6 +Signature: 82f49e810b044c27246a01bf47bf224a UNUSED LICENSES: From 9c3c233e2639bbb984b27937653b4335d50ee0a9 Mon Sep 17 00:00:00 2001 From: harbor <58758250+zzm990321@users.noreply.github.com> Date: Mon, 15 Aug 2022 20:05:26 +0800 Subject: [PATCH 314/558] Fix PlatformView multiple pointer crash caused by toMotionEvent (#34182) --- .../platform/PlatformViewsController.java | 2 +- .../platform/PlatformViewsControllerTest.java | 48 ++++++++++++++++++- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java index 4f78a732d1fe1..794d339c79452 100644 --- a/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java +++ b/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java @@ -626,7 +626,7 @@ public MotionEvent toMotionEvent( return MotionEvent.obtain( trackedEvent.getDownTime(), trackedEvent.getEventTime(), - trackedEvent.getAction(), + touch.action, touch.pointerCount, pointerProperties, pointerCoords, diff --git a/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java b/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java index d3fb9a8659efe..824c148a70086 100644 --- a/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java +++ b/shell/platform/android/test/io/flutter/plugin/platform/PlatformViewsControllerTest.java @@ -172,6 +172,51 @@ public void itUsesActionEventTypeFromFrameworkEventForVirtualDisplays() { assertNotEquals(resolvedEvent.getAction(), original.getAction()); } + @Test + public void itUsesActionEventTypeFromFrameworkEventAsActionChanged() { + MotionEventTracker motionEventTracker = MotionEventTracker.getInstance(); + PlatformViewsController platformViewsController = new PlatformViewsController(); + + MotionEvent original = + MotionEvent.obtain( + 10, // downTime + 10, // eventTime + 261, // action + 0, // x + 0, // y + 0 // metaState + ); + + MotionEventTracker.MotionEventId motionEventId = motionEventTracker.track(original); + + PlatformViewTouch frameWorkTouch = + new PlatformViewTouch( + 0, // viewId + original.getDownTime(), + original.getEventTime(), + 0, // action + 1, // pointerCount + Arrays.asList(Arrays.asList(0, 0)), // pointer properties + Arrays.asList(Arrays.asList(0., 1., 2., 3., 4., 5., 6., 7., 8.)), // pointer coords + original.getMetaState(), + original.getButtonState(), + original.getXPrecision(), + original.getYPrecision(), + original.getDeviceId(), + original.getEdgeFlags(), + original.getSource(), + original.getFlags(), + motionEventId.getId()); + MotionEvent resolvedEvent = + platformViewsController.toMotionEvent( + 1, // density + frameWorkTouch, + false // usingVirtualDisplays + ); + assertEquals(resolvedEvent.getAction(), frameWorkTouch.action); + assertNotEquals(resolvedEvent.getAction(), original.getAction()); + } + @Ignore @Test public void itUsesActionEventTypeFromMotionEventForHybridPlatformViews() { @@ -214,8 +259,7 @@ public void itUsesActionEventTypeFromMotionEventForHybridPlatformViews() { platformViewsController.toMotionEvent( /*density=*/ 1, frameWorkTouch, /*usingVirtualDisplay=*/ false); - assertNotEquals(resolvedEvent.getAction(), frameWorkTouch.action); - assertEquals(resolvedEvent.getAction(), original.getAction()); + assertEquals(resolvedEvent.getAction(), frameWorkTouch.action); } @Test From f0c3829e90ce81603f8260be346def256be5b63f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 08:13:04 -0400 Subject: [PATCH 315/558] Roll Fuchsia Mac SDK from 8JM9sWJEq4xWtq2LS... to PJ0cBTzMh-pPVIynC... (#35401) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e84a60b237a0b..4d3739bec8861 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': '8JM9sWJEq4xWtq2LSNMqLhYoiq0MCZWRq23SJBeAPSgC' + 'version': 'PJ0cBTzMh-pPVIynC_wnWSqShlOin7g2HVysb6cAyF8C' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 5fb00106be1037047139b7b975c4c14f9ee3634d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 10:12:10 -0400 Subject: [PATCH 316/558] Roll Skia from d8a4a8a96695 to 0331237b7b78 (1 revision) (#35402) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 4d3739bec8861..f8a419e3d97e2 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': 'd8a4a8a966952e9326973f05b69e0c26ff679d5c', + 'skia_revision': '0331237b7b7874250c7f82094cd460cc55154b1c', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index dfeb9827b871c..2b41aa8822f20 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 82f49e810b044c27246a01bf47bf224a +Signature: 854f8a35f9b9133c3a66548391e69ec1 UNUSED LICENSES: From 8c019cdd446fe7a510ff8e76217e221c39d82bb4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 10:49:13 -0400 Subject: [PATCH 317/558] Roll Dart SDK from bc96e1681db3 to 1cbb177c7339 (1 revision) (#35403) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index f8a419e3d97e2..cfbdceb133f57 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'bc96e1681db3741789d0baf4bd05f357c7afa9bb', + 'dart_revision': '1cbb177c73397a9f2cf44e07f9ba81c75661c208', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 198b0051a5a2094e54a1de16ee9c620bfc427d65 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 11:59:19 -0400 Subject: [PATCH 318/558] Roll Skia from 0331237b7b78 to babb35ec754b (2 revisions) (#35405) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index cfbdceb133f57..af12862fa9f09 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': '0331237b7b7874250c7f82094cd460cc55154b1c', + 'skia_revision': 'babb35ec754b583518b11d535b98a51bfc0dc90f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 2b41aa8822f20..bab1da703a53e 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 854f8a35f9b9133c3a66548391e69ec1 +Signature: 317e5d5910b70bc39832e4b51ff866e4 UNUSED LICENSES: From 33fccf5649735bd8c449def276a158b995602cc9 Mon Sep 17 00:00:00 2001 From: Bernardo Eilert Trevisan <43152751+betrevisan@users.noreply.github.com> Date: Mon, 15 Aug 2022 09:45:07 -0700 Subject: [PATCH 319/558] GLFW example with dirty region management (#35057) * Update the GLFW example callbacks. * Update the dart example. * Update CMakeLists * Update library dependencies in the BUILD file. * Documenting. * Formatting. * Update the callback name. * Move glfw_drm example to a new folder. * Create new example folder for drm_embedder. * Add the flutter spinkit dependency * Update BUILD files. * Do not compile glfw_drm example if running it on mac. * Update the executable name for the glfw_drm example. * Avoid looking for the surface and display every time since they are always the same. * Formatting. * GN formatting. * Update the way the user malloc's the existing damage * Update comment * Update example and add gitignore. Co-authored-by: Bernardo Eilert Trevisan --- BUILD.gn | 4 + examples/glfw_drm/.gitignore | 1 + examples/glfw_drm/BUILD.gn | 20 ++ examples/glfw_drm/CMakeLists.txt | 35 +++ examples/glfw_drm/FlutterEmbedderGLFW.cc | 334 +++++++++++++++++++++++ examples/glfw_drm/README.md | 37 +++ examples/glfw_drm/main.dart | 80 ++++++ examples/glfw_drm/run.sh | 33 +++ 8 files changed, 544 insertions(+) create mode 100644 examples/glfw_drm/.gitignore create mode 100644 examples/glfw_drm/BUILD.gn create mode 100644 examples/glfw_drm/CMakeLists.txt create mode 100644 examples/glfw_drm/FlutterEmbedderGLFW.cc create mode 100644 examples/glfw_drm/README.md create mode 100644 examples/glfw_drm/main.dart create mode 100755 examples/glfw_drm/run.sh diff --git a/BUILD.gn b/BUILD.gn index a4dd6ca59ce58..97c2c4fe9c38a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -84,6 +84,10 @@ group("flutter") { "//flutter/examples/glfw", "//flutter/examples/vulkan_glfw", ] + + if (!is_mac) { + public_deps += [ "//flutter/examples/glfw_drm" ] + } } # If enbaled, compile the SDK / snapshot. diff --git a/examples/glfw_drm/.gitignore b/examples/glfw_drm/.gitignore new file mode 100644 index 0000000000000..b7443460fb263 --- /dev/null +++ b/examples/glfw_drm/.gitignore @@ -0,0 +1 @@ +debug/ diff --git a/examples/glfw_drm/BUILD.gn b/examples/glfw_drm/BUILD.gn new file mode 100644 index 0000000000000..784e5654e5e69 --- /dev/null +++ b/examples/glfw_drm/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//flutter/examples/examples.gni") + +if (build_embedder_examples) { + executable("glfw_drm") { + output_name = "embedder_example_drm" + + sources = [ "FlutterEmbedderGLFW.cc" ] + + deps = [ + "//flutter/shell/platform/embedder:embedder", + "//third_party/glfw", + ] + + libs = [ "EGL" ] + } +} diff --git a/examples/glfw_drm/CMakeLists.txt b/examples/glfw_drm/CMakeLists.txt new file mode 100644 index 0000000000000..2563bd8bee05a --- /dev/null +++ b/examples/glfw_drm/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.15) +project(FlutterEmbedderGLFW) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) + +add_executable(flutter_glfw FlutterEmbedderGLFW.cc) + +############################################################ +# GLFW +############################################################ +option(GLFW_BUILD_EXAMPLES "" OFF) +option(GLFW_BUILD_TESTS "" OFF) +option(GLFW_BUILD_DOCS "" OFF) +option(GLFW_INSTALL "" OFF) +find_package(OpenGL REQUIRED COMPONENTS EGL) +include_directories(${OPENGL_INCLUDE_DIRS}) +add_subdirectory(${CMAKE_SOURCE_DIR}/../../../third_party/glfw glfw) +target_link_libraries(flutter_glfw glfw OpenGL::EGL) +include_directories(${CMAKE_SOURCE_DIR}/../../../third_party/glfw/include) + +############################################################ +# Flutter Engine +############################################################ +# This is assuming you've built a local version of the Flutter Engine. If you +# downloaded yours is from the internet you'll have to change this. +include_directories(${CMAKE_SOURCE_DIR}/../../shell/platform/embedder) +find_library(FLUTTER_LIB flutter_engine PATHS ${CMAKE_SOURCE_DIR}/../../../out/host_debug_unopt) +target_link_libraries(flutter_glfw ${FLUTTER_LIB}) + +# Copy the flutter library here since the shared library +# name is `./libflutter_engine.dylib`. +add_custom_command( + TARGET flutter_glfw POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${FLUTTER_LIB} + ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/examples/glfw_drm/FlutterEmbedderGLFW.cc b/examples/glfw_drm/FlutterEmbedderGLFW.cc new file mode 100644 index 0000000000000..d75811092f927 --- /dev/null +++ b/examples/glfw_drm/FlutterEmbedderGLFW.cc @@ -0,0 +1,334 @@ +// 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 + +#define GLFW_EXPOSE_NATIVE_EGL +#define GLFW_INCLUDE_GLEXT + +#include +#include +#include +#include +#include +#include +#include "GLFW/glfw3.h" +#include "GLFW/glfw3native.h" +#include "embedder.h" + +// This value is calculated after the window is created. +static double g_pixelRatio = 1.0; +static const size_t kInitialWindowWidth = 800; +static const size_t kInitialWindowHeight = 600; +// Maximum damage history - for triple buffering we need to store damage for +// last two frames; Some Android devices (Pixel 4) use quad buffering. +static const int kMaxHistorySize = 10; + +// Keeps track of the most recent frame damages so that existing damage can +// be easily computed. +std::list damage_history_; + +// Keeps track of the existing damage associated with each FBO ID +std::unordered_map existing_damage_map_; + +EGLDisplay display_; +EGLSurface surface_; + +static_assert(FLUTTER_ENGINE_VERSION == 1, + "This Flutter Embedder was authored against the stable Flutter " + "API at version 1. There has been a serious breakage in the " + "API. Please read the ChangeLog and take appropriate action " + "before updating this assertion"); + +void GLFWcursorPositionCallbackAtPhase(GLFWwindow* window, + FlutterPointerPhase phase, + double x, + double y) { + FlutterPointerEvent event = {}; + event.struct_size = sizeof(event); + event.phase = phase; + event.x = x * g_pixelRatio; + event.y = y * g_pixelRatio; + event.timestamp = + std::chrono::duration_cast( + std::chrono::high_resolution_clock::now().time_since_epoch()) + .count(); + FlutterEngineSendPointerEvent( + reinterpret_cast(glfwGetWindowUserPointer(window)), &event, + 1); +} + +void GLFWcursorPositionCallback(GLFWwindow* window, double x, double y) { + GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kMove, x, y); +} + +void GLFWmouseButtonCallback(GLFWwindow* window, + int key, + int action, + int mods) { + if (key == GLFW_MOUSE_BUTTON_1 && action == GLFW_PRESS) { + double x, y; + glfwGetCursorPos(window, &x, &y); + GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kDown, x, y); + glfwSetCursorPosCallback(window, GLFWcursorPositionCallback); + } + + if (key == GLFW_MOUSE_BUTTON_1 && action == GLFW_RELEASE) { + double x, y; + glfwGetCursorPos(window, &x, &y); + GLFWcursorPositionCallbackAtPhase(window, FlutterPointerPhase::kUp, x, y); + glfwSetCursorPosCallback(window, nullptr); + } +} + +static void GLFWKeyCallback(GLFWwindow* window, + int key, + int scancode, + int action, + int mods) { + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + glfwSetWindowShouldClose(window, GLFW_TRUE); + } +} + +void GLFWwindowSizeCallback(GLFWwindow* window, int width, int height) { + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = width * g_pixelRatio; + event.height = height * g_pixelRatio; + event.pixel_ratio = g_pixelRatio; + FlutterEngineSendWindowMetricsEvent( + reinterpret_cast(glfwGetWindowUserPointer(window)), + &event); +} + +// Auxiliary function used to transform a FlutterRect into the format that is +// expected by the EGL functions (i.e. array of EGLint). +static std::array RectToInts(const FlutterRect rect) { + EGLint height; + eglQuerySurface(display_, surface_, EGL_HEIGHT, &height); + + std::array res{ + static_cast(rect.left), height - static_cast(rect.bottom), + static_cast(rect.right) - static_cast(rect.left), + static_cast(rect.bottom) - static_cast(rect.top)}; + return res; +} + +// Auxiliary function to union the damage regions comprised by two FlutterRect +// element. It saves the result of this join in the rect variable. +static void JoinFlutterRect(FlutterRect* rect, FlutterRect additional_rect) { + rect->left = std::min(rect->left, additional_rect.left); + rect->top = std::min(rect->top, additional_rect.top); + rect->right = std::max(rect->right, additional_rect.right); + rect->bottom = std::max(rect->bottom, additional_rect.bottom); +} + +// Auxiliary function used to check if the given list of extensions contains the +// requested extension name. +static bool HasExtension(const char* extensions, const char* name) { + const char* r = strstr(extensions, name); + auto len = strlen(name); + // check that the extension name is terminated by space or null terminator + return r != nullptr && (r[len] == ' ' || r[len] == 0); +} + +bool RunFlutter(GLFWwindow* window, + const std::string& project_path, + const std::string& icudtl_path) { + FlutterRendererConfig config = {}; + config.type = kOpenGL; + config.open_gl.struct_size = sizeof(config.open_gl); + config.open_gl.make_current = [](void* userdata) -> bool { + glfwMakeContextCurrent(static_cast(userdata)); + return true; + }; + config.open_gl.clear_current = [](void*) -> bool { + glfwMakeContextCurrent(nullptr); // is this even a thing? + return true; + }; + config.open_gl.present_with_info = + [](void* userdata, const FlutterPresentInfo* info) -> bool { + // Free the existing damage that was allocated to this frame. + free(existing_damage_map_[info->fbo_id]); + + // Get list of extensions. + const char* extensions = eglQueryString(display_, EGL_EXTENSIONS); + + // Retrieve the set damage region function. + PFNEGLSETDAMAGEREGIONKHRPROC set_damage_region_ = nullptr; + if (HasExtension(extensions, "EGL_KHR_partial_update")) { + set_damage_region_ = reinterpret_cast( + eglGetProcAddress("eglSetDamageRegionKHR")); + } + + // Retrieve the swap buffers with damage function. + PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage_ = nullptr; + if (HasExtension(extensions, "EGL_EXT_swap_buffers_with_damage")) { + swap_buffers_with_damage_ = + reinterpret_cast( + eglGetProcAddress("eglSwapBuffersWithDamageEXT")); + } else if (HasExtension(extensions, "EGL_KHR_swap_buffers_with_damage")) { + swap_buffers_with_damage_ = + reinterpret_cast( + eglGetProcAddress("eglSwapBuffersWithDamageKHR")); + } + + if (set_damage_region_) { + // Set the buffer damage as the damage region. + auto buffer_rects = RectToInts(info->buffer_damage.damage[0]); + set_damage_region_(display_, surface_, buffer_rects.data(), 1); + } + + // Add frame damage to damage history + damage_history_.push_back(info->frame_damage.damage[0]); + if (damage_history_.size() > kMaxHistorySize) { + damage_history_.pop_front(); + } + + if (swap_buffers_with_damage_) { + // Swap buffers with frame damage. + auto frame_rects = RectToInts(info->frame_damage.damage[0]); + return swap_buffers_with_damage_(display_, surface_, frame_rects.data(), + 1); + } else { + // If the required extensions for partial repaint were not provided, do + // full repaint. + return eglSwapBuffers(display_, surface_); + } + }; + config.open_gl.fbo_callback = [](void*) -> uint32_t { + return 0; // FBO0 + }; + config.open_gl.populate_existing_damage = + [](void* userdata, intptr_t fbo_id, + FlutterDamage* existing_damage) -> void { + // Given the FBO age, create existing damage region by joining all frame + // damages since FBO was last used + EGLint age; + if (glfwExtensionSupported("GL_EXT_buffer_age") == GLFW_TRUE) { + eglQuerySurface(display_, surface_, EGL_BUFFER_AGE_EXT, &age); + } else { + age = 4; // Virtually no driver should have a swapchain length > 4. + } + + existing_damage->num_rects = 1; + + // Allocate the array of rectangles for the existing damage. + existing_damage_map_[fbo_id] = static_cast( + malloc(sizeof(FlutterRect) * existing_damage->num_rects)); + existing_damage_map_[fbo_id][0] = + FlutterRect{0, 0, kInitialWindowWidth, kInitialWindowHeight}; + existing_damage->damage = existing_damage_map_[fbo_id]; + + if (age > 1) { + --age; + // join up to (age - 1) last rects from damage history + for (auto i = damage_history_.rbegin(); + i != damage_history_.rend() && age > 0; ++i, --age) { + if (i == damage_history_.rbegin()) { + if (i != damage_history_.rend()) { + existing_damage->damage[0] = {i->left, i->top, i->right, i->bottom}; + } + } else { + JoinFlutterRect(&(existing_damage->damage[0]), *i); + } + } + } + }; + config.open_gl.gl_proc_resolver = [](void*, const char* name) -> void* { + return reinterpret_cast(glfwGetProcAddress(name)); + }; + config.open_gl.fbo_reset_after_present = true; + + // This directory is generated by `flutter build bundle`. + std::string assets_path = project_path + "/build/flutter_assets"; + FlutterProjectArgs args = { + .struct_size = sizeof(FlutterProjectArgs), + .assets_path = assets_path.c_str(), + .icu_data_path = + icudtl_path.c_str(), // Find this in your bin/cache directory. + }; + FlutterEngine engine = nullptr; + FlutterEngineResult result = + FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, // renderer + &args, window, &engine); + if (result != kSuccess || engine == nullptr) { + std::cout << "Could not run the Flutter Engine." << std::endl; + return false; + } + + glfwSetWindowUserPointer(window, engine); + GLFWwindowSizeCallback(window, kInitialWindowWidth, kInitialWindowHeight); + + return true; +} + +void printUsage() { + std::cout + << "usage: embedder_example_drm " + << std::endl; +} + +void GLFW_ErrorCallback(int error, const char* description) { + std::cout << "GLFW Error: (" << error << ") " << description << std::endl; +} + +int main(int argc, const char* argv[]) { + if (argc != 3) { + printUsage(); + return 1; + } + + std::string project_path = argv[1]; + std::string icudtl_path = argv[2]; + + glfwSetErrorCallback(GLFW_ErrorCallback); + + int result = glfwInit(); + if (result != GLFW_TRUE) { + std::cout << "Could not initialize GLFW." << std::endl; + return EXIT_FAILURE; + } + +#if defined(__linux__) + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); +#endif + + GLFWwindow* window = glfwCreateWindow( + kInitialWindowWidth, kInitialWindowHeight, "Flutter", NULL, NULL); + if (window == nullptr) { + std::cout << "Could not create GLFW window." << std::endl; + return EXIT_FAILURE; + } + + int framebuffer_width, framebuffer_height; + glfwGetFramebufferSize(window, &framebuffer_width, &framebuffer_height); + g_pixelRatio = framebuffer_width / kInitialWindowWidth; + + // Get the display and surface variables. + display_ = glfwGetEGLDisplay(); + surface_ = glfwGetEGLSurface(window); + + bool run_result = RunFlutter(window, project_path, icudtl_path); + if (!run_result) { + std::cout << "Could not run the Flutter engine." << std::endl; + return EXIT_FAILURE; + } + + glfwSetKeyCallback(window, GLFWKeyCallback); + glfwSetWindowSizeCallback(window, GLFWwindowSizeCallback); + glfwSetMouseButtonCallback(window, GLFWmouseButtonCallback); + + while (!glfwWindowShouldClose(window)) { + glfwWaitEvents(); + } + + glfwDestroyWindow(window); + glfwTerminate(); + + return EXIT_SUCCESS; +} diff --git a/examples/glfw_drm/README.md b/examples/glfw_drm/README.md new file mode 100644 index 0000000000000..a6b4018a2a998 --- /dev/null +++ b/examples/glfw_drm/README.md @@ -0,0 +1,37 @@ +# Flutter Embedder Engine GLFW Example +## Description +This is an example of how to use Flutter Engine Embedder in order to get a +Flutter project rendering in a new host environment. The intended audience is +people who need to support host environment other than the ones already provided +by Flutter. This is an advanced topic and not intended for beginners. + +In this example we are demonstrating rendering a Flutter project inside of the GUI +library [GLFW](https://www.glfw.org/). For more information about using the +embedder you can read the wiki article [Custom Flutter Engine Embedders](https://github.com/flutter/flutter/wiki/Custom-Flutter-Engine-Embedders). + +The key difference between this example and the other GLFW example in this +folder is that the present example implements dirty region management (i.e. +rendering only the regions that have changed between frames as opposed to always +rendering the entire frame). For more information on the implementation of +dirty region management within the Embedder API, see [DRM Embedder](https://flutter.dev/go/drm-embedder). + +## Running Instructions +The following example was tested on Linux but with a bit of tweaking should be +able to run on other *nix platforms and Windows. However, because this example +uses the EGL library, it is not compatible with MacOS platforms. + +The example has the following dependencies: + * [GLFW](https://www.glfw.org/) - This can be installed by running `sudo apt-get install libglfw3` + * [CMake](https://cmake.org/) - This can be installed by running `sudo apt-get install cmake` + * [EGL](https://docs.mesa3d.org/egl.html) - This can be installed by running `sudo apt-get install libglfw3-dev` + * [Flutter](https://flutter.dev/) - This can be installed from the [Flutter webpage](https://flutter.dev/docs/get-started/install) + * [Flutter Engine](https://flutter.dev) - This can be built or downloaded, see [Custom Flutter Engine Embedders](https://github.com/flutter/flutter/wiki/Custom-Flutter-Engine-Embedders) for more information. + +In order to **build** and **run** the example you should be able to go into this directory and run +`./run.sh`. + +## Troubleshooting +There are a few things you might have to tweak in order to get your build working: + * Flutter Engine Location - Inside the `CMakeList.txt` file you will see that it is set up to search for the header and library for the Flutter Engine in specific locations, those might not be the location of your Flutter Engine. + * Pixel Ratio - If the project runs but is drawing at the wrong scale you may have to tweak the `kPixelRatio` variable in `FlutterEmbedderGLFW.cc` file. + * GLFW Location - Inside the `CMakeLists.txt` we are searching for the GLFW library, if CMake can't find it you may have to edit that. diff --git a/examples/glfw_drm/main.dart b/examples/glfw_drm/main.dart new file mode 100644 index 0000000000000..d8ad9221f8e4c --- /dev/null +++ b/examples/glfw_drm/main.dart @@ -0,0 +1,80 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart' + show debugDefaultTargetPlatformOverride; +import 'package:flutter_spinkit/flutter_spinkit.dart'; + + +void main() { + // This is a hack to make Flutter think you are running on Google Fuchsia, + // otherwise you will get an error about running from an unsupported platform. + debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia; + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or simply save your changes to "hot reload" in a Flutter IDE). + // Notice that the counter didn't reset back to zero; the application + // is not restarted. + primarySwatch: Colors.blue, + ), + home: MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key? key, required this.title}) : super(key: key); + + // This widget is the home page of your application. It is stateful, meaning + // that it has a State object (defined below) that contains fields that affect + // how it looks. + + // This class is the configuration for the state. It holds the values (in this + // case the title) provided by the parent (in this case the App widget) and + // used by the build method of the State. Fields in a Widget subclass are + // always marked "final". + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + @override + Widget build(BuildContext context) { + // The Flutter framework has been optimized to make rerunning build methods + // fast, so that you can just rebuild anything that needs updating rather + // than having to individually change instances of widgets. + return Scaffold( + appBar: AppBar( + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: Text(widget.title), + ), + body: Center( + // Center is a layout widget. It takes a single child and positions it + // in the middle of the parent. + child: RepaintBoundary( + child: SpinKitRotatingCircle(color: Colors.blue, size: 50.0), + ), + ), + ); + } +} diff --git a/examples/glfw_drm/run.sh b/examples/glfw_drm/run.sh new file mode 100755 index 0000000000000..0ae097e4cc990 --- /dev/null +++ b/examples/glfw_drm/run.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -e # Exit if any program returns an error. + +################################################################# +# Make the host C++ project. +################################################################# +if [ ! -d debug ]; then + mkdir debug +fi +cd debug +cmake -DCMAKE_BUILD_TYPE=Debug .. +make + +################################################################# +# Make the guest Flutter project. +################################################################# +if [ ! -d myapp ]; then + flutter create myapp + cd myapp + flutter pub add flutter_spinkit + cd .. +fi +cd myapp +cp ../../main.dart lib/main.dart +flutter build bundle \ + --local-engine-src-path ../../../../../ \ + --local-engine=host_debug_unopt +cd - + +################################################################# +# Run the Flutter Engine Embedder +################################################################# +./flutter_glfw ./myapp ../../../../third_party/icu/common/icudtl.dat From ed8daaa4faa57f0a0b8f3486d3618973df867e59 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 15 Aug 2022 10:13:52 -0700 Subject: [PATCH 320/558] [Impeller] Revert special character escaping in impellerc (#35365) --- impeller/compiler/compiler.cc | 13 +------ impeller/compiler/compiler_test.cc | 38 ------------------- impeller/compiler/compiler_test.h | 2 - impeller/compiler/compiler_unittests.cc | 5 --- .../fixtures/shaders/general_shaders/BUILD.gn | 1 - .../functions%20with_space.frag | 34 ----------------- testing/dart/fragment_shader_test.dart | 10 ----- 7 files changed, 1 insertion(+), 102 deletions(-) delete mode 100644 lib/ui/fixtures/shaders/general_shaders/functions%20with_space.frag diff --git a/impeller/compiler/compiler.cc b/impeller/compiler/compiler.cc index b650556ccccbb..1cd435c06e5df 100644 --- a/impeller/compiler/compiler.cc +++ b/impeller/compiler/compiler.cc @@ -481,24 +481,13 @@ const std::vector& Compiler::GetIncludedFileNames() const { return included_file_names_; } -// Escape `%` and `#` characters according to doc comment at -// https://github.com/ninja-build/ninja/blob/master/src/depfile_parser.cc#L28 -static void EscapeString(std::string& str, std::stringstream& stream) { - for (auto it = str.begin(); it != str.end(); it++) { - if (*it == '%' || *it == '#') { - stream << '\\'; - } - stream << *it; - } -} - static std::string JoinStrings(std::vector items, std::string separator) { std::stringstream stream; for (size_t i = 0, count = items.size(); i < count; i++) { const auto is_last = (i == count - 1); - EscapeString(items[i], stream); + stream << items[i]; if (!is_last) { stream << separator; } diff --git a/impeller/compiler/compiler_test.cc b/impeller/compiler/compiler_test.cc index 1e7efe0f1f883..a0031fbb5c088 100644 --- a/impeller/compiler/compiler_test.cc +++ b/impeller/compiler/compiler_test.cc @@ -58,37 +58,6 @@ static std::string SLFileName(const char* fixture_name, return stream.str(); } -static std::string DepfileName(const char* fixture_name) { - std::stringstream stream; - stream << fixture_name << ".d"; - return stream.str(); -} - -bool CompilerTest::ValidateDepfileEscaped(const char* fixture_name) const { - auto depfile_name = DepfileName(fixture_name); - auto mapping = std::make_unique( - fml::OpenFile(intermediates_directory_, depfile_name.c_str(), false, - fml::FilePermission::kRead)); - - std::string contents(reinterpret_cast(mapping->GetMapping()), - mapping->GetSize()); - bool escaped = false; - for (auto it = contents.begin(); it != contents.end(); it++) { - if (*it == '\\') { - escaped = true; - } else if (*it == '%' || *it == '#') { - if (!escaped) { - VALIDATION_LOG << "Unescaped character " << *it << " in depfile."; - return false; - } - escaped = false; - } else { - escaped = false; - } - } - return true; -} - std::unique_ptr CompilerTest::GetReflectionJson( const char* fixture_name) const { auto filename = ReflectionJSONName(fixture_name); @@ -197,13 +166,6 @@ bool CompilerTest::CanCompileAndReflect(const char* fixture_name, return false; } } - - auto mapping = compiler.CreateDepfileContents({fixture_name}); - if (!fml::WriteAtomically(intermediates_directory_, - DepfileName(fixture_name).c_str(), *mapping)) { - VALIDATION_LOG << "Could not write depfile."; - return false; - } return true; } diff --git a/impeller/compiler/compiler_test.h b/impeller/compiler/compiler_test.h index d9dfdba92856f..0831a95bf13e3 100644 --- a/impeller/compiler/compiler_test.h +++ b/impeller/compiler/compiler_test.h @@ -28,8 +28,6 @@ class CompilerTest : public ::testing::TestWithParam { const char* fixture_name, SourceType source_type = SourceType::kUnknown) const; - bool ValidateDepfileEscaped(const char* fixture_name) const; - private: fml::UniqueFD intermediates_directory_; diff --git a/impeller/compiler/compiler_unittests.cc b/impeller/compiler/compiler_unittests.cc index 9c69da2bae1af..f8d1c45beb268 100644 --- a/impeller/compiler/compiler_unittests.cc +++ b/impeller/compiler/compiler_unittests.cc @@ -65,11 +65,6 @@ TEST_P(CompilerTest, MustFailDueToMultipleLocationPerStructMember) { ASSERT_FALSE(CanCompileAndReflect("struct_def_bug.vert")); } -TEST_P(CompilerTest, ShaderWithSpecialCharactersHasEscapedDepfile) { - ASSERT_TRUE(CanCompileAndReflect("sa\%m#ple.vert")); - ASSERT_TRUE(ValidateDepfileEscaped("sa\%m#ple.vert")); -} - TEST_P(CompilerTest, BindingBaseForFragShader) { if (GetParam() == TargetPlatform::kFlutterSPIRV) { // This is a failure of reflection which this target doesn't perform. diff --git a/lib/ui/fixtures/shaders/general_shaders/BUILD.gn b/lib/ui/fixtures/shaders/general_shaders/BUILD.gn index eb14c9ca2f859..640823715e8f2 100644 --- a/lib/ui/fixtures/shaders/general_shaders/BUILD.gn +++ b/lib/ui/fixtures/shaders/general_shaders/BUILD.gn @@ -11,7 +11,6 @@ if (enable_unittests) { "blue_green_sampler.frag", "children_and_uniforms.frag", "functions.frag", - "functions%20with_space.frag", "no_builtin_redefinition.frag", "no_uniforms.frag", "simple.frag", diff --git a/lib/ui/fixtures/shaders/general_shaders/functions%20with_space.frag b/lib/ui/fixtures/shaders/general_shaders/functions%20with_space.frag deleted file mode 100644 index 52bf92dbcc1cb..0000000000000 --- a/lib/ui/fixtures/shaders/general_shaders/functions%20with_space.frag +++ /dev/null @@ -1,34 +0,0 @@ -#version 320 es - -// 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. - -precision highp float; - -layout ( location = 0 ) out vec4 oColor; - -layout ( location = 0 ) uniform float a; // should be 1.0 - -float addA(float x) { - return x + a; -} - -vec2 pairWithA(float x) { - return vec2(x, a); -} - -vec3 composedFunction(float x) { - return vec3(addA(x), pairWithA(x)); -} - -float multiParam(float x, float y, float z) { - return x * y * z * a; -} - -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); -} diff --git a/testing/dart/fragment_shader_test.dart b/testing/dart/fragment_shader_test.dart index d3b1b33521145..7fdcdf2742654 100644 --- a/testing/dart/fragment_shader_test.dart +++ b/testing/dart/fragment_shader_test.dart @@ -24,16 +24,6 @@ void main() async { _expectShaderRendersGreen(shader); }); - test('simple shader with space in key renders correctly', () async { - final FragmentProgram program = await FragmentProgram.fromAsset( - 'functions with_space.frag.iplr', - ); - final Shader shader = program.shader( - floatUniforms: Float32List.fromList([1]), - ); - _expectShaderRendersGreen(shader); - }); - test('blue-green image renders green', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'blue_green_sampler.frag.iplr', From 7f28d6d39da1b6942c1863247c81752f7bd6c10f Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 15 Aug 2022 10:21:43 -0700 Subject: [PATCH 321/558] [Impeller] Map to Metal's NDC in the perspective projection utility (#35394) --- impeller/geometry/geometry_unittests.cc | 8 ++++---- impeller/geometry/matrix.h | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index c2b10a32d6798..8ba3c6e9b719d 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -284,8 +284,8 @@ TEST(GeometryTest, MatrixMakePerspective) { auto expect = Matrix{ 3.4641, 0, 0, 0, // 0, 1.73205, 0, 0, // - 0, 0, -1.22222, -1, // - 0, 0, -2.22222, 0, // + 0, 0, -1.11111, -1, // + 0, 0, -1.11111, 0, // }; ASSERT_MATRIX_NEAR(m, expect); } @@ -295,8 +295,8 @@ TEST(GeometryTest, MatrixMakePerspective) { auto expect = Matrix{ 0.915244, 0, 0, 0, // 0, 1.83049, 0, 0, // - 0, 0, -3, -1, // - 0, 0, -40, 0, // + 0, 0, -2, -1, // + 0, 0, -20, 0, // }; ASSERT_MATRIX_NEAR(m, expect); } diff --git a/impeller/geometry/matrix.h b/impeller/geometry/matrix.h index 2a622a4ed2f63..a3c300dda1830 100644 --- a/impeller/geometry/matrix.h +++ b/impeller/geometry/matrix.h @@ -336,14 +336,13 @@ struct Matrix { Scalar z_far) { Scalar height = std::tan(fov_y.radians * 0.5); Scalar width = height * aspect_ratio; - Scalar z_diff = z_near - z_far; // clang-format off return { - 1.0f / width, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f / height, 0.0f, 0.0f, - 0.0f, 0.0f, (z_near + z_far) / z_diff, -1.0f, - 0.0f, 0.0f, (2.0f * z_near * z_far) / z_diff, 0.0f + 1.0f / width, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f / height, 0.0f, 0.0f, + 0.0f, 0.0f, z_far / (z_near - z_far), -1.0f, + 0.0f, 0.0f, -(z_far * z_near) / (z_far - z_near), 0.0f, }; // clang-format on } From b4cbebe3887e7cc1f0a6f8646856bc1f1cdde53e Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 15 Aug 2022 10:22:25 -0700 Subject: [PATCH 322/558] Give filters full responsibility over commands (#35389) --- .../contents/filters/blend_filter_contents.cc | 49 +++--- .../contents/filters/blend_filter_contents.h | 9 +- .../border_mask_blur_filter_contents.cc | 101 +++++++----- .../border_mask_blur_filter_contents.h | 10 +- .../filters/color_matrix_filter_contents.cc | 106 ++++++++----- .../filters/color_matrix_filter_contents.h | 10 +- .../contents/filters/filter_contents.cc | 16 +- .../entity/contents/filters/filter_contents.h | 13 +- .../filters/gaussian_blur_filter_contents.cc | 147 ++++++++++-------- .../filters/gaussian_blur_filter_contents.h | 10 +- 10 files changed, 264 insertions(+), 207 deletions(-) diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index 75b276e5c4bff..cfbbe2296f202 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -268,32 +268,43 @@ void BlendFilterContents::SetForegroundColor(std::optional color) { foreground_color_ = color; } -bool BlendFilterContents::RenderFilter(const FilterInput::Vector& inputs, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - const Rect& coverage) const { +std::optional BlendFilterContents::RenderFilter( + const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const { if (inputs.empty()) { - return true; + return std::nullopt; } - if (inputs.size() == 1 && !foreground_color_.has_value()) { - // Nothing to blend. - return PipelineBlend(inputs, renderer, entity, pass, coverage, - Entity::BlendMode::kSource, std::nullopt); - } + ContentContext::SubpassCallback callback = [&](const ContentContext& renderer, + RenderPass& pass) { + if (inputs.size() == 1 && !foreground_color_.has_value()) { + // Nothing to blend. + return PipelineBlend(inputs, renderer, entity, pass, coverage, + Entity::BlendMode::kSource, std::nullopt); + } - if (blend_mode_ <= Entity::BlendMode::kLastPipelineBlendMode) { - return PipelineBlend(inputs, renderer, entity, pass, coverage, blend_mode_, - foreground_color_); - } + if (blend_mode_ <= Entity::BlendMode::kLastPipelineBlendMode) { + return PipelineBlend(inputs, renderer, entity, pass, coverage, + blend_mode_, foreground_color_); + } + + if (blend_mode_ <= Entity::BlendMode::kLastAdvancedBlendMode) { + return advanced_blend_proc_(inputs, renderer, entity, pass, coverage, + foreground_color_); + } + FML_UNREACHABLE(); + }; - if (blend_mode_ <= Entity::BlendMode::kLastAdvancedBlendMode) { - return advanced_blend_proc_(inputs, renderer, entity, pass, coverage, - foreground_color_); + auto out_texture = renderer.MakeSubpass(ISize(coverage.size), callback); + if (!out_texture) { + return std::nullopt; } + out_texture->SetLabel("BlendFilter Texture"); - FML_UNREACHABLE(); + return Snapshot{.texture = out_texture, + .transform = Matrix::MakeTranslation(coverage.origin)}; } } // namespace impeller diff --git a/impeller/entity/contents/filters/blend_filter_contents.h b/impeller/entity/contents/filters/blend_filter_contents.h index a52b7bf31a133..464038c9fc464 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.h +++ b/impeller/entity/contents/filters/blend_filter_contents.h @@ -31,11 +31,10 @@ class BlendFilterContents : public FilterContents { private: // |FilterContents| - bool RenderFilter(const FilterInput::Vector& inputs, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - const Rect& coverage) const override; + std::optional RenderFilter(const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const override; Entity::BlendMode blend_mode_ = Entity::BlendMode::kSourceOver; AdvancedBlendProc advanced_blend_proc_; diff --git a/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc b/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc index 2901b76060bf1..4cbf8c11d07f5 100644 --- a/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc @@ -47,63 +47,82 @@ void BorderMaskBlurFilterContents::SetBlurStyle(BlurStyle blur_style) { } } -bool BorderMaskBlurFilterContents::RenderFilter( +std::optional BorderMaskBlurFilterContents::RenderFilter( const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, - RenderPass& pass, const Rect& coverage) const { - if (inputs.empty()) { - return true; - } - using VS = BorderMaskBlurPipeline::VertexShader; using FS = BorderMaskBlurPipeline::FragmentShader; - auto& host_buffer = pass.GetTransientsBuffer(); + //---------------------------------------------------------------------------- + /// Handle inputs. + /// + + if (inputs.empty()) { + return std::nullopt; + } auto input_snapshot = inputs[0]->GetSnapshot(renderer, entity); if (!input_snapshot.has_value()) { - return true; + return std::nullopt; } auto maybe_input_uvs = input_snapshot->GetCoverageUVs(coverage); if (!maybe_input_uvs.has_value()) { - return true; + return std::nullopt; } auto input_uvs = maybe_input_uvs.value(); - VertexBufferBuilder vtx_builder; - vtx_builder.AddVertices({ - {Point(0, 0), input_uvs[0]}, - {Point(1, 0), input_uvs[1]}, - {Point(1, 1), input_uvs[3]}, - {Point(0, 0), input_uvs[0]}, - {Point(1, 1), input_uvs[3]}, - {Point(0, 1), input_uvs[2]}, - }); - auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); - - Command cmd; - cmd.label = "Border Mask Blur Filter"; - auto options = OptionsFromPass(pass); - options.blend_mode = Entity::BlendMode::kSource; - cmd.pipeline = renderer.GetBorderMaskBlurPipeline(options); - cmd.BindVertices(vtx_buffer); - - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); - frame_info.sigma_uv = Vector2(sigma_x_.sigma, sigma_y_.sigma).Abs() / - input_snapshot->texture->GetSize(); - frame_info.src_factor = src_color_factor_; - frame_info.inner_blur_factor = inner_blur_factor_; - frame_info.outer_blur_factor = outer_blur_factor_; - auto uniform_view = host_buffer.EmplaceUniform(frame_info); - VS::BindFrameInfo(cmd, uniform_view); - - auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); - FS::BindTextureSampler(cmd, input_snapshot->texture, sampler); - - return pass.AddCommand(std::move(cmd)); + //---------------------------------------------------------------------------- + /// Render to texture. + /// + + ContentContext::SubpassCallback callback = [&](const ContentContext& renderer, + RenderPass& pass) { + auto& host_buffer = pass.GetTransientsBuffer(); + + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0, 0), input_uvs[0]}, + {Point(1, 0), input_uvs[1]}, + {Point(1, 1), input_uvs[3]}, + {Point(0, 0), input_uvs[0]}, + {Point(1, 1), input_uvs[3]}, + {Point(0, 1), input_uvs[2]}, + }); + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + + Command cmd; + cmd.label = "Border Mask Blur Filter"; + auto options = OptionsFromPass(pass); + options.blend_mode = Entity::BlendMode::kSource; + cmd.pipeline = renderer.GetBorderMaskBlurPipeline(options); + cmd.BindVertices(vtx_buffer); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); + frame_info.sigma_uv = Vector2(sigma_x_.sigma, sigma_y_.sigma).Abs() / + input_snapshot->texture->GetSize(); + frame_info.src_factor = src_color_factor_; + frame_info.inner_blur_factor = inner_blur_factor_; + frame_info.outer_blur_factor = outer_blur_factor_; + auto uniform_view = host_buffer.EmplaceUniform(frame_info); + VS::BindFrameInfo(cmd, uniform_view); + + auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); + FS::BindTextureSampler(cmd, input_snapshot->texture, sampler); + + return pass.AddCommand(std::move(cmd)); + }; + + auto out_texture = renderer.MakeSubpass(ISize(coverage.size), callback); + if (!out_texture) { + return std::nullopt; + } + out_texture->SetLabel("BorderMaskBlurFilter Texture"); + + return Snapshot{.texture = out_texture, + .transform = Matrix::MakeTranslation(coverage.origin)}; } std::optional BorderMaskBlurFilterContents::GetFilterCoverage( diff --git a/impeller/entity/contents/filters/border_mask_blur_filter_contents.h b/impeller/entity/contents/filters/border_mask_blur_filter_contents.h index 6aa95d87046e4..407c7b9d52319 100644 --- a/impeller/entity/contents/filters/border_mask_blur_filter_contents.h +++ b/impeller/entity/contents/filters/border_mask_blur_filter_contents.h @@ -27,11 +27,11 @@ class BorderMaskBlurFilterContents final : public FilterContents { private: // |FilterContents| - bool RenderFilter(const FilterInput::Vector& input_textures, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - const Rect& coverage) const override; + std::optional RenderFilter( + const FilterInput::Vector& input_textures, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const override; Sigma sigma_x_; Sigma sigma_y_; diff --git a/impeller/entity/contents/filters/color_matrix_filter_contents.cc b/impeller/entity/contents/filters/color_matrix_filter_contents.cc index 0d93195d64a75..bcd81ae0d2355 100644 --- a/impeller/entity/contents/filters/color_matrix_filter_contents.cc +++ b/impeller/entity/contents/filters/color_matrix_filter_contents.cc @@ -23,50 +23,60 @@ void ColorMatrixFilterContents::SetMatrix(const ColorMatrix& matrix) { matrix_ = matrix; } -bool ColorMatrixFilterContents::RenderFilter(const FilterInput::Vector& inputs, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - const Rect& coverage) const { - if (inputs.empty()) { - return true; - } - +std::optional ColorMatrixFilterContents::RenderFilter( + const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const { using VS = ColorMatrixColorFilterPipeline::VertexShader; using FS = ColorMatrixColorFilterPipeline::FragmentShader; + //---------------------------------------------------------------------------- + /// Handle inputs. + /// + + if (inputs.empty()) { + return std::nullopt; + } + auto input_snapshot = inputs[0]->GetSnapshot(renderer, entity); if (!input_snapshot.has_value()) { - return true; + return std::nullopt; } - Command cmd; - cmd.label = "Color Matrix Filter"; - - auto options = OptionsFromPass(pass); - options.blend_mode = Entity::BlendMode::kSource; - cmd.pipeline = renderer.GetColorMatrixColorFilterPipeline(options); - - VertexBufferBuilder vtx_builder; - vtx_builder.AddVertices({ - {Point(0, 0)}, - {Point(1, 0)}, - {Point(1, 1)}, - {Point(0, 0)}, - {Point(1, 1)}, - {Point(0, 1)}, - }); - auto& host_buffer = pass.GetTransientsBuffer(); - auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); - cmd.BindVertices(vtx_buffer); - - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); - - FS::FragInfo frag_info; - const float* matrix = matrix_.array; - frag_info.color_v = Vector4(matrix[4], matrix[9], matrix[14], matrix[19]); - // clang-format off + //---------------------------------------------------------------------------- + /// Render to texture. + /// + + ContentContext::SubpassCallback callback = [&](const ContentContext& renderer, + RenderPass& pass) { + Command cmd; + cmd.label = "Color Matrix Filter"; + + auto options = OptionsFromPass(pass); + options.blend_mode = Entity::BlendMode::kSource; + cmd.pipeline = renderer.GetColorMatrixColorFilterPipeline(options); + + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0, 0)}, + {Point(1, 0)}, + {Point(1, 1)}, + {Point(0, 0)}, + {Point(1, 1)}, + {Point(0, 1)}, + }); + auto& host_buffer = pass.GetTransientsBuffer(); + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + cmd.BindVertices(vtx_buffer); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); + + FS::FragInfo frag_info; + const float* matrix = matrix_.array; + frag_info.color_v = Vector4(matrix[4], matrix[9], matrix[14], matrix[19]); + // clang-format off frag_info.color_m = Matrix( matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3], @@ -74,15 +84,25 @@ bool ColorMatrixFilterContents::RenderFilter(const FilterInput::Vector& inputs, matrix[10], matrix[11], matrix[12], matrix[13], matrix[15], matrix[16], matrix[17], matrix[18] ); - // clang-format on + // clang-format on + + auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); + FS::BindInputTexture(cmd, input_snapshot->texture, sampler); + FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); - auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); - FS::BindInputTexture(cmd, input_snapshot->texture, sampler); - FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); - VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + return pass.AddCommand(std::move(cmd)); + }; + + auto out_texture = renderer.MakeSubpass(ISize(coverage.size), callback); + if (!out_texture) { + return std::nullopt; + } + out_texture->SetLabel("ColorMatrixFilter Texture"); - return pass.AddCommand(std::move(cmd)); + return Snapshot{.texture = out_texture, + .transform = Matrix::MakeTranslation(coverage.origin)}; } } // namespace impeller diff --git a/impeller/entity/contents/filters/color_matrix_filter_contents.h b/impeller/entity/contents/filters/color_matrix_filter_contents.h index e3cdfdcd62773..e2448566d895c 100644 --- a/impeller/entity/contents/filters/color_matrix_filter_contents.h +++ b/impeller/entity/contents/filters/color_matrix_filter_contents.h @@ -24,11 +24,11 @@ class ColorMatrixFilterContents final : public FilterContents { private: // |FilterContents| - bool RenderFilter(const FilterInput::Vector& input_textures, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - const Rect& coverage) const override; + std::optional RenderFilter( + const FilterInput::Vector& input_textures, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const override; ColorMatrix matrix_; diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index b600f40dbecbd..60b1900e98148 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -220,20 +220,8 @@ std::optional FilterContents::RenderToSnapshot( return std::nullopt; } - // Render the filter into a new texture. - auto texture = renderer.MakeSubpass( - ISize(coverage->size), - [=](const ContentContext& renderer, RenderPass& pass) -> bool { - return RenderFilter(inputs_, renderer, entity_with_local_transform, - pass, coverage.value()); - }); - - if (!texture) { - return std::nullopt; - } - - return Snapshot{.texture = texture, - .transform = Matrix::MakeTranslation(coverage->origin)}; + return RenderFilter(inputs_, renderer, entity_with_local_transform, + coverage.value()); } Matrix FilterContents::GetLocalTransform() const { diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 06a5e6d4ccce9..b3064b4475025 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -101,13 +101,12 @@ class FilterContents : public Contents { const FilterInput::Vector& inputs, const Entity& entity) const; - /// @brief Takes a set of zero or more input textures and writes to an output - /// texture. - virtual bool RenderFilter(const FilterInput::Vector& inputs, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - const Rect& coverage) const = 0; + /// @brief Converts zero or more filter inputs into a new texture. + virtual std::optional RenderFilter( + const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const = 0; std::optional GetLocalCoverage(const Entity& local_entity) const; diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index e1b40d4c9f989..3de4ad2e71d6e 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -11,8 +11,10 @@ #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/geometry/rect.h" #include "impeller/geometry/scalar.h" +#include "impeller/renderer/command_buffer.h" #include "impeller/renderer/formats.h" #include "impeller/renderer/render_pass.h" +#include "impeller/renderer/render_target.h" #include "impeller/renderer/sampler_descriptor.h" #include "impeller/renderer/sampler_library.h" @@ -80,30 +82,31 @@ void DirectionalGaussianBlurFilterContents::SetSourceOverride( source_override_ = source_override; } -bool DirectionalGaussianBlurFilterContents::RenderFilter( +std::optional DirectionalGaussianBlurFilterContents::RenderFilter( const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, - RenderPass& pass, const Rect& coverage) const { - if (inputs.empty()) { - return true; - } - using VS = GaussianBlurPipeline::VertexShader; using FS = GaussianBlurPipeline::FragmentShader; - auto& host_buffer = pass.GetTransientsBuffer(); + //---------------------------------------------------------------------------- + /// Handle inputs. + /// + + if (inputs.empty()) { + return std::nullopt; + } // Input 0 snapshot and UV mapping. auto input_snapshot = inputs[0]->GetSnapshot(renderer, entity); if (!input_snapshot.has_value()) { - return true; + return std::nullopt; } auto maybe_input_uvs = input_snapshot->GetCoverageUVs(coverage); if (!maybe_input_uvs.has_value()) { - return true; + return std::nullopt; } auto input_uvs = maybe_input_uvs.value(); @@ -112,66 +115,84 @@ bool DirectionalGaussianBlurFilterContents::RenderFilter( auto source = source_override_ ? source_override_ : inputs[0]; auto source_snapshot = source->GetSnapshot(renderer, entity); if (!source_snapshot.has_value()) { - return true; + return std::nullopt; } auto maybe_source_uvs = source_snapshot->GetCoverageUVs(coverage); if (!maybe_source_uvs.has_value()) { - return true; + return std::nullopt; } auto source_uvs = maybe_source_uvs.value(); - VertexBufferBuilder vtx_builder; - vtx_builder.AddVertices({ - {Point(0, 0), input_uvs[0], source_uvs[0]}, - {Point(1, 0), input_uvs[1], source_uvs[1]}, - {Point(1, 1), input_uvs[3], source_uvs[3]}, - {Point(0, 0), input_uvs[0], source_uvs[0]}, - {Point(1, 1), input_uvs[3], source_uvs[3]}, - {Point(0, 1), input_uvs[2], source_uvs[2]}, - }); - auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); - - auto transformed_blur = entity.GetTransformation().TransformDirection( - blur_direction_ * blur_sigma_.sigma); - - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); - - FS::FragInfo frag_info; - frag_info.texture_sampler_y_coord_scale = - input_snapshot->texture->GetYCoordScale(); - frag_info.alpha_mask_sampler_y_coord_scale = - source_snapshot->texture->GetYCoordScale(); - frag_info.blur_sigma = transformed_blur.GetLength(); - frag_info.blur_radius = Radius{Sigma{frag_info.blur_sigma}}.radius; - frag_info.blur_direction = input_snapshot->transform.Invert() - .TransformDirection(transformed_blur) - .Normalize(); - frag_info.tile_mode = static_cast(tile_mode_); - frag_info.src_factor = src_color_factor_; - frag_info.inner_blur_factor = inner_blur_factor_; - frag_info.outer_blur_factor = outer_blur_factor_; - frag_info.texture_size = Point(input_snapshot->GetCoverage().value().size); - - SamplerDescriptor sampler_desc; - sampler_desc.min_filter = MinMagFilter::kLinear; - sampler_desc.mag_filter = MinMagFilter::kLinear; - auto sampler = - renderer.GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc); - - Command cmd; - cmd.label = "Gaussian Blur Filter"; - auto options = OptionsFromPass(pass); - options.blend_mode = Entity::BlendMode::kSource; - cmd.pipeline = renderer.GetGaussianBlurPipeline(options); - cmd.BindVertices(vtx_buffer); - - FS::BindTextureSampler(cmd, input_snapshot->texture, sampler); - FS::BindAlphaMaskSampler(cmd, source_snapshot->texture, sampler); - VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); - FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); - - return pass.AddCommand(cmd); + //---------------------------------------------------------------------------- + /// Render to texture. + /// + + ContentContext::SubpassCallback callback = [&](const ContentContext& renderer, + RenderPass& pass) { + auto& host_buffer = pass.GetTransientsBuffer(); + + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0, 0), input_uvs[0], source_uvs[0]}, + {Point(1, 0), input_uvs[1], source_uvs[1]}, + {Point(1, 1), input_uvs[3], source_uvs[3]}, + {Point(0, 0), input_uvs[0], source_uvs[0]}, + {Point(1, 1), input_uvs[3], source_uvs[3]}, + {Point(0, 1), input_uvs[2], source_uvs[2]}, + }); + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + + auto transformed_blur = entity.GetTransformation().TransformDirection( + blur_direction_ * blur_sigma_.sigma); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); + + FS::FragInfo frag_info; + frag_info.texture_sampler_y_coord_scale = + input_snapshot->texture->GetYCoordScale(); + frag_info.alpha_mask_sampler_y_coord_scale = + source_snapshot->texture->GetYCoordScale(); + frag_info.blur_sigma = transformed_blur.GetLength(); + frag_info.blur_radius = Radius{Sigma{frag_info.blur_sigma}}.radius; + frag_info.blur_direction = input_snapshot->transform.Invert() + .TransformDirection(transformed_blur) + .Normalize(); + frag_info.tile_mode = static_cast(tile_mode_); + frag_info.src_factor = src_color_factor_; + frag_info.inner_blur_factor = inner_blur_factor_; + frag_info.outer_blur_factor = outer_blur_factor_; + frag_info.texture_size = Point(input_snapshot->GetCoverage().value().size); + + SamplerDescriptor sampler_desc; + sampler_desc.min_filter = MinMagFilter::kLinear; + sampler_desc.mag_filter = MinMagFilter::kLinear; + auto sampler = + renderer.GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc); + + Command cmd; + cmd.label = "Gaussian Blur Filter"; + auto options = OptionsFromPass(pass); + options.blend_mode = Entity::BlendMode::kSource; + cmd.pipeline = renderer.GetGaussianBlurPipeline(options); + cmd.BindVertices(vtx_buffer); + + FS::BindTextureSampler(cmd, input_snapshot->texture, sampler); + FS::BindAlphaMaskSampler(cmd, source_snapshot->texture, sampler); + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); + + return pass.AddCommand(cmd); + }; + + auto out_texture = renderer.MakeSubpass(ISize(coverage.size), callback); + if (!out_texture) { + return std::nullopt; + } + out_texture->SetLabel("DirectionalGaussianBlurFilter Texture"); + + return Snapshot{.texture = out_texture, + .transform = Matrix::MakeTranslation(coverage.origin)}; } std::optional DirectionalGaussianBlurFilterContents::GetFilterCoverage( diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index 6091f1140233c..a7eed40b1806b 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h @@ -33,11 +33,11 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents { private: // |FilterContents| - bool RenderFilter(const FilterInput::Vector& input_textures, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - const Rect& coverage) const override; + std::optional RenderFilter( + const FilterInput::Vector& input_textures, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const override; Sigma blur_sigma_; Vector2 blur_direction_; BlurStyle blur_style_ = BlurStyle::kNormal; From bf9f07b7b573339a5a0805055ab04ce9db00048a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 15:31:05 -0400 Subject: [PATCH 323/558] Roll Dart SDK from 1cbb177c7339 to 997709f11034 (1 revision) (#35406) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index af12862fa9f09..1355bf8d3668f 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '1cbb177c73397a9f2cf44e07f9ba81c75661c208', + 'dart_revision': '997709f11034c88d514de8e35fd2160a8a8214d2', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 2c3efa0beb248c6afd4a0a5eb66ea3fb67a1f9ed Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Mon, 15 Aug 2022 13:10:34 -0700 Subject: [PATCH 324/558] [Impeller] [vulkan] Wire-up command buffer and other bits (#35380) --- .../backend/vulkan/playground_impl_vk.cc | 3 +- .../backend/vulkan/command_buffer_vk.cc | 110 +++++++++++++++++- .../backend/vulkan/command_buffer_vk.h | 20 +++- .../backend/vulkan/command_pool_vk.cc | 4 + .../renderer/backend/vulkan/command_pool_vk.h | 2 + .../renderer/backend/vulkan/context_vk.cc | 15 ++- impeller/renderer/backend/vulkan/context_vk.h | 2 + .../backend/vulkan/pipeline_library_vk.cc | 9 +- .../renderer/backend/vulkan/render_pass_vk.cc | 43 ++++++- .../renderer/backend/vulkan/render_pass_vk.h | 11 +- .../backend/vulkan/surface_producer_vk.cc | 18 +-- .../backend/vulkan/surface_producer_vk.h | 6 +- .../renderer/backend/vulkan/surface_vk.cc | 4 +- impeller/renderer/backend/vulkan/texture_vk.h | 4 +- 14 files changed, 220 insertions(+), 31 deletions(-) diff --git a/impeller/playground/backend/vulkan/playground_impl_vk.cc b/impeller/playground/backend/vulkan/playground_impl_vk.cc index f154f5326fd23..4334149260e51 100644 --- a/impeller/playground/backend/vulkan/playground_impl_vk.cc +++ b/impeller/playground/backend/vulkan/playground_impl_vk.cc @@ -107,7 +107,8 @@ PlaygroundImpl::WindowHandle PlaygroundImplVK::GetWindowHandle() const { // |PlaygroundImpl| std::unique_ptr PlaygroundImplVK::AcquireSurfaceFrame( std::shared_ptr context) { - FML_UNREACHABLE(); + ContextVK* context_vk = reinterpret_cast(context_.get()); + return context_vk->AcquireSurface(); } } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.cc b/impeller/renderer/backend/vulkan/command_buffer_vk.cc index e560ba9e652c8..c06701d515f18 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.cc @@ -5,30 +5,128 @@ #include "impeller/renderer/backend/vulkan/command_buffer_vk.h" #include "flutter/fml/logging.h" +#include "impeller/base/validation.h" +#include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/formats_vk.h" +#include "impeller/renderer/backend/vulkan/render_pass_vk.h" +#include "impeller/renderer/command_buffer.h" #include "impeller/renderer/render_target.h" namespace impeller { -CommandBufferVK::CommandBufferVK(std::weak_ptr context) - : CommandBuffer(std::move(context)) {} +std::shared_ptr CommandBufferVK::Create( + std::weak_ptr context, + vk::Device device, + vk::CommandPool command_pool, + SurfaceProducerVK* surface_producer) { + vk::CommandBufferAllocateInfo allocate_info; + allocate_info.setLevel(vk::CommandBufferLevel::ePrimary); + allocate_info.setCommandBufferCount(1); + allocate_info.setCommandPool(command_pool); + + auto res = device.allocateCommandBuffersUnique(allocate_info); + if (res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to allocate command buffer: " + << vk::to_string(res.result); + return nullptr; + } + + vk::UniqueCommandBuffer cmd = std::move(res.value[0]); + return std::make_shared(context, device, surface_producer, + std::move(cmd)); +} + +CommandBufferVK::CommandBufferVK(std::weak_ptr context, + vk::Device device, + SurfaceProducerVK* surface_producer, + vk::UniqueCommandBuffer command_buffer) + : CommandBuffer(context), + device_(device), + command_buffer_(std::move(command_buffer)), + surface_producer_(surface_producer) { + is_valid_ = true; +} CommandBufferVK::~CommandBufferVK() = default; void CommandBufferVK::SetLabel(const std::string& label) const { - FML_UNREACHABLE(); + if (auto context = context_.lock()) { + reinterpret_cast(context.get()) + ->SetDebugName(*command_buffer_, label); + } } bool CommandBufferVK::IsValid() const { - FML_UNREACHABLE(); + return is_valid_; } bool CommandBufferVK::OnSubmitCommands(CompletionCallback callback) { - FML_UNREACHABLE(); + bool result = surface_producer_->Submit(*command_buffer_); + + if (callback) { + callback(result ? CommandBuffer::Status::kCompleted + : CommandBuffer::Status::kError); + } + + return result; } std::shared_ptr CommandBufferVK::OnCreateRenderPass( RenderTarget target) const { - FML_UNREACHABLE(); + vk::CommandBufferBeginInfo begin_info; + auto res = command_buffer_->begin(begin_info); + if (res != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to begin command buffer: " << vk::to_string(res); + return nullptr; + } + + std::vector color_attachments; + for (const auto& [k, attachment] : target.GetColorAttachments()) { + const TextureDescriptor& tex_desc = + attachment.texture->GetTextureDescriptor(); + + vk::AttachmentDescription color_attachment; + color_attachment.setFormat(ToVKImageFormat(tex_desc.format)); + color_attachment.setSamples(ToVKSampleCountFlagBits(tex_desc.sample_count)); + color_attachment.setLoadOp(ToVKAttachmentLoadOp(attachment.load_action)); + color_attachment.setStoreOp(ToVKAttachmentStoreOp(attachment.store_action)); + + color_attachment.setStencilLoadOp(vk::AttachmentLoadOp::eDontCare); + color_attachment.setStencilStoreOp(vk::AttachmentStoreOp::eDontCare); + color_attachment.setInitialLayout(vk::ImageLayout::eUndefined); + color_attachment.setFinalLayout(vk::ImageLayout::ePresentSrcKHR); + + color_attachments.push_back(color_attachment); + } + + // TODO (kaushikiska): support depth and stencil attachments. + + vk::AttachmentReference color_attachment_ref; + color_attachment_ref.setAttachment(0); + color_attachment_ref.setLayout(vk::ImageLayout::eColorAttachmentOptimal); + + vk::SubpassDescription subpass_desc; + subpass_desc.setPipelineBindPoint(vk::PipelineBindPoint::eGraphics); + subpass_desc.setColorAttachmentCount(color_attachments.size()); + subpass_desc.setPColorAttachments(&color_attachment_ref); + + vk::RenderPassCreateInfo render_pass_create; + render_pass_create.setAttachmentCount(color_attachments.size()); + render_pass_create.setPAttachments(color_attachments.data()); + render_pass_create.setSubpassCount(1); + render_pass_create.setPSubpasses(&subpass_desc); + + auto render_pass_create_res = + device_.createRenderPassUnique(render_pass_create); + if (render_pass_create_res.result != vk::Result::eSuccess) { + VALIDATION_LOG << "Failed to create render pass: " + << vk::to_string(render_pass_create_res.result); + return nullptr; + } + + return std::make_shared( + context_, std::move(target), *command_buffer_, + std::move(render_pass_create_res.value)); } std::shared_ptr CommandBufferVK::OnCreateBlitPass() const { diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.h b/impeller/renderer/backend/vulkan/command_buffer_vk.h index a4525382fc9a5..ee5cb0bfec2b0 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.h @@ -5,19 +5,35 @@ #pragma once #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/surface_producer_vk.h" +#include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/command_buffer.h" namespace impeller { class CommandBufferVK final : public CommandBuffer { public: + static std::shared_ptr Create( + std::weak_ptr context, + vk::Device device, + vk::CommandPool command_pool, + SurfaceProducerVK* surface_producer); + + CommandBufferVK(std::weak_ptr context, + vk::Device device, + SurfaceProducerVK* surface_producer, + vk::UniqueCommandBuffer command_buffer); + // |CommandBuffer| ~CommandBufferVK() override; private: - friend class ContextMTL; + friend class ContextVK; - explicit CommandBufferVK(std::weak_ptr context); + vk::Device device_; + vk::UniqueCommandBuffer command_buffer_; + SurfaceProducerVK* surface_producer_; + bool is_valid_ = false; // |CommandBuffer| void SetLabel(const std::string& label) const override; diff --git a/impeller/renderer/backend/vulkan/command_pool_vk.cc b/impeller/renderer/backend/vulkan/command_pool_vk.cc index 58fb3f45c4ed2..065582402419b 100644 --- a/impeller/renderer/backend/vulkan/command_pool_vk.cc +++ b/impeller/renderer/backend/vulkan/command_pool_vk.cc @@ -21,6 +21,10 @@ std::unique_ptr CommandPoolVK::Create(vk::Device device, return std::make_unique(std::move(res.value)); } +vk::CommandPool CommandPoolVK::Get() const { + return *command_pool_; +} + CommandPoolVK::CommandPoolVK(vk::UniqueCommandPool command_pool) : command_pool_(std::move(command_pool)) {} diff --git a/impeller/renderer/backend/vulkan/command_pool_vk.h b/impeller/renderer/backend/vulkan/command_pool_vk.h index 3e57556fc53fd..034813ed49acf 100644 --- a/impeller/renderer/backend/vulkan/command_pool_vk.h +++ b/impeller/renderer/backend/vulkan/command_pool_vk.h @@ -18,6 +18,8 @@ class CommandPoolVK { ~CommandPoolVK(); + vk::CommandPool Get() const; + private: vk::UniqueCommandPool command_pool_; diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 6c3c0b3e0eac9..e5ff5257373af 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -15,6 +15,7 @@ #include "impeller/base/work_queue_common.h" #include "impeller/renderer/backend/vulkan/allocator_vk.h" #include "impeller/renderer/backend/vulkan/capabilities_vk.h" +#include "impeller/renderer/backend/vulkan/command_buffer_vk.h" #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" @@ -462,16 +463,22 @@ std::shared_ptr ContextVK::GetWorkQueue() const { } std::shared_ptr ContextVK::CreateCommandBuffer() const { - FML_UNREACHABLE(); + return CommandBufferVK::Create(weak_from_this(), *device_, + graphics_command_pool_->Get(), + surface_producer_.get()); } vk::Instance ContextVK::GetInstance() const { return *instance_; } +std::unique_ptr ContextVK::AcquireSurface() { + return surface_producer_->AcquireSurface(); +} + void ContextVK::SetupSwapchain(vk::UniqueSurfaceKHR surface) { surface_ = std::move(surface); - auto present_queue_out = PickPresentQueue(physical_device_, *surface); + auto present_queue_out = PickPresentQueue(physical_device_, *surface_); if (!present_queue_out.has_value()) { return; } @@ -479,11 +486,11 @@ void ContextVK::SetupSwapchain(vk::UniqueSurfaceKHR surface) { device_->getQueue(present_queue_out->family, present_queue_out->index); auto swapchain_details = - SwapchainDetailsVK::Create(physical_device_, *surface); + SwapchainDetailsVK::Create(physical_device_, *surface_); if (!swapchain_details) { return; } - swapchain_ = SwapchainVK::Create(*device_, *surface, *swapchain_details); + swapchain_ = SwapchainVK::Create(*device_, *surface_, *swapchain_details); auto weak_this = weak_from_this(); surface_producer_ = SurfaceProducerVK::Create( weak_this, { diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index 1741c6782743f..f8a4ce6211318 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -61,6 +61,8 @@ class ContextVK final : public Context, public BackendCast { void SetupSwapchain(vk::UniqueSurfaceKHR surface); + std::unique_ptr AcquireSurface(); + private: std::shared_ptr worker_task_runner_; vk::UniqueInstance instance_; diff --git a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc index f89d22bfb6884..931181c23b373 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -344,8 +344,13 @@ std::unique_ptr PipelineLibraryVK::CreatePipeline( } pipeline_info.setLayout(pipeline_layout.value.get()); - // TODO(WIP) - // pipeline_info.setPDepthStencilState(&depth_stencil_state_); + vk::PipelineDepthStencilStateCreateInfo depth_stencil_state; + depth_stencil_state.setDepthTestEnable(true); + depth_stencil_state.setDepthWriteEnable(true); + depth_stencil_state.setDepthCompareOp(vk::CompareOp::eLess); + depth_stencil_state.setDepthBoundsTestEnable(false); + depth_stencil_state.setStencilTestEnable(false); + pipeline_info.setPDepthStencilState(&depth_stencil_state); // See the note in the header about why this is a reader lock. ReaderLock lock(cache_mutex_); diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index 2db32a77b01ab..70da066fdbb40 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -4,8 +4,49 @@ #include "impeller/renderer/backend/vulkan/render_pass_vk.h" +#include "fml/logging.h" +#include "impeller/renderer/backend/vulkan/texture_vk.h" + namespace impeller { -// +RenderPassVK::RenderPassVK(std::weak_ptr context, + RenderTarget target, + vk::CommandBuffer command_buffer, + vk::UniqueRenderPass render_pass) + : RenderPass(context, target), + command_buffer_(command_buffer), + render_pass_(std::move(render_pass)) { + is_valid_ = true; +} + +RenderPassVK::~RenderPassVK() = default; + +bool RenderPassVK::IsValid() const { + return is_valid_; +} + +void RenderPassVK::OnSetLabel(std::string label) { + label_ = std::move(label); +} + +bool RenderPassVK::OnEncodeCommands(const Context& context) const { + if (!IsValid()) { + return false; + } + if (commands_.empty()) { + return true; + } + const auto& render_target = GetRenderTarget(); + if (!render_target.HasColorAttachment(0u)) { + return false; + } + const auto& color0 = render_target.GetColorAttachments().at(0u); + const auto& depth0 = render_target.GetDepthAttachment(); + const auto& stencil0 = render_target.GetStencilAttachment(); + + auto& wrapped_texture = TextureVK::Cast(*color0.texture); + + FML_UNREACHABLE(); +} } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index 42cec8935329d..595765c7902d8 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -5,6 +5,7 @@ #pragma once #include "flutter/fml/macros.h" +#include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" @@ -12,13 +13,21 @@ namespace impeller { class RenderPassVK final : public RenderPass { public: + RenderPassVK(std::weak_ptr context, + RenderTarget target, + vk::CommandBuffer command_buffer, + vk::UniqueRenderPass render_pass); + // |RenderPass| ~RenderPassVK() override; private: friend class CommandBufferVK; - RenderPassVK(RenderTarget target); + vk::CommandBuffer command_buffer_; + vk::UniqueRenderPass render_pass_; + std::string label_ = ""; + bool is_valid_ = false; // |RenderPass| bool IsValid() const override; diff --git a/impeller/renderer/backend/vulkan/surface_producer_vk.cc b/impeller/renderer/backend/vulkan/surface_producer_vk.cc index d0fad4b56ca94..da23dad77df1e 100644 --- a/impeller/renderer/backend/vulkan/surface_producer_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_producer_vk.cc @@ -7,6 +7,7 @@ #include #include "fml/logging.h" +#include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/surface_vk.h" namespace impeller { @@ -31,8 +32,7 @@ SurfaceProducerVK::SurfaceProducerVK( SurfaceProducerVK::~SurfaceProducerVK() = default; -std::unique_ptr SurfaceProducerVK::AcquireSurface( - vk::CommandBuffer command_buffer) { +std::unique_ptr SurfaceProducerVK::AcquireSurface() { auto fence_wait_res = create_info_.device.waitForFences({*in_flight_fence_}, VK_TRUE, UINT64_MAX); if (fence_wait_res != vk::Result::eSuccess) { @@ -52,17 +52,19 @@ std::unique_ptr SurfaceProducerVK::AcquireSurface( auto acuire_image_res = create_info_.device.acquireNextImageKHR( create_info_.swapchain->GetSwapchain(), UINT64_MAX, *image_available_semaphore_, {}, &image_index); - if (acuire_image_res != vk::Result::eSuccess) { + + if (acuire_image_res != vk::Result::eSuccess && + acuire_image_res != vk::Result::eSuboptimalKHR) { VALIDATION_LOG << "Failed to acquire next image: " << vk::to_string(acuire_image_res); return nullptr; } - SurfaceVK::SwapCallback swap_callback = [this, image_index, - command_buffer]() { - if (!Submit(command_buffer)) { - return false; - } + if (acuire_image_res == vk::Result::eSuboptimalKHR) { + VALIDATION_LOG << "Suboptimal image acquired."; + } + + SurfaceVK::SwapCallback swap_callback = [this, image_index]() { return Present(image_index); }; diff --git a/impeller/renderer/backend/vulkan/surface_producer_vk.h b/impeller/renderer/backend/vulkan/surface_producer_vk.h index 6d3ed2e116b97..debd9236f3d2f 100644 --- a/impeller/renderer/backend/vulkan/surface_producer_vk.h +++ b/impeller/renderer/backend/vulkan/surface_producer_vk.h @@ -31,15 +31,15 @@ class SurfaceProducerVK { ~SurfaceProducerVK(); - std::unique_ptr AcquireSurface(vk::CommandBuffer command_buffer); + std::unique_ptr AcquireSurface(); + + bool Submit(vk::CommandBuffer buffer); private: std::weak_ptr context_; bool SetupSyncObjects(); - bool Submit(vk::CommandBuffer buffer); - bool Present(uint32_t image_index); const SurfaceProducerCreateInfoVK create_info_; diff --git a/impeller/renderer/backend/vulkan/surface_vk.cc b/impeller/renderer/backend/vulkan/surface_vk.cc index f87a36aeb9ed8..9319d814bbeb5 100644 --- a/impeller/renderer/backend/vulkan/surface_vk.cc +++ b/impeller/renderer/backend/vulkan/surface_vk.cc @@ -5,6 +5,7 @@ #include "impeller/renderer/backend/vulkan/surface_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" +#include "impeller/renderer/surface.h" namespace impeller { std::unique_ptr SurfaceVK::WrapSwapchainImage( @@ -68,7 +69,8 @@ std::unique_ptr SurfaceVK::WrapSwapchainImage( SurfaceVK::SurfaceVK(RenderTarget target, SwapchainImageVK* swapchain_image, - SwapCallback swap_callback) {} + SwapCallback swap_callback) + : Surface(target) {} SurfaceVK::~SurfaceVK() = default; diff --git a/impeller/renderer/backend/vulkan/texture_vk.h b/impeller/renderer/backend/vulkan/texture_vk.h index e3e667c19564b..832133c972b71 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.h +++ b/impeller/renderer/backend/vulkan/texture_vk.h @@ -48,12 +48,12 @@ class TextureVK final : public Texture, public BackendCast { bool IsWrapped() const; + vk::Image GetImage() const; + private: ContextVK* context_; std::unique_ptr texture_info_; - vk::Image GetImage() const; - // |Texture| void SetLabel(std::string_view label) override; From 256a41e4d9bb3fd174d316ad70d99a9288206b15 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 17:10:44 -0400 Subject: [PATCH 325/558] Roll Skia from babb35ec754b to 060222bf1622 (1 revision) (#35410) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 1355bf8d3668f..9bd1e618f8900 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': 'babb35ec754b583518b11d535b98a51bfc0dc90f', + 'skia_revision': '060222bf1622b61886b388f09b3ed0e8579f9e09', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index bab1da703a53e..9ef5d5417d1c5 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 317e5d5910b70bc39832e4b51ff866e4 +Signature: 013aea7a6f7b8535fcd9270e0e654eee UNUSED LICENSES: From 90477c21aab597706f6a76204cef2ee6b4983cb2 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 15 Aug 2022 14:28:30 -0700 Subject: [PATCH 326/558] Fix race in PushingMutlipleFramesSetsUpNewRecordingCanvas. (#35412) --- .../platform/embedder/tests/embedder_unittests_gl.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shell/platform/embedder/tests/embedder_unittests_gl.cc b/shell/platform/embedder/tests/embedder_unittests_gl.cc index 76cf6102cdf60..cd12376085349 100644 --- a/shell/platform/embedder/tests/embedder_unittests_gl.cc +++ b/shell/platform/embedder/tests/embedder_unittests_gl.cc @@ -5,6 +5,7 @@ #include "tests/embedder_test_context.h" #define FML_USED_ON_EMBEDDER +#include #include #include @@ -2030,8 +2031,7 @@ TEST_F(EmbedderTest, constexpr size_t frames_expected = 10; fml::CountDownLatch frame_latch(frames_expected); - static size_t frames_seen; - frames_seen = 0; + std::atomic_size_t frames_seen = 0; context.AddNativeCallback("SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { frames_seen++; @@ -2039,7 +2039,7 @@ TEST_F(EmbedderTest, })); frame_latch.Wait(); - ASSERT_EQ(frames_expected, frames_seen); + ASSERT_GE(frames_seen, frames_expected); FlutterEngineShutdown(engine.release()); } @@ -2071,8 +2071,7 @@ TEST_F(EmbedderTest, constexpr size_t frames_expected = 10; fml::CountDownLatch frame_latch(frames_expected); - static size_t frames_seen; - frames_seen = 0; + std::atomic_size_t frames_seen = 0; context.AddNativeCallback("SignalNativeTest", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { frames_seen++; @@ -2080,7 +2079,7 @@ TEST_F(EmbedderTest, })); frame_latch.Wait(); - ASSERT_EQ(frames_expected, frames_seen); + ASSERT_GE(frames_seen, frames_expected); FlutterEngineShutdown(engine.release()); } From 195bc29ba5085e6eeb04d8f107eff0765ca5e322 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 18:24:05 -0400 Subject: [PATCH 327/558] Roll Skia from 060222bf1622 to de7a810734f3 (4 revisions) (#35416) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 9bd1e618f8900..c015b45b66e22 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': '060222bf1622b61886b388f09b3ed0e8579f9e09', + 'skia_revision': 'de7a810734f3323b0830f8bd8ed76c35603b85f5', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 9ef5d5417d1c5..d118237a9f5d9 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 013aea7a6f7b8535fcd9270e0e654eee +Signature: 1d8a4a4759b02a7480caa08edb9d6492 UNUSED LICENSES: From de2640e525d9490345c2b7d4d1c2551090e8ad4a Mon Sep 17 00:00:00 2001 From: Jaeheon Yi Date: Mon, 15 Aug 2022 15:56:27 -0700 Subject: [PATCH 328/558] [fuchsia] Adjust FakeFocuser inheritance (#35413) --- shell/platform/fuchsia/flutter/tests/fakes/focuser.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/shell/platform/fuchsia/flutter/tests/fakes/focuser.h b/shell/platform/fuchsia/flutter/tests/fakes/focuser.h index 275af5671f87a..aeaf8755d5661 100644 --- a/shell/platform/fuchsia/flutter/tests/fakes/focuser.h +++ b/shell/platform/fuchsia/flutter/tests/fakes/focuser.h @@ -6,12 +6,17 @@ #define FLUTTER_SHELL_PLATFORM_FUCHSIA_TESTS_FAKES_FOCUSER_H_ #include +#include + +#include + +#include "flutter/fml/logging.h" using Focuser = fuchsia::ui::views::Focuser; namespace flutter_runner::testing { -class FakeFocuser : public Focuser { +class FakeFocuser : public fuchsia::ui::views::testing::Focuser_TestBase { public: bool request_focus_called() const { return request_focus_called_; } @@ -32,6 +37,11 @@ class FakeFocuser : public Focuser { callback(std::move(result)); } + void NotImplemented_(const std::string& name) { + FML_LOG(FATAL) << "flutter_runner::Testing::FakeFocuser does not implement " + << name; + } + bool request_focus_called_ = false; bool fail_request_focus_ = false; }; From a47ddf985d5934c0a17767788a236fda9149bdbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Mon, 15 Aug 2022 16:17:04 -0700 Subject: [PATCH 329/558] [Windows] Add callback for when the next frame is drawn (#35408) --- .../windows/client_wrapper/flutter_engine.cc | 12 +++++ .../flutter_engine_unittests.cc | 33 ++++++++++++ .../include/flutter/flutter_engine.h | 9 ++++ .../testing/stub_flutter_windows_api.cc | 8 +++ .../testing/stub_flutter_windows_api.h | 4 ++ shell/platform/windows/fixtures/main.dart | 31 +++++++++++ shell/platform/windows/flutter_windows.cc | 7 +++ .../windows/flutter_windows_engine.cc | 16 ++++++ .../platform/windows/flutter_windows_engine.h | 6 +++ .../flutter_windows_engine_unittests.cc | 15 ++++++ .../windows/flutter_windows_unittests.cc | 54 +++++++++++++++++++ .../platform/windows/public/flutter_windows.h | 11 ++++ 12 files changed, 206 insertions(+) diff --git a/shell/platform/windows/client_wrapper/flutter_engine.cc b/shell/platform/windows/client_wrapper/flutter_engine.cc index f35c20cd9e5a2..00ccbbcff7cab 100644 --- a/shell/platform/windows/client_wrapper/flutter_engine.cc +++ b/shell/platform/windows/client_wrapper/flutter_engine.cc @@ -88,6 +88,18 @@ FlutterDesktopPluginRegistrarRef FlutterEngine::GetRegistrarForPlugin( return FlutterDesktopEngineGetPluginRegistrar(engine_, plugin_name.c_str()); } +void FlutterEngine::SetNextFrameCallback(std::function callback) { + next_frame_callback_ = std::move(callback); + FlutterDesktopEngineSetNextFrameCallback( + engine_, + [](void* user_data) { + FlutterEngine* self = static_cast(user_data); + self->next_frame_callback_(); + self->next_frame_callback_ = nullptr; + }, + this); +} + FlutterDesktopEngineRef FlutterEngine::RelinquishEngine() { owns_engine_ = false; return engine_; diff --git a/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc b/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc index 6f09bb960aac5..a1274998eadce 100644 --- a/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc +++ b/shell/platform/windows/client_wrapper/flutter_engine_unittests.cc @@ -46,6 +46,13 @@ class TestFlutterWindowsApi : public testing::StubFlutterWindowsApi { // |flutter::testing::StubFlutterWindowsApi| uint64_t EngineProcessMessages() override { return 99; } + // |flutter::testing::StubFlutterWindowsApi| + void EngineSetNextFrameCallback(VoidCallback callback, + void* user_data) override { + next_frame_callback_ = callback; + next_frame_user_data_ = user_data; + } + // |flutter::testing::StubFlutterWindowsApi| void EngineReloadSystemFonts() override { reload_fonts_called_ = true; } @@ -61,12 +68,20 @@ class TestFlutterWindowsApi : public testing::StubFlutterWindowsApi { return dart_entrypoint_arguments_; } + bool has_next_frame_callback() { return next_frame_callback_ != nullptr; } + void run_next_frame_callback() { + next_frame_callback_(next_frame_user_data_); + next_frame_callback_ = nullptr; + } + private: bool create_called_ = false; bool run_called_ = false; bool destroy_called_ = false; bool reload_fonts_called_ = false; std::vector dart_entrypoint_arguments_; + VoidCallback next_frame_callback_ = nullptr; + void* next_frame_user_data_ = nullptr; }; } // namespace @@ -168,4 +183,22 @@ TEST(FlutterEngineTest, DartEntrypointArgs) { EXPECT_TRUE(arguments[1] == arguments_ref[1]); } +TEST(FlutterEngineTest, SetNextFrameCallback) { + DartProject project(L"data"); + testing::ScopedStubFlutterWindowsApi scoped_api_stub( + std::make_unique()); + auto test_api = static_cast(scoped_api_stub.stub()); + + FlutterEngine engine(DartProject(L"fake/project/path")); + + bool success = false; + engine.SetNextFrameCallback([&success]() { success = true; }); + + EXPECT_TRUE(test_api->has_next_frame_callback()); + + test_api->run_next_frame_callback(); + + EXPECT_TRUE(success); +} + } // namespace flutter diff --git a/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h b/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h index 897fccfe0eb94..63a820ce2d6bd 100644 --- a/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h +++ b/shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h @@ -78,6 +78,12 @@ class FlutterEngine : public PluginRegistry { // This pointer will remain valid for the lifetime of this instance. BinaryMessenger* messenger() { return messenger_.get(); } + // Schedule a callback to be called after the next frame is drawn. + // + // This must be called from the platform thread. The callback is executed only + // once on the platform thread. + void SetNextFrameCallback(std::function callback); + private: // For access to RelinquishEngine. friend class FlutterViewController; @@ -101,6 +107,9 @@ class FlutterEngine : public PluginRegistry { // or if RelinquishEngine has been called (since the view controller will // run the engine if it hasn't already been run). bool has_been_run_ = false; + + // The callback to execute once the next frame is drawn. + std::function next_frame_callback_ = nullptr; }; } // namespace flutter diff --git a/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.cc b/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.cc index a829326a618c0..488cc49b8935b 100644 --- a/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.cc +++ b/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.cc @@ -111,6 +111,14 @@ uint64_t FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine) { return 0; } +void FlutterDesktopEngineSetNextFrameCallback(FlutterDesktopEngineRef engine, + VoidCallback callback, + void* user_data) { + if (s_stub_implementation) { + s_stub_implementation->EngineSetNextFrameCallback(callback, user_data); + } +} + void FlutterDesktopEngineReloadSystemFonts(FlutterDesktopEngineRef engine) { if (s_stub_implementation) { s_stub_implementation->EngineReloadSystemFonts(); diff --git a/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h b/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h index 125fb3614fbec..adc117a838f18 100644 --- a/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h +++ b/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h @@ -62,6 +62,10 @@ class StubFlutterWindowsApi { // Called for FlutterDesktopEngineProcessMessages. virtual uint64_t EngineProcessMessages() { return 0; } + // Called for FlutterDesktopEngineSetNextFrameCallback. + virtual void EngineSetNextFrameCallback(VoidCallback callback, + void* user_data) {} + // Called for FlutterDesktopEngineReloadSystemFonts. virtual void EngineReloadSystemFonts() {} diff --git a/shell/platform/windows/fixtures/main.dart b/shell/platform/windows/fixtures/main.dart index 2799c2f47ecf5..e2d76aa6171e7 100644 --- a/shell/platform/windows/fixtures/main.dart +++ b/shell/platform/windows/fixtures/main.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. +import 'dart:ui' as ui; + // Signals a waiting latch in the native test. void signal() native 'Signal'; @@ -11,6 +13,9 @@ void signalBoolValue(bool value) native 'SignalBoolValue'; // Signals a waiting latch in the native test, which returns a value to the fixture. bool signalBoolReturn() native 'SignalBoolReturn'; +// Notify the native test that the first frame has been scheduled. +void notifyFirstFrameScheduled() native 'NotifyFirstFrameScheduled'; + void main() { } @@ -33,3 +38,29 @@ void verifyNativeFunctionWithReturn() { bool value = signalBoolReturn(); signalBoolValue(value); } + +@pragma('vm:entry-point') +void drawHelloWorld() { + ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) { + final ui.ParagraphBuilder paragraphBuilder = ui.ParagraphBuilder(ui.ParagraphStyle()) + ..addText('Hello world'); + final ui.Paragraph paragraph = paragraphBuilder.build(); + + paragraph.layout(const ui.ParagraphConstraints(width: 800.0)); + + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + + canvas.drawParagraph(paragraph, ui.Offset.zero); + + final ui.Picture picture = recorder.endRecording(); + final ui.SceneBuilder sceneBuilder = ui.SceneBuilder() + ..addPicture(ui.Offset.zero, picture) + ..pop(); + + ui.window.render(sceneBuilder.build()); + }; + + ui.PlatformDispatcher.instance.scheduleFrame(); + notifyFirstFrameScheduled(); +} diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc index 87c6c8bd55df4..c26157e7c71c7 100644 --- a/shell/platform/windows/flutter_windows.cc +++ b/shell/platform/windows/flutter_windows.cc @@ -176,6 +176,13 @@ FlutterDesktopTextureRegistrarRef FlutterDesktopEngineGetTextureRegistrar( EngineFromHandle(engine)->texture_registrar()); } +void FlutterDesktopEngineSetNextFrameCallback(FlutterDesktopEngineRef engine, + VoidCallback callback, + void* user_data) { + EngineFromHandle(engine)->SetNextFrameCallback( + [callback, user_data]() { callback(user_data); }); +} + HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view) { return ViewFromHandle(view)->GetPlatformWindow(); } diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 972b9bb94b254..6c3d728f7e4ff 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -506,6 +506,22 @@ void FlutterWindowsEngine::ScheduleFrame() { embedder_api_.ScheduleFrame(engine_); } +void FlutterWindowsEngine::SetNextFrameCallback(fml::closure callback) { + next_frame_callback_ = std::move(callback); + + embedder_api_.SetNextFrameCallback( + engine_, + [](void* user_data) { + // Embedder callback runs on raster thread. Switch back to platform + // thread. + FlutterWindowsEngine* self = + static_cast(user_data); + + self->task_runner_->PostTask(std::move(self->next_frame_callback_)); + }, + this); +} + void FlutterWindowsEngine::SendSystemLocales() { std::vector languages = GetPreferredLanguageInfo(); std::vector flutter_locales; diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index c3c0d6109d922..3ead42238f616 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -177,6 +177,9 @@ class FlutterWindowsEngine { // Informs the engine that a new frame is needed to redraw the content. void ScheduleFrame(); + // Set the callback that is called when the next frame is drawn. + void SetNextFrameCallback(fml::closure callback); + // Attempts to register the texture with the given |texture_id|. bool RegisterExternalTexture(int64_t texture_id); @@ -294,6 +297,9 @@ class FlutterWindowsEngine { // The root isolate creation callback. fml::closure root_isolate_create_callback_; + + // The on frame drawn callback. + fml::closure next_frame_callback_; }; } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_engine_unittests.cc b/shell/platform/windows/flutter_windows_engine_unittests.cc index 191740f213ebd..87315efad58f5 100644 --- a/shell/platform/windows/flutter_windows_engine_unittests.cc +++ b/shell/platform/windows/flutter_windows_engine_unittests.cc @@ -389,5 +389,20 @@ TEST(FlutterWindowsEngine, ScheduleFrame) { EXPECT_TRUE(called); } +TEST(FlutterWindowsEngine, SetNextFrameCallback) { + std::unique_ptr engine = GetTestEngine(); + EngineModifier modifier(engine.get()); + + bool called = false; + modifier.embedder_api().SetNextFrameCallback = MOCK_ENGINE_PROC( + SetNextFrameCallback, ([&called](auto engine, auto callback, auto data) { + called = true; + return kSuccess; + })); + + engine->SetNextFrameCallback([]() {}); + EXPECT_TRUE(called); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index 4479e4cd02617..720c7b3fbc0a7 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -149,5 +149,59 @@ TEST_F(WindowsTest, VerifyNativeFunctionWithReturn) { EXPECT_TRUE(bool_value_passed); } +// Verify the next frame callback is executed. +TEST_F(WindowsTest, NextFrameCallback) { + struct Captures { + fml::AutoResetWaitableEvent frame_scheduled_latch; + fml::AutoResetWaitableEvent frame_drawn_latch; + std::thread::id thread_id; + }; + Captures captures; + + CreateNewThread("test_platform_thread")->PostTask([&]() { + captures.thread_id = std::this_thread::get_id(); + + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + builder.SetDartEntrypoint("drawHelloWorld"); + + auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + ASSERT_FALSE(captures.frame_drawn_latch.IsSignaledForTest()); + captures.frame_scheduled_latch.Signal(); + }); + context.AddNativeFunction("NotifyFirstFrameScheduled", native_entry); + + ViewControllerPtr controller{builder.Run()}; + ASSERT_NE(controller, nullptr); + + auto engine = FlutterDesktopViewControllerGetEngine(controller.get()); + + FlutterDesktopEngineSetNextFrameCallback( + engine, + [](void* user_data) { + auto captures = static_cast(user_data); + + ASSERT_TRUE(captures->frame_scheduled_latch.IsSignaledForTest()); + + // Callback should execute on platform thread. + ASSERT_EQ(std::this_thread::get_id(), captures->thread_id); + + // Signal the test passed and end the Windows message loop. + captures->frame_drawn_latch.Signal(); + ::PostQuitMessage(0); + }, + &captures); + + // Pump messages for the Windows platform task runner. + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + }); + + captures.frame_drawn_latch.Wait(); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/public/flutter_windows.h b/shell/platform/windows/public/flutter_windows.h index ca1655f1e9f40..c5306beba0730 100644 --- a/shell/platform/windows/public/flutter_windows.h +++ b/shell/platform/windows/public/flutter_windows.h @@ -17,6 +17,8 @@ extern "C" { #endif +typedef void (*VoidCallback)(void* /* user data */); + // Opaque reference to a Flutter window controller. typedef struct FlutterDesktopViewControllerState* FlutterDesktopViewControllerRef; @@ -185,6 +187,15 @@ FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine); FLUTTER_EXPORT FlutterDesktopTextureRegistrarRef FlutterDesktopEngineGetTextureRegistrar(FlutterDesktopEngineRef engine); +// Schedule a callback to be called after the next frame is drawn. +// +// This must be called from the platform thread. The callback is executed only +// once on the platform thread. +FLUTTER_EXPORT void FlutterDesktopEngineSetNextFrameCallback( + FlutterDesktopEngineRef engine, + VoidCallback callback, + void* user_data); + // ========== View ========== // Return backing HWND for manipulation in host application. From 90d8451911530b3076659f288e1cc41fb6896219 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 19:23:45 -0400 Subject: [PATCH 330/558] Roll Dart SDK from 997709f11034 to edbaaecbbbf1 (1 revision) (#35418) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index c015b45b66e22..5aaa99dc6e3d5 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '997709f11034c88d514de8e35fd2160a8a8214d2', + 'dart_revision': 'edbaaecbbbf18188df70d167cd8c1808c0465d5a', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From bbe0038e2a36e100bf0f0612cbb90163d02b257b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 21:10:14 -0400 Subject: [PATCH 331/558] Roll Fuchsia Mac SDK from PJ0cBTzMh-pPVIynC... to ehAgYZRo9fxyylrTD... (#35420) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 5aaa99dc6e3d5..a17fbf3eb386d 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'PJ0cBTzMh-pPVIynC_wnWSqShlOin7g2HVysb6cAyF8C' + 'version': 'ehAgYZRo9fxyylrTD5gF8klcrWyi7n6yjl7xMhDEy0EC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 280e9a7becad7eaa0f8af9eec6e57b89cf316d60 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 15 Aug 2022 23:42:04 -0400 Subject: [PATCH 332/558] Roll Dart SDK from edbaaecbbbf1 to 2993204cfc1e (1 revision) (#35424) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index a17fbf3eb386d..044781b4764d4 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'edbaaecbbbf18188df70d167cd8c1808c0465d5a', + 'dart_revision': '2993204cfc1e7e41be5826e6e8f122947640d8d3', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index b2071236864bc..d4e51322e9643 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: c143e3ea1bdd8ab9276906301751724b +Signature: 5c32292c6dac6d11effd54c259c10e99 UNUSED LICENSES: From 8a1ab4692ae001e0611e2e62e74eb9f2305890e3 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 15 Aug 2022 22:34:52 -0700 Subject: [PATCH 333/558] Display list multiplexer (#35421) --- ci/licenses_golden/licenses_flutter | 2 ++ display_list/BUILD.gn | 2 ++ .../display_list_builder_multiplexer.cc | 28 +++++++++++++++ .../display_list_builder_multiplexer.h | 36 +++++++++++++++++++ flow/embedded_views.h | 2 ++ flow/layers/backdrop_filter_layer.cc | 4 +++ flow/layers/color_filter_layer.cc | 7 ++-- flow/layers/layer.h | 4 +++ flow/layers/layer_tree.cc | 16 ++++++++- flow/layers/layer_tree_unittests.cc | 1 + flow/testing/layer_test.h | 6 ++++ flow/testing/mock_embedder.cc | 5 +++ flow/testing/mock_embedder.h | 3 ++ shell/common/rasterizer_unittests.cc | 1 + .../shell_test_external_view_embedder.cc | 6 ++++ .../shell_test_external_view_embedder.h | 3 ++ .../external_view_embedder.cc | 13 +++++++ .../external_view_embedder.h | 6 ++++ .../external_view_embedder_unittests.cc | 9 +++++ .../framework/Source/FlutterPlatformViews.mm | 9 +++++ .../Source/FlutterPlatformViewsTest.mm | 3 ++ .../Source/FlutterPlatformViews_Internal.h | 2 ++ .../darwin/ios/ios_external_view_embedder.h | 3 ++ .../darwin/ios/ios_external_view_embedder.mm | 6 ++++ .../embedder_external_view_embedder.cc | 6 ++++ .../embedder_external_view_embedder.h | 3 ++ .../flatland_external_view_embedder.cc | 5 +++ .../flutter/flatland_external_view_embedder.h | 3 ++ .../flutter/gfx_external_view_embedder.cc | 5 +++ .../flutter/gfx_external_view_embedder.h | 3 ++ .../fuchsia/flutter/platform_view_unittest.cc | 3 ++ .../tests/flatland_platform_view_unittest.cc | 3 ++ shell/testing/tester_main.cc | 3 ++ 33 files changed, 207 insertions(+), 4 deletions(-) create mode 100644 display_list/display_list_builder_multiplexer.cc create mode 100644 display_list/display_list_builder_multiplexer.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index a4657cb0b7e0f..02b295d603272 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -56,6 +56,8 @@ FILE: ../../../flutter/display_list/display_list_blend_mode.h FILE: ../../../flutter/display_list/display_list_builder.cc FILE: ../../../flutter/display_list/display_list_builder.h FILE: ../../../flutter/display_list/display_list_builder_benchmarks.cc +FILE: ../../../flutter/display_list/display_list_builder_multiplexer.cc +FILE: ../../../flutter/display_list/display_list_builder_multiplexer.h FILE: ../../../flutter/display_list/display_list_canvas_dispatcher.cc FILE: ../../../flutter/display_list/display_list_canvas_dispatcher.h FILE: ../../../flutter/display_list/display_list_canvas_recorder.cc diff --git a/display_list/BUILD.gn b/display_list/BUILD.gn index 0724e4a997d6b..077209220e69b 100644 --- a/display_list/BUILD.gn +++ b/display_list/BUILD.gn @@ -16,6 +16,8 @@ source_set("display_list") { "display_list_blend_mode.h", "display_list_builder.cc", "display_list_builder.h", + "display_list_builder_multiplexer.cc", + "display_list_builder_multiplexer.h", "display_list_canvas_dispatcher.cc", "display_list_canvas_dispatcher.h", "display_list_canvas_recorder.cc", diff --git a/display_list/display_list_builder_multiplexer.cc b/display_list/display_list_builder_multiplexer.cc new file mode 100644 index 0000000000000..0c029c532f89d --- /dev/null +++ b/display_list/display_list_builder_multiplexer.cc @@ -0,0 +1,28 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/display_list/display_list_builder_multiplexer.h" + +namespace flutter { + +void DisplayListBuilderMultiplexer::addBuilder(DisplayListBuilder* builder) { + builders_.push_back(builder); +} + +void DisplayListBuilderMultiplexer::saveLayer( + const SkRect* bounds, + const DlPaint* paint, + const DlImageFilter* backdrop_filter) { + for (auto* builder : builders_) { + builder->saveLayer(bounds, paint, backdrop_filter); + } +} + +void DisplayListBuilderMultiplexer::restore() { + for (auto* builder : builders_) { + builder->restore(); + } +} + +} // namespace flutter diff --git a/display_list/display_list_builder_multiplexer.h b/display_list/display_list_builder_multiplexer.h new file mode 100644 index 0000000000000..498301d136773 --- /dev/null +++ b/display_list/display_list_builder_multiplexer.h @@ -0,0 +1,36 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_MULTIPLEXER_H_ +#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_MULTIPLEXER_H_ + +#include "flutter/display_list/display_list_builder.h" +#include "flutter/display_list/display_list_image_filter.h" +#include "flutter/display_list/display_list_paint.h" +#include "flutter/fml/macros.h" + +namespace flutter { + +/// A class that mutiplexes some of the DisplayListBuilder calls to multiple +/// other builders. For now it only implements saveLayer and restore as those +/// are needed to create a replacement for PaintContext::internal_nodes_canvas. +class DisplayListBuilderMultiplexer { + public: + DisplayListBuilderMultiplexer() = default; + + void addBuilder(DisplayListBuilder* builder); + + void saveLayer(const SkRect* bounds, + const DlPaint* paint, + const DlImageFilter* backdrop_filter = nullptr); + + void restore(); + + private: + std::vector builders_; +}; + +} // namespace flutter + +#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_MULTIPLEXER_H_ diff --git a/flow/embedded_views.h b/flow/embedded_views.h index 6a678978f2c85..cc252ae527835 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -7,6 +7,7 @@ #include +#include "flutter/display_list/display_list_builder.h" #include "flutter/flow/rtree.h" #include "flutter/flow/surface_frame.h" #include "flutter/fml/memory/ref_counted.h" @@ -393,6 +394,7 @@ class ExternalViewEmbedder { } virtual std::vector GetCurrentCanvases() = 0; + virtual std::vector GetCurrentBuilders() = 0; // Must be called on the UI thread. virtual EmbedderPaintContext CompositeEmbeddedView(int view_id) = 0; diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index eb85e73b6a199..9f67b746b1c9b 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -60,6 +60,10 @@ void BackdropFilterLayer::Paint(PaintContext& context) const { AutoCachePaint save_paint(context); save_paint.setBlendMode(blend_mode_); if (context.leaf_nodes_builder) { + // Note that we perform a saveLayer directly on the + // leaf_nodes_builder here similar to how the SkCanvas + // path specifies the kLeafNodesCanvas below. + // See https:://flutter.dev/go/backdrop-filter-with-overlay-canvas context.leaf_nodes_builder->saveLayer(&paint_bounds(), save_paint.dl_paint(), filter_.get()); diff --git a/flow/layers/color_filter_layer.cc b/flow/layers/color_filter_layer.cc index 9c22dbfe258bf..02822bf68d612 100644 --- a/flow/layers/color_filter_layer.cc +++ b/flow/layers/color_filter_layer.cc @@ -61,10 +61,11 @@ void ColorFilterLayer::Paint(PaintContext& context) const { AutoCachePaint cache_paint(context); cache_paint.setColorFilter(filter_.get()); if (context.leaf_nodes_builder) { - context.leaf_nodes_builder->saveLayer(&paint_bounds(), - cache_paint.dl_paint()); + FML_DCHECK(context.builder_multiplexer); + context.builder_multiplexer->saveLayer(&paint_bounds(), + cache_paint.dl_paint()); PaintChildren(context); - context.leaf_nodes_builder->restore(); + context.builder_multiplexer->restore(); } else { Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( context, paint_bounds(), cache_paint.sk_paint()); diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 5cdd3e7db028c..17d5dc92ac0a3 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -11,6 +11,7 @@ #include #include "flutter/common/graphics/texture.h" +#include "flutter/display_list/display_list_builder_multiplexer.h" #include "flutter/flow/diff_context.h" #include "flutter/flow/embedded_views.h" #include "flutter/flow/instrumentation.h" @@ -29,7 +30,9 @@ #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkRect.h" #include "third_party/skia/include/utils/SkNWayCanvas.h" + namespace flutter { + namespace testing { class MockLayer; } // namespace testing @@ -150,6 +153,7 @@ struct PaintContext { // a |kSrcOver| blend mode. SkScalar inherited_opacity = SK_Scalar1; DisplayListBuilder* leaf_nodes_builder = nullptr; + DisplayListBuilderMultiplexer* builder_multiplexer = nullptr; }; // Represents a single composited layer. Created on the UI thread but then diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 0fafe40f62861..de7573ef4ac39 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -119,6 +119,16 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, internal_nodes_canvas.addCanvas(overlay_canvases[i]); } } + DisplayListBuilder* builder = frame.display_list_builder(); + DisplayListBuilderMultiplexer builder_multiplexer; + if (builder) { + builder_multiplexer.addBuilder(builder); + if (frame.view_embedder()) { + for (auto* view_builder : frame.view_embedder()->GetCurrentBuilders()) { + builder_multiplexer.addBuilder(view_builder); + } + } + } // clear the previous snapshots. LayerSnapshotStore* snapshot_store = nullptr; @@ -146,7 +156,8 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, .layer_snapshot_store = snapshot_store, .enable_leaf_layer_tracing = enable_leaf_layer_tracing_, .inherited_opacity = SK_Scalar1, - .leaf_nodes_builder = frame.display_list_builder(), + .leaf_nodes_builder = builder, + .builder_multiplexer = builder ? &builder_multiplexer : nullptr, // clang-format on }; @@ -191,6 +202,8 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { SkISize canvas_size = builder.getBaseLayerSize(); SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height()); internal_nodes_canvas.addCanvas(&builder); + DisplayListBuilderMultiplexer multiplexer; + multiplexer.addBuilder(builder.builder().get()); PaintContext paint_context = { // clang-format off @@ -208,6 +221,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .layer_snapshot_store = nullptr, .enable_leaf_layer_tracing = false, .leaf_nodes_builder = builder.builder().get(), + .builder_multiplexer = &multiplexer, // clang-format on }; diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc index c39867508c002..9eeac5a1f77cd 100644 --- a/flow/layers/layer_tree_unittests.cc +++ b/flow/layers/layer_tree_unittests.cc @@ -256,6 +256,7 @@ TEST_F(LayerTreeTest, PaintContextInitialization) { EXPECT_EQ(context.inherited_opacity, SK_Scalar1); EXPECT_EQ(context.leaf_nodes_builder, nullptr); + EXPECT_EQ(context.builder_multiplexer, nullptr); }; // These 4 initializers are required because they are handled by reference diff --git a/flow/testing/layer_test.h b/flow/testing/layer_test.h index 317c7109dc8dc..60b4536056ab6 100644 --- a/flow/testing/layer_test.h +++ b/flow/testing/layer_test.h @@ -12,6 +12,7 @@ #include #include +#include "flutter/display_list/display_list_builder_multiplexer.h" #include "flutter/flow/testing/mock_raster_cache.h" #include "flutter/fml/macros.h" #include "flutter/testing/canvas_test.h" @@ -92,6 +93,7 @@ class LayerTestBase : public CanvasTestBase { .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = 1.0f, .leaf_nodes_builder = display_list_recorder_.builder().get(), + .builder_multiplexer = &display_list_multiplexer_, // clang-format on }, check_board_context_{ @@ -109,6 +111,8 @@ class LayerTestBase : public CanvasTestBase { // clang-format on } { internal_display_list_canvas_.addCanvas(&display_list_recorder_); + display_list_multiplexer_.addBuilder( + display_list_recorder_.builder().get()); use_null_raster_cache(); } @@ -183,6 +187,7 @@ class LayerTestBase : public CanvasTestBase { display_list_paint_context_.leaf_nodes_canvas = nullptr; display_list_paint_context_.internal_nodes_canvas = nullptr; display_list_paint_context_.leaf_nodes_builder = nullptr; + display_list_paint_context_.builder_multiplexer = nullptr; } return display_list_; } @@ -214,6 +219,7 @@ class LayerTestBase : public CanvasTestBase { PrerollContext preroll_context_; PaintContext paint_context_; DisplayListCanvasRecorder display_list_recorder_; + DisplayListBuilderMultiplexer display_list_multiplexer_; sk_sp display_list_; SkNWayCanvas internal_display_list_canvas_; PaintContext display_list_paint_context_; diff --git a/flow/testing/mock_embedder.cc b/flow/testing/mock_embedder.cc index 6c3c7bf0a59a7..8004308d796c2 100644 --- a/flow/testing/mock_embedder.cc +++ b/flow/testing/mock_embedder.cc @@ -36,6 +36,11 @@ std::vector MockViewEmbedder::GetCurrentCanvases() { return std::vector({}); } +// |ExternalViewEmbedder| +std::vector MockViewEmbedder::GetCurrentBuilders() { + return std::vector({}); +} + // |ExternalViewEmbedder| EmbedderPaintContext MockViewEmbedder::CompositeEmbeddedView(int view_id) { return {nullptr, nullptr}; diff --git a/flow/testing/mock_embedder.h b/flow/testing/mock_embedder.h index ea6a1e09c771d..abc57d3d28530 100644 --- a/flow/testing/mock_embedder.h +++ b/flow/testing/mock_embedder.h @@ -37,6 +37,9 @@ class MockViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| std::vector GetCurrentCanvases() override; + // |ExternalViewEmbedder| + std::vector GetCurrentBuilders() override; + // |ExternalViewEmbedder| EmbedderPaintContext CompositeEmbeddedView(int view_id) override; }; diff --git a/shell/common/rasterizer_unittests.cc b/shell/common/rasterizer_unittests.cc index 35693c8de848c..45232840bf2b1 100644 --- a/shell/common/rasterizer_unittests.cc +++ b/shell/common/rasterizer_unittests.cc @@ -66,6 +66,7 @@ class MockExternalViewEmbedder : public ExternalViewEmbedder { PostPrerollResult( fml::RefPtr raster_thread_merger)); MOCK_METHOD0(GetCurrentCanvases, std::vector()); + MOCK_METHOD0(GetCurrentBuilders, std::vector()); MOCK_METHOD1(CompositeEmbeddedView, EmbedderPaintContext(int view_id)); MOCK_METHOD2(SubmitFrame, void(GrDirectContext* context, diff --git a/shell/common/shell_test_external_view_embedder.cc b/shell/common/shell_test_external_view_embedder.cc index 14482ba260c6b..579f682089517 100644 --- a/shell/common/shell_test_external_view_embedder.cc +++ b/shell/common/shell_test_external_view_embedder.cc @@ -72,6 +72,12 @@ std::vector ShellTestExternalViewEmbedder::GetCurrentCanvases() { return {}; } +// |ExternalViewEmbedder| +std::vector +ShellTestExternalViewEmbedder::GetCurrentBuilders() { + return {}; +} + // |ExternalViewEmbedder| void ShellTestExternalViewEmbedder::PushVisitedPlatformView(int64_t view_id) { visited_platform_views_.push_back(view_id); diff --git a/shell/common/shell_test_external_view_embedder.h b/shell/common/shell_test_external_view_embedder.h index 86c051e5c5963..583a09182e5fc 100644 --- a/shell/common/shell_test_external_view_embedder.h +++ b/shell/common/shell_test_external_view_embedder.h @@ -65,6 +65,9 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| std::vector GetCurrentCanvases() override; + // |ExternalViewEmbedder| + std::vector GetCurrentBuilders() override; + // |ExternalViewEmbedder| EmbedderPaintContext CompositeEmbeddedView(int view_id) override; diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.cc b/shell/platform/android/external_view_embedder/external_view_embedder.cc index 8bbb1682b2ba6..3545cb1453dce 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder.cc @@ -69,6 +69,19 @@ std::vector AndroidExternalViewEmbedder::GetCurrentCanvases() { return canvases; } +// |ExternalViewEmbedder| +std::vector +AndroidExternalViewEmbedder::GetCurrentBuilders() { + std::vector builders; + for (size_t i = 0; i < composition_order_.size(); i++) { + int64_t view_id = composition_order_[i]; + if (slices_.count(view_id) == 1) { + builders.push_back(slices_.at(view_id)->builder()); + } + } + return builders; +} + SkRect AndroidExternalViewEmbedder::GetViewRect(int view_id) const { const EmbeddedViewParams& params = view_params_.at(view_id); // TODO(egarciad): The rect should be computed from the mutator stack. diff --git a/shell/platform/android/external_view_embedder/external_view_embedder.h b/shell/platform/android/external_view_embedder/external_view_embedder.h index aa6e0729b22b6..5bae7a4e1c9e7 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder.h +++ b/shell/platform/android/external_view_embedder/external_view_embedder.h @@ -47,6 +47,12 @@ class AndroidExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| std::vector GetCurrentCanvases() override; + // |ExternalViewEmbedder| + // Similar call to GetCurrentCanvases but will return the array of + // builders being used by PlatformViews on platforms that provide + // optional DisplayListBuilder objects for rendering. + std::vector GetCurrentBuilders() override; + // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, std::unique_ptr frame) override; diff --git a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc index df21dae22820b..3005024bb9fe3 100644 --- a/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc +++ b/shell/platform/android/external_view_embedder/external_view_embedder_unittests.cc @@ -124,6 +124,9 @@ TEST(AndroidExternalViewEmbedder, GetCurrentCanvases) { ASSERT_EQ(2UL, canvases.size()); ASSERT_EQ(SkISize::Make(10, 20), canvases[0]->getBaseLayerSize()); ASSERT_EQ(SkISize::Make(10, 20), canvases[1]->getBaseLayerSize()); + + auto builders = embedder->GetCurrentBuilders(); + ASSERT_EQ(2UL, builders.size()); } TEST(AndroidExternalViewEmbedder, GetCurrentCanvasesCompositeOrder) { @@ -149,6 +152,9 @@ TEST(AndroidExternalViewEmbedder, GetCurrentCanvasesCompositeOrder) { ASSERT_EQ(2UL, canvases.size()); ASSERT_EQ(embedder->CompositeEmbeddedView(0).canvas, canvases[0]); ASSERT_EQ(embedder->CompositeEmbeddedView(1).canvas, canvases[1]); + + auto builders = embedder->GetCurrentBuilders(); + ASSERT_EQ(2UL, builders.size()); } TEST(AndroidExternalViewEmbedder, CompositeEmbeddedView) { @@ -178,6 +184,9 @@ TEST(AndroidExternalViewEmbedder, CancelFrame) { auto canvases = embedder->GetCurrentCanvases(); ASSERT_EQ(0UL, canvases.size()); + + auto builders = embedder->GetCurrentBuilders(); + ASSERT_EQ(0UL, builders.size()); } TEST(AndroidExternalViewEmbedder, RasterizerRunsOnPlatformThread) { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 2406365cc0322..9987fe6dd8265 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -379,6 +379,15 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { return canvases; } +std::vector FlutterPlatformViewsController::GetCurrentBuilders() { + std::vector builders; + for (size_t i = 0; i < composition_order_.size(); i++) { + int64_t view_id = composition_order_[i]; + builders.push_back(slices_[view_id]->builder()); + } + return builders; +} + int FlutterPlatformViewsController::CountClips(const MutatorsStack& mutators_stack) { std::vector>::const_reverse_iterator iter = mutators_stack.Bottom(); int clipCount = 0; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm index b91880b3a4d09..cc205e91bd3f6 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViewsTest.mm @@ -1076,16 +1076,19 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder { flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1)); flutterPlatformViewsController->CompositeEmbeddedView(0); XCTAssertEqual(flutterPlatformViewsController->GetCurrentCanvases().size(), 1UL); + XCTAssertEqual(flutterPlatformViewsController->GetCurrentBuilders().size(), 1UL); // Second frame, |GetCurrentCanvases| should be empty at the start flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300)); XCTAssertTrue(flutterPlatformViewsController->GetCurrentCanvases().empty()); + XCTAssertTrue(flutterPlatformViewsController->GetCurrentBuilders().empty()); auto embeddedViewParams2 = std::make_unique(finalMatrix, SkSize::Make(300, 300), stack); flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams2)); flutterPlatformViewsController->CompositeEmbeddedView(0); XCTAssertEqual(flutterPlatformViewsController->GetCurrentCanvases().size(), 1UL); + XCTAssertEqual(flutterPlatformViewsController->GetCurrentBuilders().size(), 1UL); } - (void)testThreadMergeAtEndFrame { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index 8d41b7629c8dd..c7877dc7601ed 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -165,6 +165,8 @@ class FlutterPlatformViewsController { std::vector GetCurrentCanvases(); + std::vector GetCurrentBuilders(); + EmbedderPaintContext CompositeEmbeddedView(int view_id); // The rect of the platform view at index view_id. This rect has been translated into the diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.h b/shell/platform/darwin/ios/ios_external_view_embedder.h index 296930d745f6e..03cec910bae39 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.h +++ b/shell/platform/darwin/ios/ios_external_view_embedder.h @@ -49,6 +49,9 @@ class IOSExternalViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| std::vector GetCurrentCanvases() override; + // |ExternalViewEmbedder| + std::vector GetCurrentBuilders() override; + // |ExternalViewEmbedder| EmbedderPaintContext CompositeEmbeddedView(int view_id) override; diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.mm b/shell/platform/darwin/ios/ios_external_view_embedder.mm index 392c3ba8d6105..76995be2c56ad 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -64,6 +64,12 @@ return platform_views_controller_->GetCurrentCanvases(); } +// |ExternalViewEmbedder| +std::vector IOSExternalViewEmbedder::GetCurrentBuilders() { + FML_CHECK(platform_views_controller_); + return platform_views_controller_->GetCurrentBuilders(); +} + // |ExternalViewEmbedder| EmbedderPaintContext IOSExternalViewEmbedder::CompositeEmbeddedView(int view_id) { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::CompositeEmbeddedView"); diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index 56580e3f5e89d..026d1c5d48dd3 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -110,6 +110,12 @@ std::vector EmbedderExternalViewEmbedder::GetCurrentCanvases() { return canvases; } +// |ExternalViewEmbedder| +std::vector +EmbedderExternalViewEmbedder::GetCurrentBuilders() { + return std::vector({}); +} + // |ExternalViewEmbedder| EmbedderPaintContext EmbedderExternalViewEmbedder::CompositeEmbeddedView( int view_id) { diff --git a/shell/platform/embedder/embedder_external_view_embedder.h b/shell/platform/embedder/embedder_external_view_embedder.h index 94bbf6712a46c..7921cb8b78255 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.h +++ b/shell/platform/embedder/embedder_external_view_embedder.h @@ -93,6 +93,9 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| std::vector GetCurrentCanvases() override; + // |ExternalViewEmbedder| + std::vector GetCurrentBuilders() override; + // |ExternalViewEmbedder| EmbedderPaintContext CompositeEmbeddedView(int view_id) override; diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc index 7b9ac92512996..54d91c1fe8a8e 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc @@ -56,6 +56,11 @@ std::vector FlatlandExternalViewEmbedder::GetCurrentCanvases() { return canvases; } +std::vector +FlatlandExternalViewEmbedder::GetCurrentBuilders() { + return std::vector(); +} + void FlatlandExternalViewEmbedder::PrerollCompositeEmbeddedView( int view_id, std::unique_ptr params) { diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h index 1c07f8393aac6..360e068699def 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.h @@ -64,6 +64,9 @@ class FlatlandExternalViewEmbedder final // |ExternalViewEmbedder| std::vector GetCurrentCanvases() override; + // |ExternalViewEmbedder| + std::vector GetCurrentBuilders() override; + // |ExternalViewEmbedder| void PrerollCompositeEmbeddedView( int view_id, diff --git a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.cc b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.cc index 1501e8fbd8268..1cd292764efa3 100644 --- a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.cc @@ -164,6 +164,11 @@ std::vector GfxExternalViewEmbedder::GetCurrentCanvases() { return canvases; } +std::vector +GfxExternalViewEmbedder::GetCurrentBuilders() { + return std::vector({}); +} + void GfxExternalViewEmbedder::PrerollCompositeEmbeddedView( int view_id, std::unique_ptr params) { diff --git a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h index 09be1bf769b21..c2e67e34a2845 100644 --- a/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h +++ b/shell/platform/fuchsia/flutter/gfx_external_view_embedder.h @@ -87,6 +87,9 @@ class GfxExternalViewEmbedder final : public flutter::ExternalViewEmbedder { // |ExternalViewEmbedder| std::vector GetCurrentCanvases() override; + // |ExternalViewEmbedder| + std::vector GetCurrentBuilders() override; + // |ExternalViewEmbedder| void PrerollCompositeEmbeddedView( int view_id, diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc index 4f6a9cc2149c4..3d7eb7977f5c0 100644 --- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc @@ -48,6 +48,9 @@ class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder { std::vector GetCurrentCanvases() override { return std::vector(); } + std::vector GetCurrentBuilders() override { + return std::vector(); + } void CancelFrame() override {} void BeginFrame( diff --git a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc index beaf150684a7e..f2565ac69c9c4 100644 --- a/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc +++ b/shell/platform/fuchsia/flutter/tests/flatland_platform_view_unittest.cc @@ -47,6 +47,9 @@ class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder { std::vector GetCurrentCanvases() override { return std::vector(); } + std::vector GetCurrentBuilders() override { + return std::vector(); + } void CancelFrame() override {} void BeginFrame( diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc index ecab46ac1a7f1..c1eab867f6a1c 100644 --- a/shell/testing/tester_main.cc +++ b/shell/testing/tester_main.cc @@ -59,6 +59,9 @@ class TesterExternalViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| std::vector GetCurrentCanvases() override { return {&canvas_}; } + // |ExternalViewEmbedder| + std::vector GetCurrentBuilders() override { return {}; } + // |ExternalViewEmbedder| EmbedderPaintContext CompositeEmbeddedView(int view_id) override { return {&canvas_, nullptr}; From db741c85ad099a6e3daf908c686a624ea082790e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 09:09:06 -0400 Subject: [PATCH 334/558] Roll Skia from de7a810734f3 to 0aab5ce300b8 (1 revision) (#35427) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 044781b4764d4..1e2e1692904ef 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': 'de7a810734f3323b0830f8bd8ed76c35603b85f5', + 'skia_revision': '0aab5ce300b85275eebef738269053f634d7fd5d', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index d118237a9f5d9..059e91dc898d2 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 1d8a4a4759b02a7480caa08edb9d6492 +Signature: a40d29a4bae47e65db00e127d9695c33 UNUSED LICENSES: From 688624b057dbe878a6650e2511d531791dc28d3b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 10:21:21 -0400 Subject: [PATCH 335/558] Roll Skia from 0aab5ce300b8 to f86f24288669 (1 revision) (#35429) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 1e2e1692904ef..5600062729d19 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': '0aab5ce300b85275eebef738269053f634d7fd5d', + 'skia_revision': 'f86f242886692a18f5adc1cf9cbd6740cd0870fd', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 059e91dc898d2..a65d1dec3af40 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: a40d29a4bae47e65db00e127d9695c33 +Signature: 9e11b178003dfb4d5f7eac0356b570db UNUSED LICENSES: From 136bdecaea867f0e393b8e5069d52f50e665524f Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Tue, 16 Aug 2022 07:58:05 -0700 Subject: [PATCH 336/558] Null check for the activity intent in FlutterEngineConnectionRegistry.attachToActivityInternal (#35419) --- .../engine/FlutterEngineConnectionRegistry.java | 8 +++++--- .../engine/FlutterEngineConnectionRegistryTest.java | 11 +++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java b/shell/platform/android/io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java index b3203179de19f..80aab73e04959 100644 --- a/shell/platform/android/io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java +++ b/shell/platform/android/io/flutter/embedding/engine/FlutterEngineConnectionRegistry.java @@ -331,9 +331,11 @@ private void attachToActivityInternal(@NonNull Activity activity, @NonNull Lifec this.activityPluginBinding = new FlutterEngineActivityPluginBinding(activity, lifecycle); final boolean useSoftwareRendering = - activity - .getIntent() - .getBooleanExtra(FlutterShellArgs.ARG_KEY_ENABLE_SOFTWARE_RENDERING, false); + activity.getIntent() != null + ? activity + .getIntent() + .getBooleanExtra(FlutterShellArgs.ARG_KEY_ENABLE_SOFTWARE_RENDERING, false) + : false; flutterEngine.getPlatformViewsController().setSoftwareRendering(useSoftwareRendering); // Activate the PlatformViewsController. This must happen before any plugins attempt diff --git a/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineConnectionRegistryTest.java b/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineConnectionRegistryTest.java index 8bbc729d8b3a1..975d6d052a5b1 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineConnectionRegistryTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/FlutterEngineConnectionRegistryTest.java @@ -127,15 +127,18 @@ public void softwareRendering() { Activity activity = mock(Activity.class); when(appComponent.getAppComponent()).thenReturn(activity); + // Test attachToActivity with an Activity that has no Intent. + FlutterEngineConnectionRegistry registry = + new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader); + registry.attachToActivity(appComponent, mock(Lifecycle.class)); + verify(platformViewsController).setSoftwareRendering(false); + Intent intent = mock(Intent.class); when(intent.getBooleanExtra("enable-software-rendering", false)).thenReturn(false); when(activity.getIntent()).thenReturn(intent); - FlutterEngineConnectionRegistry registry = - new FlutterEngineConnectionRegistry(context, flutterEngine, flutterLoader); - registry.attachToActivity(appComponent, mock(Lifecycle.class)); - verify(platformViewsController).setSoftwareRendering(false); + verify(platformViewsController, times(2)).setSoftwareRendering(false); when(intent.getBooleanExtra("enable-software-rendering", false)).thenReturn(true); From a6cfd3cff9a8999e929a20d843b9295bd25e0c6a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 11:47:47 -0400 Subject: [PATCH 337/558] Roll Fuchsia Mac SDK from ehAgYZRo9fxyylrTD... to 6UzpMkHKQt7i9ghiC... (#35432) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 5600062729d19..6724e105696d2 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'ehAgYZRo9fxyylrTD5gF8klcrWyi7n6yjl7xMhDEy0EC' + 'version': '6UzpMkHKQt7i9ghiCFIOavEj1Ez4S0pvwJHJwEEeQXsC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From f1ff5598904cac84f048c2d1032a48802c551bb1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 11:49:04 -0400 Subject: [PATCH 338/558] Roll Skia from f86f24288669 to e6cabf0db8cd (2 revisions) (#35430) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6724e105696d2..56283814a91ee 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': 'f86f242886692a18f5adc1cf9cbd6740cd0870fd', + 'skia_revision': 'e6cabf0db8cd255a211d415ddfb876bba12c520b', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index a65d1dec3af40..b9b31031d3f7b 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 9e11b178003dfb4d5f7eac0356b570db +Signature: 26ff7c597f4f920b6f6c4f73657826f3 UNUSED LICENSES: From 722c01238ed9c6bfba4824366ecd09d154622fc8 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 11:57:07 -0400 Subject: [PATCH 339/558] Roll Dart SDK from 2993204cfc1e to b2c192c83ed8 (1 revision) (#35431) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 56283814a91ee..87cf0d2debbe4 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '2993204cfc1e7e41be5826e6e8f122947640d8d3', + 'dart_revision': 'b2c192c83ed808fa318d220d54706d0f1cf3a8e4', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -203,7 +203,7 @@ deps = { Var('dart_git') + '/dart_style.git@49bc3ff32b5578b6e19f8fd376d668130941ee29', 'src/third_party/dart/third_party/pkg/dartdoc': - Var('dart_git') + '/dartdoc.git@446e0fd1f26b47d2b0b48505f3ed8c9f48d22f57', + Var('dart_git') + '/dartdoc.git@b3d4aa002d36c28b0af114abd0997b8521c27b11', 'src/third_party/dart/third_party/pkg/ffi': Var('dart_git') + '/ffi.git@18b2b549d55009ff594600b04705ff6161681e07', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index d4e51322e9643..1631445c3cc33 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 5c32292c6dac6d11effd54c259c10e99 +Signature: 9aa9860639c416c10e6b8b6ac788916c UNUSED LICENSES: From d88f8d8a21bcd957a5811d890b6267fad0a6aed0 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 13:38:07 -0400 Subject: [PATCH 340/558] Roll Skia from e6cabf0db8cd to af3ec775769a (16 revisions) (#35433) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 87cf0d2debbe4..49592b9527603 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': 'e6cabf0db8cd255a211d415ddfb876bba12c520b', + 'skia_revision': 'af3ec775769ad900d8936215c6326d3640905474', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index b9b31031d3f7b..512a7de5a6ed5 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 26ff7c597f4f920b6f6c4f73657826f3 +Signature: 2f4b288f73a2ca6448259df89d7a43d3 UNUSED LICENSES: From f2c4cf5967e741dc2bd23b1b6e84a4604eb63ae4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 14:53:23 -0400 Subject: [PATCH 341/558] Roll Skia from af3ec775769a to 9e5098d36e88 (7 revisions) (#35434) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 49592b9527603..d95c3349ee98c 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': 'af3ec775769ad900d8936215c6326d3640905474', + 'skia_revision': '9e5098d36e88e0eaf5a3b4eb53ed1a21dacac660', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 512a7de5a6ed5..5bbb60cbb60f4 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 2f4b288f73a2ca6448259df89d7a43d3 +Signature: 51862cb3292c52b48661a916c92b99bf UNUSED LICENSES: From 8c7d8966b1f49502a72409698c2f52c694bc0ce7 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Tue, 16 Aug 2022 12:21:03 -0700 Subject: [PATCH 342/558] Fixes the output path for release dsym. (#35338) --- sky/tools/create_full_ios_framework.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sky/tools/create_full_ios_framework.py b/sky/tools/create_full_ios_framework.py index 115f369a6bab9..82aa7f5a29ec4 100644 --- a/sky/tools/create_full_ios_framework.py +++ b/sky/tools/create_full_ios_framework.py @@ -111,7 +111,7 @@ def main(): simulator_x64_framework, simulator_arm64_framework ) framework_binary = os.path.join(framework, 'Flutter') - process_framework(args, framework, framework_binary) + process_framework(args, dst, framework, framework_binary) generate_gen_snapshot(args, dst, x64_out_dir, arm64_out_dir) zip_archive(dst) @@ -146,7 +146,9 @@ def create_framework( 'lipo', simulator_x64_dylib, simulator_arm64_dylib, '-create', '-output', simulator_framework_binary ]) - process_framework(args, simulator_framework, simulator_framework_binary) + process_framework( + args, dst, simulator_framework, simulator_framework_binary + ) simulator_framework = simulator_framework else: simulator_framework = simulator_x64_framework @@ -168,9 +170,12 @@ def zip_archive(dst): 'zip', '-r', 'artifacts.zip', 'gen_snapshot_arm64', 'Flutter.xcframework' ], cwd=dst) + if (os.path.exists(os.path.join(dst, 'Flutter.dSYM'))): + subprocess.check_call(['zip', '-r', 'Flutter.dSYM.zip', 'Flutter.dSYM'], + cwd=dst) -def process_framework(args, framework, framework_binary): +def process_framework(args, dst, framework, framework_binary): if args.strip_bitcode: subprocess.check_call([ 'xcrun', 'bitcode_strip', '-r', framework_binary, '-o', framework_binary From c007c40aed330d9dd1f50602739956207b21ca8a Mon Sep 17 00:00:00 2001 From: JsouLiang Date: Wed, 17 Aug 2022 03:24:48 +0800 Subject: [PATCH 343/558] Use DlImageFilter for ImageFilterLayer (#34837) --- display_list/display_list_image_filter.cc | 2 +- display_list/display_list_image_filter.h | 10 +- flow/layers/image_filter_layer.cc | 60 +++-- flow/layers/image_filter_layer.h | 8 +- flow/layers/image_filter_layer_unittests.cc | 264 +++++++++++--------- flow/layers/layer.h | 10 +- flow/layers/opacity_layer_unittests.cc | 2 +- lib/ui/compositing/scene_builder.cc | 4 +- 8 files changed, 196 insertions(+), 164 deletions(-) diff --git a/display_list/display_list_image_filter.cc b/display_list/display_list_image_filter.cc index 8d4a98fb89e6a..4e43649a208e0 100644 --- a/display_list/display_list_image_filter.cc +++ b/display_list/display_list_image_filter.cc @@ -28,7 +28,7 @@ std::shared_ptr DlImageFilter::From( } std::shared_ptr DlImageFilter::makeWithLocalMatrix( - const SkMatrix& matrix) { + const SkMatrix& matrix) const { if (matrix.isIdentity()) { return shared(); } diff --git a/display_list/display_list_image_filter.h b/display_list/display_list_image_filter.h index 4a0063b8b48cb..c495c4cf098b2 100644 --- a/display_list/display_list_image_filter.h +++ b/display_list/display_list_image_filter.h @@ -95,7 +95,7 @@ class DlImageFilter } virtual std::shared_ptr makeWithLocalMatrix( - const SkMatrix& matrix); + const SkMatrix& matrix) const; // Return a DlComposeImageFilter pointer to this object iff it is a Compose // type of ImageFilter, otherwise return nullptr. @@ -634,7 +634,7 @@ class DlColorFilterImageFilter final : public DlImageFilter { } std::shared_ptr makeWithLocalMatrix( - const SkMatrix& matrix) override { + const SkMatrix& matrix) const override { return shared(); } @@ -764,7 +764,7 @@ class DlUnknownImageFilter final : public DlImageFilter { SkRect* map_local_bounds(const SkRect& input_bounds, SkRect& output_bounds) const override { - if (modifies_transparent_black()) { + if (!sk_filter_ || modifies_transparent_black()) { output_bounds = input_bounds; return nullptr; } @@ -775,7 +775,7 @@ class DlUnknownImageFilter final : public DlImageFilter { SkIRect* map_device_bounds(const SkIRect& input_bounds, const SkMatrix& ctm, SkIRect& output_bounds) const override { - if (modifies_transparent_black()) { + if (!sk_filter_ || modifies_transparent_black()) { output_bounds = input_bounds; return nullptr; } @@ -787,7 +787,7 @@ class DlUnknownImageFilter final : public DlImageFilter { SkIRect* get_input_device_bounds(const SkIRect& output_bounds, const SkMatrix& ctm, SkIRect& input_bounds) const override { - if (modifies_transparent_black()) { + if (!sk_filter_ || modifies_transparent_black()) { input_bounds = output_bounds; return nullptr; } diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index 4793bfd8f0d03..addccef60d533 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -3,12 +3,13 @@ // found in the LICENSE file. #include "flutter/flow/layers/image_filter_layer.h" +#include "flutter/display_list/display_list_comparable.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache_util.h" namespace flutter { -ImageFilterLayer::ImageFilterLayer(sk_sp filter) +ImageFilterLayer::ImageFilterLayer(std::shared_ptr filter) : CacheableContainerLayer( RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer), filter_(std::move(filter)), @@ -19,7 +20,7 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { auto* prev = static_cast(old_layer); if (!context->IsSubtreeDirty()) { FML_DCHECK(prev); - if (filter_ != prev->filter_) { + if (NotEquals(filter_, prev->filter_)) { context->MarkSubtreeDirty(context->GetOldLayerPaintRegion(old_layer)); } } @@ -29,9 +30,10 @@ void ImageFilterLayer::Diff(DiffContext* context, const Layer* old_layer) { if (filter) { // This transform will be applied to every child rect in the subtree context->PushFilterBoundsAdjustment([filter](SkRect rect) { - return SkRect::Make( - filter->filterBounds(rect.roundOut(), SkMatrix::I(), - SkImageFilter::kForward_MapDirection)); + SkIRect filter_out_bounds; + filter->map_device_bounds(rect.roundOut(), SkMatrix::I(), + filter_out_bounds); + return SkRect::Make(filter_out_bounds); }); } } @@ -50,7 +52,6 @@ void ImageFilterLayer::Preroll(PrerollContext* context, SkRect child_bounds = SkRect::MakeEmpty(); PrerollChildren(context, matrix, &child_bounds); - context->subtree_can_inherit_opacity = true; // We always paint with a saveLayer (or a cached rendering), // so we can always apply opacity in any of those cases. @@ -61,10 +62,11 @@ void ImageFilterLayer::Preroll(PrerollContext* context, return; } - const SkIRect filter_input_bounds = child_bounds.roundOut(); - SkIRect filter_output_bounds = filter_->filterBounds( - filter_input_bounds, SkMatrix::I(), SkImageFilter::kForward_MapDirection); - child_bounds = SkRect::Make(filter_output_bounds); + const SkIRect filter_in_bounds = child_bounds.roundOut(); + SkIRect filter_out_bounds; + filter_->map_device_bounds(filter_in_bounds, SkMatrix::I(), + filter_out_bounds); + child_bounds = SkRect::Make(filter_out_bounds); set_paint_bounds(child_bounds); @@ -83,23 +85,31 @@ void ImageFilterLayer::Paint(PaintContext& context) const { FML_DCHECK(needs_painting(context)); AutoCachePaint cache_paint(context); - - if (layer_raster_cache_item_->IsCacheChildren()) { - cache_paint.setImageFilter(transformed_filter_); - } - if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { - return; + if (context.raster_cache) { + if (layer_raster_cache_item_->IsCacheChildren()) { + cache_paint.setImageFilter(transformed_filter_.get()); + } + if (layer_raster_cache_item_->Draw(context, cache_paint.sk_paint())) { + return; + } } - cache_paint.setImageFilter(filter_); - - // Normally a save_layer is sized to the current layer bounds, but in this - // case the bounds of the child may not be the same as the filtered version - // so we use the bounds of the child container which do not include any - // modifications that the filter might apply. - Layer::AutoSaveLayer save_layer = Layer::AutoSaveLayer::Create( - context, child_paint_bounds(), cache_paint.sk_paint()); - PaintChildren(context); + cache_paint.setImageFilter(filter_.get()); + if (context.leaf_nodes_builder) { + FML_DCHECK(context.builder_multiplexer); + context.builder_multiplexer->saveLayer(&child_paint_bounds(), + cache_paint.dl_paint()); + PaintChildren(context); + context.builder_multiplexer->restore(); + } else { + // Normally a save_layer is sized to the current layer bounds, but in this + // case the bounds of the child may not be the same as the filtered version + // so we use the bounds of the child container which do not include any + // modifications that the filter might apply. + Layer::AutoSaveLayer save_layer = Layer::AutoSaveLayer::Create( + context, child_paint_bounds(), cache_paint.sk_paint()); + PaintChildren(context); + } } } // namespace flutter diff --git a/flow/layers/image_filter_layer.h b/flow/layers/image_filter_layer.h index bb2f3a6d60335..e4987bd9fb75b 100644 --- a/flow/layers/image_filter_layer.h +++ b/flow/layers/image_filter_layer.h @@ -5,15 +5,17 @@ #ifndef FLUTTER_FLOW_LAYERS_IMAGE_FILTER_LAYER_H_ #define FLUTTER_FLOW_LAYERS_IMAGE_FILTER_LAYER_H_ +#include #include "flutter/flow/layers/cacheable_layer.h" #include "flutter/flow/layers/layer.h" +#include "include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkImageFilter.h" namespace flutter { class ImageFilterLayer : public CacheableContainerLayer { public: - explicit ImageFilterLayer(sk_sp filter); + explicit ImageFilterLayer(std::shared_ptr filter); void Diff(DiffContext* context, const Layer* old_layer) override; @@ -22,8 +24,8 @@ class ImageFilterLayer : public CacheableContainerLayer { void Paint(PaintContext& context) const override; private: - sk_sp filter_; - sk_sp transformed_filter_; + std::shared_ptr filter_; + std::shared_ptr transformed_filter_; FML_DISALLOW_COPY_AND_ASSIGN(ImageFilterLayer); }; diff --git a/flow/layers/image_filter_layer_unittests.cc b/flow/layers/image_filter_layer_unittests.cc index 546331452a9fa..2ad4a7e3e86d6 100644 --- a/flow/layers/image_filter_layer_unittests.cc +++ b/flow/layers/image_filter_layer_unittests.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "flutter/display_list/display_list_tile_mode.h" #include "flutter/flow/layers/image_filter_layer.h" #include "flutter/flow/layers/layer_tree.h" @@ -23,7 +24,7 @@ using ImageFilterLayerTest = LayerTest; #ifndef NDEBUG TEST_F(ImageFilterLayerTest, PaintingEmptyLayerDies) { - auto layer = std::make_shared(sk_sp()); + auto layer = std::make_shared(nullptr); layer->Preroll(preroll_context(), SkMatrix()); EXPECT_EQ(layer->paint_bounds(), kEmptyRect); @@ -37,7 +38,7 @@ TEST_F(ImageFilterLayerTest, PaintBeforePrerollDies) { const SkRect child_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f); const SkPath child_path = SkPath().addRect(child_bounds); auto mock_layer = std::make_shared(child_path); - auto layer = std::make_shared(sk_sp()); + auto layer = std::make_shared(nullptr); layer->Add(mock_layer); EXPECT_EQ(layer->paint_bounds(), kEmptyRect); @@ -81,11 +82,10 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) { 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); - auto layer_filter = SkImageFilters::MatrixTransform( - SkMatrix(), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); + 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(layer_filter); + auto layer = std::make_shared(dl_image_filter); layer->Add(mock_layer); const SkRect child_rounded_bounds = @@ -97,18 +97,23 @@ TEST_F(ImageFilterLayerTest, SimpleFilter) { EXPECT_TRUE(layer->needs_painting(paint_context())); EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); - SkPaint filter_paint; - filter_paint.setImageFilter(layer_filter); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector({ - MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, filter_paint, - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}, - })); + DisplayListBuilder expected_builder; + /* ImageFilterLayer::Paint() */ { + 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(); + 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) { @@ -117,11 +122,11 @@ TEST_F(ImageFilterLayerTest, SimpleFilterBounds) { const SkPath child_path = SkPath().addRect(child_bounds); const SkPaint child_paint = SkPaint(SkColors::kYellow); const SkMatrix filter_transform = SkMatrix::Scale(2.0, 2.0); - auto layer_filter = SkImageFilters::MatrixTransform( - filter_transform, - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); + + auto dl_image_filter = std::make_shared( + filter_transform, DlImageSampling::kMipmapLinear); auto mock_layer = std::make_shared(child_path, child_paint); - auto layer = std::make_shared(layer_filter); + auto layer = std::make_shared(dl_image_filter); layer->Add(mock_layer); const SkRect filter_bounds = SkRect::MakeLTRB(10.0f, 12.0f, 42.0f, 44.0f); @@ -132,18 +137,23 @@ TEST_F(ImageFilterLayerTest, SimpleFilterBounds) { EXPECT_TRUE(layer->needs_painting(paint_context())); EXPECT_EQ(mock_layer->parent_matrix(), initial_transform); - SkPaint filter_paint; - filter_paint.setImageFilter(layer_filter); - layer->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector({ - MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{child_bounds, filter_paint, - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path, child_paint}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}, - })); + DisplayListBuilder expected_builder; + /* ImageFilterLayer::Paint() */ { + 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(); + 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, MultipleChildren) { @@ -154,12 +164,11 @@ TEST_F(ImageFilterLayerTest, MultipleChildren) { SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f)); const SkPaint child_paint1 = SkPaint(SkColors::kYellow); const SkPaint child_paint2 = SkPaint(SkColors::kCyan); - auto layer_filter = SkImageFilters::MatrixTransform( - SkMatrix(), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); + auto dl_image_filter = std::make_shared( + SkMatrix(), DlImageSampling::kMipmapLinear); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); - auto layer = std::make_shared(layer_filter); + auto layer = std::make_shared(dl_image_filter); layer->Add(mock_layer1); layer->Add(mock_layer2); @@ -178,19 +187,27 @@ TEST_F(ImageFilterLayerTest, MultipleChildren) { EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); - SkPaint filter_paint; - filter_paint.setImageFilter(layer_filter); - layer->Paint(paint_context()); - EXPECT_EQ( - mock_canvas().draw_calls(), - std::vector({MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{children_bounds, - filter_paint, nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path2, child_paint2}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}})); + DisplayListBuilder expected_builder; + /* ImageFilterLayer::Paint() */ { + DlPaint dl_paint; + dl_paint.setImageFilter(dl_image_filter.get()); + expected_builder.saveLayer(&children_bounds, &dl_paint); + { + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path1, + DlPaint().setColor(DlColor::kYellow())); + } + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path2, + DlPaint().setColor(DlColor::kCyan())); + } + } + } + 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, Nested) { @@ -201,16 +218,14 @@ TEST_F(ImageFilterLayerTest, Nested) { SkPath().addRect(child_bounds.makeOffset(3.0f, 0.0f)); const SkPaint child_paint1 = SkPaint(SkColors::kYellow); const SkPaint child_paint2 = SkPaint(SkColors::kCyan); - auto layer_filter1 = SkImageFilters::MatrixTransform( - SkMatrix(), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); - auto layer_filter2 = SkImageFilters::MatrixTransform( - SkMatrix(), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); + auto dl_image_filter1 = std::make_shared( + SkMatrix(), DlImageSampling::kMipmapLinear); + auto dl_image_filter2 = std::make_shared( + SkMatrix(), DlImageSampling::kMipmapLinear); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); - auto layer1 = std::make_shared(layer_filter1); - auto layer2 = std::make_shared(layer_filter2); + auto layer1 = std::make_shared(dl_image_filter1); + auto layer2 = std::make_shared(dl_image_filter2); layer2->Add(mock_layer2); layer1->Add(mock_layer1); layer1->Add(layer2); @@ -236,35 +251,43 @@ TEST_F(ImageFilterLayerTest, Nested) { EXPECT_EQ(mock_layer1->parent_matrix(), initial_transform); EXPECT_EQ(mock_layer2->parent_matrix(), initial_transform); - SkPaint filter_paint1, filter_paint2; - filter_paint1.setImageFilter(layer_filter1); - filter_paint2.setImageFilter(layer_filter2); - layer1->Paint(paint_context()); - EXPECT_EQ(mock_canvas().draw_calls(), - std::vector({ - MockCanvas::DrawCall{ - 0, MockCanvas::SaveLayerData{children_bounds, filter_paint1, - nullptr, 1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::DrawPathData{child_path1, child_paint1}}, - MockCanvas::DrawCall{ - 1, MockCanvas::SaveLayerData{child_path2.getBounds(), - filter_paint2, nullptr, 2}}, - MockCanvas::DrawCall{ - 2, MockCanvas::DrawPathData{child_path2, child_paint2}}, - MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, - MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}, - })); + DisplayListBuilder expected_builder; + /* ImageFilterLayer::Paint() */ { + DlPaint dl_paint; + dl_paint.setImageFilter(dl_image_filter1.get()); + expected_builder.saveLayer(&children_bounds, &dl_paint); + { + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path1, + DlPaint().setColor(DlColor::kYellow())); + } + /* ImageFilterLayer::Paint() */ { + DlPaint child_paint; + child_paint.setImageFilter(dl_image_filter2.get()); + expected_builder.saveLayer(&child_path2.getBounds(), &child_paint); + /* MockLayer::Paint() */ { + expected_builder.drawPath(child_path2, + DlPaint().setColor(DlColor::kCyan())); + } + expected_builder.restore(); + } + } + } + expected_builder.restore(); + auto expected_display_list = expected_builder.Build(); + + layer1->Paint(display_list_paint_context()); + EXPECT_TRUE(DisplayListsEQ_Verbose(display_list(), expected_display_list)); } TEST_F(ImageFilterLayerTest, Readback) { - auto layer_filter = SkImageFilters::MatrixTransform( - SkMatrix(), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); + auto dl_image_filter = std::make_shared( + SkMatrix(), DlImageSampling::kLinear); + auto initial_transform = SkMatrix(); // ImageFilterLayer does not read from surface - auto layer = std::make_shared(layer_filter); + auto layer = std::make_shared(dl_image_filter); preroll_context()->surface_needs_readback = false; layer->Preroll(preroll_context(), initial_transform); EXPECT_FALSE(preroll_context()->surface_needs_readback); @@ -279,14 +302,13 @@ TEST_F(ImageFilterLayerTest, Readback) { } TEST_F(ImageFilterLayerTest, CacheChild) { - auto layer_filter = SkImageFilters::MatrixTransform( - SkMatrix(), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); + auto dl_image_filter = std::make_shared( + SkMatrix(), DlImageSampling::kMipmapLinear); auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); auto mock_layer = std::make_shared(child_path); - auto layer = std::make_shared(layer_filter); + auto layer = std::make_shared(dl_image_filter); layer->Add(mock_layer); SkMatrix cache_ctm = initial_transform; @@ -320,9 +342,8 @@ TEST_F(ImageFilterLayerTest, CacheChild) { } TEST_F(ImageFilterLayerTest, CacheChildren) { - auto layer_filter = SkImageFilters::MatrixTransform( - SkMatrix(), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); + auto dl_image_filter = std::make_shared( + SkMatrix(), DlImageSampling::kMipmapLinear); auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); SkPaint paint = SkPaint(); @@ -330,7 +351,7 @@ TEST_F(ImageFilterLayerTest, CacheChildren) { const SkPath child_path2 = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); auto mock_layer1 = std::make_shared(child_path1); auto mock_layer2 = std::make_shared(child_path2); - auto layer = std::make_shared(layer_filter); + auto layer = std::make_shared(dl_image_filter); layer->Add(mock_layer1); layer->Add(mock_layer2); @@ -366,14 +387,14 @@ TEST_F(ImageFilterLayerTest, CacheChildren) { } TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) { - auto layer_filter = SkImageFilters::MatrixTransform( - SkMatrix(), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); + auto dl_image_filter = std::make_shared( + SkMatrix(), DlImageSampling::kMipmapLinear); + auto initial_transform = SkMatrix::Translate(50.0, 25.5); auto other_transform = SkMatrix::Scale(1.0, 2.0); const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); auto mock_layer = std::make_shared(child_path); - auto layer = std::make_shared(layer_filter); + auto layer = std::make_shared(dl_image_filter); layer->Add(mock_layer); SkMatrix cache_ctm = initial_transform; @@ -416,12 +437,12 @@ TEST_F(ImageFilterLayerTest, OpacityInheritance) { 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); - auto layer_filter = SkImageFilters::MatrixTransform( - SkMatrix(), - SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear), nullptr); + auto dl_image_filter = std::make_shared( + SkMatrix(), DlImageSampling::kMipmapLinear); + // The mock_layer child will not be compatible with opacity auto mock_layer = MockLayer::Make(child_path, child_paint); - auto image_filter_layer = std::make_shared(layer_filter); + auto image_filter_layer = std::make_shared(dl_image_filter); image_filter_layer->Add(mock_layer); PrerollContext* context = preroll_context(); @@ -439,20 +460,20 @@ TEST_F(ImageFilterLayerTest, OpacityInheritance) { opacity_layer->Preroll(context, SkMatrix::I()); EXPECT_TRUE(opacity_layer->children_can_accept_opacity()); - auto dl_image_filter = DlImageFilter::From(layer_filter); DisplayListBuilder expected_builder; /* OpacityLayer::Paint() */ { expected_builder.save(); { expected_builder.translate(offset.fX, offset.fY); /* ImageFilterLayer::Paint() */ { - expected_builder.setColor(opacity_alpha << 24); - expected_builder.setImageFilter(dl_image_filter.get()); - expected_builder.saveLayer(&child_path.getBounds(), true); + DlPaint image_filter_paint; + image_filter_paint.setColor(opacity_alpha << 24); + image_filter_paint.setImageFilter(dl_image_filter.get()); + expected_builder.saveLayer(&child_path.getBounds(), + &image_filter_paint); /* MockLayer::Paint() */ { - expected_builder.setColor(child_paint.getColor()); - expected_builder.setImageFilter(nullptr); - expected_builder.drawPath(child_path); + expected_builder.drawPath(child_path, + DlPaint().setColor(child_paint.getColor())); } expected_builder.restore(); } @@ -467,18 +488,18 @@ TEST_F(ImageFilterLayerTest, OpacityInheritance) { using ImageFilterLayerDiffTest = DiffContextTest; TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { - auto filter = SkImageFilters::Blur(10, 10, SkTileMode::kClamp, nullptr); - + auto dl_blur_filter = + std::make_shared(10, 10, DlTileMode::kClamp); { // tests later assume 30px paint area, fail early if that's not the case - auto paint_rect = - filter->filterBounds(SkIRect::MakeWH(10, 10), SkMatrix::I(), - SkImageFilter::kForward_MapDirection); - EXPECT_EQ(paint_rect, SkIRect::MakeLTRB(-30, -30, 40, 40)); + SkIRect input_bounds; + dl_blur_filter->get_input_device_bounds(SkIRect::MakeWH(10, 10), + SkMatrix::I(), input_bounds); + EXPECT_EQ(input_bounds, SkIRect::MakeLTRB(-30, -30, 40, 40)); } MockLayerTree l1; - auto filter_layer = std::make_shared(filter); + auto filter_layer = std::make_shared(dl_blur_filter); auto path = SkPath().addRect(SkRect::MakeLTRB(100, 100, 110, 110)); filter_layer->Add(std::make_shared(path)); l1.root()->Add(filter_layer); @@ -514,21 +535,22 @@ TEST_F(ImageFilterLayerDiffTest, ImageFilterLayer) { } TEST_F(ImageFilterLayerDiffTest, ImageFilterLayerInflatestChildSize) { - auto filter = SkImageFilters::Blur(10, 10, SkTileMode::kClamp, nullptr); + auto dl_blur_filter = + std::make_shared(10, 10, DlTileMode::kClamp); { // tests later assume 30px paint area, fail early if that's not the case - auto paint_rect = - filter->filterBounds(SkIRect::MakeWH(10, 10), SkMatrix::I(), - SkImageFilter::kForward_MapDirection); - EXPECT_EQ(paint_rect, SkIRect::MakeLTRB(-30, -30, 40, 40)); + SkIRect input_bounds; + dl_blur_filter->get_input_device_bounds(SkIRect::MakeWH(10, 10), + SkMatrix::I(), input_bounds); + EXPECT_EQ(input_bounds, SkIRect::MakeLTRB(-30, -30, 40, 40)); } MockLayerTree l1; // Use nested filter layers to check if both contribute to child bounds - auto filter_layer_1_1 = std::make_shared(filter); - auto filter_layer_1_2 = std::make_shared(filter); + auto filter_layer_1_1 = std::make_shared(dl_blur_filter); + auto filter_layer_1_2 = std::make_shared(dl_blur_filter); filter_layer_1_1->Add(filter_layer_1_2); auto path = SkPath().addRect(SkRect::MakeLTRB(100, 100, 110, 110)); filter_layer_1_2->Add( @@ -537,9 +559,9 @@ TEST_F(ImageFilterLayerDiffTest, ImageFilterLayerInflatestChildSize) { // second layer tree with identical filter layers but different child layer MockLayerTree l2; - auto filter_layer2_1 = std::make_shared(filter); + auto filter_layer2_1 = std::make_shared(dl_blur_filter); filter_layer2_1->AssignOldLayer(filter_layer_1_1.get()); - auto filter_layer2_2 = std::make_shared(filter); + auto filter_layer2_2 = std::make_shared(dl_blur_filter); filter_layer2_2->AssignOldLayer(filter_layer_1_2.get()); filter_layer2_1->Add(filter_layer2_2); filter_layer2_2->Add( diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 17d5dc92ac0a3..bb57b430fa3b0 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -227,16 +227,14 @@ class Layer { ~AutoCachePaint() { context_.inherited_opacity = sk_paint_.getAlphaf(); } - void setImageFilter(sk_sp filter) { - sk_paint_.setImageFilter(filter); - dl_paint_.setImageFilter(DlImageFilter::From(filter)); + void setImageFilter(const DlImageFilter* filter) { + sk_paint_.setImageFilter(!filter ? nullptr : filter->skia_object()); + dl_paint_.setImageFilter(filter); update_needs_paint(); } void setColorFilter(const DlColorFilter* filter) { - if (!filter) - return; - sk_paint_.setColorFilter(filter->skia_object()); + sk_paint_.setColorFilter(!filter ? nullptr : filter->skia_object()); dl_paint_.setColorFilter(filter); update_needs_paint(); } diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index c662e73284ec4..6844b9bc50682 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -523,7 +523,7 @@ TEST_F(OpacityLayerTest, OpacityInheritanceThroughImageFilter) { auto opacityLayer = std::make_shared(128, SkPoint::Make(20, 20)); auto filterLayer = std::make_shared( - SkImageFilters::Blur(5.0, 5.0, nullptr)); + std::make_shared(5.0, 5.0, DlTileMode::kClamp)); auto mockLayer = MockLayer::MakeOpacityCompatible(SkPath()); filterLayer->Add(mockLayer); opacityLayer->Add(filterLayer); diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 74859e2b8df4b..3967c20088d9b 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -152,8 +152,8 @@ void SceneBuilder::pushColorFilter(Dart_Handle layer_handle, void SceneBuilder::pushImageFilter(Dart_Handle layer_handle, const ImageFilter* image_filter, fml::RefPtr oldLayer) { - auto layer = std::make_shared( - image_filter->filter()->skia_object()); + auto layer = + std::make_shared(image_filter->filter()); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); From c0dc80a673443fc1a7e2fe5a529498043986f549 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 16:08:22 -0400 Subject: [PATCH 344/558] Roll Skia from 9e5098d36e88 to 97da42fc6ecc (4 revisions) (#35435) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d95c3349ee98c..eeac84d2e1585 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': '9e5098d36e88e0eaf5a3b4eb53ed1a21dacac660', + 'skia_revision': '97da42fc6ecc3c399eb79f3f3128742a92e5b67e', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 5bbb60cbb60f4..b90b497aa400c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 51862cb3292c52b48661a916c92b99bf +Signature: cc649450e3a8b677cc4c22a08f427b97 UNUSED LICENSES: From af294fbae0b4cc21270c7bfb0e96df2f761d02e6 Mon Sep 17 00:00:00 2001 From: magicianA Date: Wed, 17 Aug 2022 04:10:19 +0800 Subject: [PATCH 345/558] [Impeller] Clamp texture decompression to maximum supported texture size. (#35373) --- impeller/renderer/allocator.h | 2 ++ .../renderer/backend/gles/allocator_gles.cc | 5 +++ .../renderer/backend/gles/allocator_gles.h | 3 ++ .../renderer/backend/metal/allocator_mtl.h | 4 +++ .../renderer/backend/metal/allocator_mtl.mm | 33 +++++++++++++++++++ .../renderer/backend/vulkan/allocator_vk.cc | 7 ++++ .../renderer/backend/vulkan/allocator_vk.h | 3 ++ lib/ui/painting/image_decoder_impeller.cc | 13 ++++++-- lib/ui/painting/image_decoder_impeller.h | 4 ++- lib/ui/painting/image_decoder_unittests.cc | 8 +++-- 10 files changed, 77 insertions(+), 5 deletions(-) diff --git a/impeller/renderer/allocator.h b/impeller/renderer/allocator.h index eb88a620ff986..e4f189f02f6ed 100644 --- a/impeller/renderer/allocator.h +++ b/impeller/renderer/allocator.h @@ -69,6 +69,8 @@ class Allocator { std::shared_ptr CreateBufferWithCopy( const fml::Mapping& mapping); + virtual ISize GetMaxTextureSizeSupported() const = 0; + protected: Allocator(); diff --git a/impeller/renderer/backend/gles/allocator_gles.cc b/impeller/renderer/backend/gles/allocator_gles.cc index 5f08256ab0031..8873272c315c8 100644 --- a/impeller/renderer/backend/gles/allocator_gles.cc +++ b/impeller/renderer/backend/gles/allocator_gles.cc @@ -42,4 +42,9 @@ std::shared_ptr AllocatorGLES::CreateTexture( return std::make_shared(reactor_, std::move(desc)); } +// |Allocator| +ISize AllocatorGLES::GetMaxTextureSizeSupported() const { + return reactor_->GetProcTable().GetCapabilities()->max_texture_size; +} + } // namespace impeller diff --git a/impeller/renderer/backend/gles/allocator_gles.h b/impeller/renderer/backend/gles/allocator_gles.h index 7b322938d351b..1336b19ecb8cd 100644 --- a/impeller/renderer/backend/gles/allocator_gles.h +++ b/impeller/renderer/backend/gles/allocator_gles.h @@ -35,6 +35,9 @@ class AllocatorGLES final : public Allocator { StorageMode mode, const TextureDescriptor& desc) override; + // |Allocator| + ISize GetMaxTextureSizeSupported() const override; + FML_DISALLOW_COPY_AND_ASSIGN(AllocatorGLES); }; diff --git a/impeller/renderer/backend/metal/allocator_mtl.h b/impeller/renderer/backend/metal/allocator_mtl.h index 64f4c59c9f7c9..62cb0eee4a0c6 100644 --- a/impeller/renderer/backend/metal/allocator_mtl.h +++ b/impeller/renderer/backend/metal/allocator_mtl.h @@ -26,6 +26,7 @@ class AllocatorMTL final : public Allocator { bool supports_memoryless_targets_ = false; bool supports_uma_ = false; bool is_valid_ = false; + ISize max_texture_supported_; AllocatorMTL(id device, std::string label); @@ -41,6 +42,9 @@ class AllocatorMTL final : public Allocator { StorageMode mode, const TextureDescriptor& desc) override; + // |Allocator| + ISize GetMaxTextureSizeSupported() const override; + FML_DISALLOW_COPY_AND_ASSIGN(AllocatorMTL); }; diff --git a/impeller/renderer/backend/metal/allocator_mtl.mm b/impeller/renderer/backend/metal/allocator_mtl.mm index 4a5dafae668a2..fad4803ed077c 100644 --- a/impeller/renderer/backend/metal/allocator_mtl.mm +++ b/impeller/renderer/backend/metal/allocator_mtl.mm @@ -50,6 +50,34 @@ static bool DeviceHasUnifiedMemoryArchitecture(id device) { FML_UNREACHABLE(); } +static ISize DeviceMaxTextureSizeSupported(id device) { + // Since Apple didn't expose API for us to get the max texture size, we have + // to use hardcoded data from + // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf + // According to the feature set table, there are two supported max sizes : + // 16384 and 8192 for devices flutter support. The former is used on macs and + // latest ios devices. The latter is used on old ios devices. + if (@available(macOS 10.15, iOS 13, tvOS 13, *)) { + if ([device supportsFamily:MTLGPUFamilyApple3] || + [device supportsFamily:MTLGPUFamilyMacCatalyst1] || + [device supportsFamily:MTLGPUFamilyMac1]) { + return {16384, 16384}; + } + return {8192, 8192}; + } else { +#if FML_OS_IOS + if ([device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1] || + [device supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) { + return {16384, 16384}; + } +#endif +#if FML_OS_MACOSX + return {16384, 16384}; +#endif + return {8192, 8192}; + } +} + AllocatorMTL::AllocatorMTL(id device, std::string label) : device_(device), allocator_label_(std::move(label)) { if (!device_) { @@ -58,6 +86,7 @@ static bool DeviceHasUnifiedMemoryArchitecture(id device) { supports_memoryless_targets_ = DeviceSupportsMemorylessTargets(device_); supports_uma_ = DeviceHasUnifiedMemoryArchitecture(device_); + max_texture_supported_ = DeviceMaxTextureSizeSupported(device_); is_valid_ = true; } @@ -173,4 +202,8 @@ static MTLStorageMode ToMTLStorageMode(StorageMode mode, return std::make_shared(desc, texture); } +ISize AllocatorMTL::GetMaxTextureSizeSupported() const { + return max_texture_supported_; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/allocator_vk.cc b/impeller/renderer/backend/vulkan/allocator_vk.cc index 0d6304c3eebdb..9df48d6a0211b 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.cc +++ b/impeller/renderer/backend/vulkan/allocator_vk.cc @@ -153,4 +153,11 @@ std::shared_ptr AllocatorVK::CreateBuffer(StorageMode mode, std::move(device_allocation)); } +// |Allocator| +ISize AllocatorVK::GetMaxTextureSizeSupported() const { + // TODO(magicianA): Get correct max texture size for Vulkan. + // 4096 is the required limit, see below: + // 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 58141f2093870..aa254d0d94315 100644 --- a/impeller/renderer/backend/vulkan/allocator_vk.h +++ b/impeller/renderer/backend/vulkan/allocator_vk.h @@ -45,6 +45,9 @@ class AllocatorVK final : public Allocator { StorageMode mode, const TextureDescriptor& desc) override; + // |Allocator| + ISize GetMaxTextureSizeSupported() const override; + FML_DISALLOW_COPY_AND_ASSIGN(AllocatorVK); }; diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc index 4e1108b01f668..29b43314cfd79 100644 --- a/lib/ui/painting/image_decoder_impeller.cc +++ b/lib/ui/painting/image_decoder_impeller.cc @@ -58,7 +58,8 @@ static std::optional ToPixelFormat(SkColorType type) { std::shared_ptr ImageDecoderImpeller::DecompressTexture( ImageDescriptor* descriptor, - SkISize target_size) { + SkISize target_size, + impeller::ISize max_texture_size) { TRACE_EVENT0("impeller", __FUNCTION__); if (!descriptor) { FML_DLOG(ERROR) << "Invalid descriptor."; @@ -70,6 +71,10 @@ std::shared_ptr ImageDecoderImpeller::DecompressTexture( << "Uncompressed images are not implemented in Impeller yet."; return nullptr; } + target_size.set(std::min(static_cast(max_texture_size.width), + target_size.width()), + std::min(static_cast(max_texture_size.height), + target_size.height())); const SkISize source_size = descriptor->image_info().dimensions(); auto decode_size = descriptor->get_scaled_dimensions(std::max( @@ -200,8 +205,12 @@ void ImageDecoderImpeller::Decode(fml::RefPtr descriptor, io_runner = runners_.GetIOTaskRunner(), // result // ]() { + auto max_size_supported = + context->GetResourceAllocator()->GetMaxTextureSizeSupported(); + // Always decompress on the concurrent runner. - auto bitmap = DecompressTexture(raw_descriptor, target_size); + auto bitmap = + DecompressTexture(raw_descriptor, target_size, max_size_supported); if (!bitmap) { result(nullptr); return; diff --git a/lib/ui/painting/image_decoder_impeller.h b/lib/ui/painting/image_decoder_impeller.h index c5d38c135491d..921419f11ef5b 100644 --- a/lib/ui/painting/image_decoder_impeller.h +++ b/lib/ui/painting/image_decoder_impeller.h @@ -9,6 +9,7 @@ #include "flutter/fml/macros.h" #include "flutter/lib/ui/painting/image_decoder.h" +#include "impeller/geometry/size.h" namespace impeller { class Context; @@ -33,7 +34,8 @@ class ImageDecoderImpeller final : public ImageDecoder { static std::shared_ptr DecompressTexture( ImageDescriptor* descriptor, - SkISize target_size); + SkISize target_size, + impeller::ISize max_texture_size); private: using FutureContext = std::shared_future>; diff --git a/lib/ui/painting/image_decoder_unittests.cc b/lib/ui/painting/image_decoder_unittests.cc index 6f143ace9ed50..658ec8d97864e 100644 --- a/lib/ui/painting/image_decoder_unittests.cc +++ b/lib/ui/painting/image_decoder_unittests.cc @@ -503,10 +503,14 @@ TEST(ImageDecoderTest, VerifySimpleDecoding) { SkISize::Make(6, 2)); #if IMPELLER_SUPPORTS_RENDERING - ASSERT_EQ(ImageDecoderImpeller::DecompressTexture(descriptor.get(), - SkISize::Make(6, 2)) + ASSERT_EQ(ImageDecoderImpeller::DecompressTexture( + descriptor.get(), SkISize::Make(6, 2), {100, 100}) ->dimensions(), SkISize::Make(6, 2)); + ASSERT_EQ(ImageDecoderImpeller::DecompressTexture( + descriptor.get(), SkISize::Make(60, 20), {10, 10}) + ->dimensions(), + SkISize::Make(10, 10)); #endif // IMPELLER_SUPPORTS_RENDERING } From 43cb3133e51da312e7f82a0010f1a383479a7281 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Tue, 16 Aug 2022 13:12:04 -0700 Subject: [PATCH 346/558] Adds artifacts to mac_ios release. (#35366) --- ci/builders/mac_ios_engine_release.json | 75 ++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/ci/builders/mac_ios_engine_release.json b/ci/builders/mac_ios_engine_release.json index adbd385d465ad..65d02956f2516 100644 --- a/ci/builders/mac_ios_engine_release.json +++ b/ci/builders/mac_ios_engine_release.json @@ -38,7 +38,10 @@ "name": "ios_release", "ninja": { "config": "ios_release", - "targets": [], + "targets": [ + "flutter/shell/platform/darwin/ios:flutter_framework", + "flutter/lib/snapshot:generate_snapshot_bin" + ], "tool": "autoninja" }, "tests": [] @@ -69,5 +72,73 @@ "tests": [] } ], - "tests": [] + "tests": [], + "generators": { + "tasks": [ + { + "name": "release-FlutterMacOS.framework", + "parameters": [ + "--dst", + "out/release", + "--arm64-out-dir", + "out/ios_release", + "--simulator-x64-out-dir", + "out/ios_debug_sim", + "--simulator-arm64-out-dir", + "out/ios_debug_sim_arm64", + "--dsym", + "--strip" + ], + "script": "flutter/sky/tools/create_full_ios_framework.py", + "language": "python" + }, + { + "name": "release-nobitcode-FlutterMacOS.framework", + "parameters": [ + "--dst", + "out/release-nobitcode", + "--arm64-out-dir", + "out/ios_release", + "--simulator-x64-out-dir", + "out/ios_debug_sim", + "--simulator-arm64-out-dir", + "out/ios_debug_sim_arm64", + "--strip-bitcode", + "--dsym", + "--strip" + ], + "script": "flutter/sky/tools/create_full_ios_framework.py", + "language": "python" + }, + { + "name": "Release-macos-gen-snapshots", + "parameters": [ + "--dst", + "out/release", + "--arm64-out-dir", + "out/ios_release" + ], + "script": "flutter/sky/tools/create_macos_gen_snapshots.py", + "language": "python" + } + ] + }, + "archives": [ + { + "source": "out/release/artifacts.zip", + "destination": "ios-release/artifacts.zip" + }, + { + "source": "out/release/Flutter.dSYM.zip", + "destination": "ios-release/Flutter.dSYM.zip" + }, + { + "source": "out/release-nobitcode/artifacts.zip", + "destination": "ios-release-nobitcode/artifacts.zip" + }, + { + "source": "out/release-nobitcode/Flutter.dSYM.zip", + "destination": "ios-release-nobitcode/Flutter.dSYM.zip" + } + ] } From 69ee0c7094f3a7beac435dca0159f57dafc53030 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 16:16:22 -0400 Subject: [PATCH 347/558] Roll Dart SDK from b2c192c83ed8 to b67ebd581c8f (1 revision) (#35436) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 61 ++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index eeac84d2e1585..3fcdc27b55e4b 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'b2c192c83ed808fa318d220d54706d0f1cf3a8e4', + 'dart_revision': 'b67ebd581c8f7a774224dafde93f927c9be575f7', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 1631445c3cc33..cf99f9ea91ee2 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 9aa9860639c416c10e6b8b6ac788916c +Signature: 3bf84e51a3275839112721420d2cb2f1 UNUSED LICENSES: @@ -10298,6 +10298,7 @@ FILE: ../../../third_party/dart/runtime/tools/wiki/templates/includes/auto-refre FILE: ../../../third_party/dart/runtime/tools/wiki/templates/includes/favicon.html FILE: ../../../third_party/dart/runtime/tools/wiki/templates/page.html FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/arm64_macos.expect @@ -10309,11 +10310,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/ia3 FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/doublex20/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/arm64_macos.expect @@ -10325,11 +10328,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/ia32 FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/floatx20/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_macos.expect @@ -10341,11 +10346,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/arm64_macos.expect @@ -10357,11 +10364,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/ia32 FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/mixedx20/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/arm64_macos.expect @@ -10373,11 +10382,31 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress46127/x64_win.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/arm64_fuchsia.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/arm64_ios.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/arm64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/arm64_macos.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/arm_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/arm_ios.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/arm_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/ia32_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/ia32_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/ia32_win.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/riscv32_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/x64_fuchsia.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/x64_ios.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/x64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/x64_macos.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/regress_fuchsia105336/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/arm64_macos.expect @@ -10389,11 +10418,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128byte FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct128bytesx1/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/arm64_macos.expect @@ -10405,11 +10436,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytes FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct12bytesFloatx6/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/arm64_macos.expect @@ -10421,23 +10454,28 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytes FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesHomogenousx10/x64_win.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10/x64_win.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_2/x64_win.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct16bytesMixedx10_3/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/arm64_macos.expect @@ -10449,11 +10487,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct3bytesx10/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/arm64_macos.expect @@ -10465,11 +10505,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesP FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesPackedx10/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/arm64_macos.expect @@ -10481,11 +10523,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct8bytesx1/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/arm64_macos.expect @@ -10497,11 +10541,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/structPacked/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/arm64_macos.expect @@ -10513,11 +10559,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLa FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_VeryLargeStruct/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/arm64_macos.expect @@ -10529,11 +10577,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floata FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatarray/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/arm64_macos.expect @@ -10545,11 +10595,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_floatx4/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/arm64_macos.expect @@ -10561,11 +10613,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8ar FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8array/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/arm64_macos.expect @@ -10577,11 +10631,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x1 FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/struct_int8x10/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/arm64_macos.expect @@ -10593,11 +10649,13 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesH FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_macos.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union16bytesHomogenousx10/x64_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_android.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/arm64_macos.expect @@ -10609,6 +10667,7 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPa FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/ia32_win.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/riscv32_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/riscv64_linux.expect +FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_fuchsia.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_ios.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_linux.expect FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_macos.expect From da9028d7999539a1dbc1ea88494b78afb2ebbe9d Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 16 Aug 2022 14:03:36 -0700 Subject: [PATCH 348/558] [Impeller] Avoid unnecessary pre-pass when filtering images (#35422) --- impeller/aiks/canvas.cc | 3 +-- impeller/aiks/paint_pass_delegate.cc | 4 +-- .../contents/filters/filter_contents.cc | 5 ++-- .../filters/gaussian_blur_filter_contents.cc | 24 ++++++++++------- impeller/entity/contents/texture_contents.cc | 26 +++++++++++++++++++ impeller/entity/contents/texture_contents.h | 12 ++++++++- impeller/entity/entity_pass.cc | 3 +-- impeller/renderer/snapshot.h | 5 +++- 8 files changed, 61 insertions(+), 21 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 6fd63ee662e06..2e167659e6b78 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -274,8 +274,7 @@ void Canvas::DrawImageRect(std::shared_ptr image, return; } - auto contents = std::make_shared(); - contents->SetPath(PathBuilder{}.AddRect(dest).TakePath()); + auto contents = TextureContents::MakeRect(dest); contents->SetTexture(image->GetTexture()); contents->SetSourceRect(source); contents->SetSamplerDescriptor(std::move(sampler)); diff --git a/impeller/aiks/paint_pass_delegate.cc b/impeller/aiks/paint_pass_delegate.cc index f5d6598309f61..146549f604daf 100644 --- a/impeller/aiks/paint_pass_delegate.cc +++ b/impeller/aiks/paint_pass_delegate.cc @@ -34,9 +34,7 @@ bool PaintPassDelegate::CanCollapseIntoParentPass() { // |EntityPassDelgate| std::shared_ptr PaintPassDelegate::CreateContentsForSubpassTarget( std::shared_ptr target) { - auto contents = std::make_shared(); - contents->SetPath( - PathBuilder{}.AddRect(Rect::MakeSize(target->GetSize())).TakePath()); + auto contents = TextureContents::MakeRect(Rect::MakeSize(target->GetSize())); contents->SetTexture(target); contents->SetSourceRect(Rect::MakeSize(target->GetSize())); contents->SetOpacity(paint_.color.alpha); diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index 60b1900e98148..cc5c76c930b35 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -152,10 +152,9 @@ bool FilterContents::Render(const ContentContext& renderer, // Draw the result texture, respecting the transform and clip stack. - auto contents = std::make_shared(); - contents->SetPath( - PathBuilder{}.AddRect(filter_coverage.value()).GetCurrentPath()); + auto contents = TextureContents::MakeRect(filter_coverage.value()); contents->SetTexture(snapshot.texture); + contents->SetSamplerDescriptor(snapshot.sampler_descriptor); contents->SetSourceRect(Rect::MakeSize(snapshot.texture->GetSize())); Entity e; diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 3de4ad2e71d6e..43b53d702a213 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -104,6 +104,7 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( if (!input_snapshot.has_value()) { return std::nullopt; } + auto maybe_input_uvs = input_snapshot->GetCoverageUVs(coverage); if (!maybe_input_uvs.has_value()) { return std::nullopt; @@ -164,12 +165,6 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( frag_info.outer_blur_factor = outer_blur_factor_; frag_info.texture_size = Point(input_snapshot->GetCoverage().value().size); - SamplerDescriptor sampler_desc; - sampler_desc.min_filter = MinMagFilter::kLinear; - sampler_desc.mag_filter = MinMagFilter::kLinear; - auto sampler = - renderer.GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc); - Command cmd; cmd.label = "Gaussian Blur Filter"; auto options = OptionsFromPass(pass); @@ -177,8 +172,14 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( cmd.pipeline = renderer.GetGaussianBlurPipeline(options); cmd.BindVertices(vtx_buffer); - FS::BindTextureSampler(cmd, input_snapshot->texture, sampler); - FS::BindAlphaMaskSampler(cmd, source_snapshot->texture, sampler); + FS::BindTextureSampler( + cmd, input_snapshot->texture, + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + input_snapshot->sampler_descriptor)); + FS::BindAlphaMaskSampler( + cmd, source_snapshot->texture, + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + source_snapshot->sampler_descriptor)); VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info)); @@ -191,8 +192,13 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( } out_texture->SetLabel("DirectionalGaussianBlurFilter Texture"); + SamplerDescriptor sampler_desc; + sampler_desc.min_filter = MinMagFilter::kLinear; + sampler_desc.mag_filter = MinMagFilter::kLinear; + return Snapshot{.texture = out_texture, - .transform = Matrix::MakeTranslation(coverage.origin)}; + .transform = Matrix::MakeTranslation(coverage.origin), + .sampler_descriptor = sampler_desc}; } std::optional DirectionalGaussianBlurFilterContents::GetFilterCoverage( diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc index 10a72daab7073..4e77668d1dda2 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc @@ -4,12 +4,14 @@ #include "texture_contents.h" +#include #include #include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" +#include "impeller/geometry/path_builder.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/sampler_library.h" #include "impeller/tessellator/tessellator.h" @@ -20,8 +22,16 @@ TextureContents::TextureContents() = default; TextureContents::~TextureContents() = default; +std::shared_ptr TextureContents::MakeRect(Rect destination) { + auto contents = std::make_shared(); + contents->path_ = PathBuilder{}.AddRect(destination).TakePath(); + contents->is_rect_ = true; + return contents; +} + void TextureContents::SetPath(Path path) { path_ = std::move(path); + is_rect_ = false; } void TextureContents::SetTexture(std::shared_ptr texture) { @@ -43,6 +53,22 @@ std::optional TextureContents::GetCoverage(const Entity& entity) const { return path_.GetTransformedBoundingBox(entity.GetTransformation()); }; +std::optional TextureContents::RenderToSnapshot( + const ContentContext& renderer, + const Entity& entity) const { + // Passthrough textures that have simple rectangle paths and complete source + // rects. + if (is_rect_ && source_rect_ == Rect::MakeSize(texture_->GetSize())) { + auto scale = + Vector2(path_.GetBoundingBox()->size / Size(texture_->GetSize())); + return Snapshot{ + .texture = texture_, + .transform = entity.GetTransformation() * Matrix::MakeScale(scale), + .sampler_descriptor = sampler_descriptor_}; + } + return Contents::RenderToSnapshot(renderer, entity); +} + bool TextureContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { diff --git a/impeller/entity/contents/texture_contents.h b/impeller/entity/contents/texture_contents.h index 4b02d88c0b69e..b218a08503ab9 100644 --- a/impeller/entity/contents/texture_contents.h +++ b/impeller/entity/contents/texture_contents.h @@ -23,6 +23,11 @@ class TextureContents final : public Contents { ~TextureContents() override; + /// @brief A common case factory that marks the texture contents as having a + /// destination rectangle. In this situation, a subpass can be avoided + /// when image filters are applied. + static std::shared_ptr MakeRect(Rect destination); + void SetPath(Path path); void SetTexture(std::shared_ptr texture); @@ -42,13 +47,18 @@ class TextureContents final : public Contents { // |Contents| std::optional GetCoverage(const Entity& entity) const override; + // |Contents| + std::optional RenderToSnapshot(const ContentContext& renderer, + const Entity& entity) const override; + // |Contents| bool Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const override; - public: + private: Path path_; + bool is_rect_ = false; std::shared_ptr texture_; SamplerDescriptor sampler_descriptor_ = {}; diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 2a317b042fd58..832dfe8273404 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -161,8 +161,7 @@ bool EntityPass::Render(ContentContext& renderer, { auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize()); - auto contents = std::make_shared(); - contents->SetPath(PathBuilder{}.AddRect(size_rect).TakePath()); + auto contents = TextureContents::MakeRect(size_rect); contents->SetTexture(offscreen_target.GetRenderTargetTexture()); contents->SetSourceRect(size_rect); diff --git a/impeller/renderer/snapshot.h b/impeller/renderer/snapshot.h index a0fe419b069bf..65a4c9a73cfb7 100644 --- a/impeller/renderer/snapshot.h +++ b/impeller/renderer/snapshot.h @@ -11,6 +11,7 @@ #include "flutter/fml/macros.h" #include "impeller/geometry/matrix.h" #include "impeller/geometry/rect.h" +#include "impeller/renderer/sampler_descriptor.h" #include "impeller/renderer/texture.h" namespace impeller { @@ -18,12 +19,14 @@ namespace impeller { class ContentContext; class Entity; -/// Represents a texture and its intended draw position. +/// Represents a texture and its intended draw transform/sampler configuration. struct Snapshot { std::shared_ptr texture; /// The transform that should be applied to this texture for rendering. Matrix transform; + SamplerDescriptor sampler_descriptor; + std::optional GetCoverage() const; /// @brief Get the transform that converts screen space coordinates to the UV From afa316d355e237abaed2a51ed5a3d3020b47fe8c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 17:21:23 -0400 Subject: [PATCH 349/558] Roll Skia from 97da42fc6ecc to 846684e10fea (2 revisions) (#35439) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 3fcdc27b55e4b..1d5c822e0fbe5 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': '97da42fc6ecc3c399eb79f3f3128742a92e5b67e', + 'skia_revision': '846684e10fea426704cd062a5f780446ae7fde8a', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index b90b497aa400c..6465fab2f7008 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: cc649450e3a8b677cc4c22a08f427b97 +Signature: 264670de252323e79ee620595d794444 UNUSED LICENSES: From eb7428a51ddd5b4eabcc1513e18b6ca0c37ff73b Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Tue, 16 Aug 2022 14:32:48 -0700 Subject: [PATCH 350/558] [Mac] Add test for AXPlatformNodeCocoa (#35437) Adds an initial test of looking up the macOS-specific AXPlatformNodeMac C++ node wrapper and the AXPlatformNodeCocoa Objective-C wrapper, in addition to the existing platform-agnostic accessibility tests that run on macOS today. This is initial test infrastructure to support authoring tests for an upcoming fix to the issue below. Issue: https://github.com/flutter/flutter/issues/102416 --- ci/licenses_golden/licenses_flutter | 2 + third_party/accessibility/BUILD.gn | 13 +++++ .../platform/ax_platform_node_mac_unittest.h | 29 +++++++++++ .../platform/ax_platform_node_mac_unittest.mm | 49 +++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.h create mode 100644 third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.mm diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 02b295d603272..35ee303be224e 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -3258,6 +3258,8 @@ ORIGIN: ../../../third_party/icu/scripts/LICENSE TYPE: LicenseType.bsd FILE: ../../../flutter/third_party/accessibility/ax/ax_tree_data.cc FILE: ../../../flutter/third_party/accessibility/ax/ax_tree_data.h +FILE: ../../../flutter/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.h +FILE: ../../../flutter/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.mm FILE: ../../../flutter/third_party/accessibility/ax/platform/ax_platform_node_win.cc FILE: ../../../flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h FILE: ../../../flutter/third_party/accessibility/ax/platform/ax_platform_node_win_unittest.cc diff --git a/third_party/accessibility/BUILD.gn b/third_party/accessibility/BUILD.gn index 469849c8196da..eb217af52fe73 100644 --- a/third_party/accessibility/BUILD.gn +++ b/third_party/accessibility/BUILD.gn @@ -75,6 +75,19 @@ if (enable_unittests) { "ax/platform/test_ax_node_wrapper.h", ] + if (is_mac) { + sources += [ "ax/platform/ax_platform_node_mac_unittest.mm" ] + frameworks = [ + "AppKit.framework", + "CoreFoundation.framework", + "CoreGraphics.framework", + "CoreText.framework", + "IOSurface.framework", + ] + + cflags_objcc = flutter_cflags_objcc + ldflags = [ "-ObjC" ] + } if (is_win) { sources += [ "ax/platform/ax_fragment_root_win_unittest.cc", diff --git a/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.h b/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.h new file mode 100644 index 0000000000000..96c34ebb0d15f --- /dev/null +++ b/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.h @@ -0,0 +1,29 @@ +// Copyright 2015 The Chromium 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 UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_MAC_UNITTEST_H_ +#define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_MAC_UNITTEST_H_ + +#include "ax_platform_node_mac.h" +#include "ax_platform_node_unittest.h" + +namespace ui { + +// A test fixture that supports accessing the macOS-specific node +// implementations for the AXTree under test. +class AXPlatformNodeMacTest : public AXPlatformNodeTest { + public: + AXPlatformNodeMacTest(); + ~AXPlatformNodeMacTest() override; + + void SetUp() override; + void TearDown() override; + + protected: + AXPlatformNode* AXPlatformNodeFromNode(AXNode* node); +}; + +} // namespace ui + +#endif // UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_MAC_UNITTEST_H_ diff --git a/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.mm b/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.mm new file mode 100644 index 0000000000000..7597942518466 --- /dev/null +++ b/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.mm @@ -0,0 +1,49 @@ +// Copyright 2015 The Chromium 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 "ax_platform_node_mac_unittest.h" + +#include "ax_platform_node_mac.h" +#include "gtest/gtest.h" +#include "test_ax_node_wrapper.h" +#include "third_party/accessibility/ax/ax_node_data.h" + +namespace ui { + +AXPlatformNodeMacTest::AXPlatformNodeMacTest() = default; + +AXPlatformNodeMacTest::~AXPlatformNodeMacTest() = default; + +void AXPlatformNodeMacTest::SetUp() {} + +void AXPlatformNodeMacTest::TearDown() { + // Destroy the tree and make sure we're not leaking any objects. + DestroyTree(); + TestAXNodeWrapper::SetGlobalIsWebContent(false); + ASSERT_EQ(0U, AXPlatformNodeBase::GetInstanceCountForTesting()); +} + +AXPlatformNode* AXPlatformNodeMacTest::AXPlatformNodeFromNode(AXNode* node) { + const TestAXNodeWrapper* wrapper = TestAXNodeWrapper::GetOrCreate(GetTree(), node); + return wrapper ? wrapper->ax_platform_node() : nullptr; +} + +// Verify that we can get an AXPlatformNodeMac and AXPlatformNodeCocoa from the tree. +TEST_F(AXPlatformNodeMacTest, CanGetCocoaPlatformNodeFromTree) { + AXNodeData root; + root.id = 1; + root.relative_bounds.bounds = gfx::RectF(0, 0, 40, 40); + + Init(root); + AXNode* root_node = GetRootAsAXNode(); + ASSERT_TRUE(root_node != nullptr); + + AXPlatformNode* platform_node = AXPlatformNodeFromNode(root_node); + ASSERT_TRUE(platform_node != nullptr); + + AXPlatformNodeCocoa* native_root = platform_node->GetNativeViewAccessible(); + EXPECT_TRUE(native_root != nullptr); +} + +} // namespace ui From 590c01fe9920d71e38609045e3bc97495a6f00df Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 16 Aug 2022 15:29:21 -0700 Subject: [PATCH 351/558] [Impeller] When the blur sigma approaches zero, passthrough (#35423) --- .../filters/gaussian_blur_filter_contents.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 43b53d702a213..9c3034ff36449 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -27,14 +27,6 @@ DirectionalGaussianBlurFilterContents:: ~DirectionalGaussianBlurFilterContents() = default; void DirectionalGaussianBlurFilterContents::SetSigma(Sigma sigma) { - if (sigma.sigma < kEhCloseEnough) { - // This cutoff is an implementation detail of the blur that's tied to the - // fragment shader. When the blur is set to 0, having a value slightly above - // zero makes the shader do 1 finite sample to pass the image through with - // no blur (while retaining correct alpha mask behavior). - blur_sigma_ = Sigma{kEhCloseEnough}; - return; - } blur_sigma_ = sigma; } @@ -105,6 +97,10 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( return std::nullopt; } + if (blur_sigma_.sigma < kEhCloseEnough) { + return input_snapshot.value(); // No blur to render. + } + auto maybe_input_uvs = input_snapshot->GetCoverageUVs(coverage); if (!maybe_input_uvs.has_value()) { return std::nullopt; From 0dd222b39fd76e4e6ceb8537fc48fe1145d0d9fd Mon Sep 17 00:00:00 2001 From: Xilai Zhang Date: Tue, 16 Aug 2022 15:33:08 -0700 Subject: [PATCH 352/558] [gn + generator ] add codesign configs for generator tasks in ios/artifacts.zip (#35417) --- sky/tools/create_full_ios_framework.py | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sky/tools/create_full_ios_framework.py b/sky/tools/create_full_ios_framework.py index 82aa7f5a29ec4..c90087ef1526f 100644 --- a/sky/tools/create_full_ios_framework.py +++ b/sky/tools/create_full_ios_framework.py @@ -165,9 +165,34 @@ def create_framework( ]) +def embed_codesign_configuration(config_path, contents): + with open(config_path, 'w') as f: + f.writelines(contents) + + def zip_archive(dst): + ios_file_with_entitlements = ['gen_snapshot_arm64\n'] + ios_file_without_entitlements = [ + 'Flutter.xcframework/ios-arm64/Flutter.framework/Flutter\n', + 'Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter\n' + ] + embed_codesign_configuration( + os.path.join(dst, 'entitlements.txt'), ios_file_with_entitlements + ) + + embed_codesign_configuration( + os.path.join(dst, 'without_entitlements.txt'), + ios_file_without_entitlements + ) + subprocess.check_call([ - 'zip', '-r', 'artifacts.zip', 'gen_snapshot_arm64', 'Flutter.xcframework' + 'zip', + '-r', + 'artifacts.zip', + 'gen_snapshot_arm64', + 'Flutter.xcframework', + 'entitlements.txt', + 'without_entitlements.txt', ], cwd=dst) if (os.path.exists(os.path.join(dst, 'Flutter.dSYM'))): From 028a5bcebfabac73a1fd190301980c249b700103 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 19:13:48 -0400 Subject: [PATCH 353/558] Roll Skia from 846684e10fea to 6d785ddbfe5e (3 revisions) (#35440) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 1d5c822e0fbe5..f19c2cfee86de 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': '846684e10fea426704cd062a5f780446ae7fde8a', + 'skia_revision': '6d785ddbfe5ed7987f4cb71844425cf33dce818f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 6465fab2f7008..20d629ea88997 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 264670de252323e79ee620595d794444 +Signature: 35c38178ae8c14f7962e3bfefc86e06d UNUSED LICENSES: From 246f24589107bd80442420ad56bcbc7cf934b3cc Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 16 Aug 2022 17:06:58 -0700 Subject: [PATCH 354/558] [Impeller] Implement drawShadow (#35426) --- impeller/aiks/canvas.cc | 6 +- impeller/aiks/canvas.h | 4 +- .../display_list/display_list_dispatcher.cc | 62 ++++++++++++++++++- .../display_list/display_list_unittests.cc | 28 +++++++++ 4 files changed, 95 insertions(+), 5 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 2e167659e6b78..b19e042c7d929 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -83,6 +83,10 @@ void Canvas::Concat(const Matrix& xformation) { xformation_stack_.back().xformation = GetCurrentTransformation() * xformation; } +void Canvas::PreConcat(const Matrix& xformation) { + xformation_stack_.back().xformation = xformation * GetCurrentTransformation(); +} + void Canvas::ResetTransform() { xformation_stack_.back().xformation = {}; } @@ -227,8 +231,6 @@ void Canvas::RestoreClip() { GetCurrentPass().AddEntity(std::move(entity)); } -void Canvas::DrawShadow(Path path, Color color, Scalar elevation) {} - void Canvas::DrawPicture(Picture picture) { if (!picture.pass) { return; diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index 78f6fa9a0f627..780fccefbcbcc 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -54,6 +54,8 @@ class Canvas { void Concat(const Matrix& xformation); + void PreConcat(const Matrix& xformation); + void Translate(const Vector3& offset); void Scale(const Vector2& scale); @@ -89,8 +91,6 @@ class Canvas { Path path, Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect); - void DrawShadow(Path path, Color color, Scalar elevation); - void DrawPicture(Picture picture); void DrawTextFrame(TextFrame text_frame, Point position, Paint paint); diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 68739c5b98af2..cce7ee1f4a988 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -4,6 +4,7 @@ #include "impeller/display_list/display_list_dispatcher.h" +#include #include #include @@ -1061,7 +1062,66 @@ void DisplayListDispatcher::drawShadow(const SkPath& path, const SkScalar elevation, bool transparent_occluder, SkScalar dpr) { - UNIMPLEMENTED; + Color spot_color = ToColor(color); + spot_color.alpha *= 0.25; + + // Compute the spot color -- ported from SkShadowUtils::ComputeTonalColors. + { + Scalar max = + std::max(std::max(spot_color.red, spot_color.green), spot_color.blue); + Scalar min = + std::min(std::min(spot_color.red, spot_color.green), spot_color.blue); + Scalar luminance = (min + max) * 0.5; + + Scalar alpha_adjust = + (2.6f + (-2.66667f + 1.06667f * spot_color.alpha) * spot_color.alpha) * + spot_color.alpha; + Scalar color_alpha = + (3.544762f + (-4.891428f + 2.3466f * luminance) * luminance) * + luminance; + color_alpha = std::clamp(alpha_adjust * color_alpha, 0.0f, 1.0f); + + Scalar greyscale_alpha = + std::clamp(spot_color.alpha * (1 - 0.4f * luminance), 0.0f, 1.0f); + + Scalar color_scale = color_alpha * (1 - greyscale_alpha); + Scalar tonal_alpha = color_scale + greyscale_alpha; + Scalar unpremul_scale = color_scale / tonal_alpha; + spot_color = Color(unpremul_scale * spot_color.red, + unpremul_scale * spot_color.green, + unpremul_scale * spot_color.blue, tonal_alpha); + } + + Vector3 light_position(0, -1, 1); + Scalar occluder_z = dpr * elevation; + + constexpr Scalar kLightRadius = 800 / 600; // Light radius / light height + + Paint paint; + paint.style = Paint::Style::kFill; + paint.color = spot_color; + paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kNormal, + .sigma = Radius{kLightRadius * occluder_z / + canvas_.GetCurrentTransformation().GetScale().y}, + }; + + canvas_.Save(); + canvas_.PreConcat( + Matrix::MakeTranslation(Vector2(0, -occluder_z * light_position.y))); + + SkRect rect; + SkRRect rrect; + if (path.isRect(&rect)) { + canvas_.DrawRect(ToRect(rect), std::move(paint)); + } else if (path.isRRect(&rrect) && rrect.isSimple()) { + canvas_.DrawRRect(ToRect(rrect.rect()), rrect.getSimpleRadii().fX, + std::move(paint)); + } else { + canvas_.DrawPath(ToPath(path), std::move(paint)); + } + + canvas_.Restore(); } Picture DisplayListDispatcher::EndRecordingAsPicture() { diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index 08e4bb352d2af..b887c22e49bae 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -16,6 +16,7 @@ #include "impeller/display_list/display_list_playground.h" #include "impeller/geometry/point.h" #include "impeller/playground/widgets.h" +#include "include/core/SkRRect.h" #include "third_party/imgui/imgui.h" #include "third_party/skia/include/core/SkClipOp.h" #include "third_party/skia/include/core/SkColor.h" @@ -493,5 +494,32 @@ TEST_P(DisplayListTest, CanDrawZeroLengthLine) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(DisplayListTest, CanDrawShadow) { + flutter::DisplayListBuilder builder; + std::array paths = { + SkPath{}.addRect(SkRect::MakeXYWH(0, 0, 200, 100)), + SkPath{}.addRRect( + SkRRect::MakeRectXY(SkRect::MakeXYWH(0, 0, 200, 100), 30, 30)), + SkPath{}.addCircle(100, 50, 50), + }; + builder.setColor(flutter::DlColor::kWhite()); + builder.drawPaint(); + builder.setColor(flutter::DlColor::kCyan()); + builder.translate(100, 100); + for (size_t x = 0; x < paths.size(); x++) { + builder.save(); + for (size_t y = 0; y < 5; y++) { + builder.drawShadow(paths[x], flutter::DlColor::kBlack(), 3 + y * 5, false, + 1); + builder.drawPath(paths[x]); + builder.translate(0, 200); + } + builder.restore(); + builder.translate(300, 0); + } + + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller From 18b5b1eddd88d341054e5ea449f8bac235e6084b Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 16 Aug 2022 17:20:50 -0700 Subject: [PATCH 355/558] [Impeller] Use flatbuffers in blobcat. (#35443) --- ci/licenses_golden/licenses_flutter | 4 +- impeller/blobcat/BUILD.gn | 17 +++- impeller/blobcat/blob.fbs | 23 +++++ impeller/blobcat/blob.h | 43 --------- impeller/blobcat/blob_library.cc | 87 +++++++---------- impeller/blobcat/blob_library.h | 12 +-- impeller/blobcat/{blob.cc => blob_types.h} | 7 +- impeller/blobcat/blob_writer.cc | 93 +++++++------------ impeller/blobcat/blob_writer.h | 10 +- impeller/blobcat/blobcat_unittests.cc | 14 +-- .../backend/gles/shader_library_gles.cc | 6 +- .../backend/vulkan/shader_library_vk.cc | 6 +- 12 files changed, 138 insertions(+), 184 deletions(-) create mode 100644 impeller/blobcat/blob.fbs delete mode 100644 impeller/blobcat/blob.h rename impeller/blobcat/{blob.cc => blob_types.h} (75%) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 35ee303be224e..43992af7790e7 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -470,10 +470,10 @@ FILE: ../../../flutter/impeller/base/work_queue.cc FILE: ../../../flutter/impeller/base/work_queue.h FILE: ../../../flutter/impeller/base/work_queue_common.cc FILE: ../../../flutter/impeller/base/work_queue_common.h -FILE: ../../../flutter/impeller/blobcat/blob.cc -FILE: ../../../flutter/impeller/blobcat/blob.h +FILE: ../../../flutter/impeller/blobcat/blob.fbs FILE: ../../../flutter/impeller/blobcat/blob_library.cc FILE: ../../../flutter/impeller/blobcat/blob_library.h +FILE: ../../../flutter/impeller/blobcat/blob_types.h FILE: ../../../flutter/impeller/blobcat/blob_writer.cc FILE: ../../../flutter/impeller/blobcat/blob_writer.h FILE: ../../../flutter/impeller/blobcat/blobcat_main.cc diff --git a/impeller/blobcat/BUILD.gn b/impeller/blobcat/BUILD.gn index b38d29bdcfe9d..a70f4a4ec10ff 100644 --- a/impeller/blobcat/BUILD.gn +++ b/impeller/blobcat/BUILD.gn @@ -2,19 +2,30 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//third_party/flatbuffers/flatbuffers.gni") import("../tools/impeller.gni") +config("blobcat_config") { + configs = [ "//flutter/impeller:impeller_public_config" ] + include_dirs = [ "$root_gen_dir/flutter" ] +} + +flatbuffers("blobcat_flatbuffers") { + flatbuffers = [ "blob.fbs" ] + public_configs = [ ":blobcat_config" ] + public_deps = [ "//third_party/flatbuffers" ] +} + impeller_component("blobcat_lib") { sources = [ - "blob.cc", - "blob.h", "blob_library.cc", "blob_library.h", "blob_writer.cc", "blob_writer.h", ] - deps = [ + public_deps = [ + ":blobcat_flatbuffers", "../base", "//flutter/fml", ] diff --git a/impeller/blobcat/blob.fbs b/impeller/blobcat/blob.fbs new file mode 100644 index 0000000000000..741c6bfca567d --- /dev/null +++ b/impeller/blobcat/blob.fbs @@ -0,0 +1,23 @@ +// 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. + +namespace impeller.fb; + +enum Stage:byte { + kVertex, + kFragment, +} + +table Blob { + stage: Stage; + name: string; + mapping: [ubyte]; +} + +table BlobLibrary { + items: [Blob]; +} + +root_type BlobLibrary; +file_identifier "BCAT"; diff --git a/impeller/blobcat/blob.h b/impeller/blobcat/blob.h deleted file mode 100644 index dc8ec7e472c15..0000000000000 --- a/impeller/blobcat/blob.h +++ /dev/null @@ -1,43 +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 -#include - -#include "flutter/fml/macros.h" -#include "flutter/fml/mapping.h" - -namespace impeller { - -constexpr const uint32_t kBlobCatMagic = 0x0B10BCA7; -struct BlobHeader { - uint32_t magic = kBlobCatMagic; - uint32_t blob_count = 0u; -}; - -struct Blob { - enum class ShaderType : uint8_t { - kVertex, - kFragment, - }; - - static constexpr size_t kMaxNameLength = 32u; - - ShaderType type = ShaderType::kVertex; - uint64_t offset = 0; - uint64_t length = 0; - uint8_t name[kMaxNameLength] = {}; -}; - -struct BlobDescription { - Blob::ShaderType type; - std::string name; - std::shared_ptr mapping; -}; - -} // namespace impeller diff --git a/impeller/blobcat/blob_library.cc b/impeller/blobcat/blob_library.cc index 94af2799f9252..12c0730721127 100644 --- a/impeller/blobcat/blob_library.cc +++ b/impeller/blobcat/blob_library.cc @@ -6,66 +6,49 @@ #include +#include "impeller/base/validation.h" +#include "impeller/blobcat/blob_flatbuffers.h" + namespace impeller { -BlobLibrary::BlobLibrary(std::shared_ptr mapping) - : mapping_(std::move(mapping)) { - if (!mapping_ || mapping_->GetMapping() == nullptr) { - FML_LOG(ERROR) << "Invalid mapping."; - return; +constexpr BlobShaderType ToShaderType(fb::Stage stage) { + switch (stage) { + case fb::Stage::kVertex: + return BlobShaderType::kVertex; + case fb::Stage::kFragment: + return BlobShaderType::kFragment; } + FML_UNREACHABLE(); +} - BlobHeader header; - std::vector blobs; - - size_t offset = 0u; - - // Read the header. - { - const size_t read_size = sizeof(BlobHeader); - if (mapping_->GetSize() < offset + read_size) { - return; - } - std::memcpy(&header, mapping_->GetMapping() + offset, read_size); - offset += read_size; - - // Validate the header. - if (header.magic != kBlobCatMagic) { - FML_LOG(ERROR) << "Invalid blob magic."; - return; - } - - blobs.resize(header.blob_count); +BlobLibrary::BlobLibrary(std::shared_ptr payload) + : payload_(std::move(payload)) { + if (!payload_ || payload_->GetMapping() == nullptr) { + VALIDATION_LOG << "Blob mapping was absent."; + return; } - // Read the blob descriptions. - { - const size_t read_size = sizeof(Blob) * header.blob_count; - ::memcpy(blobs.data(), mapping_->GetMapping() + offset, read_size); - offset += read_size; // NOLINT(clang-analyzer-deadcode.DeadStores) + if (!fb::BlobLibraryBufferHasIdentifier(payload_->GetMapping())) { + VALIDATION_LOG << "Invalid blob magic."; + return; } - // Read the blobs. - { - for (size_t i = 0; i < header.blob_count; i++) { - const auto& blob = blobs[i]; + auto blob_library = fb::GetBlobLibrary(payload_->GetMapping()); + if (!blob_library) { + return; + } + if (auto items = blob_library->items()) { + for (auto i = items->begin(), end = items->end(); i != end; i++) { BlobKey key; - key.type = blob.type; - key.name = std::string{reinterpret_cast(blob.name)}; - auto mapping = std::make_shared( - mapping_->GetMapping() + blob.offset, // offset - blob.length, // length - [mapping = mapping_](const uint8_t* data, size_t size) {} - // release proc - ); - - auto inserted = blobs_.insert({key, mapping}); - if (!inserted.second) { - FML_LOG(ERROR) << "Shader library had duplicate shader named " - << key.name; - return; - } + key.name = i->name()->str(); + key.type = ToShaderType(i->stage()); + blobs_[key] = std::make_shared( + i->mapping()->Data(), i->mapping()->size(), + [payload = payload_](auto, auto) { + // The pointers are into the base payload. Instead of copying the + // data, just hold onto the payload. + }); } } @@ -84,7 +67,7 @@ size_t BlobLibrary::GetShaderCount() const { return blobs_.size(); } -std::shared_ptr BlobLibrary::GetMapping(Blob::ShaderType type, +std::shared_ptr BlobLibrary::GetMapping(BlobShaderType type, std::string name) const { BlobKey key; key.type = type; @@ -94,7 +77,7 @@ std::shared_ptr BlobLibrary::GetMapping(Blob::ShaderType type, } size_t BlobLibrary::IterateAllBlobs( - std::function& mapping)> callback) const { diff --git a/impeller/blobcat/blob_library.h b/impeller/blobcat/blob_library.h index c548ec95315d1..7d5a8b598f282 100644 --- a/impeller/blobcat/blob_library.h +++ b/impeller/blobcat/blob_library.h @@ -11,13 +11,13 @@ #include "flutter/fml/hash_combine.h" #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" -#include "impeller/blobcat/blob.h" +#include "impeller/blobcat/blob_types.h" namespace impeller { class BlobLibrary { public: - BlobLibrary(std::shared_ptr mapping); + explicit BlobLibrary(std::shared_ptr payload); BlobLibrary(BlobLibrary&&); @@ -27,17 +27,17 @@ class BlobLibrary { size_t GetShaderCount() const; - std::shared_ptr GetMapping(Blob::ShaderType type, + std::shared_ptr GetMapping(BlobShaderType type, std::string name) const; size_t IterateAllBlobs( - std::function& mapping)>) const; private: struct BlobKey { - Blob::ShaderType type = Blob::ShaderType::kFragment; + BlobShaderType type = BlobShaderType::kFragment; std::string name; struct Hash { @@ -60,7 +60,7 @@ class BlobLibrary { BlobKey::Hash, BlobKey::Equal>; - std::shared_ptr mapping_; + std::shared_ptr payload_; Blobs blobs_; bool is_valid_ = false; diff --git a/impeller/blobcat/blob.cc b/impeller/blobcat/blob_types.h similarity index 75% rename from impeller/blobcat/blob.cc rename to impeller/blobcat/blob_types.h index e7f97177af870..7c22d907d06ab 100644 --- a/impeller/blobcat/blob.cc +++ b/impeller/blobcat/blob_types.h @@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "impeller/blobcat/blob.h" +#pragma once namespace impeller { -// +enum class BlobShaderType { + kVertex, + kFragment, +}; } // namespace impeller diff --git a/impeller/blobcat/blob_writer.cc b/impeller/blobcat/blob_writer.cc index be500f5e9f64b..abba520b261c1 100644 --- a/impeller/blobcat/blob_writer.cc +++ b/impeller/blobcat/blob_writer.cc @@ -7,18 +7,20 @@ #include #include +#include "impeller/blobcat/blob_flatbuffers.h" + namespace impeller { BlobWriter::BlobWriter() = default; BlobWriter::~BlobWriter() = default; -std::optional InferShaderTypefromFileExtension( +std::optional InferShaderTypefromFileExtension( const std::filesystem::path& path) { if (path == ".vert") { - return Blob::ShaderType::kVertex; + return BlobShaderType::kVertex; } else if (path == ".frag") { - return Blob::ShaderType::kFragment; + return BlobShaderType::kFragment; } return std::nullopt; } @@ -67,79 +69,48 @@ bool BlobWriter::AddBlobAtPath(const std::string& std_path) { std::move(file_mapping)); } -bool BlobWriter::AddBlob(Blob::ShaderType type, +bool BlobWriter::AddBlob(BlobShaderType type, std::string name, std::shared_ptr mapping) { if (name.empty() || !mapping || mapping->GetMapping() == nullptr) { return false; } - if (name.length() >= Blob::kMaxNameLength) { - FML_LOG(ERROR) << "Blob name length was too long."; - return false; - } - blob_descriptions_.emplace_back( BlobDescription{type, std::move(name), std::move(mapping)}); return true; } -std::shared_ptr BlobWriter::CreateMapping() const { - BlobHeader header; - header.blob_count = blob_descriptions_.size(); - - uint64_t offset = sizeof(BlobHeader) + (sizeof(Blob) * header.blob_count); - - std::vector blobs; - { - blobs.resize(header.blob_count); - for (size_t i = 0; i < header.blob_count; i++) { - const auto& desc = blob_descriptions_[i]; - blobs[i].type = desc.type; - blobs[i].offset = offset; - blobs[i].length = desc.mapping->GetSize(); - std::memcpy(reinterpret_cast(blobs[i].name), desc.name.data(), - desc.name.size()); - offset += blobs[i].length; - } +constexpr fb::Stage ToStage(BlobShaderType type) { + switch (type) { + case BlobShaderType::kVertex: + return fb::Stage::kVertex; + case BlobShaderType::kFragment: + return fb::Stage::kFragment; } + FML_UNREACHABLE(); +} - { - auto buffer = std::make_shared>(); - buffer->resize(offset, 0); - - size_t write_offset = 0u; - - // Write the header. - { - const size_t write_length = sizeof(header); - std::memcpy(buffer->data() + write_offset, &header, write_length); - write_offset += write_length; - } - - // Write the blob descriptions. - { - const size_t write_length = blobs.size() * sizeof(Blob); - std::memcpy(buffer->data() + write_offset, blobs.data(), write_length); - write_offset += write_length; - } - - // Write the blobs themselves. - { - for (size_t i = 0; i < header.blob_count; i++) { - const auto& desc = blob_descriptions_[i]; - const size_t write_length = desc.mapping->GetSize(); - std::memcpy(buffer->data() + write_offset, desc.mapping->GetMapping(), - write_length); - write_offset += write_length; - } +std::shared_ptr BlobWriter::CreateMapping() const { + fb::BlobLibraryT blobs; + for (const auto& blob_description : blob_descriptions_) { + auto mapping = blob_description.mapping; + if (!mapping) { + return nullptr; } - FML_CHECK(write_offset == offset); - return std::make_shared( - buffer->data(), buffer->size(), - [buffer](const uint8_t* data, size_t size) {}); + auto desc = std::make_unique(); + desc->name = blob_description.name; + desc->stage = ToStage(blob_description.type); + desc->mapping = {mapping->GetMapping(), + mapping->GetMapping() + mapping->GetSize()}; + blobs.items.emplace_back(std::move(desc)); } - return nullptr; + auto builder = std::make_shared(); + builder->Finish(fb::BlobLibrary::Pack(*builder.get(), &blobs), + fb::BlobLibraryIdentifier()); + return std::make_shared(builder->GetBufferPointer(), + builder->GetSize(), + [builder](auto, auto) {}); } } // namespace impeller diff --git a/impeller/blobcat/blob_writer.h b/impeller/blobcat/blob_writer.h index bbf60213ac73a..eb2f80c3e4a17 100644 --- a/impeller/blobcat/blob_writer.h +++ b/impeller/blobcat/blob_writer.h @@ -10,7 +10,7 @@ #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" -#include "impeller/blobcat/blob.h" +#include "impeller/blobcat/blob_types.h" namespace impeller { @@ -22,13 +22,19 @@ class BlobWriter { [[nodiscard]] bool AddBlobAtPath(const std::string& path); - [[nodiscard]] bool AddBlob(Blob::ShaderType type, + [[nodiscard]] bool AddBlob(BlobShaderType type, std::string name, std::shared_ptr mapping); std::shared_ptr CreateMapping() const; private: + struct BlobDescription { + BlobShaderType type; + std::string name; + std::shared_ptr mapping; + }; + std::vector blob_descriptions_; FML_DISALLOW_COPY_AND_ASSIGN(BlobWriter); diff --git a/impeller/blobcat/blobcat_unittests.cc b/impeller/blobcat/blobcat_unittests.cc index bc5bab227d667..6fc8783f652bd 100644 --- a/impeller/blobcat/blobcat_unittests.cc +++ b/impeller/blobcat/blobcat_unittests.cc @@ -27,15 +27,15 @@ const std::string CreateStringFromMapping(const fml::Mapping& mapping) { TEST(BlobTest, CanReadAndWriteBlobs) { BlobWriter writer; - ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kVertex, "Hello", + ASSERT_TRUE(writer.AddBlob(BlobShaderType::kVertex, "Hello", CreateMappingFromString("World"))); - ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kFragment, "Foo", + ASSERT_TRUE(writer.AddBlob(BlobShaderType::kFragment, "Foo", CreateMappingFromString("Bar"))); - ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kVertex, "Baz", + ASSERT_TRUE(writer.AddBlob(BlobShaderType::kVertex, "Baz", CreateMappingFromString("Bang"))); - ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kVertex, "Ping", + ASSERT_TRUE(writer.AddBlob(BlobShaderType::kVertex, "Ping", CreateMappingFromString("Pong"))); - ASSERT_TRUE(writer.AddBlob(Blob::ShaderType::kFragment, "Pang", + ASSERT_TRUE(writer.AddBlob(BlobShaderType::kFragment, "Pang", CreateMappingFromString("World"))); auto mapping = writer.CreateMapping(); @@ -46,9 +46,9 @@ TEST(BlobTest, CanReadAndWriteBlobs) { ASSERT_EQ(library.GetShaderCount(), 5u); // Wrong type. - ASSERT_EQ(library.GetMapping(Blob::ShaderType::kFragment, "Hello"), nullptr); + ASSERT_EQ(library.GetMapping(BlobShaderType::kFragment, "Hello"), nullptr); - auto hello_vtx = library.GetMapping(Blob::ShaderType::kVertex, "Hello"); + auto hello_vtx = library.GetMapping(BlobShaderType::kVertex, "Hello"); ASSERT_NE(hello_vtx, nullptr); ASSERT_EQ(CreateStringFromMapping(*hello_vtx), "World"); } diff --git a/impeller/renderer/backend/gles/shader_library_gles.cc b/impeller/renderer/backend/gles/shader_library_gles.cc index bfe199aa06017..b20e46d160f90 100644 --- a/impeller/renderer/backend/gles/shader_library_gles.cc +++ b/impeller/renderer/backend/gles/shader_library_gles.cc @@ -14,11 +14,11 @@ namespace impeller { -static ShaderStage ToShaderStage(Blob::ShaderType type) { +static ShaderStage ToShaderStage(BlobShaderType type) { switch (type) { - case Blob::ShaderType::kVertex: + case BlobShaderType::kVertex: return ShaderStage::kVertex; - case Blob::ShaderType::kFragment: + case BlobShaderType::kFragment: return ShaderStage::kFragment; } FML_UNREACHABLE(); diff --git a/impeller/renderer/backend/vulkan/shader_library_vk.cc b/impeller/renderer/backend/vulkan/shader_library_vk.cc index f7811e2c7ecf8..e7bb8ec661c82 100644 --- a/impeller/renderer/backend/vulkan/shader_library_vk.cc +++ b/impeller/renderer/backend/vulkan/shader_library_vk.cc @@ -11,11 +11,11 @@ namespace impeller { -static ShaderStage ToShaderStage(Blob::ShaderType type) { +static ShaderStage ToShaderStage(BlobShaderType type) { switch (type) { - case Blob::ShaderType::kVertex: + case BlobShaderType::kVertex: return ShaderStage::kVertex; - case Blob::ShaderType::kFragment: + case BlobShaderType::kFragment: return ShaderStage::kFragment; } FML_UNREACHABLE(); From eee040d9a9b486e4604959be0ef2f1cfc91e7647 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 20:34:17 -0400 Subject: [PATCH 356/558] Roll Dart SDK from b67ebd581c8f to 5f02953a8f89 (1 revision) (#35445) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f19c2cfee86de..9b682095a33c0 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'b67ebd581c8f7a774224dafde93f927c9be575f7', + 'dart_revision': '5f02953a8f89bebfac5d11e507a3a198fd6c0b49', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index cf99f9ea91ee2..1765093c8244d 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 3bf84e51a3275839112721420d2cb2f1 +Signature: 9dac3ac76b959c40b4d90a663e2cf13e UNUSED LICENSES: From cd35ae3706a4e628e3112ff9cb81388a4e947b07 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 16 Aug 2022 20:36:14 -0400 Subject: [PATCH 357/558] Roll Skia from 6d785ddbfe5e to d121e0a831fa (2 revisions) (#35444) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 9b682095a33c0..f130fda209620 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': '6d785ddbfe5ed7987f4cb71844425cf33dce818f', + 'skia_revision': 'd121e0a831fa17e062a7923fdedf11a4cd5988b7', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 20d629ea88997..6465fab2f7008 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 35c38178ae8c14f7962e3bfefc86e06d +Signature: 264670de252323e79ee620595d794444 UNUSED LICENSES: From 2e6d4dc5b5134e78aeb4477790506943e0ad7349 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 16 Aug 2022 19:44:36 -0700 Subject: [PATCH 358/558] [Impeller] Update code comments about DL methods that Flutter doesn't expose. (#35447) --- impeller/display_list/display_list_dispatcher.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index cce7ee1f4a988..e01b4d5c98630 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -737,8 +737,8 @@ static Path ToPath(const SkPath& path) { break; case SkPathFillType::kInverseWinding: case SkPathFillType::kInverseEvenOdd: - // TODO(104848): Support the inverse winding modes. - UNIMPLEMENTED; + // Flutter doesn't expose these path fill types. These are only visible + // via the dispatcher interface. We should never get here. fill_type = FillType::kNonZero; break; } @@ -1003,11 +1003,9 @@ void DisplayListDispatcher::drawImageLattice( const SkRect& dst, flutter::DlFilterMode filter, bool render_with_attributes) { - // Needs https://github.com/flutter/flutter/issues/95434 // Don't implement this one since it is not exposed by flutter, // Skia internally converts calls to drawImageNine into this method, // which is then converted back to drawImageNine by display list. - UNIMPLEMENTED; } // |flutter::Dispatcher| From 468576508b4fa5e750d49ee59c0a6f2ad20ea1e8 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 16 Aug 2022 19:46:04 -0700 Subject: [PATCH 359/558] [Impeller] Skip all playground tests if SHIFT, SUPER, or CTRL is held. (#35446) --- impeller/playground/playground.cc | 9 +++++++++ impeller/playground/playground.h | 2 ++ impeller/playground/playground_test.cc | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index ab0457cee5a88..f09fa9638d3f4 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -126,12 +126,21 @@ void Playground::TeardownWindow() { impl_.reset(); } +static std::atomic_bool gShouldOpenNewPlaygrounds = true; + +bool Playground::ShouldOpenNewPlaygrounds() { + return gShouldOpenNewPlaygrounds; +} + static void PlaygroundKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_RELEASE) { + if (mods & (GLFW_MOD_CONTROL | GLFW_MOD_SUPER | GLFW_MOD_SHIFT)) { + gShouldOpenNewPlaygrounds = false; + } ::glfwSetWindowShouldClose(window, GLFW_TRUE); } } diff --git a/impeller/playground/playground.h b/impeller/playground/playground.h index cbb38bd423b19..8b65b6f68ce3c 100644 --- a/impeller/playground/playground.h +++ b/impeller/playground/playground.h @@ -34,6 +34,8 @@ class Playground { static constexpr bool is_enabled() { return is_enabled_; } + static bool ShouldOpenNewPlaygrounds(); + void SetupWindow(PlaygroundBackend backend); void TeardownWindow(); diff --git a/impeller/playground/playground_test.cc b/impeller/playground/playground_test.cc index 3cb7c946a8868..1627cf9a711f5 100644 --- a/impeller/playground/playground_test.cc +++ b/impeller/playground/playground_test.cc @@ -16,6 +16,11 @@ void PlaygroundTest::SetUp() { return; } + if (!Playground::ShouldOpenNewPlaygrounds()) { + GTEST_SKIP_("Skipping due to user action."); + return; + } + SetupWindow(GetParam()); } From 5c16e358caaa66966125fbae4dee5dd59ebdec7b Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 16 Aug 2022 19:49:57 -0700 Subject: [PATCH 360/558] Pass the snapshot transform to the final blit (#35448) --- .../filters/color_matrix_filter_contents.cc | 6 ++- .../contents/filters/filter_contents.cc | 6 ++- impeller/entity/entity_unittests.cc | 39 +++++++++++++------ 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/impeller/entity/contents/filters/color_matrix_filter_contents.cc b/impeller/entity/contents/filters/color_matrix_filter_contents.cc index bcd81ae0d2355..3280e98df1d4a 100644 --- a/impeller/entity/contents/filters/color_matrix_filter_contents.cc +++ b/impeller/entity/contents/filters/color_matrix_filter_contents.cc @@ -95,14 +95,16 @@ std::optional ColorMatrixFilterContents::RenderFilter( return pass.AddCommand(std::move(cmd)); }; - auto out_texture = renderer.MakeSubpass(ISize(coverage.size), callback); + auto out_texture = + renderer.MakeSubpass(input_snapshot->texture->GetSize(), callback); if (!out_texture) { return std::nullopt; } out_texture->SetLabel("ColorMatrixFilter Texture"); return Snapshot{.texture = out_texture, - .transform = Matrix::MakeTranslation(coverage.origin)}; + .transform = input_snapshot->transform, + .sampler_descriptor = input_snapshot->sampler_descriptor}; } } // namespace impeller diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index cc5c76c930b35..115eac6b948ca 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -152,14 +152,16 @@ bool FilterContents::Render(const ContentContext& renderer, // Draw the result texture, respecting the transform and clip stack. - auto contents = TextureContents::MakeRect(filter_coverage.value()); + auto texture_rect = Rect::MakeSize(snapshot.texture->GetSize()); + auto contents = TextureContents::MakeRect(texture_rect); contents->SetTexture(snapshot.texture); contents->SetSamplerDescriptor(snapshot.sampler_descriptor); - contents->SetSourceRect(Rect::MakeSize(snapshot.texture->GetSize())); + contents->SetSourceRect(texture_rect); Entity e; e.SetBlendMode(entity.GetBlendMode()); e.SetStencilDepth(entity.GetStencilDepth()); + e.SetTransformation(snapshot.transform); return contents->Render(renderer, e, pass); } diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index a10da41ce5c17..d74c38a939686 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -1482,8 +1482,7 @@ TEST_P(EntityTest, ColorMatrixFilterEditable) { // If this is the first frame, set the ImGui's initial size and postion. if (first_frame) { first_frame = false; - ImGui::SetNextWindowSize({500, 150}); - ImGui::SetNextWindowPos({260, 600}); + ImGui::SetNextWindowPos({10, 10}); } // UI state. @@ -1493,15 +1492,27 @@ TEST_P(EntityTest, ColorMatrixFilterEditable) { 0, 0, 1, 0, 0, // 0, 0, 0, 1, 0, // }; + static float offset[2] = {500, 400}; + static float rotation = 0; + static float scale[2] = {0.65, 0.65}; + static float skew[2] = {0, 0}; // Define the ImGui - ImGui::Begin("Color Matrix"); - std::string label = "##1"; - label.c_str(); - for (int i = 0; i < 20; i += 5) { - ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, - &(color_matrix.array[i]), 5, NULL, NULL, "%.2f", 0); - label[2]++; + ImGui::Begin("Color Matrix", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + { + std::string label = "##1"; + label.c_str(); + for (int i = 0; i < 20; i += 5) { + ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, + &(color_matrix.array[i]), 5, NULL, NULL, "%.2f", 0); + label[2]++; + } + + ImGui::SliderFloat2("Translation", &offset[0], 0, + pass.GetRenderTargetSize().width); + ImGui::SliderFloat("Rotation", &rotation, 0, kPi * 2); + ImGui::SliderFloat2("Scale", &scale[0], 0, 3); + ImGui::SliderFloat2("Skew", &skew[0], -3, 3); } ImGui::End(); @@ -1511,9 +1522,13 @@ TEST_P(EntityTest, ColorMatrixFilterEditable) { // Define the entity with the color matrix filter. Entity entity; - entity.SetTransformation(Matrix::MakeScale(GetContentScale()) * - Matrix::MakeTranslation({250, 200}) * - Matrix::MakeScale(Vector2{0.5, 0.5})); + entity.SetTransformation( + Matrix::MakeScale(GetContentScale()) * + Matrix::MakeTranslation(Vector3(offset[0], offset[1])) * + Matrix::MakeRotationZ(Radians(rotation)) * + Matrix::MakeScale(Vector2(scale[0], scale[1])) * + Matrix::MakeSkew(skew[0], skew[1]) * + Matrix::MakeTranslation(-Point(bay_bridge->GetSize()) / 2)); entity.SetContents(filter); entity.Render(context, pass); From 4024ff17ac5fffeeb42570777a8303b36328327b Mon Sep 17 00:00:00 2001 From: xiaomiao Date: Wed, 17 Aug 2022 11:10:20 +0800 Subject: [PATCH 361/558] Fix the issue that PrerollContext.has_texture_layer is sticky. (#35425) --- flow/layers/container_layer.cc | 10 +++++-- flow/layers/container_layer_unittests.cc | 36 ++++++++++++++++++++++++ flow/testing/mock_layer.cc | 8 ++++-- flow/testing/mock_layer.h | 6 +++- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index ad6fd9126e200..a37f7d92f4759 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -134,15 +134,19 @@ void ContainerLayer::PrerollChildren(PrerollContext* context, // Platform views have no children, so context->has_platform_view should // always be false. FML_DCHECK(!context->has_platform_view); + FML_DCHECK(!context->has_texture_layer); + bool child_has_platform_view = false; bool child_has_texture_layer = false; bool subtree_can_inherit_opacity = context->subtree_can_inherit_opacity; for (auto& layer : layers_) { - // Reset context->has_platform_view to false so that layers aren't treated - // as if they have a platform view based on one being previously found in a - // sibling tree. + // Reset context->has_platform_view and context->has_texture_layer to false + // so that layers aren't treated as if they have a platform view or texture + // layer based on one being previously found in a sibling tree. context->has_platform_view = false; + context->has_texture_layer = false; + // Initialize the "inherit opacity" flag to false and allow the layer to // override the answer during its |Preroll| context->subtree_can_inherit_opacity = false; diff --git a/flow/layers/container_layer_unittests.cc b/flow/layers/container_layer_unittests.cc index 577ed32ffb493..f1c6df8cdf203 100644 --- a/flow/layers/container_layer_unittests.cc +++ b/flow/layers/container_layer_unittests.cc @@ -29,6 +29,14 @@ TEST_F(ContainerLayerTest, LayerWithParentHasPlatformView) { "!context->has_platform_view"); } +TEST_F(ContainerLayerTest, LayerWithParentHasTextureLayer) { + auto layer = std::make_shared(); + + preroll_context()->has_texture_layer = true; + EXPECT_DEATH_IF_SUPPORTED(layer->Preroll(preroll_context(), SkMatrix()), + "!context->has_texture_layer"); +} + TEST_F(ContainerLayerTest, PaintingEmptyLayerDies) { auto layer = std::make_shared(); @@ -55,6 +63,34 @@ TEST_F(ContainerLayerTest, PaintBeforePrerollDies) { } #endif +TEST_F(ContainerLayerTest, LayerWithParentHasTextureLayerNeedsResetFlag) { + SkPath child_path1; + child_path1.addRect(5.0f, 6.0f, 20.5f, 21.5f); + SkPath child_path2; + child_path2.addRect(8.0f, 2.0f, 16.5f, 14.5f); + SkPaint child_paint1(SkColors::kGray); + SkPaint child_paint2(SkColors::kGreen); + + auto mock_layer1 = std::make_shared( + child_path1, child_paint1, false /* fake_has_platform_view */, false, + false, true /* fake_has_texture_layer */); + auto mock_layer2 = std::make_shared(child_path2, child_paint2); + + auto root = std::make_shared(); + auto container_layer1 = std::make_shared(); + auto container_layer2 = std::make_shared(); + root->Add(container_layer1); + root->Add(container_layer2); + container_layer1->Add(mock_layer1); + container_layer2->Add(mock_layer2); + + EXPECT_EQ(preroll_context()->has_texture_layer, false); + root->Preroll(preroll_context(), SkMatrix()); + EXPECT_EQ(preroll_context()->has_texture_layer, true); + // The flag for holding texture layer from parent needs to be clear + EXPECT_EQ(mock_layer2->parent_has_texture_layer(), false); +} + TEST_F(ContainerLayerTest, Simple) { SkPath child_path; child_path.addRect(5.0f, 6.0f, 20.5f, 21.5f); diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc index 6ff049469c2b1..618a1d566798f 100644 --- a/flow/testing/mock_layer.cc +++ b/flow/testing/mock_layer.cc @@ -14,12 +14,14 @@ MockLayer::MockLayer(SkPath path, SkPaint paint, bool fake_has_platform_view, bool fake_reads_surface, - bool fake_opacity_compatible) + bool fake_opacity_compatible, + bool fake_has_texture_layer) : fake_paint_path_(path), fake_paint_(paint), fake_has_platform_view_(fake_has_platform_view), fake_reads_surface_(fake_reads_surface), - fake_opacity_compatible_(fake_opacity_compatible) {} + fake_opacity_compatible_(fake_opacity_compatible), + fake_has_texture_layer_(fake_has_texture_layer) {} bool MockLayer::IsReplacing(DiffContext* context, const Layer* layer) const { // Similar to PictureLayer, only return true for identical mock layers; @@ -41,8 +43,10 @@ void MockLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { parent_matrix_ = matrix; parent_cull_rect_ = context->cull_rect; parent_has_platform_view_ = context->has_platform_view; + parent_has_texture_layer_ = context->has_texture_layer; context->has_platform_view = fake_has_platform_view_; + context->has_texture_layer = fake_has_texture_layer_; set_paint_bounds(fake_paint_path_.getBounds()); if (fake_reads_surface_) { context->surface_needs_readback = true; diff --git a/flow/testing/mock_layer.h b/flow/testing/mock_layer.h index 4e34fa1639d77..ad6bc2cc12b1e 100644 --- a/flow/testing/mock_layer.h +++ b/flow/testing/mock_layer.h @@ -28,7 +28,8 @@ class MockLayer : public Layer { SkPaint paint = SkPaint(), bool fake_has_platform_view = false, bool fake_reads_surface = false, - bool fake_opacity_compatible_ = false); + bool fake_opacity_compatible_ = false, + bool fake_has_texture_layer = false); static std::shared_ptr Make(SkPath path, SkPaint paint = SkPaint()) { @@ -46,6 +47,7 @@ class MockLayer : public Layer { const SkMatrix& parent_matrix() { return parent_matrix_; } const SkRect& parent_cull_rect() { return parent_cull_rect_; } bool parent_has_platform_view() { return parent_has_platform_view_; } + bool parent_has_texture_layer() { return parent_has_texture_layer_; } bool IsReplacing(DiffContext* context, const Layer* layer) const override; void Diff(DiffContext* context, const Layer* old_layer) override; @@ -58,9 +60,11 @@ class MockLayer : public Layer { SkPath fake_paint_path_; SkPaint fake_paint_; bool parent_has_platform_view_ = false; + bool parent_has_texture_layer_ = false; bool fake_has_platform_view_ = false; bool fake_reads_surface_ = false; bool fake_opacity_compatible_ = false; + bool fake_has_texture_layer_ = false; FML_DISALLOW_COPY_AND_ASSIGN(MockLayer); }; From fa91de4b20728ae73c2b2c1fc1cd00e7daecd56b Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Wed, 17 Aug 2022 11:40:22 +0800 Subject: [PATCH 362/558] [Impeller] Support 'matrix' parameter for color sources (#35400) --- ci/licenses_golden/licenses_flutter | 9 +- impeller/aiks/aiks_unittests.cc | 192 +++++++++++++----- impeller/aiks/paint.h | 2 +- .../shader_lib/impeller/transform.glsl | 14 ++ .../display_list/display_list_dispatcher.cc | 33 ++- impeller/entity/BUILD.gn | 8 +- .../entity/contents/color_source_contents.cc | 37 ++++ .../entity/contents/color_source_contents.h | 39 ++++ impeller/entity/contents/content_context.cc | 4 +- impeller/entity/contents/content_context.h | 18 +- .../contents/linear_gradient_contents.cc | 32 ++- .../contents/linear_gradient_contents.h | 10 +- impeller/entity/contents/path_contents.cc | 13 -- impeller/entity/contents/path_contents.h | 24 --- .../contents/radial_gradient_contents.cc | 24 +-- .../contents/radial_gradient_contents.h | 10 +- .../contents/sweep_gradient_contents.cc | 24 +-- .../entity/contents/sweep_gradient_contents.h | 10 +- .../entity/contents/tiled_texture_contents.cc | 29 +-- .../entity/contents/tiled_texture_contents.h | 10 +- impeller/entity/shaders/gradient_fill.vert | 11 +- ...nt_fill.frag => linear_gradient_fill.frag} | 4 +- .../entity/shaders/radial_gradient_fill.frag | 4 +- .../entity/shaders/radial_gradient_fill.vert | 16 -- .../entity/shaders/sweep_gradient_fill.frag | 4 +- .../entity/shaders/sweep_gradient_fill.vert | 16 -- .../entity/shaders/tiled_texture_fill.vert | 8 +- 27 files changed, 342 insertions(+), 263 deletions(-) create mode 100644 impeller/compiler/shader_lib/impeller/transform.glsl create mode 100644 impeller/entity/contents/color_source_contents.cc create mode 100644 impeller/entity/contents/color_source_contents.h delete mode 100644 impeller/entity/contents/path_contents.cc delete mode 100644 impeller/entity/contents/path_contents.h rename impeller/entity/shaders/{gradient_fill.frag => linear_gradient_fill.frag} (90%) delete mode 100644 impeller/entity/shaders/radial_gradient_fill.vert delete mode 100644 impeller/entity/shaders/sweep_gradient_fill.vert diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 43992af7790e7..45074c8482c87 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -500,6 +500,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/texture.glsl +FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/transform.glsl FILE: ../../../flutter/impeller/compiler/shader_lib/impeller/types.glsl FILE: ../../../flutter/impeller/compiler/source_options.cc FILE: ../../../flutter/impeller/compiler/source_options.h @@ -556,6 +557,8 @@ FILE: ../../../flutter/impeller/entity/contents/atlas_contents.cc FILE: ../../../flutter/impeller/entity/contents/atlas_contents.h FILE: ../../../flutter/impeller/entity/contents/clip_contents.cc FILE: ../../../flutter/impeller/entity/contents/clip_contents.h +FILE: ../../../flutter/impeller/entity/contents/color_source_contents.cc +FILE: ../../../flutter/impeller/entity/contents/color_source_contents.h FILE: ../../../flutter/impeller/entity/contents/content_context.cc FILE: ../../../flutter/impeller/entity/contents/content_context.h FILE: ../../../flutter/impeller/entity/contents/contents.cc @@ -581,8 +584,6 @@ FILE: ../../../flutter/impeller/entity/contents/filters/inputs/texture_filter_in FILE: ../../../flutter/impeller/entity/contents/filters/inputs/texture_filter_input.h FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.cc FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.h -FILE: ../../../flutter/impeller/entity/contents/path_contents.cc -FILE: ../../../flutter/impeller/entity/contents/path_contents.h FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.h FILE: ../../../flutter/impeller/entity/contents/rrect_shadow_contents.cc @@ -641,10 +642,9 @@ FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.frag FILE: ../../../flutter/impeller/entity/shaders/gaussian_blur.vert FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert -FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.vert +FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fill.frag -FILE: ../../../flutter/impeller/entity/shaders/radial_gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert FILE: ../../../flutter/impeller/entity/shaders/solid_fill.frag @@ -652,7 +652,6 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.frag FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.vert FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.frag -FILE: ../../../flutter/impeller/entity/shaders/sweep_gradient_fill.vert 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 diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 55a8c32993fd7..05b4a381696a7 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -13,6 +13,7 @@ #include "impeller/entity/contents/tiled_texture_contents.h" #include "impeller/geometry/color.h" #include "impeller/geometry/geometry_unittests.h" +#include "impeller/geometry/matrix.h" #include "impeller/geometry/path_builder.h" #include "impeller/playground/widgets.h" #include "impeller/renderer/command_buffer.h" @@ -125,7 +126,21 @@ TEST_P(AiksTest, CanRenderTiledTexture) { ImGui::Combo("Min Mag filter", &selected_min_mag_filter, min_mag_filter_names, sizeof(min_mag_filter_names) / sizeof(char*)); + static Matrix matrix = { + 1, 0, 0, 0, // + 0, 1, 0, 0, // + 0, 0, 1, 0, // + 0, 0, 0, 1 // + }; + std::string label = "##1"; + label.c_str(); + for (int i = 0; i < 4; i++) { + ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), + 4, NULL, NULL, "%.2f", 0); + label[2]++; + } ImGui::End(); + Canvas canvas; Paint paint; canvas.Translate({100.0, 100.0, 0}); @@ -140,6 +155,7 @@ TEST_P(AiksTest, CanRenderTiledTexture) { contents->SetTexture(texture); contents->SetTileModes(x_tile_mode, y_tile_mode); contents->SetSamplerDescriptor(descriptor); + contents->SetMatrix(matrix); return contents; }; canvas.DrawRect({0, 0, 600, 600}, paint); @@ -282,86 +298,162 @@ TEST_P(AiksTest, CanSaveLayerStandalone) { } TEST_P(AiksTest, CanRenderLinearGradient) { - Canvas canvas; - Paint paint; - std::vector offsets = { - {0, 0, 0}, {0, 300, 0}, {300, 0, 0}, {300, 300, 0}}; - std::vector tile_modes = { - Entity::TileMode::kClamp, Entity::TileMode::kRepeat, - Entity::TileMode::kMirror, Entity::TileMode::kDecal}; - for (int i = 0; i < 4; i++) { - canvas.Save(); - canvas.Translate(offsets[i]); - Entity::TileMode tile_mode = tile_modes[i]; + bool first_frame = true; + auto callback = [&](AiksContext& renderer, RenderTarget& render_target) { + if (first_frame) { + first_frame = false; + ImGui::SetNextWindowSize({480, 100}); + ImGui::SetNextWindowPos({100, 550}); + } + + const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; + const Entity::TileMode tile_modes[] = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + + static int selected_tile_mode = 0; + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); + static Matrix matrix = { + 1, 0, 0, 0, // + 0, 1, 0, 0, // + 0, 0, 1, 0, // + 0, 0, 0, 1 // + }; + std::string label = "##1"; + label.c_str(); + for (int i = 0; i < 4; i++) { + ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), + 4, NULL, NULL, "%.2f", 0); + label[2]++; + } + ImGui::End(); + + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + auto tile_mode = tile_modes[selected_tile_mode]; paint.color_source = [tile_mode]() { auto contents = std::make_shared(); - contents->SetEndPoints({0, 0}, {100, 100}); + contents->SetEndPoints({0, 0}, {200, 200}); std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, Color{0.1294, 0.5882, 0.9529, 1.0}}; contents->SetColors(std::move(colors)); contents->SetTileMode(tile_mode); + contents->SetMatrix(matrix); return contents; }; - canvas.DrawRect({0, 0, 200, 200}, paint); - canvas.Restore(); - } - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); + canvas.DrawRect({0, 0, 600, 600}, paint); + return renderer.Render(canvas.EndRecordingAsPicture(), render_target); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); } TEST_P(AiksTest, CanRenderRadialGradient) { - Canvas canvas; - Paint paint; - std::vector offsets = { - {0, 0, 0}, {0, 300, 0}, {300, 0, 0}, {300, 300, 0}}; - std::vector tile_modes = { - Entity::TileMode::kClamp, Entity::TileMode::kRepeat, - Entity::TileMode::kMirror, Entity::TileMode::kDecal}; - for (int i = 0; i < 4; i++) { - canvas.Save(); - canvas.Translate(offsets[i]); - Entity::TileMode tile_mode = tile_modes[i]; + bool first_frame = true; + auto callback = [&](AiksContext& renderer, RenderTarget& render_target) { + if (first_frame) { + first_frame = false; + ImGui::SetNextWindowSize({480, 100}); + ImGui::SetNextWindowPos({100, 550}); + } + + const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; + const Entity::TileMode tile_modes[] = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + + static int selected_tile_mode = 0; + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); + static Matrix matrix = { + 1, 0, 0, 0, // + 0, 1, 0, 0, // + 0, 0, 1, 0, // + 0, 0, 0, 1 // + }; + std::string label = "##1"; + label.c_str(); + for (int i = 0; i < 4; i++) { + ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), + 4, NULL, NULL, "%.2f", 0); + label[2]++; + } + ImGui::End(); + + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + auto tile_mode = tile_modes[selected_tile_mode]; paint.color_source = [tile_mode]() { auto contents = std::make_shared(); - contents->SetCenterAndRadius({50, 50}, 50); + contents->SetCenterAndRadius({100, 100}, 100); std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, Color{0.1294, 0.5882, 0.9529, 1.0}}; contents->SetColors(std::move(colors)); contents->SetTileMode(tile_mode); + contents->SetMatrix(matrix); return contents; }; - canvas.DrawRect({0, 0, 200, 200}, paint); - canvas.Restore(); - } - - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); + canvas.DrawRect({0, 0, 600, 600}, paint); + return renderer.Render(canvas.EndRecordingAsPicture(), render_target); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); } TEST_P(AiksTest, CanRenderSweepGradient) { - Canvas canvas; - Paint paint; - std::vector offsets = { - {0, 0, 0}, {0, 300, 0}, {300, 0, 0}, {300, 300, 0}}; - std::vector tile_modes = { - Entity::TileMode::kClamp, Entity::TileMode::kRepeat, - Entity::TileMode::kMirror, Entity::TileMode::kDecal}; - for (int i = 0; i < 4; i++) { - canvas.Save(); - canvas.Translate(offsets[i]); - Entity::TileMode tile_mode = tile_modes[i]; + bool first_frame = true; + auto callback = [&](AiksContext& renderer, RenderTarget& render_target) { + if (first_frame) { + first_frame = false; + ImGui::SetNextWindowSize({480, 100}); + ImGui::SetNextWindowPos({100, 550}); + } + + const char* tile_mode_names[] = {"Clamp", "Repeat", "Mirror", "Decal"}; + const Entity::TileMode tile_modes[] = { + Entity::TileMode::kClamp, Entity::TileMode::kRepeat, + Entity::TileMode::kMirror, Entity::TileMode::kDecal}; + + static int selected_tile_mode = 0; + ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); + ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, + sizeof(tile_mode_names) / sizeof(char*)); + static Matrix matrix = { + 1, 0, 0, 0, // + 0, 1, 0, 0, // + 0, 0, 1, 0, // + 0, 0, 0, 1 // + }; + std::string label = "##1"; + label.c_str(); + for (int i = 0; i < 4; i++) { + ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, &(matrix.vec[i]), + 4, NULL, NULL, "%.2f", 0); + label[2]++; + } + ImGui::End(); + + Canvas canvas; + Paint paint; + canvas.Translate({100.0, 100.0, 0}); + auto tile_mode = tile_modes[selected_tile_mode]; paint.color_source = [tile_mode]() { auto contents = std::make_shared(); - contents->SetCenterAndAngles({50, 50}, Degrees(45), Degrees(135)); + contents->SetCenterAndAngles({100, 100}, Degrees(45), Degrees(135)); std::vector colors = {Color{0.9568, 0.2627, 0.2118, 1.0}, Color{0.1294, 0.5882, 0.9529, 1.0}}; contents->SetColors(std::move(colors)); contents->SetTileMode(tile_mode); + contents->SetMatrix(matrix); return contents; }; - canvas.DrawRect({0, 0, 200, 200}, paint); - canvas.Restore(); - } - - ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); + canvas.DrawRect({0, 0, 600, 600}, paint); + return renderer.Render(canvas.EndRecordingAsPicture(), render_target); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); } TEST_P(AiksTest, CanRenderDifferentShapesWithSameColorSource) { diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index b150c868e3b7e..ba01221e3b3f9 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -25,7 +25,7 @@ struct Paint { using MaskFilterProc = std::function(FilterInput::Ref, bool is_solid_color)>; - using ColorSourceProc = std::function()>; + using ColorSourceProc = std::function()>; enum class Style { kFill, diff --git a/impeller/compiler/shader_lib/impeller/transform.glsl b/impeller/compiler/shader_lib/impeller/transform.glsl new file mode 100644 index 0000000000000..e57bdf0b14194 --- /dev/null +++ b/impeller/compiler/shader_lib/impeller/transform.glsl @@ -0,0 +1,14 @@ +// 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 TRANSFORM_GLSL_ +#define TRANSFORM_GLSL_ + +/// Returns the Cartesian coordinates of `position` in `transform` space. +vec2 IPVec2TransformPosition(mat4 matrix, vec2 point) { + vec4 transformed = matrix * vec4(point, 0, 1); + return transformed.xy / transformed.w; +} + +#endif diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index e01b4d5c98630..9f08a4bfc49e9 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -161,6 +161,17 @@ static impeller::SamplerDescriptor ToSamplerDescriptor( return desc; } +static Matrix ToMatrix(const SkMatrix& m) { + return Matrix{ + // clang-format off + m[0], m[3], 0, m[6], + m[1], m[4], 0, m[7], + 0, 0, 1, 0, + m[2], m[5], 0, m[8], + // clang-format on + }; +} + // |flutter::Dispatcher| void DisplayListDispatcher::setAntiAlias(bool aa) { // Nothing to do because AA is implicit. @@ -305,12 +316,14 @@ void DisplayListDispatcher::setColorSource( colors.emplace_back(ToColor(linear->colors()[i])); } auto tile_mode = ToTileMode(linear->tile_mode()); + auto matrix = ToMatrix(linear->matrix()); paint_.color_source = [start_point, end_point, colors = std::move(colors), - tile_mode]() { + tile_mode, matrix]() { auto contents = std::make_shared(); contents->SetEndPoints(start_point, end_point); contents->SetColors(std::move(colors)); contents->SetTileMode(tile_mode); + contents->SetMatrix(matrix); return contents; }; return; @@ -326,12 +339,14 @@ void DisplayListDispatcher::setColorSource( colors.emplace_back(ToColor(radialGradient->colors()[i])); } auto tile_mode = ToTileMode(radialGradient->tile_mode()); + auto matrix = ToMatrix(radialGradient->matrix()); paint_.color_source = [center, radius, colors = std::move(colors), - tile_mode]() { + tile_mode, matrix]() { auto contents = std::make_shared(); - contents->SetCenterAndRadius(center, radius), - contents->SetColors(std::move(colors)); + contents->SetCenterAndRadius(center, radius); + contents->SetColors(std::move(colors)); contents->SetTileMode(tile_mode); + contents->SetMatrix(matrix); return contents; }; return; @@ -349,12 +364,14 @@ void DisplayListDispatcher::setColorSource( colors.emplace_back(ToColor(sweepGradient->colors()[i])); } auto tile_mode = ToTileMode(sweepGradient->tile_mode()); + auto matrix = ToMatrix(sweepGradient->matrix()); paint_.color_source = [center, start_angle, end_angle, - colors = std::move(colors), tile_mode]() { + colors = std::move(colors), tile_mode, matrix]() { auto contents = std::make_shared(); contents->SetCenterAndAngles(center, start_angle, end_angle); contents->SetColors(std::move(colors)); contents->SetTileMode(tile_mode); + contents->SetMatrix(matrix); return contents; }; return; @@ -367,12 +384,14 @@ void DisplayListDispatcher::setColorSource( auto x_tile_mode = ToTileMode(image_color_source->horizontal_tile_mode()); auto y_tile_mode = ToTileMode(image_color_source->vertical_tile_mode()); auto desc = ToSamplerDescriptor(image_color_source->sampling()); - paint_.color_source = [texture, x_tile_mode, y_tile_mode, desc]() { + auto matrix = ToMatrix(image_color_source->matrix()); + paint_.color_source = [texture, x_tile_mode, y_tile_mode, desc, + matrix]() { auto contents = std::make_shared(); contents->SetTexture(texture); contents->SetTileModes(x_tile_mode, y_tile_mode); contents->SetSamplerDescriptor(desc); - // TODO(109384) Support 'matrix' parameter for all color sources. + contents->SetMatrix(matrix); return contents; }; return; diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index cce9b2e138370..8ac8d402be1b3 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -36,10 +36,9 @@ impeller_shaders("entity_shaders") { "shaders/gaussian_blur.vert", "shaders/glyph_atlas.frag", "shaders/glyph_atlas.vert", - "shaders/gradient_fill.frag", "shaders/gradient_fill.vert", + "shaders/linear_gradient_fill.frag", "shaders/radial_gradient_fill.frag", - "shaders/radial_gradient_fill.vert", "shaders/rrect_blur.vert", "shaders/rrect_blur.frag", "shaders/solid_fill.frag", @@ -47,7 +46,6 @@ impeller_shaders("entity_shaders") { "shaders/solid_stroke.frag", "shaders/solid_stroke.vert", "shaders/sweep_gradient_fill.frag", - "shaders/sweep_gradient_fill.vert", "shaders/texture_fill.frag", "shaders/texture_fill.vert", "shaders/tiled_texture_fill.frag", @@ -63,6 +61,8 @@ impeller_component("entity") { "contents/atlas_contents.h", "contents/clip_contents.cc", "contents/clip_contents.h", + "contents/color_source_contents.cc", + "contents/color_source_contents.h", "contents/content_context.cc", "contents/content_context.h", "contents/contents.cc", @@ -87,8 +87,6 @@ impeller_component("entity") { "contents/filters/inputs/texture_filter_input.h", "contents/linear_gradient_contents.cc", "contents/linear_gradient_contents.h", - "contents/path_contents.cc", - "contents/path_contents.h", "contents/radial_gradient_contents.cc", "contents/radial_gradient_contents.h", "contents/rrect_shadow_contents.cc", diff --git a/impeller/entity/contents/color_source_contents.cc b/impeller/entity/contents/color_source_contents.cc new file mode 100644 index 0000000000000..3a8f26a29e7aa --- /dev/null +++ b/impeller/entity/contents/color_source_contents.cc @@ -0,0 +1,37 @@ +// 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 "color_source_contents.h" + +#include "impeller/entity/entity.h" +#include "impeller/geometry/matrix.h" + +namespace impeller { + +ColorSourceContents::ColorSourceContents() = default; + +ColorSourceContents::~ColorSourceContents() = default; + +void ColorSourceContents::SetPath(Path path) { + path_ = path; +} + +const Path& ColorSourceContents::GetPath() const { + return path_; +} + +void ColorSourceContents::SetMatrix(Matrix matrix) { + inverse_matrix_ = matrix.Invert(); +} + +const Matrix& ColorSourceContents::GetInverseMatrix() const { + return inverse_matrix_; +} + +std::optional ColorSourceContents::GetCoverage( + const Entity& entity) const { + return path_.GetTransformedBoundingBox(entity.GetTransformation()); +}; + +} // namespace impeller diff --git a/impeller/entity/contents/color_source_contents.h b/impeller/entity/contents/color_source_contents.h new file mode 100644 index 0000000000000..94386bd111ed5 --- /dev/null +++ b/impeller/entity/contents/color_source_contents.h @@ -0,0 +1,39 @@ +// 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/fml/macros.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/geometry/matrix.h" +#include "impeller/geometry/path.h" + +namespace impeller { + +class ColorSourceContents : public Contents { + public: + ColorSourceContents(); + + ~ColorSourceContents() override; + + void SetPath(Path path); + + void SetMatrix(Matrix matrix); + + // |Contents| + std::optional GetCoverage(const Entity& entity) const override; + + protected: + const Path& GetPath() const; + + const Matrix& GetInverseMatrix() const; + + private: + Path path_; + Matrix inverse_matrix_; + + FML_DISALLOW_COPY_AND_ASSIGN(ColorSourceContents); +}; + +} // namespace impeller diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 3ab9ec79738ba..10d9bee9cc01e 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -149,10 +149,10 @@ ContentContext::ContentContext(std::shared_ptr context) return; } - gradient_fill_pipelines_[{}] = - CreateDefaultPipeline(*context_); solid_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); + linear_gradient_fill_pipelines_[{}] = + CreateDefaultPipeline(*context_); radial_gradient_fill_pipelines_[{}] = CreateDefaultPipeline(*context_); sweep_gradient_fill_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 98b50420c9d71..194278a437bd9 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -40,10 +40,9 @@ #include "impeller/entity/gaussian_blur.vert.h" #include "impeller/entity/glyph_atlas.frag.h" #include "impeller/entity/glyph_atlas.vert.h" -#include "impeller/entity/gradient_fill.frag.h" #include "impeller/entity/gradient_fill.vert.h" +#include "impeller/entity/linear_gradient_fill.frag.h" #include "impeller/entity/radial_gradient_fill.frag.h" -#include "impeller/entity/radial_gradient_fill.vert.h" #include "impeller/entity/rrect_blur.frag.h" #include "impeller/entity/rrect_blur.vert.h" #include "impeller/entity/solid_fill.frag.h" @@ -51,7 +50,6 @@ #include "impeller/entity/solid_stroke.frag.h" #include "impeller/entity/solid_stroke.vert.h" #include "impeller/entity/sweep_gradient_fill.frag.h" -#include "impeller/entity/sweep_gradient_fill.vert.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" #include "impeller/entity/tiled_texture_fill.frag.h" @@ -62,14 +60,14 @@ namespace impeller { -using GradientFillPipeline = - PipelineT; +using LinearGradientFillPipeline = + PipelineT; using SolidFillPipeline = PipelineT; using RadialGradientFillPipeline = - PipelineT; + PipelineT; using SweepGradientFillPipeline = - PipelineT; + PipelineT; using BlendPipeline = PipelineT; using RRectBlurPipeline = PipelineT; @@ -160,9 +158,9 @@ class ContentContext { bool IsValid() const; - std::shared_ptr GetGradientFillPipeline( + std::shared_ptr GetLinearGradientFillPipeline( ContentContextOptions opts) const { - return GetPipeline(gradient_fill_pipelines_, opts); + return GetPipeline(linear_gradient_fill_pipelines_, opts); } std::shared_ptr GetRadialGradientFillPipeline( @@ -335,8 +333,8 @@ class ContentContext { // These are mutable because while the prototypes are created eagerly, any // variants requested from that are lazily created and cached in the variants // map. - mutable Variants gradient_fill_pipelines_; mutable Variants solid_fill_pipelines_; + mutable Variants linear_gradient_fill_pipelines_; mutable Variants radial_gradient_fill_pipelines_; mutable Variants sweep_gradient_fill_pipelines_; mutable Variants rrect_blur_pipelines_; diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index 374e990d4e5a0..7eb09622eb663 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -16,10 +16,6 @@ LinearGradientContents::LinearGradientContents() = default; LinearGradientContents::~LinearGradientContents() = default; -void LinearGradientContents::SetPath(Path path) { - path_ = std::move(path); -} - void LinearGradientContents::SetEndPoints(Point start_point, Point end_point) { start_point_ = start_point; end_point_ = end_point; @@ -43,26 +39,21 @@ const std::vector& LinearGradientContents::GetColors() const { return colors_; } -std::optional LinearGradientContents::GetCoverage( - const Entity& entity) const { - return path_.GetTransformedBoundingBox(entity.GetTransformation()); -}; - bool LinearGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - using VS = GradientFillPipeline::VertexShader; - using FS = GradientFillPipeline::FragmentShader; + using VS = LinearGradientFillPipeline::VertexShader; + using FS = LinearGradientFillPipeline::FragmentShader; auto vertices_builder = VertexBufferBuilder(); { - auto result = - Tessellator{}.Tessellate(path_.GetFillType(), path_.CreatePolyline(), - [&vertices_builder](Point point) { - VS::PerVertexData vtx; - vtx.vertices = point; - vertices_builder.AppendVertex(vtx); - }); + auto result = Tessellator{}.Tessellate(GetPath().GetFillType(), + GetPath().CreatePolyline(), + [&vertices_builder](Point point) { + VS::PerVertexData vtx; + vtx.position = point; + vertices_builder.AppendVertex(vtx); + }); if (result == Tessellator::Result::kInputError) { return true; @@ -75,6 +66,7 @@ bool LinearGradientContents::Render(const ContentContext& renderer, VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); FS::GradientInfo gradient_info; gradient_info.start_point = start_point_; @@ -85,8 +77,8 @@ bool LinearGradientContents::Render(const ContentContext& renderer, Command cmd; cmd.label = "LinearGradientFill"; - cmd.pipeline = - renderer.GetGradientFillPipeline(OptionsFromPassAndEntity(pass, entity)); + cmd.pipeline = renderer.GetLinearGradientFillPipeline( + OptionsFromPassAndEntity(pass, entity)); cmd.stencil_reference = entity.GetStencilDepth(); cmd.BindVertices( vertices_builder.CreateVertexBuffer(pass.GetTransientsBuffer())); diff --git a/impeller/entity/contents/linear_gradient_contents.h b/impeller/entity/contents/linear_gradient_contents.h index 71605fdd0fd43..4ba2c82afcebe 100644 --- a/impeller/entity/contents/linear_gradient_contents.h +++ b/impeller/entity/contents/linear_gradient_contents.h @@ -9,7 +9,7 @@ #include #include "flutter/fml/macros.h" -#include "impeller/entity/contents/path_contents.h" +#include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" @@ -17,17 +17,12 @@ namespace impeller { -class LinearGradientContents final : public PathContents { +class LinearGradientContents final : public ColorSourceContents { public: LinearGradientContents(); ~LinearGradientContents() override; - void SetPath(Path path) override; - - // |Contents| - std::optional GetCoverage(const Entity& entity) const override; - // |Contents| bool Render(const ContentContext& renderer, const Entity& entity, @@ -42,7 +37,6 @@ class LinearGradientContents final : public PathContents { const std::vector& GetColors() const; private: - Path path_; Point start_point_; Point end_point_; std::vector colors_; diff --git a/impeller/entity/contents/path_contents.cc b/impeller/entity/contents/path_contents.cc deleted file mode 100644 index afa956a8cdb10..0000000000000 --- a/impeller/entity/contents/path_contents.cc +++ /dev/null @@ -1,13 +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 "path_contents.h" - -namespace impeller { - -PathContents::PathContents() = default; - -PathContents::~PathContents() = default; - -} // namespace impeller diff --git a/impeller/entity/contents/path_contents.h b/impeller/entity/contents/path_contents.h deleted file mode 100644 index f02430570f6c8..0000000000000 --- a/impeller/entity/contents/path_contents.h +++ /dev/null @@ -1,24 +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/fml/macros.h" -#include "impeller/entity/contents/contents.h" -#include "impeller/geometry/path.h" - -namespace impeller { - -class PathContents : public Contents { - public: - PathContents(); - - ~PathContents() override; - - virtual void SetPath(Path path) = 0; - - FML_DISALLOW_COPY_AND_ASSIGN(PathContents); -}; - -} // namespace impeller diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index e39b622dc4aec..605a5fe81d5ef 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -16,10 +16,6 @@ RadialGradientContents::RadialGradientContents() = default; RadialGradientContents::~RadialGradientContents() = default; -void RadialGradientContents::SetPath(Path path) { - path_ = std::move(path); -} - void RadialGradientContents::SetCenterAndRadius(Point center, Scalar radius) { center_ = center; radius_ = radius; @@ -43,11 +39,6 @@ const std::vector& RadialGradientContents::GetColors() const { return colors_; } -std::optional RadialGradientContents::GetCoverage( - const Entity& entity) const { - return path_.GetTransformedBoundingBox(entity.GetTransformation()); -}; - bool RadialGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { @@ -56,13 +47,13 @@ bool RadialGradientContents::Render(const ContentContext& renderer, auto vertices_builder = VertexBufferBuilder(); { - auto result = - Tessellator{}.Tessellate(path_.GetFillType(), path_.CreatePolyline(), - [&vertices_builder](Point point) { - VS::PerVertexData vtx; - vtx.vertices = point; - vertices_builder.AppendVertex(vtx); - }); + auto result = Tessellator{}.Tessellate(GetPath().GetFillType(), + GetPath().CreatePolyline(), + [&vertices_builder](Point point) { + VS::PerVertexData vtx; + vtx.position = point; + vertices_builder.AppendVertex(vtx); + }); if (result == Tessellator::Result::kInputError) { return true; @@ -75,6 +66,7 @@ bool RadialGradientContents::Render(const ContentContext& renderer, VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); FS::GradientInfo gradient_info; gradient_info.center = center_; diff --git a/impeller/entity/contents/radial_gradient_contents.h b/impeller/entity/contents/radial_gradient_contents.h index 7db7cef5adf9b..226e9d8b7b513 100644 --- a/impeller/entity/contents/radial_gradient_contents.h +++ b/impeller/entity/contents/radial_gradient_contents.h @@ -9,7 +9,7 @@ #include #include "flutter/fml/macros.h" -#include "impeller/entity/contents/path_contents.h" +#include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" @@ -17,17 +17,12 @@ namespace impeller { -class RadialGradientContents final : public PathContents { +class RadialGradientContents final : public ColorSourceContents { public: RadialGradientContents(); ~RadialGradientContents() override; - void SetPath(Path path) override; - - // |Contents| - std::optional GetCoverage(const Entity& entity) const override; - // |Contents| bool Render(const ContentContext& renderer, const Entity& entity, @@ -42,7 +37,6 @@ class RadialGradientContents final : public PathContents { const std::vector& GetColors() const; private: - Path path_; 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 d3874e1095bf7..a5b332d239e68 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -16,10 +16,6 @@ SweepGradientContents::SweepGradientContents() = default; SweepGradientContents::~SweepGradientContents() = default; -void SweepGradientContents::SetPath(Path path) { - path_ = std::move(path); -} - void SweepGradientContents::SetCenterAndAngles(Point center, Degrees start_angle, Degrees end_angle) { @@ -49,11 +45,6 @@ const std::vector& SweepGradientContents::GetColors() const { return colors_; } -std::optional SweepGradientContents::GetCoverage( - const Entity& entity) const { - return path_.GetTransformedBoundingBox(entity.GetTransformation()); -}; - bool SweepGradientContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { @@ -62,13 +53,13 @@ bool SweepGradientContents::Render(const ContentContext& renderer, auto vertices_builder = VertexBufferBuilder(); { - auto result = - Tessellator{}.Tessellate(path_.GetFillType(), path_.CreatePolyline(), - [&vertices_builder](Point point) { - VS::PerVertexData vtx; - vtx.vertices = point; - vertices_builder.AppendVertex(vtx); - }); + auto result = Tessellator{}.Tessellate(GetPath().GetFillType(), + GetPath().CreatePolyline(), + [&vertices_builder](Point point) { + VS::PerVertexData vtx; + vtx.position = point; + vertices_builder.AppendVertex(vtx); + }); if (result == Tessellator::Result::kInputError) { return true; @@ -81,6 +72,7 @@ bool SweepGradientContents::Render(const ContentContext& renderer, VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(); + frame_info.matrix = GetInverseMatrix(); FS::GradientInfo gradient_info; gradient_info.center = center_; diff --git a/impeller/entity/contents/sweep_gradient_contents.h b/impeller/entity/contents/sweep_gradient_contents.h index cfd21249b49cb..2a2b345f740a0 100644 --- a/impeller/entity/contents/sweep_gradient_contents.h +++ b/impeller/entity/contents/sweep_gradient_contents.h @@ -9,7 +9,7 @@ #include #include "flutter/fml/macros.h" -#include "impeller/entity/contents/path_contents.h" +#include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/color.h" #include "impeller/geometry/path.h" @@ -18,17 +18,12 @@ namespace impeller { -class SweepGradientContents final : public PathContents { +class SweepGradientContents final : public ColorSourceContents { public: SweepGradientContents(); ~SweepGradientContents() override; - void SetPath(Path path) override; - - // |Contents| - std::optional GetCoverage(const Entity& entity) const override; - // |Contents| bool Render(const ContentContext& renderer, const Entity& entity, @@ -43,7 +38,6 @@ class SweepGradientContents final : public PathContents { const std::vector& GetColors() const; private: - Path path_; Point center_; Scalar bias_; Scalar scale_; diff --git a/impeller/entity/contents/tiled_texture_contents.cc b/impeller/entity/contents/tiled_texture_contents.cc index c3b6521ca97fe..d6eacd3385e64 100644 --- a/impeller/entity/contents/tiled_texture_contents.cc +++ b/impeller/entity/contents/tiled_texture_contents.cc @@ -17,10 +17,6 @@ TiledTextureContents::TiledTextureContents() = default; TiledTextureContents::~TiledTextureContents() = default; -void TiledTextureContents::SetPath(Path path) { - path_ = std::move(path); -} - void TiledTextureContents::SetTexture(std::shared_ptr texture) { texture_ = std::move(texture); } @@ -35,11 +31,6 @@ void TiledTextureContents::SetSamplerDescriptor(SamplerDescriptor desc) { sampler_descriptor_ = std::move(desc); } -std::optional TiledTextureContents::GetCoverage( - const Entity& entity) const { - return path_.GetTransformedBoundingBox(entity.GetTransformation()); -}; - bool TiledTextureContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { @@ -50,7 +41,7 @@ bool TiledTextureContents::Render(const ContentContext& renderer, using VS = TiledTextureFillVertexShader; using FS = TiledTextureFillFragmentShader; - const auto coverage_rect = path_.GetBoundingBox(); + const auto coverage_rect = GetPath().GetBoundingBox(); if (!coverage_rect.has_value()) { return true; @@ -67,14 +58,13 @@ bool TiledTextureContents::Render(const ContentContext& renderer, VertexBufferBuilder vertex_builder; { - const auto tess_result = - Tessellator{}.Tessellate(path_.GetFillType(), path_.CreatePolyline(), - [&vertex_builder, &texture_size](Point vtx) { - VS::PerVertexData data; - data.position = vtx; - data.texture_coords = vtx / texture_size; - vertex_builder.AppendVertex(data); - }); + const auto tess_result = Tessellator{}.Tessellate( + GetPath().GetFillType(), GetPath().CreatePolyline(), + [&vertex_builder](Point vtx) { + VS::PerVertexData data; + data.position = vtx; + vertex_builder.AppendVertex(data); + }); if (tess_result == Tessellator::Result::kInputError) { return true; @@ -93,6 +83,9 @@ bool TiledTextureContents::Render(const ContentContext& renderer, VS::VertInfo vert_info; vert_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(); + vert_info.matrix = GetInverseMatrix(); + vert_info.texture_size = Vector2{static_cast(texture_size.width), + static_cast(texture_size.height)}; FS::FragInfo frag_info; frag_info.texture_sampler_y_coord_scale = texture_->GetYCoordScale(); diff --git a/impeller/entity/contents/tiled_texture_contents.h b/impeller/entity/contents/tiled_texture_contents.h index 378ff9051eb34..95806119c2950 100644 --- a/impeller/entity/contents/tiled_texture_contents.h +++ b/impeller/entity/contents/tiled_texture_contents.h @@ -9,24 +9,19 @@ #include #include "flutter/fml/macros.h" -#include "impeller/entity/contents/path_contents.h" +#include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/path.h" #include "impeller/renderer/sampler_descriptor.h" namespace impeller { -class TiledTextureContents final : public PathContents { +class TiledTextureContents final : public ColorSourceContents { public: TiledTextureContents(); ~TiledTextureContents() override; - void SetPath(Path path) override; - - // |Contents| - std::optional GetCoverage(const Entity& entity) const override; - // |Contents| bool Render(const ContentContext& renderer, const Entity& entity, @@ -39,7 +34,6 @@ class TiledTextureContents final : public PathContents { void SetSamplerDescriptor(SamplerDescriptor desc); private: - Path path_; std::shared_ptr texture_; SamplerDescriptor sampler_descriptor_ = {}; Entity::TileMode x_tile_mode_; diff --git a/impeller/entity/shaders/gradient_fill.vert b/impeller/entity/shaders/gradient_fill.vert index f9d0ccdabfc3e..4b793dbfa183d 100644 --- a/impeller/entity/shaders/gradient_fill.vert +++ b/impeller/entity/shaders/gradient_fill.vert @@ -2,15 +2,18 @@ // 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; + mat4 matrix; } frame_info; -in vec2 vertices; +in vec2 position; -out vec2 interpolated_vertices; +out vec2 v_position; void main() { - gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); - interpolated_vertices = vertices; + gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); + v_position = IPVec2TransformPosition(frame_info.matrix, position); } diff --git a/impeller/entity/shaders/gradient_fill.frag b/impeller/entity/shaders/linear_gradient_fill.frag similarity index 90% rename from impeller/entity/shaders/gradient_fill.frag rename to impeller/entity/shaders/linear_gradient_fill.frag index 407cd98bc2dfe..5282d4d623bf7 100644 --- a/impeller/entity/shaders/gradient_fill.frag +++ b/impeller/entity/shaders/linear_gradient_fill.frag @@ -12,14 +12,14 @@ uniform GradientInfo { float tile_mode; } gradient_info; -in vec2 interpolated_vertices; +in vec2 v_position; out vec4 frag_color; void main() { float len = length(gradient_info.end_point - gradient_info.start_point); float dot = dot( - interpolated_vertices - gradient_info.start_point, + v_position - gradient_info.start_point, gradient_info.end_point - gradient_info.start_point ); float t = dot / (len * len); diff --git a/impeller/entity/shaders/radial_gradient_fill.frag b/impeller/entity/shaders/radial_gradient_fill.frag index 07a7f9eeb39a3..3804d2f9bba35 100644 --- a/impeller/entity/shaders/radial_gradient_fill.frag +++ b/impeller/entity/shaders/radial_gradient_fill.frag @@ -12,12 +12,12 @@ uniform GradientInfo { float tile_mode; } gradient_info; -in vec2 interpolated_vertices; +in vec2 v_position; out vec4 frag_color; void main() { - float len = length(interpolated_vertices - gradient_info.center); + 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); diff --git a/impeller/entity/shaders/radial_gradient_fill.vert b/impeller/entity/shaders/radial_gradient_fill.vert deleted file mode 100644 index f9d0ccdabfc3e..0000000000000 --- a/impeller/entity/shaders/radial_gradient_fill.vert +++ /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. - -uniform FrameInfo { - mat4 mvp; -} frame_info; - -in vec2 vertices; - -out vec2 interpolated_vertices; - -void main() { - gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); - interpolated_vertices = vertices; -} diff --git a/impeller/entity/shaders/sweep_gradient_fill.frag b/impeller/entity/shaders/sweep_gradient_fill.frag index 8a7365d0c291b..f7ab313319cbf 100644 --- a/impeller/entity/shaders/sweep_gradient_fill.frag +++ b/impeller/entity/shaders/sweep_gradient_fill.frag @@ -14,12 +14,12 @@ uniform GradientInfo { float tile_mode; } gradient_info; -in vec2 interpolated_vertices; +in vec2 v_position; out vec4 frag_color; void main() { - vec2 coord = interpolated_vertices - gradient_info.center; + 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; diff --git a/impeller/entity/shaders/sweep_gradient_fill.vert b/impeller/entity/shaders/sweep_gradient_fill.vert deleted file mode 100644 index f9d0ccdabfc3e..0000000000000 --- a/impeller/entity/shaders/sweep_gradient_fill.vert +++ /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. - -uniform FrameInfo { - mat4 mvp; -} frame_info; - -in vec2 vertices; - -out vec2 interpolated_vertices; - -void main() { - gl_Position = frame_info.mvp * vec4(vertices, 0.0, 1.0); - interpolated_vertices = vertices; -} diff --git a/impeller/entity/shaders/tiled_texture_fill.vert b/impeller/entity/shaders/tiled_texture_fill.vert index c8abc9aaabbce..db73769940067 100644 --- a/impeller/entity/shaders/tiled_texture_fill.vert +++ b/impeller/entity/shaders/tiled_texture_fill.vert @@ -2,17 +2,21 @@ // 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; + mat4 matrix; + vec2 texture_size; } vert_info; in vec2 position; -in vec2 texture_coords; out vec2 v_texture_coords; void main() { gl_Position = vert_info.mvp * vec4(position, 0.0, 1.0); - v_texture_coords = texture_coords; + vec2 transformed = IPVec2TransformPosition(vert_info.matrix, position); + v_texture_coords = transformed / vert_info.texture_size; } From e480e68d34a7be989ad04598b218b1834c73ea5e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 00:42:23 -0400 Subject: [PATCH 363/558] Roll Fuchsia Mac SDK from 6UzpMkHKQt7i9ghiC... to 82kDMgkOeplHieWa6... (#35451) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index f130fda209620..2b6ce60b66b06 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': '6UzpMkHKQt7i9ghiCFIOavEj1Ez4S0pvwJHJwEEeQXsC' + 'version': '82kDMgkOeplHieWa6F8XhIj84EU8igyYxEKA_I2twvMC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 899cc167aa7cffabe1c90c097d616df4c64b0fb9 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 00:54:27 -0400 Subject: [PATCH 364/558] Roll Dart SDK from 5f02953a8f89 to 4491c2531cad (1 revision) (#35452) --- DEPS | 8 ++++---- ci/licenses_golden/licenses_third_party | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/DEPS b/DEPS index 2b6ce60b66b06..dea437ed582b6 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '5f02953a8f89bebfac5d11e507a3a198fd6c0b49', + 'dart_revision': '4491c2531cad4f1c1703dc703fa5d398c301eb4b', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -50,8 +50,8 @@ vars = { 'dart_pub_rev': 'ac7db6c07318efa4a8712110275eaf70f96a6d00', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': 'e00c0ea769e32821d91c0880da8eb736839a6e6d', - 'dart_webdev_rev': '8afdb97e783b32f78cb59bd83161f9ab62b2c7f7', - 'dart_webkit_inspection_protocol_rev': '57522d6b29d94903b765c757079d906555d5a171', + 'dart_webdev_rev': '1de398efc16a707ede884d629c1c0a7edea8b5fd', + 'dart_webkit_inspection_protocol_rev': '57ebca4b97310a10774c59c0fb056d8f23bd5cee', 'dart_yaml_edit_rev': '01589b3ce447b03aed991db49f1ec6445ad5476d', 'dart_zlib_rev': '27c2f474b71d0d20764f86f60ef8b00da1a16cda', @@ -221,7 +221,7 @@ deps = { Var('dart_git') + '/html.git@8243e967caad9932c13971af3b2a7c8f028383d5', 'src/third_party/dart/third_party/pkg/http': - Var('dart_git') + '/http.git@c440755e7c101abf153b52755545f21698e9da63', + Var('dart_git') + '/http.git@d54c4e005dfe150921d92fc6017e54358c3f23cc', 'src/third_party/dart/third_party/pkg/http_multi_server': Var('dart_git') + '/http_multi_server.git@20bf079c8955d1250a45afb9cb096472a724a551', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 1765093c8244d..c3e1facd55d96 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 9dac3ac76b959c40b4d90a663e2cf13e +Signature: 935109db0528b9172e9a517d89f42812 UNUSED LICENSES: @@ -10781,6 +10781,7 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/string_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/symbol_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/timer_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/type.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/uri_patch.dart FILE: ../../../third_party/dart/sdk/lib/ffi/c_type.dart FILE: ../../../third_party/dart/sdk/lib/ffi/native_finalizer.dart FILE: ../../../third_party/dart/sdk/lib/js/js_wasm.dart From 3b64bfceab5db72abc151c18ae40d7f65444d3b2 Mon Sep 17 00:00:00 2001 From: ColdPaleLight Date: Wed, 17 Aug 2022 13:58:04 +0800 Subject: [PATCH 365/558] [Impeller] Fix Metal validation failures on CanRenderTiledTexture/Metal (#35449) --- impeller/aiks/aiks_unittests.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 05b4a381696a7..7176d08f39f5c 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -93,7 +93,8 @@ TEST_P(AiksTest, CanRenderTiledTexture) { auto context = GetContext(); ASSERT_TRUE(context); bool first_frame = true; - auto texture = CreateTextureForFixture("table_mountain_nx.png"); + auto texture = CreateTextureForFixture("table_mountain_nx.png", + /*enable_mipmapping=*/true); auto callback = [&](AiksContext& renderer, RenderTarget& render_target) { if (first_frame) { first_frame = false; From b9ba9ce9b5102759c6d3868b9a80879179d407bd Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 02:05:48 -0400 Subject: [PATCH 366/558] Roll Skia from d121e0a831fa to a7e5d28fb32a (1 revision) (#35454) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index dea437ed582b6..e8a2d3265e429 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': 'd121e0a831fa17e062a7923fdedf11a4cd5988b7', + 'skia_revision': 'a7e5d28fb32a27a3ba7c956da86e03dd3a515435', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 6465fab2f7008..a2afe06bc133b 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 264670de252323e79ee620595d794444 +Signature: 21d957cf10b83813f0cf92172504dd62 UNUSED LICENSES: From 295776ac1ff36d44995c18a6a151bfa1fdc77a9a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 03:32:19 -0400 Subject: [PATCH 367/558] Roll Skia from a7e5d28fb32a to 545157bb176d (2 revisions) (#35455) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e8a2d3265e429..1c9951aa6e0db 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': 'a7e5d28fb32a27a3ba7c956da86e03dd3a515435', + 'skia_revision': '545157bb176da0c6cb750d51afa711b273204feb', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index a2afe06bc133b..4631eb4178219 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 21d957cf10b83813f0cf92172504dd62 +Signature: 52c606cf60548b6c36e9a34d55efe3e4 UNUSED LICENSES: From 5c141850e4278c4e00db34c63449f1ce0951dbf1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 09:52:19 -0400 Subject: [PATCH 368/558] Roll Skia from 545157bb176d to 003f5711b3ff (2 revisions) (#35461) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 1c9951aa6e0db..fe11f9ad820cf 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': '545157bb176da0c6cb750d51afa711b273204feb', + 'skia_revision': '003f5711b3ff9296f7d4a5d50548aeabde10c95d', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 4631eb4178219..9c52d33552475 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 52c606cf60548b6c36e9a34d55efe3e4 +Signature: 634e3be4387ca1772f3a52c23fdbd208 UNUSED LICENSES: From fa316fccb372d6b0b3c69986f7d0afeb2fd773ca Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 11:02:43 -0400 Subject: [PATCH 369/558] Roll Skia from 003f5711b3ff to 21282c5960a7 (3 revisions) (#35462) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index fe11f9ad820cf..56a30b6dfba15 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': '003f5711b3ff9296f7d4a5d50548aeabde10c95d', + 'skia_revision': '21282c5960a7169eb786567b85954c0097636d70', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 9c52d33552475..f87c00a157640 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 634e3be4387ca1772f3a52c23fdbd208 +Signature: 34c58b08e31f95f70fddfa7ad690a935 UNUSED LICENSES: @@ -2223,7 +2223,6 @@ FILE: ../../../third_party/skia/src/sksl/ir/SkSLTernaryExpression.h FILE: ../../../third_party/skia/src/sksl/ir/SkSLType.cpp FILE: ../../../third_party/skia/src/sksl/ir/SkSLType.h FILE: ../../../third_party/skia/src/sksl/ir/SkSLTypeReference.h -FILE: ../../../third_party/skia/src/sksl/ir/SkSLUnresolvedFunction.h FILE: ../../../third_party/skia/src/sksl/ir/SkSLVarDeclarations.h FILE: ../../../third_party/skia/src/sksl/ir/SkSLVariable.h FILE: ../../../third_party/skia/src/sksl/ir/SkSLVariableReference.h From df186d820011bbb4a39c993d0549756ee11ead44 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 11:09:10 -0400 Subject: [PATCH 370/558] Roll Dart SDK from 4491c2531cad to 12d3e976a829 (1 revision) (#35463) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 56a30b6dfba15..248c6e8ae2e4a 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '4491c2531cad4f1c1703dc703fa5d398c301eb4b', + 'dart_revision': '12d3e976a829f5bd6814bbd3f49e704f7a109df7', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index c3e1facd55d96..eecdf91c29b6e 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 935109db0528b9172e9a517d89f42812 +Signature: 06a1546eea452adff5a0d818fa6c132f UNUSED LICENSES: From b78bc4f298b9362055c5bea1a240009fa6f200de Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 12:15:58 -0400 Subject: [PATCH 371/558] Roll Skia from 21282c5960a7 to 4b720a135d0d (3 revisions) (#35464) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 248c6e8ae2e4a..c0669c0b972e1 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': '21282c5960a7169eb786567b85954c0097636d70', + 'skia_revision': '4b720a135d0d755bb901e2397b971a48df56694d', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f87c00a157640..b2ec890010868 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 34c58b08e31f95f70fddfa7ad690a935 +Signature: 1c4de7b494d39d32665f8a1a683391df UNUSED LICENSES: From ba62c6510edc9937bee48a45b8ec84f743ed5aa1 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 17 Aug 2022 09:23:57 -0700 Subject: [PATCH 372/558] [Impeller] Fix transform in TextureContents::RenderToSnaphot passthrough path (#35458) --- impeller/entity/contents/texture_contents.cc | 17 +++++++++----- impeller/entity/entity_unittests.cc | 24 ++++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc index 4e77668d1dda2..758b31e16d8db 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc @@ -56,15 +56,20 @@ std::optional TextureContents::GetCoverage(const Entity& entity) const { std::optional TextureContents::RenderToSnapshot( const ContentContext& renderer, const Entity& entity) const { + auto bounds = path_.GetBoundingBox(); + if (!bounds.has_value()) { + return std::nullopt; + } + // Passthrough textures that have simple rectangle paths and complete source // rects. if (is_rect_ && source_rect_ == Rect::MakeSize(texture_->GetSize())) { - auto scale = - Vector2(path_.GetBoundingBox()->size / Size(texture_->GetSize())); - return Snapshot{ - .texture = texture_, - .transform = entity.GetTransformation() * Matrix::MakeScale(scale), - .sampler_descriptor = sampler_descriptor_}; + auto scale = Vector2(bounds->size / Size(texture_->GetSize())); + return Snapshot{.texture = texture_, + .transform = entity.GetTransformation() * + Matrix::MakeTranslation(bounds->origin) * + Matrix::MakeScale(scale), + .sampler_descriptor = sampler_descriptor_}; } return Contents::RenderToSnapshot(renderer, entity); } diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index d74c38a939686..4fa1f959ee397 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -871,6 +871,9 @@ TEST_P(EntityTest, GaussianBlurFilter) { static float rotation = 0; static float scale[2] = {0.65, 0.65}; static float skew[2] = {0, 0}; + static float path_rect[4] = {0, 0, + static_cast(boston->GetSize().width), + static_cast(boston->GetSize().height)}; ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); { @@ -889,7 +892,7 @@ TEST_P(EntityTest, GaussianBlurFilter) { pass_variation_names, sizeof(pass_variation_names) / sizeof(char*)); } - ImGui::SliderFloat2("Sigma", &blur_amount[0], 0, 200); + ImGui::SliderFloat2("Sigma", blur_amount, 0, 200); ImGui::Combo("Blur style", &selected_blur_style, blur_style_names, sizeof(blur_style_names) / sizeof(char*)); ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, @@ -897,21 +900,23 @@ TEST_P(EntityTest, GaussianBlurFilter) { ImGui::ColorEdit4("Cover color", reinterpret_cast(&cover_color)); ImGui::ColorEdit4("Bounds color", reinterpret_cast(&bounds_color)); - ImGui::SliderFloat2("Translation", &offset[0], 0, + ImGui::SliderFloat2("Translation", offset, 0, pass.GetRenderTargetSize().width); ImGui::SliderFloat("Rotation", &rotation, 0, kPi * 2); - ImGui::SliderFloat2("Scale", &scale[0], 0, 3); - ImGui::SliderFloat2("Skew", &skew[0], -3, 3); + ImGui::SliderFloat2("Scale", scale, 0, 3); + ImGui::SliderFloat2("Skew", skew, -3, 3); + ImGui::SliderFloat4("Path XYWH", path_rect, -1000, 1000); } ImGui::End(); std::shared_ptr input; Size input_size; + auto input_rect = + Rect::MakeXYWH(path_rect[0], path_rect[1], path_rect[2], path_rect[3]); if (selected_input_type == 0) { auto texture = std::make_shared(); - auto input_rect = Rect::MakeSize(boston->GetSize()); - texture->SetSourceRect(input_rect); + texture->SetSourceRect(Rect::MakeSize(boston->GetSize())); texture->SetPath(PathBuilder{}.AddRect(input_rect).TakePath()); texture->SetTexture(boston); texture->SetOpacity(input_color.alpha); @@ -920,7 +925,6 @@ TEST_P(EntityTest, GaussianBlurFilter) { input_size = input_rect.size; } else { auto fill = std::make_shared(); - auto input_rect = Rect::MakeSize(boston->GetSize()); fill->SetColor(input_color); fill->SetPath(PathBuilder{}.AddRect(input_rect).TakePath()); @@ -964,8 +968,7 @@ TEST_P(EntityTest, GaussianBlurFilter) { // unfiltered input. Entity cover_entity; cover_entity.SetContents(SolidColorContents::Make( - PathBuilder{}.AddRect(Rect::MakeSize(input_size)).TakePath(), - cover_color)); + PathBuilder{}.AddRect(input_rect).TakePath(), cover_color)); cover_entity.SetTransformation(ctm); cover_entity.Render(context, pass); @@ -1504,7 +1507,8 @@ TEST_P(EntityTest, ColorMatrixFilterEditable) { label.c_str(); for (int i = 0; i < 20; i += 5) { ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float, - &(color_matrix.array[i]), 5, NULL, NULL, "%.2f", 0); + &(color_matrix.array[i]), 5, nullptr, nullptr, + "%.2f", 0); label[2]++; } From e7cadc42973b8bed8bc821b6d22a0f9d8f08fd3d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 13:30:14 -0400 Subject: [PATCH 373/558] Roll Skia from 4b720a135d0d to 9c0d90c2a9ab (4 revisions) (#35465) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c0669c0b972e1..891e9a79fa561 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': '4b720a135d0d755bb901e2397b971a48df56694d', + 'skia_revision': '9c0d90c2a9ab91083e81dc19454e56e38e09c913', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index b2ec890010868..1731321d21850 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 1c4de7b494d39d32665f8a1a683391df +Signature: 4a77b936c5b20788ed6b4317fea18727 UNUSED LICENSES: From 3df3a6e8eba5314f518151bedd6da0a981e9f32f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 13:38:13 -0400 Subject: [PATCH 374/558] Roll Fuchsia Mac SDK from 82kDMgkOeplHieWa6... to R1EXVFo9K-RXLNVOG... (#35466) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 891e9a79fa561..856ea8bf184fb 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': '82kDMgkOeplHieWa6F8XhIj84EU8igyYxEKA_I2twvMC' + 'version': 'R1EXVFo9K-RXLNVOGPk4JquIgcTl8EeFWHPqRrx4SiIC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From f86e19f3572326f9a85f364756838d00b5a900b9 Mon Sep 17 00:00:00 2001 From: Jenn Magder Date: Wed, 17 Aug 2022 11:15:05 -0700 Subject: [PATCH 375/558] Prevent leaking inputViews between iOS unit tests (#35450) --- .../darwin/ios/framework/Source/FlutterTextInputPluginTest.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm index 41ed193411a84..aec571a812510 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterTextInputPluginTest.mm @@ -1137,6 +1137,7 @@ - (void)testInputViewsHasNonNilInputDelegate { @"composingExtent" : @3 }]; OCMVerify([mockInputView setInputDelegate:[OCMArg isNotNil]]); + [inputView removeFromSuperview]; } } From 6f8c99debd14e7d2d3555cea53f6c6e11f8343e9 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Wed, 17 Aug 2022 11:22:58 -0700 Subject: [PATCH 376/558] Roll buildroot to 4dfab138e7dcc4d174ad0032c102d0f9055ba904. (#35310) --- DEPS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 856ea8bf184fb..800faf9684de8 100644 --- a/DEPS +++ b/DEPS @@ -61,7 +61,7 @@ vars = { 'download_dart_sdk': True, # Checkout Android dependencies only on platforms where we build for Android targets. - 'download_android_deps': 'host_os == "mac" or host_os == "linux"', + 'download_android_deps': 'host_os == "mac" or (host_os == "linux" and host_cpu == "x64")', # Checkout Windows dependencies only if we are building on Windows. 'download_windows_deps' : 'host_os == "win"', @@ -102,7 +102,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + '0881a07a2203d23e21712cc5829ec5469ae19e3d', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '4dfab138e7dcc4d174ad0032c102d0f9055ba904', # Fuchsia compatibility # @@ -638,7 +638,7 @@ deps = { 'src/buildtools/linux-arm64/clang': { 'packages': [ { - 'package': 'fuchsia/third_party/clang/linux-amd64', + 'package': 'fuchsia/third_party/clang/linux-arm64', 'version': 'git_revision:d9e02a30b16ea65a7da87913c40af03e22c9571f' } ], From 8eda7e4d730229f1eabe84a41bd2515fc9ec0172 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 17 Aug 2022 11:39:22 -0700 Subject: [PATCH 377/558] Clean up blend filter (#35456) --- impeller/entity/contents/contents.cc | 14 +- .../contents/filters/blend_filter_contents.cc | 361 ++++++++++-------- .../contents/filters/blend_filter_contents.h | 13 +- 3 files changed, 206 insertions(+), 182 deletions(-) diff --git a/impeller/entity/contents/contents.cc b/impeller/entity/contents/contents.cc index c0f4831f1e442..a6c77db7bb5fa 100644 --- a/impeller/entity/contents/contents.cc +++ b/impeller/entity/contents/contents.cc @@ -32,19 +32,19 @@ Contents::~Contents() = default; std::optional Contents::RenderToSnapshot( const ContentContext& renderer, const Entity& entity) const { - auto bounds = GetCoverage(entity); - if (!bounds.has_value()) { + auto coverage = GetCoverage(entity); + if (!coverage.has_value()) { return std::nullopt; } auto texture = renderer.MakeSubpass( - ISize::Ceil(bounds->size), - [&contents = *this, &entity, &bounds](const ContentContext& renderer, - RenderPass& pass) -> bool { + ISize::Ceil(coverage->size), + [&contents = *this, &entity, &coverage](const ContentContext& renderer, + RenderPass& pass) -> bool { Entity sub_entity; sub_entity.SetBlendMode(Entity::BlendMode::kSourceOver); sub_entity.SetTransformation( - Matrix::MakeTranslation(Vector3(-bounds->origin)) * + Matrix::MakeTranslation(Vector3(-coverage->origin)) * entity.GetTransformation()); return contents.Render(renderer, sub_entity, pass); }); @@ -54,7 +54,7 @@ std::optional Contents::RenderToSnapshot( } return Snapshot{.texture = texture, - .transform = Matrix::MakeTranslation(bounds->origin)}; + .transform = Matrix::MakeTranslation(coverage->origin)}; } bool Contents::ShouldRender(const Entity& entity, diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index cfbbe2296f202..2a8e647fee3b3 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -28,29 +28,33 @@ using PipelineProc = std::shared_ptr (ContentContext::*)(ContentContextOptions) const; template -static bool AdvancedBlend(const FilterInput::Vector& inputs, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - const Rect& coverage, - std::optional foreground_color, - PipelineProc pipeline_proc) { +static std::optional AdvancedBlend( + const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage, + std::optional foreground_color, + PipelineProc pipeline_proc) { using VS = typename TPipeline::VertexShader; using FS = typename TPipeline::FragmentShader; + //---------------------------------------------------------------------------- + /// Handle inputs. + /// + const size_t total_inputs = inputs.size() + (foreground_color.has_value() ? 1 : 0); if (total_inputs < 2) { - return false; + return std::nullopt; } auto dst_snapshot = inputs[0]->GetSnapshot(renderer, entity); if (!dst_snapshot.has_value()) { - return true; + return std::nullopt; } auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(coverage); if (!maybe_dst_uvs.has_value()) { - return true; + return std::nullopt; } auto dst_uvs = maybe_dst_uvs.value(); @@ -59,175 +63,208 @@ static bool AdvancedBlend(const FilterInput::Vector& inputs, if (!foreground_color.has_value()) { src_snapshot = inputs[1]->GetSnapshot(renderer, entity); if (!src_snapshot.has_value()) { - return true; + return std::nullopt; } auto maybe_src_uvs = src_snapshot->GetCoverageUVs(coverage); if (!maybe_src_uvs.has_value()) { - return true; + return std::nullopt; } src_uvs = maybe_src_uvs.value(); } - auto& host_buffer = pass.GetTransientsBuffer(); - - auto size = pass.GetRenderTargetSize(); - VertexBufferBuilder vtx_builder; - vtx_builder.AddVertices({ - {Point(0, 0), dst_uvs[0], src_uvs[0]}, - {Point(size.width, 0), dst_uvs[1], src_uvs[1]}, - {Point(size.width, size.height), dst_uvs[3], src_uvs[3]}, - {Point(0, 0), dst_uvs[0], src_uvs[0]}, - {Point(size.width, size.height), dst_uvs[3], src_uvs[3]}, - {Point(0, size.height), dst_uvs[2], src_uvs[2]}, - }); - auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); - - auto options = OptionsFromPassAndEntity(pass, entity); - std::shared_ptr pipeline = - std::invoke(pipeline_proc, renderer, options); - - Command cmd; - cmd.label = "Advanced Blend Filter"; - cmd.BindVertices(vtx_buffer); - cmd.pipeline = std::move(pipeline); - - typename FS::BlendInfo blend_info; - - auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); - FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, sampler); - blend_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); - - if (foreground_color.has_value()) { - blend_info.color_factor = 1; - blend_info.color = foreground_color.value(); - // This texture will not be sampled from due to the color factor. But this - // is present so that validation doesn't trip on a missing binding. - FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, sampler); - } else { - blend_info.color_factor = 0; - FS::BindTextureSamplerSrc(cmd, src_snapshot->texture, sampler); - blend_info.src_y_coord_scale = src_snapshot->texture->GetYCoordScale(); - } - auto blend_uniform = host_buffer.EmplaceUniform(blend_info); - FS::BindBlendInfo(cmd, blend_uniform); - - typename VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(size); - - auto uniform_view = host_buffer.EmplaceUniform(frame_info); - VS::BindFrameInfo(cmd, uniform_view); - pass.AddCommand(cmd); - - return true; -} - -static bool PipelineBlend(const FilterInput::Vector& inputs, - const ContentContext& renderer, - const Entity& entity, - RenderPass& pass, - const Rect& coverage, - Entity::BlendMode pipeline_blend, - std::optional foreground_color) { - using VS = BlendPipeline::VertexShader; - using FS = BlendPipeline::FragmentShader; - - auto& host_buffer = pass.GetTransientsBuffer(); - - auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); + //---------------------------------------------------------------------------- + /// Render to texture. + /// - Command cmd; - cmd.label = "Pipeline Blend Filter"; - auto options = OptionsFromPass(pass); - - auto add_blend_command = [&](std::optional input) { - if (!input.has_value()) { - return false; - } - auto input_coverage = input->GetCoverage(); - if (!input_coverage.has_value()) { - return false; - } - - FS::BindTextureSamplerSrc(cmd, input->texture, sampler); + ContentContext::SubpassCallback callback = [&](const ContentContext& renderer, + RenderPass& pass) { + auto& host_buffer = pass.GetTransientsBuffer(); - auto size = input->texture->GetSize(); - VertexBufferBuilder vtx_builder; + auto size = pass.GetRenderTargetSize(); + VertexBufferBuilder vtx_builder; vtx_builder.AddVertices({ - {Point(0, 0), Point(0, 0)}, - {Point(size.width, 0), Point(1, 0)}, - {Point(size.width, size.height), Point(1, 1)}, - {Point(0, 0), Point(0, 0)}, - {Point(size.width, size.height), Point(1, 1)}, - {Point(0, size.height), Point(0, 1)}, + {Point(0, 0), dst_uvs[0], src_uvs[0]}, + {Point(size.width, 0), dst_uvs[1], src_uvs[1]}, + {Point(size.width, size.height), dst_uvs[3], src_uvs[3]}, + {Point(0, 0), dst_uvs[0], src_uvs[0]}, + {Point(size.width, size.height), dst_uvs[3], src_uvs[3]}, + {Point(0, size.height), dst_uvs[2], src_uvs[2]}, }); auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + + auto options = OptionsFromPassAndEntity(pass, entity); + std::shared_ptr pipeline = + std::invoke(pipeline_proc, renderer, options); + + Command cmd; + cmd.label = "Advanced Blend Filter"; cmd.BindVertices(vtx_buffer); + cmd.pipeline = std::move(pipeline); + + typename FS::BlendInfo blend_info; + + auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); + FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, sampler); + blend_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale(); + + if (foreground_color.has_value()) { + blend_info.color_factor = 1; + blend_info.color = foreground_color.value(); + // This texture will not be sampled from due to the color factor. But + // this is present so that validation doesn't trip on a missing + // binding. + FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, sampler); + } else { + blend_info.color_factor = 0; + FS::BindTextureSamplerSrc(cmd, src_snapshot->texture, sampler); + blend_info.src_y_coord_scale = src_snapshot->texture->GetYCoordScale(); + } + auto blend_uniform = host_buffer.EmplaceUniform(blend_info); + FS::BindBlendInfo(cmd, blend_uniform); - VS::FrameInfo frame_info; - frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * - Matrix::MakeTranslation(-coverage.origin) * - input->transform; + typename VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(size); auto uniform_view = host_buffer.EmplaceUniform(frame_info); VS::BindFrameInfo(cmd, uniform_view); - pass.AddCommand(cmd); + return true; }; - // Draw the first texture using kSource. - - options.blend_mode = Entity::BlendMode::kSource; - cmd.pipeline = renderer.GetBlendPipeline(options); - if (!add_blend_command(inputs[0]->GetSnapshot(renderer, entity))) { - return true; + auto out_texture = renderer.MakeSubpass(ISize(coverage.size), callback); + if (!out_texture) { + return std::nullopt; } + out_texture->SetLabel("Advanced Blend Filter Texture"); - // Write subsequent textures using the selected blend mode. + return Snapshot{.texture = out_texture, + .transform = Matrix::MakeTranslation(coverage.origin), + .sampler_descriptor = dst_snapshot->sampler_descriptor}; +} - if (inputs.size() >= 2) { - options.blend_mode = pipeline_blend; +static std::optional PipelineBlend( + const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage, + Entity::BlendMode pipeline_blend, + std::optional foreground_color) { + using VS = BlendPipeline::VertexShader; + using FS = BlendPipeline::FragmentShader; + + ContentContext::SubpassCallback callback = [&](const ContentContext& renderer, + RenderPass& pass) { + auto& host_buffer = pass.GetTransientsBuffer(); + + auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); + + Command cmd; + cmd.label = "Pipeline Blend Filter"; + auto options = OptionsFromPass(pass); + + auto add_blend_command = [&](std::optional input) { + if (!input.has_value()) { + return false; + } + auto input_coverage = input->GetCoverage(); + if (!input_coverage.has_value()) { + return false; + } + + FS::BindTextureSamplerSrc(cmd, input->texture, sampler); + + auto size = input->texture->GetSize(); + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0, 0), Point(0, 0)}, + {Point(size.width, 0), Point(1, 0)}, + {Point(size.width, size.height), Point(1, 1)}, + {Point(0, 0), Point(0, 0)}, + {Point(size.width, size.height), Point(1, 1)}, + {Point(0, size.height), Point(0, 1)}, + }); + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + cmd.BindVertices(vtx_buffer); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * + Matrix::MakeTranslation(-coverage.origin) * + input->transform; + + auto uniform_view = host_buffer.EmplaceUniform(frame_info); + VS::BindFrameInfo(cmd, uniform_view); + + pass.AddCommand(cmd); + return true; + }; + + // Draw the first texture using kSource. + + options.blend_mode = Entity::BlendMode::kSource; cmd.pipeline = renderer.GetBlendPipeline(options); + if (!add_blend_command(inputs[0]->GetSnapshot(renderer, entity))) { + return true; + } - for (auto texture_i = inputs.begin() + 1; texture_i < inputs.end(); - texture_i++) { - auto input = texture_i->get()->GetSnapshot(renderer, entity); - if (!add_blend_command(input)) { - return true; + // Write subsequent textures using the selected blend mode. + + if (inputs.size() >= 2) { + options.blend_mode = pipeline_blend; + cmd.pipeline = renderer.GetBlendPipeline(options); + + for (auto texture_i = inputs.begin() + 1; texture_i < inputs.end(); + texture_i++) { + auto input = texture_i->get()->GetSnapshot(renderer, entity); + if (!add_blend_command(input)) { + return true; + } } } - } - // If a foreground color is set, blend it in. + // If a foreground color is set, blend it in. - if (foreground_color.has_value()) { - auto contents = std::make_shared(); - contents->SetPath(PathBuilder{} - .AddRect(Rect::MakeSize(pass.GetRenderTargetSize())) - .TakePath()); - contents->SetColor(foreground_color.value()); + if (foreground_color.has_value()) { + auto contents = std::make_shared(); + contents->SetPath(PathBuilder{} + .AddRect(Rect::MakeSize(pass.GetRenderTargetSize())) + .TakePath()); + contents->SetColor(foreground_color.value()); - Entity foreground_entity; - foreground_entity.SetBlendMode(pipeline_blend); - foreground_entity.SetContents(contents); - if (!foreground_entity.Render(renderer, pass)) { - return false; + Entity foreground_entity; + foreground_entity.SetBlendMode(pipeline_blend); + foreground_entity.SetContents(contents); + if (!foreground_entity.Render(renderer, pass)) { + return false; + } } + + return true; + }; + + auto out_texture = renderer.MakeSubpass(ISize(coverage.size), callback); + if (!out_texture) { + return std::nullopt; } + out_texture->SetLabel("Pipeline Blend Filter Texture"); - return true; + return Snapshot{ + .texture = out_texture, + .transform = Matrix::MakeTranslation(coverage.origin), + .sampler_descriptor = + inputs[0]->GetSnapshot(renderer, entity)->sampler_descriptor}; } -#define BLEND_CASE(mode) \ - case Entity::BlendMode::k##mode: \ - advanced_blend_proc_ = \ - [](const FilterInput::Vector& inputs, const ContentContext& renderer, \ - const Entity& entity, RenderPass& pass, const Rect& coverage, \ - std::optional fg_color) { \ - PipelineProc p = &ContentContext::GetBlend##mode##Pipeline; \ - return AdvancedBlend( \ - inputs, renderer, entity, pass, coverage, fg_color, p); \ - }; \ +#define BLEND_CASE(mode) \ + case Entity::BlendMode::k##mode: \ + advanced_blend_proc_ = [](const FilterInput::Vector& inputs, \ + const ContentContext& renderer, \ + const Entity& entity, const Rect& coverage, \ + std::optional fg_color) { \ + PipelineProc p = &ContentContext::GetBlend##mode##Pipeline; \ + return AdvancedBlend(inputs, renderer, entity, \ + coverage, fg_color, p); \ + }; \ break; void BlendFilterContents::SetBlendMode(Entity::BlendMode blend_mode) { @@ -277,34 +314,22 @@ std::optional BlendFilterContents::RenderFilter( return std::nullopt; } - ContentContext::SubpassCallback callback = [&](const ContentContext& renderer, - RenderPass& pass) { - if (inputs.size() == 1 && !foreground_color_.has_value()) { - // Nothing to blend. - return PipelineBlend(inputs, renderer, entity, pass, coverage, - Entity::BlendMode::kSource, std::nullopt); - } - - if (blend_mode_ <= Entity::BlendMode::kLastPipelineBlendMode) { - return PipelineBlend(inputs, renderer, entity, pass, coverage, - blend_mode_, foreground_color_); - } - - if (blend_mode_ <= Entity::BlendMode::kLastAdvancedBlendMode) { - return advanced_blend_proc_(inputs, renderer, entity, pass, coverage, - foreground_color_); - } - FML_UNREACHABLE(); - }; + if (inputs.size() == 1 && !foreground_color_.has_value()) { + // Nothing to blend. + return PipelineBlend(inputs, renderer, entity, coverage, + Entity::BlendMode::kSource, std::nullopt); + } - auto out_texture = renderer.MakeSubpass(ISize(coverage.size), callback); - if (!out_texture) { - return std::nullopt; + if (blend_mode_ <= Entity::BlendMode::kLastPipelineBlendMode) { + return PipelineBlend(inputs, renderer, entity, coverage, blend_mode_, + foreground_color_); } - out_texture->SetLabel("BlendFilter Texture"); - return Snapshot{.texture = out_texture, - .transform = Matrix::MakeTranslation(coverage.origin)}; + if (blend_mode_ <= Entity::BlendMode::kLastAdvancedBlendMode) { + return advanced_blend_proc_(inputs, renderer, entity, coverage, + foreground_color_); + } + FML_UNREACHABLE(); } } // namespace impeller diff --git a/impeller/entity/contents/filters/blend_filter_contents.h b/impeller/entity/contents/filters/blend_filter_contents.h index 464038c9fc464..22ec3040364b8 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.h +++ b/impeller/entity/contents/filters/blend_filter_contents.h @@ -11,13 +11,12 @@ namespace impeller { class BlendFilterContents : public FilterContents { public: - using AdvancedBlendProc = - std::function foreground_color)>; + using AdvancedBlendProc = std::function( + const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage, + std::optional foreground_color)>; BlendFilterContents(); From c107ae73a373862a16a9e6e376df6d4a036833b8 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 14:41:51 -0400 Subject: [PATCH 378/558] Roll Skia from 9c0d90c2a9ab to 2c809890958e (1 revision) (#35467) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 800faf9684de8..6d3f7d403618d 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': '9c0d90c2a9ab91083e81dc19454e56e38e09c913', + 'skia_revision': '2c809890958ed6543f97717ba50b92936880ef8f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 1731321d21850..220b5f83a1f8a 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 4a77b936c5b20788ed6b4317fea18727 +Signature: 4cc7a622d7364e176339799d098ae066 UNUSED LICENSES: From a91226d88602599440ec347188ab8461501d367b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 15:20:13 -0400 Subject: [PATCH 379/558] Roll Clang Linux from 3a20597776a5 to d9e02a30b16e (#35469) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 6d3f7d403618d..9332c47f75a9a 100644 --- a/DEPS +++ b/DEPS @@ -628,7 +628,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/clang/linux-amd64', - 'version': 'git_revision:3a20597776a5d2920e511d81653b4d2b6ca0c855' + 'version': 'git_revision:d9e02a30b16ea65a7da87913c40af03e22c9571f' } ], 'condition': 'host_os == "linux" and host_cpu == "x64"', From 4b32f2ea24622011729face61e91bf09e6178de0 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 15:57:20 -0400 Subject: [PATCH 380/558] Roll Skia from 2c809890958e to ea5dda2e0bfb (4 revisions) (#35471) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 9332c47f75a9a..c420fbeda8a88 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': '2c809890958ed6543f97717ba50b92936880ef8f', + 'skia_revision': 'ea5dda2e0bfbdd7619ac8339dfeb906ed1666162', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 220b5f83a1f8a..1f712804be2e2 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 4cc7a622d7364e176339799d098ae066 +Signature: e367af7999540bd3545e89008e7516dd UNUSED LICENSES: From 4b8d1fad35cd2ebbf7cc575c295686b12749de48 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 16:17:05 -0400 Subject: [PATCH 381/558] Roll Dart SDK from 12d3e976a829 to e28a15dfbb27 (3 revisions) (#35472) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index c420fbeda8a88..ea964112b736e 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '12d3e976a829f5bd6814bbd3f49e704f7a109df7', + 'dart_revision': 'e28a15dfbb27468240805b1a72dc15e459343f7b', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -46,7 +46,7 @@ vars = { 'dart_clock_rev': '2507a228773c5e877fc9e3330080b234aad965c0', 'dart_collection_rev': '414ffa1bc8ba18bd608bbf916d95715311d89ac1', 'dart_devtools_rev': 'd131d19091f6b89ac89486bd92440a25a523e8b0', - 'dart_protobuf_rev': '7edcdde795cd63f147d4b3c9c054d6bcd8b0ead2', + 'dart_protobuf_rev': '9cf05f6e9f53d88b4b6c1f6f1accec09bcd5cca7', 'dart_pub_rev': 'ac7db6c07318efa4a8712110275eaf70f96a6d00', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': 'e00c0ea769e32821d91c0880da8eb736839a6e6d', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index eecdf91c29b6e..fde8b20e40978 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 06a1546eea452adff5a0d818fa6c132f +Signature: 204d0cc3d9d2ac5b972976a5c835aa9a UNUSED LICENSES: From e8d5233a81b62833c5a9afe9b8cfe8ec35c7927f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 17:13:04 -0400 Subject: [PATCH 382/558] Roll Skia from ea5dda2e0bfb to c4a974300ee6 (3 revisions) (#35475) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index ea964112b736e..669fcfd44ae4f 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': 'ea5dda2e0bfbdd7619ac8339dfeb906ed1666162', + 'skia_revision': 'c4a974300ee6e1f94cd8aa0af640dd3b63b29d66', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 1f712804be2e2..1d076e71ffa58 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e367af7999540bd3545e89008e7516dd +Signature: d891a472c409694deb94e692b549598f UNUSED LICENSES: @@ -2043,7 +2043,6 @@ FILE: ../../../third_party/skia/src/core/SkAutoMalloc.h FILE: ../../../third_party/skia/src/core/SkAutoPixmapStorage.cpp FILE: ../../../third_party/skia/src/core/SkAutoPixmapStorage.h FILE: ../../../third_party/skia/src/core/SkBlendModePriv.h -FILE: ../../../third_party/skia/src/core/SkColorFilter_Matrix.h FILE: ../../../third_party/skia/src/core/SkColorSpace.cpp FILE: ../../../third_party/skia/src/core/SkColorSpacePriv.h FILE: ../../../third_party/skia/src/core/SkCpu.cpp From fbbd8c6bab64982f6fbce27eac0927e47b96771c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Wed, 17 Aug 2022 14:50:46 -0700 Subject: [PATCH 383/558] [Windows] Don't crash if GetPointerType is unsupported (#35442) --- ci/licenses_golden/licenses_flutter | 2 + shell/platform/windows/BUILD.gn | 4 + shell/platform/windows/direct_manipulation.h | 5 +- .../testing/mock_direct_manipulation.h | 30 +++++ shell/platform/windows/testing/mock_window.cc | 10 +- shell/platform/windows/testing/mock_window.h | 7 +- .../windows/testing/mock_windows_proc_table.h | 30 +++++ shell/platform/windows/window.cc | 19 ++-- shell/platform/windows/window.h | 8 +- shell/platform/windows/window_unittests.cc | 104 ++++++++++++++++-- shell/platform/windows/windows_proc_table.cc | 28 +++++ shell/platform/windows/windows_proc_table.h | 42 +++++++ 12 files changed, 269 insertions(+), 20 deletions(-) create mode 100644 shell/platform/windows/testing/mock_direct_manipulation.h create mode 100644 shell/platform/windows/testing/mock_windows_proc_table.h create mode 100644 shell/platform/windows/windows_proc_table.cc create mode 100644 shell/platform/windows/windows_proc_table.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 45074c8482c87..3b3ec37ae638d 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2487,6 +2487,8 @@ FILE: ../../../flutter/shell/platform/windows/window_proc_delegate_manager.h FILE: ../../../flutter/shell/platform/windows/window_proc_delegate_manager_unittests.cc FILE: ../../../flutter/shell/platform/windows/window_state.h FILE: ../../../flutter/shell/platform/windows/window_unittests.cc +FILE: ../../../flutter/shell/platform/windows/windows_proc_table.cc +FILE: ../../../flutter/shell/platform/windows/windows_proc_table.h FILE: ../../../flutter/shell/profiling/sampling_profiler.cc FILE: ../../../flutter/shell/profiling/sampling_profiler.h FILE: ../../../flutter/shell/profiling/sampling_profiler_unittest.cc diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 194e17f1f1e6d..fd570feb1abae 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -103,6 +103,8 @@ source_set("flutter_windows_source") { "window_proc_delegate_manager.cc", "window_proc_delegate_manager.h", "window_state.h", + "windows_proc_table.cc", + "windows_proc_table.h", ] libs = [ @@ -189,6 +191,7 @@ executable("flutter_windows_unittests") { "testing/engine_modifier.h", "testing/flutter_window_test.cc", "testing/flutter_window_test.h", + "testing/mock_direct_manipulation.h", "testing/mock_gl_functions.h", "testing/mock_text_input_manager.cc", "testing/mock_text_input_manager.h", @@ -196,6 +199,7 @@ executable("flutter_windows_unittests") { "testing/mock_window.h", "testing/mock_window_binding_handler.cc", "testing/mock_window_binding_handler.h", + "testing/mock_windows_proc_table.h", "testing/test_keyboard.cc", "testing/test_keyboard.h", "testing/test_keyboard_unittests.cc", diff --git a/shell/platform/windows/direct_manipulation.h b/shell/platform/windows/direct_manipulation.h index f25470ab4235d..40317333f6916 100644 --- a/shell/platform/windows/direct_manipulation.h +++ b/shell/platform/windows/direct_manipulation.h @@ -22,6 +22,7 @@ class DirectManipulationEventHandler; class DirectManipulationOwner { public: explicit DirectManipulationOwner(Window* window); + virtual ~DirectManipulationOwner() = default; // Initialize a DirectManipulation viewport with specified width and height. // These should match the width and height of the application window. int Init(unsigned int width, unsigned int height); @@ -34,7 +35,7 @@ class DirectManipulationOwner { WindowBindingHandlerDelegate* binding_handler_delegate); // Called when DM_POINTERHITTEST occurs with an acceptable pointer type. Will // start DirectManipulation for that interaction. - void SetContact(UINT contactId); + virtual void SetContact(UINT contactId); // Called to get updates from DirectManipulation. Should be called frequently // to provide smooth updates. void Update(); @@ -57,6 +58,8 @@ class DirectManipulationOwner { Microsoft::WRL::ComPtr viewport_; // Child needed for operation of the DirectManipulation API. fml::RefPtr handler_; + + FML_DISALLOW_COPY_AND_ASSIGN(DirectManipulationOwner); }; // Implements DirectManipulation event handling interfaces, receives calls from diff --git a/shell/platform/windows/testing/mock_direct_manipulation.h b/shell/platform/windows/testing/mock_direct_manipulation.h new file mode 100644 index 0000000000000..be1fe35027f07 --- /dev/null +++ b/shell/platform/windows/testing/mock_direct_manipulation.h @@ -0,0 +1,30 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_DIRECT_MANIPULATION_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_DIRECT_MANIPULATION_H_ + +#include "flutter/shell/platform/windows/direct_manipulation.h" +#include "gmock/gmock.h" + +namespace flutter { +namespace testing { + +/// Mock for the |DirectManipulationOwner| base class. +class MockDirectManipulationOwner : public DirectManipulationOwner { + public: + explicit MockDirectManipulationOwner(Window* window) + : DirectManipulationOwner(window){}; + virtual ~MockDirectManipulationOwner() = default; + + MOCK_METHOD1(SetContact, void(UINT contact_id)); + + private: + FML_DISALLOW_COPY_AND_ASSIGN(MockDirectManipulationOwner); +}; + +} // namespace testing +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_DIRECT_MANIPULATION_H_ diff --git a/shell/platform/windows/testing/mock_window.cc b/shell/platform/windows/testing/mock_window.cc index a6d3dcda64b14..9021aecb3352a 100644 --- a/shell/platform/windows/testing/mock_window.cc +++ b/shell/platform/windows/testing/mock_window.cc @@ -7,8 +7,9 @@ namespace flutter { namespace testing { MockWindow::MockWindow() : Window(){}; -MockWindow::MockWindow(std::unique_ptr text_input_manager) - : Window(std::move(text_input_manager)){}; +MockWindow::MockWindow(std::unique_ptr window_proc_table, + std::unique_ptr text_input_manager) + : Window(std::move(window_proc_table), std::move(text_input_manager)){}; MockWindow::~MockWindow() = default; @@ -23,6 +24,11 @@ LRESULT MockWindow::Win32DefWindowProc(HWND hWnd, return kWmResultDefault; } +void MockWindow::SetDirectManipulationOwner( + std::unique_ptr owner) { + direct_manipulation_owner_ = std::move(owner); +} + LRESULT MockWindow::InjectWindowMessage(UINT const message, WPARAM const wparam, LPARAM const lparam) { diff --git a/shell/platform/windows/testing/mock_window.h b/shell/platform/windows/testing/mock_window.h index 107e016c390f8..8885096fa1d28 100644 --- a/shell/platform/windows/testing/mock_window.h +++ b/shell/platform/windows/testing/mock_window.h @@ -18,7 +18,8 @@ namespace testing { class MockWindow : public Window { public: MockWindow(); - MockWindow(std::unique_ptr text_input_manager); + MockWindow(std::unique_ptr windows_proc_table, + std::unique_ptr text_input_manager); virtual ~MockWindow(); // Prevent copying. @@ -28,6 +29,10 @@ class MockWindow : public Window { // Wrapper for GetCurrentDPI() which is a protected method. UINT GetDpi(); + // Set the Direct Manipulation owner for testing purposes. + void SetDirectManipulationOwner( + std::unique_ptr owner); + // Simulates a WindowProc message from the OS. LRESULT InjectWindowMessage(UINT const message, WPARAM const wparam, diff --git a/shell/platform/windows/testing/mock_windows_proc_table.h b/shell/platform/windows/testing/mock_windows_proc_table.h new file mode 100644 index 0000000000000..7c136def68654 --- /dev/null +++ b/shell/platform/windows/testing/mock_windows_proc_table.h @@ -0,0 +1,30 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WINDOWS_PROC_TABLE_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WINDOWS_PROC_TABLE_H_ + +#include "flutter/shell/platform/windows/windows_proc_table.h" +#include "gmock/gmock.h" + +namespace flutter { +namespace testing { + +/// Mock for the |WindowsProcTable| base class. +class MockWindowsProcTable : public WindowsProcTable { + public: + MockWindowsProcTable() = default; + virtual ~MockWindowsProcTable() = default; + + MOCK_METHOD2(GetPointerType, + BOOL(UINT32 pointer_id, POINTER_INPUT_TYPE* pointer_type)); + + private: + FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsProcTable); +}; + +} // namespace testing +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_MOCK_WINDOWS_PROC_TABLE_H_ diff --git a/shell/platform/windows/window.cc b/shell/platform/windows/window.cc index a61ac35a4c909..08f5368a1472a 100644 --- a/shell/platform/windows/window.cc +++ b/shell/platform/windows/window.cc @@ -52,10 +52,12 @@ static const int kLinesPerScrollWindowsDefault = 3; } // namespace -Window::Window() : Window(nullptr) {} +Window::Window() : Window(nullptr, nullptr) {} -Window::Window(std::unique_ptr text_input_manager) +Window::Window(std::unique_ptr windows_proc_table, + std::unique_ptr text_input_manager) : touch_id_generator_(kMinTouchDeviceId, kMaxTouchDeviceId), + windows_proc_table_(std::move(windows_proc_table)), text_input_manager_(std::move(text_input_manager)) { // Get the DPI of the primary monitor as the initial DPI. If Per-Monitor V2 is // supported, |current_dpi_| should be updated in the @@ -67,6 +69,9 @@ Window::Window(std::unique_ptr text_input_manager) // https://github.com/flutter/flutter/issues/107248 UpdateScrollOffsetMultiplier(); + if (windows_proc_table_ == nullptr) { + windows_proc_table_ = std::make_unique(); + } if (text_input_manager_ == nullptr) { text_input_manager_ = std::make_unique(); } @@ -482,11 +487,11 @@ Window::HandleMessage(UINT const message, break; case DM_POINTERHITTEST: { if (direct_manipulation_owner_) { - UINT contactId = GET_POINTERID_WPARAM(wparam); - POINTER_INPUT_TYPE pointerType; - if (GetPointerType(contactId, &pointerType) && - pointerType == PT_TOUCHPAD) { - direct_manipulation_owner_->SetContact(contactId); + UINT contact_id = GET_POINTERID_WPARAM(wparam); + POINTER_INPUT_TYPE pointer_type; + if (windows_proc_table_->GetPointerType(contact_id, &pointer_type) && + pointer_type == PT_TOUCHPAD) { + direct_manipulation_owner_->SetContact(contact_id); } } break; diff --git a/shell/platform/windows/window.h b/shell/platform/windows/window.h index fe62fa5d2e965..7782803b10a52 100644 --- a/shell/platform/windows/window.h +++ b/shell/platform/windows/window.h @@ -18,6 +18,7 @@ #include "flutter/shell/platform/windows/keyboard_manager.h" #include "flutter/shell/platform/windows/sequential_id_generator.h" #include "flutter/shell/platform/windows/text_input_manager.h" +#include "flutter/shell/platform/windows/windows_proc_table.h" #include "flutter/third_party/accessibility/gfx/native_widget_types.h" namespace flutter { @@ -28,7 +29,8 @@ namespace flutter { class Window : public KeyboardManager::WindowDelegate { public: Window(); - Window(std::unique_ptr text_input_manager); + Window(std::unique_ptr windows_proc_table, + std::unique_ptr text_input_manager); virtual ~Window(); // Initializes as a child window with size using |width| and |height| and @@ -266,6 +268,10 @@ class Window : public KeyboardManager::WindowDelegate { double mouse_x_ = 0; double mouse_y_ = 0; + // Abstracts Windows APIs that may not be available on all supported versions + // of Windows. + std::unique_ptr windows_proc_table_; + // Manages IME state. std::unique_ptr text_input_manager_; diff --git a/shell/platform/windows/window_unittests.cc b/shell/platform/windows/window_unittests.cc index 22750e2755a90..1557d03b7a6a3 100644 --- a/shell/platform/windows/window_unittests.cc +++ b/shell/platform/windows/window_unittests.cc @@ -4,11 +4,15 @@ #include +#include "flutter/shell/platform/windows/testing/mock_direct_manipulation.h" #include "flutter/shell/platform/windows/testing/mock_text_input_manager.h" #include "flutter/shell/platform/windows/testing/mock_window.h" +#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" using testing::_; +using testing::Eq; using testing::InSequence; using testing::Invoke; using testing::Return; @@ -39,9 +43,11 @@ TEST(MockWindow, VerticalScroll) { } TEST(MockWindow, OnImeCompositionCompose) { - MockTextInputManager* text_input_manager = new MockTextInputManager(); + auto windows_proc_table = std::make_unique(); + auto* text_input_manager = new MockTextInputManager(); std::unique_ptr text_input_manager_ptr(text_input_manager); - MockWindow window(std::move(text_input_manager_ptr)); + MockWindow window(std::move(windows_proc_table), + std::move(text_input_manager_ptr)); EXPECT_CALL(*text_input_manager, GetComposingString()) .WillRepeatedly( Return(std::optional(std::u16string(u"nihao")))); @@ -63,9 +69,11 @@ TEST(MockWindow, OnImeCompositionCompose) { } TEST(MockWindow, OnImeCompositionResult) { - MockTextInputManager* text_input_manager = new MockTextInputManager(); + auto windows_proc_table = std::make_unique(); + auto* text_input_manager = new MockTextInputManager(); std::unique_ptr text_input_manager_ptr(text_input_manager); - MockWindow window(std::move(text_input_manager_ptr)); + MockWindow window(std::move(windows_proc_table), + std::move(text_input_manager_ptr)); EXPECT_CALL(*text_input_manager, GetComposingString()) .WillRepeatedly( Return(std::optional(std::u16string(u"nihao")))); @@ -87,9 +95,11 @@ TEST(MockWindow, OnImeCompositionResult) { } TEST(MockWindow, OnImeCompositionResultAndCompose) { - MockTextInputManager* text_input_manager = new MockTextInputManager(); + auto windows_proc_table = std::make_unique(); + auto* text_input_manager = new MockTextInputManager(); std::unique_ptr text_input_manager_ptr(text_input_manager); - MockWindow window(std::move(text_input_manager_ptr)); + MockWindow window(std::move(windows_proc_table), + std::move(text_input_manager_ptr)); // This situation is that Google Japanese Input finished composing "今日" in // "今日は" but is still composing "は". @@ -123,9 +133,11 @@ TEST(MockWindow, OnImeCompositionResultAndCompose) { } TEST(MockWindow, OnImeCompositionClearChange) { - MockTextInputManager* text_input_manager = new MockTextInputManager(); + auto windows_proc_table = std::make_unique(); + auto* text_input_manager = new MockTextInputManager(); std::unique_ptr text_input_manager_ptr(text_input_manager); - MockWindow window(std::move(text_input_manager_ptr)); + MockWindow window(std::move(windows_proc_table), + std::move(text_input_manager_ptr)); EXPECT_CALL(window, OnComposeChange(std::u16string(u""), 0)).Times(1); EXPECT_CALL(window, OnComposeCommit()).Times(1); ON_CALL(window, OnImeComposition) @@ -272,5 +284,81 @@ TEST(MockWindow, Paint) { window.InjectWindowMessage(WM_PAINT, 0, 0); } +// Verify direct manipulation isn't notified of pointer hit tests. +TEST(MockWindow, PointerHitTest) { + UINT32 pointer_id = 123; + auto windows_proc_table = std::make_unique(); + auto text_input_manager = std::make_unique(); + + EXPECT_CALL(*windows_proc_table, GetPointerType(Eq(pointer_id), _)) + .Times(1) + .WillOnce([](UINT32 pointer_id, POINTER_INPUT_TYPE* type) { + *type = PT_POINTER; + return TRUE; + }); + + MockWindow window(std::move(windows_proc_table), + std::move(text_input_manager)); + + auto direct_manipulation = + std::make_unique(&window); + + EXPECT_CALL(*direct_manipulation, SetContact).Times(0); + + window.SetDirectManipulationOwner(std::move(direct_manipulation)); + window.InjectWindowMessage(DM_POINTERHITTEST, MAKEWPARAM(pointer_id, 0), 0); +} + +// Verify direct manipulation is notified of touchpad hit tests. +TEST(MockWindow, TouchPadHitTest) { + UINT32 pointer_id = 123; + auto windows_proc_table = std::make_unique(); + auto text_input_manager = std::make_unique(); + + EXPECT_CALL(*windows_proc_table, GetPointerType(Eq(pointer_id), _)) + .Times(1) + .WillOnce([](UINT32 pointer_id, POINTER_INPUT_TYPE* type) { + *type = PT_TOUCHPAD; + return TRUE; + }); + + MockWindow window(std::move(windows_proc_table), + std::move(text_input_manager)); + + auto direct_manipulation = + std::make_unique(&window); + + EXPECT_CALL(*direct_manipulation, SetContact(Eq(pointer_id))).Times(1); + + window.SetDirectManipulationOwner(std::move(direct_manipulation)); + window.InjectWindowMessage(DM_POINTERHITTEST, MAKEWPARAM(pointer_id, 0), 0); +} + +// Verify direct manipulation isn't notified of unknown hit tests. +// This can happen if determining the pointer type fails, for example, +// if GetPointerType is unsupported by the current Windows version. +// See: https://github.com/flutter/flutter/issues/109412 +TEST(MockWindow, UnknownPointerTypeSkipsDirectManipulation) { + UINT32 pointer_id = 123; + auto windows_proc_table = std::make_unique(); + auto text_input_manager = std::make_unique(); + + EXPECT_CALL(*windows_proc_table, GetPointerType(Eq(pointer_id), _)) + .Times(1) + .WillOnce( + [](UINT32 pointer_id, POINTER_INPUT_TYPE* type) { return FALSE; }); + + MockWindow window(std::move(windows_proc_table), + std::move(text_input_manager)); + + auto direct_manipulation = + std::make_unique(&window); + + EXPECT_CALL(*direct_manipulation, SetContact).Times(0); + + window.SetDirectManipulationOwner(std::move(direct_manipulation)); + window.InjectWindowMessage(DM_POINTERHITTEST, MAKEWPARAM(pointer_id, 0), 0); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/windows_proc_table.cc b/shell/platform/windows/windows_proc_table.cc new file mode 100644 index 0000000000000..d2b5bd99f4264 --- /dev/null +++ b/shell/platform/windows/windows_proc_table.cc @@ -0,0 +1,28 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/windows/windows_proc_table.h" + +namespace flutter { + +WindowsProcTable::WindowsProcTable() { + user32_ = fml::NativeLibrary::Create("user32.dll"); + get_pointer_type_ = + user32_->ResolveFunction("GetPointerType"); +} + +WindowsProcTable::~WindowsProcTable() { + user32_ = nullptr; +} + +BOOL WindowsProcTable::GetPointerType(UINT32 pointer_id, + POINTER_INPUT_TYPE* pointer_type) { + if (!get_pointer_type_.has_value()) { + return FALSE; + } + + return get_pointer_type_.value()(pointer_id, pointer_type); +} + +} // namespace flutter diff --git a/shell/platform/windows/windows_proc_table.h b/shell/platform/windows/windows_proc_table.h new file mode 100644 index 0000000000000..db6397d2e4781 --- /dev/null +++ b/shell/platform/windows/windows_proc_table.h @@ -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. + +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOWS_PROC_TABLE_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOWS_PROC_TABLE_H_ + +#include "flutter/fml/native_library.h" + +#include + +namespace flutter { + +// Lookup table for Windows APIs that aren't available on all versions of +// Windows. +class WindowsProcTable { + public: + WindowsProcTable(); + virtual ~WindowsProcTable(); + + // Retrieves the pointer type for a specified pointer. + // + // Used to react differently to touch or pen inputs. Returns false on failure. + // Available in Windows 8 and newer, otherwise returns false. + virtual BOOL GetPointerType(UINT32 pointer_id, + POINTER_INPUT_TYPE* pointer_type); + + private: + using GetPointerType_ = BOOL __stdcall(UINT32 pointerId, + POINTER_INPUT_TYPE* pointerType); + + // The User32.dll library, used to resolve functions at runtime. + fml::RefPtr user32_; + + std::optional get_pointer_type_; + + FML_DISALLOW_COPY_AND_ASSIGN(WindowsProcTable); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOWS_PROC_TABLE_H_ From 61d68749a3aac802a831a1207be3246a1aa6ae21 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 17 Aug 2022 14:55:06 -0700 Subject: [PATCH 384/558] don't report GPU image size (#35473) --- lib/ui/painting/image.cc | 14 ++++---------- lib/ui/painting/image_encoding_unittests.cc | 1 + 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/ui/painting/image.cc b/lib/ui/painting/image.cc index 91a6c6eea7a08..c0c8f47beada6 100644 --- a/lib/ui/painting/image.cc +++ b/lib/ui/painting/image.cc @@ -40,15 +40,9 @@ void CanvasImage::dispose() { } size_t CanvasImage::GetAllocationSize() const { - auto size = sizeof(this); - if (image_) { - size += image_->GetApproximateByteSize(); - } - // The VM will assert if we set a value larger than or close to - // std::numeric_limits::max(). - // https://github.com/dart-lang/sdk/issues/49332 - return std::clamp( - size, static_cast(0), - static_cast(std::numeric_limits::max() / 10)); + // We don't actually want Dart's GC to use the size of this object to make GC + // decisions, as it is generally both created and disposed in the framework. + // This is similar to why we do not report the sizes of engine layers. + return sizeof(*this); } } // namespace flutter diff --git a/lib/ui/painting/image_encoding_unittests.cc b/lib/ui/painting/image_encoding_unittests.cc index 7b6d0eb8c1965..22dd425ffc21d 100644 --- a/lib/ui/painting/image_encoding_unittests.cc +++ b/lib/ui/painting/image_encoding_unittests.cc @@ -125,6 +125,7 @@ TEST_F(ShellTest, EncodeImageAccessesSyncSwitch) { image_handle, tonic::DartWrappable::kPeerIndex, &peer); ASSERT_FALSE(Dart_IsError(result)); CanvasImage* canvas_image = reinterpret_cast(peer); + ASSERT_EQ(canvas_image->GetAllocationSize(), sizeof(*canvas_image)); int64_t format = -1; result = Dart_IntegerToInt64(format_handle, &format); From 96124d11a2d4e5ce6a62e59100f0630071c4cf90 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 18:25:02 -0400 Subject: [PATCH 385/558] Roll Skia from c4a974300ee6 to 02b8283c77d7 (3 revisions) (#35476) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 669fcfd44ae4f..f6eb04c3ee76b 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': 'c4a974300ee6e1f94cd8aa0af640dd3b63b29d66', + 'skia_revision': '02b8283c77d7516b99c27a0e6b5039e208d328d5', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 1d076e71ffa58..cb510ba5e6a48 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d891a472c409694deb94e692b549598f +Signature: 1a21d18a9217cb3846235870be5b6f3c UNUSED LICENSES: From 32d8c521da4bd1c461e2d0db6a25ab3a64e6df77 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 19:37:07 -0400 Subject: [PATCH 386/558] Roll Skia from 02b8283c77d7 to ee397c6f083e (3 revisions) (#35477) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f6eb04c3ee76b..598b189c43289 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': '02b8283c77d7516b99c27a0e6b5039e208d328d5', + 'skia_revision': 'ee397c6f083eaed489f7dbc137d893dc24e3e07c', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index cb510ba5e6a48..f673fe24e996d 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 1a21d18a9217cb3846235870be5b6f3c +Signature: a4e07f51e85734f8700e500fb8820a67 UNUSED LICENSES: From 654f8029aad43c2a032495ffbd695e5d717cc79e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 17 Aug 2022 20:47:22 -0400 Subject: [PATCH 387/558] Roll Skia from ee397c6f083e to 4d50c634c2bf (2 revisions) (#35480) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 598b189c43289..164480afd47e9 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': 'ee397c6f083eaed489f7dbc137d893dc24e3e07c', + 'skia_revision': '4d50c634c2bf643a82f97c930721a91433e804df', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f673fe24e996d..c71d56f8c3be8 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: a4e07f51e85734f8700e500fb8820a67 +Signature: 975d1d5d06c835e3c0770e914b625166 UNUSED LICENSES: From a77ead45a80a8d5306a47345c50c38aec687a0df Mon Sep 17 00:00:00 2001 From: Xilai Zhang Date: Wed, 17 Aug 2022 17:55:36 -0700 Subject: [PATCH 388/558] [gn + codesign] use join to concatenate (#35474) --- sky/tools/create_full_ios_framework.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sky/tools/create_full_ios_framework.py b/sky/tools/create_full_ios_framework.py index c90087ef1526f..fb3dd707b595c 100644 --- a/sky/tools/create_full_ios_framework.py +++ b/sky/tools/create_full_ios_framework.py @@ -167,14 +167,14 @@ def create_framework( def embed_codesign_configuration(config_path, contents): with open(config_path, 'w') as f: - f.writelines(contents) + f.write('\n'.join(contents) + '\n') def zip_archive(dst): - ios_file_with_entitlements = ['gen_snapshot_arm64\n'] + ios_file_with_entitlements = ['gen_snapshot_arm64'] ios_file_without_entitlements = [ - 'Flutter.xcframework/ios-arm64/Flutter.framework/Flutter\n', - 'Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter\n' + 'Flutter.xcframework/ios-arm64/Flutter.framework/Flutter', + 'Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter' ] embed_codesign_configuration( os.path.join(dst, 'entitlements.txt'), ios_file_with_entitlements From 3d85fe7ee454b642780f867d64d3c506dfc2a621 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 01:57:12 -0400 Subject: [PATCH 389/558] Roll Skia from 4d50c634c2bf to 751cad567169 (1 revision) (#35483) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 164480afd47e9..fbd027f4e2da5 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': '4d50c634c2bf643a82f97c930721a91433e804df', + 'skia_revision': '751cad5671694c27e03518ced923081079d7b87c', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index c71d56f8c3be8..0b88a5bc32088 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 975d1d5d06c835e3c0770e914b625166 +Signature: b2cddc66dc898ef08f8bc1d004c7d2cb UNUSED LICENSES: From 9807e5ce95c7eae5183864576948b4f97fd4c732 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 02:34:47 -0400 Subject: [PATCH 390/558] Roll Fuchsia Mac SDK from R1EXVFo9K-RXLNVOG... to 1hIAHHOhq9Acf2u3d... (#35484) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index fbd027f4e2da5..e1ac9fa6e7d41 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'R1EXVFo9K-RXLNVOGPk4JquIgcTl8EeFWHPqRrx4SiIC' + 'version': '1hIAHHOhq9Acf2u3dwEe2__qTlaQTSxxm5o6s_RK1qMC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 34024512fa931ce4c984fa3c174c57c615321d97 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 02:42:08 -0400 Subject: [PATCH 391/558] Roll Fuchsia Linux SDK from OkIFye3iRfA9DknTF... to gqQZ7EN2TeYTzOqKI... (#35485) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 315 ++++++++++++---------------- sky/packages/sky_engine/LICENSE | 28 --- 3 files changed, 139 insertions(+), 206 deletions(-) diff --git a/DEPS b/DEPS index e1ac9fa6e7d41..ee3f44a1891b0 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'OkIFye3iRfA9DknTFPlAZ-xJdNubmiaj1DOQgJqxRPAC' + 'version': 'gqQZ7EN2TeYTzOqKIjxGXNNpoDcz68MXn-l9Vtg2fYoC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 18a777b923b07..c7b22d2885907 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: a318ffc376bb966a95c05568cf493f5b +Signature: 1b38c5821e7b2fd78bd830c6346c2ef5 UNUSED LICENSES: @@ -561,6 +561,7 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.scenic/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.types/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.views/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ultrasound/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.unknown/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.channel/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.channelcontrol/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.config/meta.json @@ -1312,6 +1313,7 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.scenic/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.types/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.views/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ultrasound/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.unknown/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.channel/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.channelcontrol/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.config/meta.json @@ -1960,6 +1962,7 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.scenic/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.types/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.views/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ultrasound/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.unknown/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.channel/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.channelcontrol/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.config/meta.json @@ -2395,7 +2398,6 @@ TYPE: LicenseType.bsd FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/boot/bootfs.h FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/boot/driver-config.h FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/boot/image.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/boot/sysconfig.h FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/dlfcn.h FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/features.h FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/pci.h @@ -2407,7 +2409,6 @@ FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/time.h FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/boot/bootfs.h FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/boot/driver-config.h FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/boot/image.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/boot/sysconfig.h FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/dlfcn.h FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/features.h FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/pci.h @@ -2853,174 +2854,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== -==================================================================================================== -LIBRARY: fuchsia_sdk -ORIGIN: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/boot/multiboot.h + ../../../fuchsia/sdk/linux/LICENSE -TYPE: LicenseType.bsd -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/boot/multiboot.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/boot/multiboot.h ----------------------------------------------------------------------------------------------------- -Copyright 2016 The Fuchsia Authors. All rights reserved. -Copyright (c) 2009 Corey Tabaka - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -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. -==================================================================================================== - -==================================================================================================== -LIBRARY: fuchsia_sdk -ORIGIN: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/boot/netboot.h + ../../../fuchsia/sdk/linux/LICENSE -TYPE: LicenseType.bsd -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/assert.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/boot/netboot.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/compiler.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/errors.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/i2c.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/usb.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/usb/audio.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/usb/hid.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/usb/ums.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/listnode.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/pixelformat.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/processargs.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/status.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/debug.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/exception.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/log.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/object.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/pci.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/port.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/profile.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/resource.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/types.h -FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/types.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/assert.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/boot/netboot.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/compiler.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/errors.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/i2c.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/usb.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/usb/audio.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/usb/hid.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/usb/ums.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/listnode.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/pixelformat.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/processargs.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/status.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/debug.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/exception.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/log.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/object.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/pci.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/port.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/profile.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/resource.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/types.h -FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/types.h -FILE: ../../../fuchsia/sdk/linux/dart/fidl/lib/src/interface.dart -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component.runner/component_runner.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.fonts/font_provider.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.math/math.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.media.playback/problem.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.media.playback/seeking_reader.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.media/audio.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/module_context.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/session_shell.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/story_controller.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/story_info.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/story_provider.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/component_controller.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/environment.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/environment_controller.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/launcher.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/loader.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/runner.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.tracing.provider/provider.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.policy/presenter.fidl -FILE: ../../../fuchsia/sdk/linux/pkg/fdio/include/lib/fdio/fdio.h -FILE: ../../../fuchsia/sdk/linux/pkg/fdio/include/lib/fdio/io.h -FILE: ../../../fuchsia/sdk/linux/pkg/fdio/include/lib/fdio/vfs.h -FILE: ../../../fuchsia/sdk/linux/pkg/fdio/include/lib/fdio/watcher.h -FILE: ../../../fuchsia/sdk/linux/pkg/fit/include/lib/fit/thread_checker.h -FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp_no_converters/include/lib/media/cpp/timeline_function.h -FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp_no_converters/include/lib/media/cpp/timeline_rate.h -FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp_no_converters/timeline_function.cc -FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp_no_converters/timeline_rate.cc -FILE: ../../../fuchsia/sdk/linux/pkg/sync/include/lib/sync/completion.h -FILE: ../../../fuchsia/sdk/linux/pkg/sys_cpp/include/lib/sys/cpp/termination_reason.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/channel.cc -FILE: ../../../fuchsia/sdk/linux/pkg/zx/event.cc -FILE: ../../../fuchsia/sdk/linux/pkg/zx/eventpair.cc -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/channel.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/event.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/eventpair.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/job.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/object.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/object_traits.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/port.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/process.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/socket.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/task.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/thread.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/time.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/vmar.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/vmo.h -FILE: ../../../fuchsia/sdk/linux/pkg/zx/job.cc -FILE: ../../../fuchsia/sdk/linux/pkg/zx/port.cc -FILE: ../../../fuchsia/sdk/linux/pkg/zx/process.cc -FILE: ../../../fuchsia/sdk/linux/pkg/zx/socket.cc -FILE: ../../../fuchsia/sdk/linux/pkg/zx/thread.cc -FILE: ../../../fuchsia/sdk/linux/pkg/zx/vmar.cc -FILE: ../../../fuchsia/sdk/linux/pkg/zx/vmo.cc ----------------------------------------------------------------------------------------------------- -Copyright 2016 The Fuchsia Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -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. -==================================================================================================== - ==================================================================================================== LIBRARY: fuchsia_sdk ORIGIN: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/device/audio.h + ../../../fuchsia/sdk/linux/LICENSE @@ -3307,13 +3140,12 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.input.report/touch.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.input.report/units.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.inspect/tree.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.intl/property_provider.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.io/connection-info.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.io/connection-options.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.io/directory2.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.io/file2.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.io/io.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.io/node-protocols.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.io/node2.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.io/rights-request.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.kernel/kernel-counter.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.kernel/kernel-debug.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.kernel/kernel-stats.fidl @@ -3474,7 +3306,6 @@ FILE: ../../../fuchsia/sdk/linux/pkg/vfs_cpp/include/lib/vfs/cpp/internal/file_c FILE: ../../../fuchsia/sdk/linux/pkg/vfs_cpp/include/lib/vfs/cpp/internal/node.h FILE: ../../../fuchsia/sdk/linux/pkg/vfs_cpp/include/lib/vfs/cpp/internal/node_connection.h FILE: ../../../fuchsia/sdk/linux/pkg/vfs_cpp/include/lib/vfs/cpp/lazy_dir.h -FILE: ../../../fuchsia/sdk/linux/pkg/vfs_cpp/include/lib/vfs/cpp/node_kind.h FILE: ../../../fuchsia/sdk/linux/pkg/vfs_cpp/include/lib/vfs/cpp/pseudo_dir.h FILE: ../../../fuchsia/sdk/linux/pkg/vfs_cpp/include/lib/vfs/cpp/pseudo_file.h FILE: ../../../fuchsia/sdk/linux/pkg/vfs_cpp/include/lib/vfs/cpp/remote_dir.h @@ -3525,6 +3356,136 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== +==================================================================================================== +LIBRARY: fuchsia_sdk +ORIGIN: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/usb/audio.h + ../../../fuchsia/sdk/linux/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/assert.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/compiler.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/errors.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/usb.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/usb/audio.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/usb/hid.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/hw/usb/ums.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/listnode.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/pixelformat.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/processargs.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/status.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/debug.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/exception.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/log.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/object.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/pci.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/port.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/profile.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/resource.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/syscalls/types.h +FILE: ../../../fuchsia/sdk/linux/arch/arm64/sysroot/include/zircon/types.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/assert.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/compiler.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/errors.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/usb.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/usb/audio.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/usb/hid.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/hw/usb/ums.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/listnode.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/pixelformat.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/processargs.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/status.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/debug.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/exception.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/log.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/object.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/pci.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/port.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/profile.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/resource.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/syscalls/types.h +FILE: ../../../fuchsia/sdk/linux/arch/x64/sysroot/include/zircon/types.h +FILE: ../../../fuchsia/sdk/linux/dart/fidl/lib/src/interface.dart +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.component.runner/component_runner.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.fonts/font_provider.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.math/math.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.media.playback/problem.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.media.playback/seeking_reader.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.media/audio.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/module_context.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/session_shell.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/story_controller.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/story_info.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.modular/story_provider.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/component_controller.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/environment.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/environment_controller.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/launcher.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/loader.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.sys/runner.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.tracing.provider/provider.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.policy/presenter.fidl +FILE: ../../../fuchsia/sdk/linux/pkg/fdio/include/lib/fdio/fdio.h +FILE: ../../../fuchsia/sdk/linux/pkg/fdio/include/lib/fdio/io.h +FILE: ../../../fuchsia/sdk/linux/pkg/fdio/include/lib/fdio/vfs.h +FILE: ../../../fuchsia/sdk/linux/pkg/fdio/include/lib/fdio/watcher.h +FILE: ../../../fuchsia/sdk/linux/pkg/fit/include/lib/fit/thread_checker.h +FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp_no_converters/include/lib/media/cpp/timeline_function.h +FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp_no_converters/include/lib/media/cpp/timeline_rate.h +FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp_no_converters/timeline_function.cc +FILE: ../../../fuchsia/sdk/linux/pkg/media_cpp_no_converters/timeline_rate.cc +FILE: ../../../fuchsia/sdk/linux/pkg/sync/include/lib/sync/completion.h +FILE: ../../../fuchsia/sdk/linux/pkg/sys_cpp/include/lib/sys/cpp/termination_reason.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/channel.cc +FILE: ../../../fuchsia/sdk/linux/pkg/zx/event.cc +FILE: ../../../fuchsia/sdk/linux/pkg/zx/eventpair.cc +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/channel.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/event.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/eventpair.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/job.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/object.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/object_traits.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/port.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/process.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/socket.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/task.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/thread.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/time.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/vmar.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/include/lib/zx/vmo.h +FILE: ../../../fuchsia/sdk/linux/pkg/zx/job.cc +FILE: ../../../fuchsia/sdk/linux/pkg/zx/port.cc +FILE: ../../../fuchsia/sdk/linux/pkg/zx/process.cc +FILE: ../../../fuchsia/sdk/linux/pkg/zx/socket.cc +FILE: ../../../fuchsia/sdk/linux/pkg/zx/thread.cc +FILE: ../../../fuchsia/sdk/linux/pkg/zx/vmar.cc +FILE: ../../../fuchsia/sdk/linux/pkg/zx/vmo.cc +---------------------------------------------------------------------------------------------------- +Copyright 2016 The Fuchsia Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +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. +==================================================================================================== + ==================================================================================================== LIBRARY: fuchsia_sdk ORIGIN: ../../../fuchsia/sdk/linux/dart/fidl/lib/fidl.dart + ../../../LICENSE @@ -3616,7 +3577,6 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.images/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.input.report/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.input/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.intl/overview.fidl -FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.io/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.kernel/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.legacymetrics/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.lightsensor/overview.fidl @@ -3669,6 +3629,7 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointerinjector/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.policy/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.scenic/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.views/overview.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.unknown/unknown.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.config/config.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.weave/overview.fidl @@ -3685,7 +3646,7 @@ FILE: ../../../fuchsia/sdk/linux/pkg/async/include/lib/async/sequence_id.h FILE: ../../../fuchsia/sdk/linux/pkg/fidl_base/include/lib/fidl/cpp/transaction_header.h FILE: ../../../fuchsia/sdk/linux/pkg/fidl_base/include/lib/fidl/cpp/transport_err.h FILE: ../../../fuchsia/sdk/linux/pkg/fidl_base/include/lib/fidl/cpp/wire_format_metadata.h -FILE: ../../../fuchsia/sdk/linux/pkg/fidl_cpp/include/lib/fidl/cpp/internal/transport_err_hlcpp.h +FILE: ../../../fuchsia/sdk/linux/pkg/fidl_cpp/include/lib/fidl/cpp/unknown_interactions_hlcpp.h FILE: ../../../fuchsia/sdk/linux/pkg/fit/include/lib/fit/inline_any.h FILE: ../../../fuchsia/sdk/linux/pkg/fit/include/lib/fit/inline_any_internal.h FILE: ../../../fuchsia/sdk/linux/pkg/inspect/client.shard.cml @@ -3860,4 +3821,4 @@ 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: 17 +Total license count: 16 diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index a9e91b2f11ea2..0d79c7f510f5c 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -7469,34 +7469,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- fuchsia_sdk -Copyright 2016 The Fuchsia Authors. All rights reserved. -Copyright (c) 2009 Corey Tabaka - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -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. --------------------------------------------------------------------------------- -fuchsia_sdk - Copyright 2017 The Fuchsia Authors. All rights reserved. Redistribution and use in source and binary forms, with or without From 1311fea574d64b37e42c2ba5e16f7872671233d7 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 03:09:38 -0400 Subject: [PATCH 392/558] Roll Skia from 751cad567169 to 246d7e915ff6 (1 revision) (#35486) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ee3f44a1891b0..8001eafd76f7b 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': '751cad5671694c27e03518ced923081079d7b87c', + 'skia_revision': '246d7e915ff63b88e8c66b9f777dd6c04ab55a80', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 0b88a5bc32088..48c0e603ee876 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b2cddc66dc898ef08f8bc1d004c7d2cb +Signature: 1fa2791e4c1852661efa87cbe00d4e17 UNUSED LICENSES: From e85e13d3d2ff85731b43f2829e33b36222d07c35 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 11:56:08 -0400 Subject: [PATCH 393/558] Roll Skia from 246d7e915ff6 to c9cdc4aef040 (1 revision) (#35494) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 8001eafd76f7b..62d8372c6df7c 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': '246d7e915ff63b88e8c66b9f777dd6c04ab55a80', + 'skia_revision': 'c9cdc4aef040fb0c09005c78591f70b489315501', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 73b5da22efa7733924e280c8e5e4681cd5598b07 Mon Sep 17 00:00:00 2001 From: "Stephen (Alex) Wallen" Date: Thu, 18 Aug 2022 09:04:07 -0700 Subject: [PATCH 394/558] [macOS] A11y Zoom Crash (#35453) --- .../ax/platform/ax_platform_node_mac.mm | 4 +++- .../platform/ax_platform_node_mac_unittest.mm | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/third_party/accessibility/ax/platform/ax_platform_node_mac.mm b/third_party/accessibility/ax/platform/ax_platform_node_mac.mm index 78c318bba2e36..572b2ca741266 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_mac.mm +++ b/third_party/accessibility/ax/platform/ax_platform_node_mac.mm @@ -1016,7 +1016,9 @@ - (NSRange)accessibilityRangeForLine:(NSInteger)line { } - (NSRange)accessibilityRangeForPosition:(NSPoint)point { - BASE_UNREACHABLE(); + // TODO(a-wallen): Framework needs to send Text Metrics + // to the AXTree in order for a NSPoint (x, y) to be + // translated to the appropriate range of UTF-16 chars. return NSMakeRange(0, 0); } diff --git a/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.mm b/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.mm index 7597942518466..2b7629a8c0655 100644 --- a/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.mm +++ b/third_party/accessibility/ax/platform/ax_platform_node_mac_unittest.mm @@ -46,4 +46,25 @@ EXPECT_TRUE(native_root != nullptr); } +// Test that [AXPlatformNodeCocoa accessbilityRangeForPosition:] doesn't crash. +// https://github.com/flutter/flutter/issues/102416 +TEST_F(AXPlatformNodeMacTest, AccessibilityRangeForPositionDoesntCrash) { + AXNodeData root; + root.id = 1; + root.relative_bounds.bounds = gfx::RectF(0, 0, 40, 40); + + Init(root); + AXNode* root_node = GetRootAsAXNode(); + ASSERT_TRUE(root_node != nullptr); + + AXPlatformNode* platform_node = AXPlatformNodeFromNode(root_node); + ASSERT_TRUE(platform_node != nullptr); + + NSPoint point = NSMakePoint(0, 0); + AXPlatformNodeCocoa* native_root = platform_node->GetNativeViewAccessible(); + ASSERT_TRUE(native_root != nullptr); + + [native_root accessibilityRangeForPosition:(NSPoint)point]; +} + } // namespace ui From bf5582d35cb2adaaec56dfe5c64e7a8fa0dab003 Mon Sep 17 00:00:00 2001 From: Chris Evans Date: Thu, 18 Aug 2022 17:26:53 +0100 Subject: [PATCH 395/558] Add analyze_snapshot as a build dependency (#35495) --- BUILD.gn | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BUILD.gn b/BUILD.gn index 97c2c4fe9c38a..c775e52733b2e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -90,7 +90,7 @@ group("flutter") { } } - # If enbaled, compile the SDK / snapshot. + # If enabled, compile the SDK / snapshot. if (!is_fuchsia) { public_deps += [ "//flutter/lib/snapshot:generate_snapshot_bins" ] @@ -104,6 +104,9 @@ group("flutter") { # gen_snapshot for the host and not the target. "//third_party/dart/runtime/bin:gen_snapshot", + # Built alongside gen_snapshot for 64 bit targets + "//third_party/dart/runtime/bin:analyze_snapshot", + # Impeller artifacts - compiler and libtessellator "//flutter/impeller/compiler:impellerc", "//flutter/impeller/tessellator:tessellator_shared", From 0e3ea3e723265bcd3c03dfaa452cec199707c5f3 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 12:33:23 -0400 Subject: [PATCH 396/558] Roll Dart SDK from e28a15dfbb27 to d89d5a7170f1 (4 revisions) (#35496) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 62d8372c6df7c..c9bd5bbf0ab43 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'e28a15dfbb27468240805b1a72dc15e459343f7b', + 'dart_revision': 'd89d5a7170f11e4a4df9dd181cba4490a444fcee', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index fde8b20e40978..ae0832e00ba42 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 204d0cc3d9d2ac5b972976a5c835aa9a +Signature: 1848a5ce55d69934a9554b0e9dc098e3 UNUSED LICENSES: From b8603c05f086785e31c462d581d0a78b17c46819 Mon Sep 17 00:00:00 2001 From: xiaomiao Date: Fri, 19 Aug 2022 00:43:24 +0800 Subject: [PATCH 397/558] Move task running to UI thread for loadDartDefferredLibrary. (#35460) --- shell/common/shell.cc | 22 +++++++++++++++++---- shell/common/shell_unittests.cc | 34 ++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/shell/common/shell.cc b/shell/common/shell.cc index bc8594bc90cdb..25ad7d7f94332 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -1371,15 +1371,29 @@ void Shell::LoadDartDeferredLibrary( void Shell::LoadDartDeferredLibraryError(intptr_t loading_unit_id, const std::string error_message, bool transient) { - engine_->LoadDartDeferredLibraryError(loading_unit_id, error_message, - transient); + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetUITaskRunner(), + [engine = weak_engine_, loading_unit_id, error_message, transient] { + if (engine) { + engine->LoadDartDeferredLibraryError(loading_unit_id, error_message, + transient); + } + }); } void Shell::UpdateAssetResolverByType( std::unique_ptr updated_asset_resolver, AssetResolver::AssetResolverType type) { - engine_->GetAssetManager()->UpdateResolverByType( - std::move(updated_asset_resolver), type); + fml::TaskRunner::RunNowOrPostTask( + task_runners_.GetUITaskRunner(), + fml::MakeCopyable( + [engine = weak_engine_, type, + asset_resolver = std::move(updated_asset_resolver)]() mutable { + if (engine) { + engine->GetAssetManager()->UpdateResolverByType( + std::move(asset_resolver), type); + } + })); } // |Engine::Delegate| diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 124dbf5d45a70..5d513b5239541 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -3339,9 +3339,9 @@ TEST_F(ShellTest, ImageGeneratorRegistryNotNullAfterParentShellDestroyed) { TEST_F(ShellTest, UpdateAssetResolverByTypeReplaces) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture(); - ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", - ThreadHost::Type::Platform); - auto task_runner = thread_host.platform_thread->GetTaskRunner(); + + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); auto shell = CreateShell(std::move(settings), task_runners); @@ -3351,7 +3351,10 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeReplaces) { auto configuration = RunConfiguration::InferFromSettings(settings); configuration.SetEntrypoint("emptyMain"); auto asset_manager = configuration.GetAssetManager(); - RunEngine(shell.get(), std::move(configuration)); + + shell->RunEngine(std::move(configuration), [&](auto result) { + ASSERT_EQ(result, Engine::RunStatus::Success); + }); auto platform_view = std::make_unique(*shell.get(), std::move(task_runners)); @@ -3381,9 +3384,9 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeReplaces) { TEST_F(ShellTest, UpdateAssetResolverByTypeAppends) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture(); - ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".", - ThreadHost::Type::Platform); - auto task_runner = thread_host.platform_thread->GetTaskRunner(); + + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); auto shell = CreateShell(std::move(settings), task_runners); @@ -3393,7 +3396,10 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeAppends) { auto configuration = RunConfiguration::InferFromSettings(settings); configuration.SetEntrypoint("emptyMain"); auto asset_manager = configuration.GetAssetManager(); - RunEngine(shell.get(), std::move(configuration)); + + shell->RunEngine(std::move(configuration), [&](auto result) { + ASSERT_EQ(result, Engine::RunStatus::Success); + }); auto platform_view = std::make_unique(*shell.get(), std::move(task_runners)); @@ -3456,10 +3462,9 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeNull) { TEST_F(ShellTest, UpdateAssetResolverByTypeDoesNotReplaceMismatchType) { ASSERT_FALSE(DartVMRef::IsInstanceRunning()); Settings settings = CreateSettingsForFixture(); - ThreadHost thread_host(ThreadHost::ThreadHostConfig( - "io.flutter.test." + GetCurrentTestName() + ".", - ThreadHost::Type::Platform)); - auto task_runner = thread_host.platform_thread->GetTaskRunner(); + + fml::MessageLoop::EnsureInitializedForCurrentThread(); + auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); TaskRunners task_runners("test", task_runner, task_runner, task_runner, task_runner); auto shell = CreateShell(std::move(settings), task_runners); @@ -3469,7 +3474,10 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeDoesNotReplaceMismatchType) { auto configuration = RunConfiguration::InferFromSettings(settings); configuration.SetEntrypoint("emptyMain"); auto asset_manager = configuration.GetAssetManager(); - RunEngine(shell.get(), std::move(configuration)); + + shell->RunEngine(std::move(configuration), [&](auto result) { + ASSERT_EQ(result, Engine::RunStatus::Success); + }); auto platform_view = std::make_unique(*shell.get(), std::move(task_runners)); From 82465fc712bc1e9ef6dcefd5e5dbf06cfb616579 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 13:07:25 -0400 Subject: [PATCH 398/558] Roll Skia from c9cdc4aef040 to d59180011f60 (9 revisions) (#35498) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c9bd5bbf0ab43..9f5116ec02c33 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': 'c9cdc4aef040fb0c09005c78591f70b489315501', + 'skia_revision': 'd59180011f6068ab5d6e5f9ce996189b4c4f9e3f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 48c0e603ee876..ba20dbb6ade89 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 1fa2791e4c1852661efa87cbe00d4e17 +Signature: 667cf7714a63ffdb73773293f6180bd2 UNUSED LICENSES: From c090055485cf85510c7d26f6710b4e81f7739120 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 14:21:11 -0400 Subject: [PATCH 399/558] Roll Skia from d59180011f60 to 439c4708a042 (4 revisions) (#35500) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 9f5116ec02c33..1d36eb1477b0d 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': 'd59180011f6068ab5d6e5f9ce996189b4c4f9e3f', + 'skia_revision': '439c4708a0428dcba7e45c1549760309931c903f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index ba20dbb6ade89..36d8c28473e0f 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 667cf7714a63ffdb73773293f6180bd2 +Signature: 1892bb3f5de42e8b771b5d8e9a4b964d UNUSED LICENSES: From e14d885d3f628d6f1ea02f9c2625942a9f2ee5e7 Mon Sep 17 00:00:00 2001 From: simonla Date: Fri, 19 Aug 2022 02:45:47 +0800 Subject: [PATCH 400/558] Avoid object creation during each frame (#35343) --- .../android/io/flutter/view/VsyncWaiter.java | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/shell/platform/android/io/flutter/view/VsyncWaiter.java b/shell/platform/android/io/flutter/view/VsyncWaiter.java index c5021460da89b..80f5658dea569 100644 --- a/shell/platform/android/io/flutter/view/VsyncWaiter.java +++ b/shell/platform/android/io/flutter/view/VsyncWaiter.java @@ -47,6 +47,7 @@ public void onDisplayChanged(int displayId) { private static DisplayListener listener; private long refreshPeriodNanos = -1; private FlutterJNI flutterJNI; + private FrameCallback frameCallback = new FrameCallback(0); @NonNull public static VsyncWaiter getInstance(float fps, @NonNull FlutterJNI flutterJNI) { @@ -85,22 +86,41 @@ public static void reset() { listener = null; } + private class FrameCallback implements Choreographer.FrameCallback { + + private long cookie; + + FrameCallback(long cookie) { + this.cookie = cookie; + } + + @Override + public void doFrame(long frameTimeNanos) { + long delay = System.nanoTime() - frameTimeNanos; + if (delay < 0) { + delay = 0; + } + flutterJNI.onVsync(delay, refreshPeriodNanos, cookie); + frameCallback = this; + } + } + private final FlutterJNI.AsyncWaitForVsyncDelegate asyncWaitForVsyncDelegate = new FlutterJNI.AsyncWaitForVsyncDelegate() { + + private Choreographer.FrameCallback obtainFrameCallback(final long cookie) { + if (frameCallback != null) { + frameCallback.cookie = cookie; + FrameCallback ret = frameCallback; + frameCallback = null; + return ret; + } + return new FrameCallback(cookie); + } + @Override public void asyncWaitForVsync(long cookie) { - Choreographer.getInstance() - .postFrameCallback( - new Choreographer.FrameCallback() { - @Override - public void doFrame(long frameTimeNanos) { - long delay = System.nanoTime() - frameTimeNanos; - if (delay < 0) { - delay = 0; - } - flutterJNI.onVsync(delay, refreshPeriodNanos, cookie); - } - }); + Choreographer.getInstance().postFrameCallback(obtainFrameCallback(cookie)); } }; From da611f8b7e48fd639a289aacf0fd8f78ac8ac473 Mon Sep 17 00:00:00 2001 From: Bernardo Eilert Trevisan <43152751+betrevisan@users.noreply.github.com> Date: Thu, 18 Aug 2022 12:00:55 -0700 Subject: [PATCH 401/558] [Impeller] Linear Gamma to sRGB filter implementation. (#35388) --- ci/licenses_golden/licenses_flutter | 4 + .../display_list/display_list_dispatcher.cc | 7 +- impeller/entity/BUILD.gn | 4 + impeller/entity/contents/content_context.cc | 2 + impeller/entity/contents/content_context.h | 10 +++ .../contents/filters/filter_contents.cc | 8 ++ .../entity/contents/filters/filter_contents.h | 3 + .../filters/linear_to_srgb_filter_contents.cc | 83 +++++++++++++++++++ .../filters/linear_to_srgb_filter_contents.h | 29 +++++++ impeller/entity/entity_unittests.cc | 52 ++++++++++++ .../entity/shaders/linear_to_srgb_filter.frag | 28 +++++++ .../entity/shaders/linear_to_srgb_filter.vert | 15 ++++ 12 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc create mode 100644 impeller/entity/contents/filters/linear_to_srgb_filter_contents.h create mode 100644 impeller/entity/shaders/linear_to_srgb_filter.frag create mode 100644 impeller/entity/shaders/linear_to_srgb_filter.vert diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 3b3ec37ae638d..14de4f81e9b71 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -582,6 +582,8 @@ FILE: ../../../flutter/impeller/entity/contents/filters/inputs/filter_input.h FILE: ../../../flutter/impeller/entity/contents/filters/inputs/filter_input_unittests.cc FILE: ../../../flutter/impeller/entity/contents/filters/inputs/texture_filter_input.cc FILE: ../../../flutter/impeller/entity/contents/filters/inputs/texture_filter_input.h +FILE: ../../../flutter/impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc +FILE: ../../../flutter/impeller/entity/contents/filters/linear_to_srgb_filter_contents.h FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.cc FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.h FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc @@ -644,6 +646,8 @@ FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.frag FILE: ../../../flutter/impeller/entity/shaders/glyph_atlas.vert FILE: ../../../flutter/impeller/entity/shaders/gradient_fill.vert FILE: ../../../flutter/impeller/entity/shaders/linear_gradient_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/radial_gradient_fill.frag FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.frag FILE: ../../../flutter/impeller/entity/shaders/rrect_blur.vert diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 9f08a4bfc49e9..f483856b6a4dc 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -441,9 +441,10 @@ void DisplayListDispatcher::setColorFilter( UNIMPLEMENTED; break; case flutter::DlColorFilterType::kLinearToSrgbGamma: - FML_LOG(ERROR) << "requested DlColorFilterType::kLinearToSrgbGamma"; - UNIMPLEMENTED; - break; + paint_.color_filter = [](FilterInput::Ref input) { + return FilterContents::MakeLinearToSrgbFilter({input}); + }; + return; case flutter::DlColorFilterType::kUnknown: FML_LOG(ERROR) << "requested DlColorFilterType::kUnknown"; UNIMPLEMENTED; diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 8ac8d402be1b3..270f3c8a64baf 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -37,6 +37,8 @@ impeller_shaders("entity_shaders") { "shaders/glyph_atlas.frag", "shaders/glyph_atlas.vert", "shaders/gradient_fill.vert", + "shaders/linear_to_srgb_filter.frag", + "shaders/linear_to_srgb_filter.vert", "shaders/linear_gradient_fill.frag", "shaders/radial_gradient_fill.frag", "shaders/rrect_blur.vert", @@ -85,6 +87,8 @@ impeller_component("entity") { "contents/filters/inputs/filter_input.h", "contents/filters/inputs/texture_filter_input.cc", "contents/filters/inputs/texture_filter_input.h", + "contents/filters/linear_to_srgb_filter_contents.cc", + "contents/filters/linear_to_srgb_filter_contents.h", "contents/linear_gradient_contents.cc", "contents/linear_gradient_contents.h", "contents/radial_gradient_contents.cc", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 10d9bee9cc01e..030fb6b1398d4 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -199,6 +199,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); color_matrix_color_filter_pipelines_[{}] = CreateDefaultPipeline(*context_); + linear_to_srgb_filter_pipelines_[{}] = + CreateDefaultPipeline(*context_); solid_stroke_pipelines_[{}] = CreateDefaultPipeline(*context_); glyph_atlas_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 194278a437bd9..f984a1da068a1 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -42,6 +42,8 @@ #include "impeller/entity/glyph_atlas.vert.h" #include "impeller/entity/gradient_fill.vert.h" #include "impeller/entity/linear_gradient_fill.frag.h" +#include "impeller/entity/linear_to_srgb_filter.frag.h" +#include "impeller/entity/linear_to_srgb_filter.vert.h" #include "impeller/entity/radial_gradient_fill.frag.h" #include "impeller/entity/rrect_blur.frag.h" #include "impeller/entity/rrect_blur.vert.h" @@ -113,6 +115,8 @@ using BorderMaskBlurPipeline = using ColorMatrixColorFilterPipeline = PipelineT; +using LinearToSrgbFilterPipeline = + PipelineT; using SolidStrokePipeline = PipelineT; using GlyphAtlasPipeline = @@ -211,6 +215,11 @@ class ContentContext { return GetPipeline(color_matrix_color_filter_pipelines_, opts); } + std::shared_ptr GetLinearToSrgbFilterPipeline( + ContentContextOptions opts) const { + return GetPipeline(linear_to_srgb_filter_pipelines_, opts); + } + std::shared_ptr GetSolidStrokePipeline( ContentContextOptions opts) const { return GetPipeline(solid_stroke_pipelines_, opts); @@ -345,6 +354,7 @@ class ContentContext { mutable Variants border_mask_blur_pipelines_; mutable Variants color_matrix_color_filter_pipelines_; + mutable Variants linear_to_srgb_filter_pipelines_; mutable Variants solid_stroke_pipelines_; mutable Variants clip_pipelines_; mutable Variants glyph_atlas_pipelines_; diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index 115eac6b948ca..48a79fd87849f 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -19,6 +19,7 @@ #include "impeller/entity/contents/filters/color_matrix_filter_contents.h" #include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" +#include "impeller/entity/contents/filters/linear_to_srgb_filter_contents.h" #include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/path_builder.h" @@ -122,6 +123,13 @@ std::shared_ptr FilterContents::MakeColorMatrix( return filter; } +std::shared_ptr FilterContents::MakeLinearToSrgbFilter( + FilterInput::Ref input) { + auto filter = std::make_shared(); + filter->SetInputs({input}); + return filter; +} + FilterContents::FilterContents() = default; FilterContents::~FilterContents() = default; diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index b3064b4475025..677ebc1dbae15 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -66,6 +66,9 @@ class FilterContents : public Contents { FilterInput::Ref input, const ColorMatrix& matrix); + static std::shared_ptr MakeLinearToSrgbFilter( + FilterInput::Ref input); + FilterContents(); ~FilterContents() override; diff --git a/impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc b/impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc new file mode 100644 index 0000000000000..ff9b65087b7a4 --- /dev/null +++ b/impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc @@ -0,0 +1,83 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/entity/contents/filters/linear_to_srgb_filter_contents.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/geometry/point.h" +#include "impeller/geometry/vector.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/sampler_library.h" + +namespace impeller { + +LinearToSrgbFilterContents::LinearToSrgbFilterContents() = default; + +LinearToSrgbFilterContents::~LinearToSrgbFilterContents() = default; + +std::optional LinearToSrgbFilterContents::RenderFilter( + const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const { + if (inputs.empty()) { + return std::nullopt; + } + + using VS = LinearToSrgbFilterPipeline::VertexShader; + using FS = LinearToSrgbFilterPipeline::FragmentShader; + + auto input_snapshot = inputs[0]->GetSnapshot(renderer, entity); + if (!input_snapshot.has_value()) { + return std::nullopt; + } + + ContentContext::SubpassCallback callback = [&](const ContentContext& renderer, + RenderPass& pass) { + Command cmd; + cmd.label = "Linear to sRGB Filter"; + + auto options = OptionsFromPass(pass); + options.blend_mode = Entity::BlendMode::kSource; + cmd.pipeline = renderer.GetLinearToSrgbFilterPipeline(options); + + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0, 0)}, + {Point(1, 0)}, + {Point(1, 1)}, + {Point(0, 0)}, + {Point(1, 1)}, + {Point(0, 1)}, + }); + + auto& host_buffer = pass.GetTransientsBuffer(); + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + cmd.BindVertices(vtx_buffer); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); + + auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); + FS::BindInputTexture(cmd, input_snapshot->texture, sampler); + + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + + return pass.AddCommand(std::move(cmd)); + }; + + auto out_texture = + renderer.MakeSubpass(input_snapshot->texture->GetSize(), callback); + if (!out_texture) { + return std::nullopt; + } + out_texture->SetLabel("LinearToSrgb Texture"); + + return Snapshot{.texture = out_texture, + .transform = input_snapshot->transform, + .sampler_descriptor = input_snapshot->sampler_descriptor}; +} + +} // namespace impeller diff --git a/impeller/entity/contents/filters/linear_to_srgb_filter_contents.h b/impeller/entity/contents/filters/linear_to_srgb_filter_contents.h new file mode 100644 index 0000000000000..ec1424c2573da --- /dev/null +++ b/impeller/entity/contents/filters/linear_to_srgb_filter_contents.h @@ -0,0 +1,29 @@ +// 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 "impeller/entity/contents/filters/filter_contents.h" +#include "impeller/entity/contents/filters/inputs/filter_input.h" + +namespace impeller { + +class LinearToSrgbFilterContents final : public FilterContents { + public: + LinearToSrgbFilterContents(); + + ~LinearToSrgbFilterContents() override; + + private: + // |FilterContents| + std::optional RenderFilter( + const FilterInput::Vector& input_textures, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const override; + + FML_DISALLOW_COPY_AND_ASSIGN(LinearToSrgbFilterContents); +}; + +} // namespace impeller diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 4fa1f959ee397..260b9e480505a 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -8,6 +8,7 @@ #include "flutter/testing/testing.h" #include "impeller/entity/contents/atlas_contents.h" #include "impeller/entity/contents/clip_contents.h" +#include "impeller/entity/contents/contents.h" #include "impeller/entity/contents/filters/blend_filter_contents.h" #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" @@ -1542,5 +1543,56 @@ TEST_P(EntityTest, ColorMatrixFilterEditable) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(EntityTest, LinearToSrgbFilterCoverageIsCorrect) { + // Set up a simple color background. + auto fill = std::make_shared(); + fill->SetPath( + PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath()); + fill->SetColor(Color::MintCream()); + + auto filter = FilterContents::MakeLinearToSrgbFilter(FilterInput::Make(fill)); + + Entity e; + e.SetTransformation(Matrix()); + + // Confirm that the actual filter coverage matches the expected coverage. + auto actual = filter->GetCoverage(e); + auto expected = Rect::MakeXYWH(0, 0, 300, 400); + + ASSERT_TRUE(actual.has_value()); + ASSERT_RECT_NEAR(actual.value(), expected); +} + +TEST_P(EntityTest, LinearToSrgbFilter) { + auto image = CreateTextureForFixture("kalimba.jpg"); + ASSERT_TRUE(image); + + auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { + auto filtered = + FilterContents::MakeLinearToSrgbFilter(FilterInput::Make(image)); + + // Define the entity that will serve as the control image as a Gaussian blur + // filter with no filter at all. + Entity entity_left; + entity_left.SetTransformation(Matrix::MakeScale(GetContentScale()) * + Matrix::MakeTranslation({100, 300}) * + Matrix::MakeScale(Vector2{0.5, 0.5})); + auto unfiltered = FilterContents::MakeGaussianBlur(FilterInput::Make(image), + Sigma{0}, Sigma{0}); + entity_left.SetContents(unfiltered); + + // Define the entity that will be filtered from linear to sRGB. + Entity entity_right; + entity_right.SetTransformation(Matrix::MakeScale(GetContentScale()) * + Matrix::MakeTranslation({500, 300}) * + Matrix::MakeScale(Vector2{0.5, 0.5})); + entity_right.SetContents(filtered); + return entity_left.Render(context, pass) && + entity_right.Render(context, pass); + }; + + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/shaders/linear_to_srgb_filter.frag b/impeller/entity/shaders/linear_to_srgb_filter.frag new file mode 100644 index 0000000000000..fea911c14f1e5 --- /dev/null +++ b/impeller/entity/shaders/linear_to_srgb_filter.frag @@ -0,0 +1,28 @@ +// 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 + +// A color filter that applies the sRGB gamma curve to the color. +// +// This filter is used so that the colors are suitable for display in monitors. + +uniform sampler2D input_texture; + +in vec2 v_position; +out vec4 frag_color; + +void main() { + vec4 input_color = texture(input_texture, v_position); + + for (int i = 0; i < 4; i++) { + if (input_color[i] <= 0.0031308) { + input_color[i] = input_color[i] * 12.92; + } else { + input_color[i] = 1.055 * pow(input_color[i], (1.0 / 2.4)) - 0.055; + } + } + + frag_color = input_color; +} diff --git a/impeller/entity/shaders/linear_to_srgb_filter.vert b/impeller/entity/shaders/linear_to_srgb_filter.vert new file mode 100644 index 0000000000000..b741b2744ec60 --- /dev/null +++ b/impeller/entity/shaders/linear_to_srgb_filter.vert @@ -0,0 +1,15 @@ +// 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. + +uniform FrameInfo { + mat4 mvp; +} frame_info; + +in vec2 position; +out vec2 v_position; + +void main() { + v_position = position; + gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); +} From f578e0571d4bd01a31b4c4c35de8a1c0dfbfa5d3 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 16:40:22 -0400 Subject: [PATCH 402/558] Roll Clang Windows from d9e02a30b16e to 60d276923902 (#35509) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 1d36eb1477b0d..c10938f10231a 100644 --- a/DEPS +++ b/DEPS @@ -650,7 +650,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/clang/windows-amd64', - 'version': 'git_revision:d9e02a30b16ea65a7da87913c40af03e22c9571f' + 'version': 'git_revision:60d276923902051192eba692e5312e605c9d9f65' } ], 'condition': 'download_windows_deps', From 3cad00e0087bc9be56446d70daaa51f507a201d8 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 16:41:51 -0400 Subject: [PATCH 403/558] Roll Fuchsia Mac SDK from 1hIAHHOhq9Acf2u3d... to 5jtXFOH7XU5RNDLkY... (#35503) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index c10938f10231a..a97bc761c34e1 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': '1hIAHHOhq9Acf2u3dwEe2__qTlaQTSxxm5o6s_RK1qMC' + 'version': '5jtXFOH7XU5RNDLkYQJgiQYkr0OQ715MInl58Qho0Q0C' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 2965ffb927f771a45ae879ecbd88ea64ee295e37 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 16:42:40 -0400 Subject: [PATCH 404/558] Roll Skia from 439c4708a042 to 9a51e6deb112 (4 revisions) (#35504) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 35 ++++++++++++++++---------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/DEPS b/DEPS index a97bc761c34e1..0cb2b837bae5a 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': '439c4708a0428dcba7e45c1549760309931c903f', + 'skia_revision': '9a51e6deb112a113ca133c48a3be12ed3c5a9a0a', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 36d8c28473e0f..070c15872de74 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 1892bb3f5de42e8b771b5d8e9a4b964d +Signature: 1008dd7e91b37ffa0192d2cf9c12bfcf UNUSED LICENSES: @@ -7556,12 +7556,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: skia -ORIGIN: ../../../third_party/skia/src/core/SkMatrixImageFilter.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/core/SkScan_AAAPath.cpp + ../../../third_party/skia/LICENSE TYPE: LicenseType.bsd -FILE: ../../../third_party/skia/src/core/SkMatrixImageFilter.cpp -FILE: ../../../third_party/skia/src/core/SkMatrixImageFilter.h +FILE: ../../../third_party/skia/src/core/SkScan_AAAPath.cpp ---------------------------------------------------------------------------------------------------- -Copyright 2014 The Android Open Source Project +Copyright 2016 The Android Open Source Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -7594,11 +7593,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: skia -ORIGIN: ../../../third_party/skia/src/core/SkScan_AAAPath.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/core/SkStrikeSpec.cpp + ../../../third_party/skia/LICENSE TYPE: LicenseType.bsd -FILE: ../../../third_party/skia/src/core/SkScan_AAAPath.cpp +FILE: ../../../third_party/skia/src/core/SkStrikeSpec.cpp ---------------------------------------------------------------------------------------------------- -Copyright 2016 The Android Open Source Project +Copyright 2019 The Android Open Source Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -7631,11 +7630,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: skia -ORIGIN: ../../../third_party/skia/src/core/SkStrikeSpec.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/core/SkTraceEvent.h + ../../../third_party/skia/LICENSE TYPE: LicenseType.bsd -FILE: ../../../third_party/skia/src/core/SkStrikeSpec.cpp +FILE: ../../../third_party/skia/src/core/SkTraceEvent.h ---------------------------------------------------------------------------------------------------- -Copyright 2019 The Android Open Source Project +Copyright (c) 2014 Google Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -7668,11 +7667,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: skia -ORIGIN: ../../../third_party/skia/src/core/SkTraceEvent.h + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/effects/imagefilters/SkBlendImageFilter.cpp + ../../../third_party/skia/LICENSE TYPE: LicenseType.bsd -FILE: ../../../third_party/skia/src/core/SkTraceEvent.h +FILE: ../../../third_party/skia/src/effects/imagefilters/SkBlendImageFilter.cpp +FILE: ../../../third_party/skia/src/effects/imagefilters/SkPictureImageFilter.cpp ---------------------------------------------------------------------------------------------------- -Copyright (c) 2014 Google Inc. +Copyright 2013 The Android Open Source Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -7705,12 +7705,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: skia -ORIGIN: ../../../third_party/skia/src/effects/imagefilters/SkBlendImageFilter.cpp + ../../../third_party/skia/LICENSE +ORIGIN: ../../../third_party/skia/src/effects/imagefilters/SkMatrixTransformImageFilter.cpp + ../../../third_party/skia/LICENSE TYPE: LicenseType.bsd -FILE: ../../../third_party/skia/src/effects/imagefilters/SkBlendImageFilter.cpp -FILE: ../../../third_party/skia/src/effects/imagefilters/SkPictureImageFilter.cpp +FILE: ../../../third_party/skia/src/effects/imagefilters/SkMatrixTransformImageFilter.cpp ---------------------------------------------------------------------------------------------------- -Copyright 2013 The Android Open Source Project +Copyright 2014 The Android Open Source Project Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are From e7fccf533298e59aa76de65949e8310603519c9f Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Thu, 18 Aug 2022 14:54:59 -0700 Subject: [PATCH 405/558] Add Point::AngleTo (#35510) --- impeller/geometry/geometry_unittests.cc | 29 +++++++++++++++++++++++++ impeller/geometry/point.h | 4 ++++ 2 files changed, 33 insertions(+) diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 8ba3c6e9b719d..84eec3be14703 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -773,6 +773,35 @@ TEST(GeometryTest, PointAbs) { ASSERT_POINT_NEAR(a_abs, expected); } +TEST(GeometryTest, PointAngleTo) { + // Negative result in the CCW (with up = -Y) direction. + { + Point a(1, 1); + Point b(1, -1); + Radians actual = a.AngleTo(b); + Radians expected = Radians{-kPi / 2}; + ASSERT_FLOAT_EQ(actual.radians, expected.radians); + } + + // Check the other direction to ensure the result is signed correctly. + { + Point a(1, -1); + Point b(1, 1); + Radians actual = a.AngleTo(b); + Radians expected = Radians{kPi / 2}; + ASSERT_FLOAT_EQ(actual.radians, expected.radians); + } + + // Differences in magnitude should have no impact on the result. + { + Point a(100, -100); + Point b(0.01, 0.01); + Radians actual = a.AngleTo(b); + Radians expected = Radians{kPi / 2}; + ASSERT_FLOAT_EQ(actual.radians, expected.radians); + } +} + TEST(GeometryTest, CanUseVector3AssignmentOperators) { { Vector3 p(1, 2, 4); diff --git a/impeller/geometry/point.h b/impeller/geometry/point.h index 5fd01ea9a2812..04b5461dbe036 100644 --- a/impeller/geometry/point.h +++ b/impeller/geometry/point.h @@ -204,6 +204,10 @@ struct TPoint { return *this - axis * this->Dot(axis) * 2; } + constexpr Radians AngleTo(const TPoint& p) const { + return Radians{std::atan2(this->Cross(p), this->Dot(p))}; + } + constexpr bool IsZero() const { return x == 0 && y == 0; } }; From 50cfc83e2c9bee1417f7bfeeff79428a54be7776 Mon Sep 17 00:00:00 2001 From: WenJingRui <2539699336@qq.com> Date: Fri, 19 Aug 2022 06:26:00 +0800 Subject: [PATCH 406/558] [iOS] Avoid keyboard animation junk and laggy on Promotion devices. (#34871) --- ci/licenses_golden/licenses_flutter | 1 + shell/platform/darwin/ios/BUILD.gn | 1 + .../framework/Source/FlutterViewController.mm | 79 ++++++++++++------- .../Source/FlutterViewControllerTest.mm | 17 +++- .../Source/FlutterViewControllerTest_mrc.mm | 59 ++++++++++++++ .../framework/Source/VsyncWaiterIosTest.mm | 21 +++++ .../ios/framework/Source/vsync_waiter_ios.h | 10 +++ .../ios/framework/Source/vsync_waiter_ios.mm | 5 +- .../IosUnitTests.xcodeproj/project.pbxproj | 2 + 9 files changed, 163 insertions(+), 32 deletions(-) create mode 100644 shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest_mrc.mm diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 14de4f81e9b71..dfa73e2f41a3f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1814,6 +1814,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterView.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest_mrc.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewResponder.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewTest.mm diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 74aa338ab2971..e3a8339e22033 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -201,6 +201,7 @@ source_set("ios_test_flutter_mrc") { "framework/Source/FlutterEngineTest_mrc.mm", "framework/Source/FlutterPlatformPluginTest.mm", "framework/Source/FlutterPlatformViewsTest.mm", + "framework/Source/FlutterViewControllerTest_mrc.mm", "framework/Source/FlutterViewTest.mm", "framework/Source/VsyncWaiterIosTest.mm", "framework/Source/accessibility_bridge_test.mm", diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 315611072f9cd..cc7947421f8f3 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -26,6 +26,7 @@ #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h" #import "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #import "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h" #import "flutter/shell/platform/darwin/ios/platform_view_ios.h" #import "flutter/shell/platform/embedder/embedder.h" @@ -62,7 +63,7 @@ @interface FlutterViewController () recorder) { + if (!weakSelf) { + return; + } + fml::scoped_nsobject flutterViewController( + [(FlutterViewController*)weakSelf.get() retain]); + if (!flutterViewController) { + return; + } + + if ([flutterViewController keyboardAnimationView].superview == nil) { + // Ensure the keyboardAnimationView is in view hierarchy when animation running. + [flutterViewController.get().view addSubview:[flutterViewController keyboardAnimationView]]; + } + if ([flutterViewController keyboardAnimationView].layer.presentationLayer) { + CGFloat value = + [flutterViewController keyboardAnimationView].layer.presentationLayer.frame.origin.y; + flutterViewController.get()->_viewportMetrics.physical_view_inset_bottom = value; + [flutterViewController updateViewportMetrics]; + } + }; + flutter::Shell& shell = [_engine.get() shell]; + NSAssert(_keyboardAnimationVSyncClient == nil, + @"_keyboardAnimationVSyncClient must be nil when setup"); + _keyboardAnimationVSyncClient = + [[VSyncClient alloc] initWithTaskRunner:shell.GetTaskRunners().GetPlatformTaskRunner() + callback:callback]; + _keyboardAnimationVSyncClient.allowPauseAfterVsync = NO; + [_keyboardAnimationVSyncClient await]; +} + +- (void)invalidateKeyboardAnimationVSyncClient { + [_keyboardAnimationVSyncClient invalidate]; + [_keyboardAnimationVSyncClient release]; + _keyboardAnimationVSyncClient = nil; } - (void)removeKeyboardAnimationView { @@ -1318,18 +1351,6 @@ - (void)ensureViewportMetricsIsCorrect { } } -- (void)onDisplayLink { - if ([self keyboardAnimationView].superview == nil) { - // Ensure the keyboardAnimationView is in view hierarchy when animation running. - [self.view addSubview:[self keyboardAnimationView]]; - } - if ([self keyboardAnimationView].layer.presentationLayer) { - CGFloat value = [self keyboardAnimationView].layer.presentationLayer.frame.origin.y; - _viewportMetrics.physical_view_inset_bottom = value; - [self updateViewportMetrics]; - } -} - - (void)handlePressEvent:(FlutterUIPressProxy*)press nextAction:(void (^)())next API_AVAILABLE(ios(13.4)) { if (@available(iOS 13.4, *)) { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm index 556d87f584ecb..d3f4de66f8710 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest.mm @@ -126,8 +126,9 @@ - (void)goToApplicationLifecycle:(nonnull NSString*)state; - (void)keyboardWillChangeFrame:(NSNotification*)notification; - (void)keyboardWillBeHidden:(NSNotification*)notification; - (void)startKeyBoardAnimation:(NSTimeInterval)duration; +- (void)setupKeyboardAnimationVsyncClient; - (void)ensureViewportMetricsIsCorrect; -- (void)invalidateDisplayLink; +- (void)invalidateKeyboardAnimationVSyncClient; - (void)addInternalPlugins; - (flutter::PointerData)generatePointerDataForFake; - (void)sharedSetupWithProject:(nullable FlutterDartProject*)project @@ -159,6 +160,18 @@ - (void)tearDown { self.messageSent = nil; } +- (void)testStartKeyboardAnimationWillInvokeSetupKeyboardAnimationVsyncClient { + FlutterEngine* engine = [[FlutterEngine alloc] init]; + [engine runWithEntrypoint:nil]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engine + nibName:nil + bundle:nil]; + FlutterViewController* viewControllerMock = OCMPartialMock(viewController); + viewControllerMock.targetViewInsetBottom = 100; + [viewControllerMock startKeyBoardAnimation:0.25]; + OCMVerify([viewControllerMock setupKeyboardAnimationVsyncClient]); +} + - (void)testkeyboardWillChangeFrameWillStartKeyboardAnimation { FlutterEngine* mockEngine = OCMPartialMock([[FlutterEngine alloc] init]); [mockEngine createShell:@"" libraryURI:@"" initialRoute:nil]; @@ -223,7 +236,7 @@ - (void)testEnsureViewportMetricsWillInvokeAndDisplayLinkWillInvalidateInViewDid id viewControllerMock = OCMPartialMock(viewController); [viewControllerMock viewDidDisappear:YES]; OCMVerify([viewControllerMock ensureViewportMetricsIsCorrect]); - OCMVerify([viewControllerMock invalidateDisplayLink]); + OCMVerify([viewControllerMock invalidateKeyboardAnimationVSyncClient]); } - (void)testViewDidDisappearDoesntPauseEngineWhenNotTheViewController { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest_mrc.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest_mrc.mm new file mode 100644 index 0000000000000..f4cc21706ef47 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewControllerTest_mrc.mm @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import +#import + +#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h" +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#import "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h" + +FLUTTER_ASSERT_NOT_ARC + +@interface VSyncClient (Testing) + +- (CADisplayLink*)getDisplayLink; + +@end + +@interface FlutterViewController (Testing) + +@property(nonatomic, assign) double targetViewInsetBottom; +@property(nonatomic, retain) VSyncClient* keyboardAnimationVSyncClient; + +- (void)setupKeyboardAnimationVsyncClient; + +@end + +@interface FlutterViewControllerTest_mrc : XCTestCase +@end + +@implementation FlutterViewControllerTest_mrc + +- (void)testSetupKeyboardAnimationVsyncClientWillCreateNewVsyncClientForFlutterViewController { + id bundleMock = OCMPartialMock([NSBundle mainBundle]); + OCMStub([bundleMock objectForInfoDictionaryKey:@"CADisableMinimumFrameDurationOnPhone"]) + .andReturn(@YES); + id mockDisplayLinkManager = [OCMockObject mockForClass:[DisplayLinkManager class]]; + double maxFrameRate = 120; + [[[mockDisplayLinkManager stub] andReturnValue:@(maxFrameRate)] displayRefreshRate]; + FlutterEngine* engine = [[FlutterEngine alloc] init]; + [engine runWithEntrypoint:nil]; + FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engine + nibName:nil + bundle:nil]; + [viewController setupKeyboardAnimationVsyncClient]; + XCTAssertNotNil(viewController.keyboardAnimationVSyncClient); + CADisplayLink* link = [viewController.keyboardAnimationVSyncClient getDisplayLink]; + XCTAssertNotNil(link); + if (@available(iOS 15.0, *)) { + XCTAssertEqual(link.preferredFrameRateRange.maximum, maxFrameRate); + XCTAssertEqual(link.preferredFrameRateRange.preferred, maxFrameRate); + XCTAssertEqual(link.preferredFrameRateRange.minimum, maxFrameRate / 2); + } else { + XCTAssertEqual(link.preferredFramesPerSecond, maxFrameRate); + } +} + +@end diff --git a/shell/platform/darwin/ios/framework/Source/VsyncWaiterIosTest.mm b/shell/platform/darwin/ios/framework/Source/VsyncWaiterIosTest.mm index 124bdee2e8441..4ac0529808ed7 100644 --- a/shell/platform/darwin/ios/framework/Source/VsyncWaiterIosTest.mm +++ b/shell/platform/darwin/ios/framework/Source/VsyncWaiterIosTest.mm @@ -22,6 +22,7 @@ @interface VSyncClient (Testing) - (CADisplayLink*)getDisplayLink; +- (void)onDisplayLink:(CADisplayLink*)link; @end @@ -30,6 +31,26 @@ @interface VsyncWaiterIosTest : XCTestCase @implementation VsyncWaiterIosTest +- (void)testSetAllowPauseAfterVsyncCorrect { + auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest"); + VSyncClient* vsyncClient = [[[VSyncClient alloc] + initWithTaskRunner:thread_task_runner + callback:[](std::unique_ptr recorder) {}] + autorelease]; + CADisplayLink* link = [vsyncClient getDisplayLink]; + vsyncClient.allowPauseAfterVsync = NO; + [vsyncClient await]; + [vsyncClient onDisplayLink:link]; + XCTAssertFalse(link.isPaused); + + vsyncClient.allowPauseAfterVsync = YES; + [vsyncClient await]; + [vsyncClient onDisplayLink:link]; + XCTAssertTrue(link.isPaused); + + [vsyncClient release]; +} + - (void)testSetCorrectVariableRefreshRates { auto thread_task_runner = CreateNewThread("VsyncWaiterIosTest"); auto callback = [](std::unique_ptr recorder) {}; diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h index 9b5d5aa519bd9..9185fb00978d9 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h @@ -30,6 +30,16 @@ @interface VSyncClient : NSObject +//------------------------------------------------------------------------------ +/// @brief Default value is YES. Vsync client will pause vsync callback after receiving +/// a vsync signal. Setting this property to NO can avoid this and vsync client +/// will trigger vsync callback continuously. +/// +/// +/// @param allowPauseAfterVsync Allow vsync client to pause after receiving a vsync signal. +/// +@property(nonatomic, assign) BOOL allowPauseAfterVsync; + - (instancetype)initWithTaskRunner:(fml::RefPtr)task_runner callback:(flutter::VsyncWaiter::Callback)callback; diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm index 0e6b2f5e68dad..439ba868ff8b5 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm @@ -57,6 +57,7 @@ - (instancetype)initWithTaskRunner:(fml::RefPtr)task_runner if (self) { current_refresh_rate_ = [DisplayLinkManager displayRefreshRate]; + _allowPauseAfterVsync = YES; callback_ = std::move(callback); display_link_ = fml::scoped_nsobject { [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain] @@ -111,7 +112,9 @@ - (void)onDisplayLink:(CADisplayLink*)link { current_refresh_rate_ = round(1 / (frame_target_time - frame_start_time).ToSecondsF()); recorder->RecordVsync(frame_start_time, frame_target_time); - display_link_.get().paused = YES; + if (_allowPauseAfterVsync) { + display_link_.get().paused = YES; + } callback_(std::move(recorder)); } diff --git a/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj b/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj index 3632c55063a94..b14ff6444597d 100644 --- a/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj +++ b/testing/ios/IosUnitTests/IosUnitTests.xcodeproj/project.pbxproj @@ -72,6 +72,7 @@ 689EC1E2281B30D3008FEB58 /* FlutterSpellCheckPluginTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterSpellCheckPluginTest.mm; sourceTree = ""; }; 68B6091227F62F990036AC78 /* VsyncWaiterIosTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = VsyncWaiterIosTest.mm; sourceTree = ""; }; 3DD7D38C27D2B81000DA365C /* FlutterUndoManagerPluginTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterUndoManagerPluginTest.mm; sourceTree = ""; }; + 73F12C22288F92FF00AFC3A6 /* FlutterViewControllerTest_mrc.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = FlutterViewControllerTest_mrc.mm; sourceTree = ""; }; F7521D7226BB671E005F15C5 /* libios_test_flutter.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libios_test_flutter.dylib; path = "../../../../out/$(FLUTTER_ENGINE)/libios_test_flutter.dylib"; sourceTree = ""; }; F7521D7526BB673E005F15C5 /* libocmock_shared.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libocmock_shared.dylib; path = "../../../../out/$(FLUTTER_ENGINE)/libocmock_shared.dylib"; sourceTree = ""; }; F77E081726FA9CE6003E6E4C /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = "../../../../out/$(FLUTTER_ENGINE)/Flutter.framework"; sourceTree = ""; }; @@ -112,6 +113,7 @@ 0AC2331224BA71D300A85907 /* FlutterEnginePlatformViewTest.mm */, 0AC2331924BA71D300A85907 /* FlutterPluginAppLifeCycleDelegateTest.mm */, 0AC2332124BA71D300A85907 /* FlutterViewControllerTest.mm */, + 73F12C22288F92FF00AFC3A6 /* FlutterViewControllerTest_mrc.mm */, ); name = Source; path = ../../../shell/platform/darwin/ios/framework/Source; From 4fbe41dc4e34f6bebb93abc235fe2c17bab216e8 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 18 Aug 2022 16:12:11 -0700 Subject: [PATCH 407/558] Support deferred GPU images in ImageShaders (#35323) --- display_list/display_list.h | 1 + display_list/display_list_builder.cc | 7 ++ display_list/display_list_color_source.cc | 9 ++ display_list/display_list_color_source.h | 106 +++++++++++++++++- .../display_list_color_source_unittests.cc | 49 ++++++++ display_list/display_list_image.h | 11 ++ display_list/display_list_image_skia.cc | 5 + display_list/display_list_image_skia.h | 3 + display_list/display_list_ops.h | 23 ++++ flow/layers/shader_mask_layer.cc | 12 +- flow/layers/shader_mask_layer.h | 10 +- flow/layers/shader_mask_layer_unittests.cc | 38 ++++--- .../display_list/display_list_dispatcher.cc | 1 + .../display_list_image_impeller.cc | 6 + .../display_list_image_impeller.h | 3 + lib/ui/compositing/scene_builder.cc | 3 +- .../display_list_deferred_image_gpu.cc | 5 + .../display_list_deferred_image_gpu.h | 3 + lib/ui/painting/display_list_image_gpu.cc | 8 ++ lib/ui/painting/display_list_image_gpu.h | 3 + lib/ui/painting/fragment_program.cc | 12 +- lib/ui/painting/fragment_shader.cc | 10 +- lib/ui/painting/fragment_shader.h | 9 +- lib/ui/painting/image_shader.cc | 6 - lib/ui/painting/paint.cc | 9 +- testing/dart/fragment_shader_test.dart | 32 ++++++ testing/dart/image_shader_test.dart | 10 +- 27 files changed, 334 insertions(+), 60 deletions(-) diff --git a/display_list/display_list.h b/display_list/display_list.h index 3731a575b8cac..8eab4494ef9b6 100644 --- a/display_list/display_list.h +++ b/display_list/display_list.h @@ -90,6 +90,7 @@ namespace flutter { V(SetPodColorSource) \ V(SetSkColorSource) \ V(SetImageColorSource) \ + V(SetRuntimeEffectColorSource) \ \ V(ClearImageFilter) \ V(SetPodImageFilter) \ diff --git a/display_list/display_list_builder.cc b/display_list/display_list_builder.cc index 4b7c1c0e81c97..788938e4b05b7 100644 --- a/display_list/display_list_builder.cc +++ b/display_list/display_list_builder.cc @@ -6,6 +6,7 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_blend_mode.h" +#include "flutter/display_list/display_list_color_source.h" #include "flutter/display_list/display_list_ops.h" namespace flutter { @@ -184,6 +185,12 @@ void DisplayListBuilder::onSetColorSource(const DlColorSource* source) { new (pod) DlSweepGradientColorSource(sweep); break; } + case DlColorSourceType::kRuntimeEffect: { + const DlRuntimeEffectColorSource* effect = source->asRuntimeEffect(); + FML_DCHECK(effect); + Push(0, 0, effect); + break; + } case DlColorSourceType::kUnknown: Push(0, 0, source->skia_object()); break; diff --git a/display_list/display_list_color_source.cc b/display_list/display_list_color_source.cc index c8ff65b2aca03..4348abbe8b5cf 100644 --- a/display_list/display_list_color_source.cc +++ b/display_list/display_list_color_source.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/display_list/display_list_color_source.h" +#include "display_list_color_source.h" #include "flutter/display_list/display_list_sampling_options.h" namespace flutter { @@ -128,4 +129,12 @@ std::shared_ptr DlColorSource::MakeSweep( return std::move(ret); } +std::shared_ptr DlColorSource::MakeRuntimeEffect( + sk_sp runtime_effect, + std::vector> samplers, + sk_sp uniform_data) { + return std::make_shared( + std::move(runtime_effect), std::move(samplers), std::move(uniform_data)); +} + } // namespace flutter diff --git a/display_list/display_list_color_source.h b/display_list/display_list_color_source.h index 97c303714913b..d38217bd25f59 100644 --- a/display_list/display_list_color_source.h +++ b/display_list/display_list_color_source.h @@ -15,6 +15,7 @@ #include "flutter/fml/logging.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/effects/SkGradientShader.h" +#include "third_party/skia/include/effects/SkRuntimeEffect.h" namespace flutter { @@ -24,6 +25,7 @@ class DlLinearGradientColorSource; class DlRadialGradientColorSource; class DlConicalGradientColorSource; class DlSweepGradientColorSource; +class DlRuntimeEffectColorSource; class DlUnknownColorSource; // The DisplayList ColorSource class. This class implements all of the @@ -43,6 +45,7 @@ enum class DlColorSourceType { kRadialGradient, kConicalGradient, kSweepGradient, + kRuntimeEffect, kUnknown }; @@ -104,6 +107,11 @@ class DlColorSource DlTileMode tile_mode, const SkMatrix* matrix = nullptr); + static std::shared_ptr MakeRuntimeEffect( + sk_sp runtime_effect, + std::vector> samplers, + sk_sp uniform_data); + virtual bool is_opaque() const = 0; virtual std::shared_ptr with_sampling( @@ -143,6 +151,19 @@ class DlColorSource return nullptr; } + virtual const DlRuntimeEffectColorSource* asRuntimeEffect() const { + return nullptr; + } + + // If this filter contains images, specifies the owning context for those + // images. + // Images with a DlImage::OwningContext::kRaster must only call skia_object + // on the raster task runner. + // A nullopt return means there is no image. + virtual std::optional owning_context() const { + return std::nullopt; + } + protected: DlColorSource() = default; @@ -229,12 +250,10 @@ class DlImageColorSource final : public SkRefCnt, DlColorSourceType type() const override { return DlColorSourceType::kImage; } size_t size() const override { return sizeof(*this); } - bool is_opaque() const override { - // TODO(109286): Consider implementing 'isOpaque' on 'DlImage'. - if (!image_->skia_image()) { - return false; - } - return image_->skia_image()->isOpaque(); + bool is_opaque() const override { return image_->isOpaque(); } + + std::optional owning_context() const override { + return image_->owning_context(); } sk_sp image() const { return image_; } @@ -636,6 +655,81 @@ class DlSweepGradientColorSource final : public DlGradientColorSourceBase { FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlSweepGradientColorSource); }; +class DlRuntimeEffectColorSource final : public DlColorSource { + public: + DlRuntimeEffectColorSource( + sk_sp runtime_effect, + std::vector> samplers, + sk_sp uniform_data) + : runtime_effect_(std::move(runtime_effect)), + samplers_(std::move(samplers)), + uniform_data_(std::move(uniform_data)) {} + + const DlRuntimeEffectColorSource* asRuntimeEffect() const override { + return this; + } + + std::shared_ptr shared() const override { + return std::make_shared( + runtime_effect_, samplers_, uniform_data_); + } + + DlColorSourceType type() const override { + return DlColorSourceType::kRuntimeEffect; + } + size_t size() const override { return sizeof(*this); } + + bool is_opaque() const override { return false; } + + const sk_sp runtime_effect() const { + return runtime_effect_; + } + const std::vector> samplers() const { + return samplers_; + } + const sk_sp uniform_data() const { return uniform_data_; } + + sk_sp skia_object() const override { + if (!runtime_effect_) { + return nullptr; + } + std::vector> sk_samplers(samplers_.size()); + for (size_t i = 0; i < samplers_.size(); i++) { + sk_samplers[i] = samplers_[i]->skia_object(); + } + return runtime_effect_->makeShader(uniform_data_, sk_samplers.data(), + sk_samplers.size()); + } + + protected: + bool equals_(DlColorSource const& other) const override { + FML_DCHECK(other.type() == DlColorSourceType::kRuntimeEffect); + auto that = static_cast(&other); + if (runtime_effect_ != that->runtime_effect_) { + return false; + } + if (uniform_data_ != that->uniform_data_) { + return false; + } + if (samplers_.size() != that->samplers_.size()) { + return false; + } + for (size_t i = 0; i < samplers_.size(); i++) { + if (samplers_[i] != that->samplers_[i]) { + return false; + } + } + return true; + } + + private: + sk_sp runtime_effect_; + std::vector> samplers_; + sk_sp uniform_data_; + + FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlRuntimeEffectColorSource); +}; + class DlUnknownColorSource final : public DlColorSource { public: DlUnknownColorSource(sk_sp shader) : sk_shader_(shader) {} diff --git a/display_list/display_list_color_source_unittests.cc b/display_list/display_list_color_source_unittests.cc index 9a23dfe415f7b..351d94a4f08a6 100644 --- a/display_list/display_list_color_source_unittests.cc +++ b/display_list/display_list_color_source_unittests.cc @@ -8,6 +8,7 @@ #include "flutter/display_list/display_list_image.h" #include "flutter/display_list/display_list_sampling_options.h" #include "flutter/display_list/types.h" +#include "third_party/skia/include/core/SkString.h" #include "third_party/skia/include/core/SkSurface.h" namespace flutter { @@ -27,6 +28,15 @@ static sk_sp MakeTestImage(int w, int h, SkColor color) { return DlImage::Make(surface->makeImageSnapshot()); } +static const sk_sp kTestRuntimeEffect1 = + SkRuntimeEffect::MakeForShader( + SkString("vec4 main(vec2 p) { return vec4(0); }")) + .effect; +static const sk_sp kTestRuntimeEffect2 = + SkRuntimeEffect::MakeForShader( + SkString("vec4 main(vec2 p) { return vec4(1); }")) + .effect; + static const sk_sp kTestImage1 = MakeTestImage(10, 10, SK_ColorGREEN); static const sk_sp kTestAlphaImage1 = MakeTestImage(10, 10, SK_ColorTRANSPARENT); @@ -138,6 +148,7 @@ TEST(DisplayListColorSource, FromSkiaImageShader) { ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, FromSkiaLinearGradient) { @@ -177,6 +188,7 @@ TEST(DisplayListColorSource, FromSkiaRadialGradient) { ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, FromSkiaConicalGradient) { @@ -197,6 +209,7 @@ TEST(DisplayListColorSource, FromSkiaConicalGradient) { ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, FromSkiaSweepGradient) { @@ -217,6 +230,7 @@ TEST(DisplayListColorSource, FromSkiaSweepGradient) { ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, FromSkiaUnrecognizedShader) { @@ -231,6 +245,7 @@ TEST(DisplayListColorSource, FromSkiaUnrecognizedShader) { ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, ColorConstructor) { @@ -253,6 +268,7 @@ TEST(DisplayListColorSource, ColorAsColor) { ASSERT_EQ(source.asRadialGradient(), nullptr); ASSERT_EQ(source.asConicalGradient(), nullptr); ASSERT_EQ(source.asSweepGradient(), nullptr); + ASSERT_EQ(source.asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, ColorContents) { @@ -400,6 +416,7 @@ TEST(DisplayListColorSource, LinearGradientAsLinear) { ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, LinearGradientContents) { @@ -518,6 +535,7 @@ TEST(DisplayListColorSource, RadialGradientAsRadial) { ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, RadialGradientContents) { @@ -636,6 +654,7 @@ TEST(DisplayListColorSource, ConicalGradientAsConical) { ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asSweepGradient(), nullptr); + ASSERT_EQ(source->asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, ConicalGradientContents) { @@ -770,6 +789,7 @@ TEST(DisplayListColorSource, SweepGradientAsSweep) { ASSERT_EQ(source->asLinearGradient(), nullptr); ASSERT_EQ(source->asRadialGradient(), nullptr); ASSERT_EQ(source->asConicalGradient(), nullptr); + ASSERT_EQ(source->asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, SweepGradientContents) { @@ -888,6 +908,7 @@ TEST(DisplayListColorSource, UnknownAsNone) { ASSERT_EQ(source.asRadialGradient(), nullptr); ASSERT_EQ(source.asConicalGradient(), nullptr); ASSERT_EQ(source.asSweepGradient(), nullptr); + ASSERT_EQ(source.asRuntimeEffect(), nullptr); } TEST(DisplayListColorSource, UnknownContents) { @@ -916,5 +937,33 @@ TEST(DisplayListColorSource, UnknownNotEquals) { TestNotEquals(source1, source2, "SkShader differs"); } +TEST(DisplayListColorSource, RuntimeEffect) { + std::shared_ptr source1 = + DlColorSource::MakeRuntimeEffect(kTestRuntimeEffect1, {}, nullptr); + std::shared_ptr source2 = + DlColorSource::MakeRuntimeEffect(kTestRuntimeEffect2, {}, nullptr); + std::shared_ptr source3 = + DlColorSource::MakeRuntimeEffect(nullptr, {}, nullptr); + + ASSERT_EQ(source1->type(), DlColorSourceType::kRuntimeEffect); + ASSERT_EQ(source1->asRuntimeEffect(), source1.get()); + ASSERT_NE(source2->asRuntimeEffect(), source1.get()); + + ASSERT_EQ(source1->asImage(), nullptr); + ASSERT_EQ(source1->asColor(), nullptr); + ASSERT_EQ(source1->asLinearGradient(), nullptr); + ASSERT_EQ(source1->asRadialGradient(), nullptr); + ASSERT_EQ(source1->asConicalGradient(), nullptr); + ASSERT_EQ(source1->asSweepGradient(), nullptr); + + ASSERT_NE(source1->skia_object(), nullptr); + ASSERT_EQ(source3->skia_object(), nullptr); + + TestEquals(source1, source1); + TestEquals(source3, source3); + TestNotEquals(source1, source2, "SkRuntimeEffect differs"); + TestNotEquals(source2, source3, "SkRuntimeEffect differs"); +} + } // namespace testing } // namespace flutter diff --git a/display_list/display_list_image.h b/display_list/display_list_image.h index 6f22b31e29ab2..19ae1d935bf6d 100644 --- a/display_list/display_list_image.h +++ b/display_list/display_list_image.h @@ -54,6 +54,17 @@ class DlImage : public SkRefCnt { /// virtual std::shared_ptr impeller_texture() const = 0; + //---------------------------------------------------------------------------- + /// @brief If the pixel format of this image ignores alpha, this returns + /// true. This method might conservatively return false when it + /// cannot guarnatee an opaque image, for example when the pixel + /// format of the image supports alpha but the image is made up of + /// entirely opaque pixels. + /// + /// @return True if the pixel format of this image ignores alpha. + /// + virtual bool isOpaque() const = 0; + virtual bool isTextureBacked() const = 0; //---------------------------------------------------------------------------- diff --git a/display_list/display_list_image_skia.cc b/display_list/display_list_image_skia.cc index 2e2dddb5cba59..07fd84143b8fc 100644 --- a/display_list/display_list_image_skia.cc +++ b/display_list/display_list_image_skia.cc @@ -21,6 +21,11 @@ std::shared_ptr DlImageSkia::impeller_texture() const { return nullptr; } +// |DlImage| +bool DlImageSkia::isOpaque() const { + return image_ ? image_->isOpaque() : false; +} + // |DlImage| bool DlImageSkia::isTextureBacked() const { return image_ ? image_->isTextureBacked() : false; diff --git a/display_list/display_list_image_skia.h b/display_list/display_list_image_skia.h index 70f9871823083..7e76de802aa97 100644 --- a/display_list/display_list_image_skia.h +++ b/display_list/display_list_image_skia.h @@ -23,6 +23,9 @@ class DlImageSkia final : public DlImage { // |DlImage| std::shared_ptr impeller_texture() const override; + // |DlImage| + bool isOpaque() const override; + // |DlImage| bool isTextureBacked() const override; diff --git a/display_list/display_list_ops.h b/display_list/display_list_ops.h index 052e7c9343bc9..061f29365df45 100644 --- a/display_list/display_list_ops.h +++ b/display_list/display_list_ops.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_OPS_H_ #define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_OPS_H_ +#include "display_list_color_source.h" #include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_blend_mode.h" #include "flutter/display_list/display_list_dispatcher.h" @@ -246,6 +247,28 @@ struct SetImageColorSourceOp : DLOp { } }; +// 56 bytes: 4 byte header, 4 byte padding, 8 for vtable, 8 * 2 for sk_sps, 24 +// for the std::vector. +struct SetRuntimeEffectColorSourceOp : DLOp { + static const auto kType = DisplayListOpType::kSetRuntimeEffectColorSource; + + SetRuntimeEffectColorSourceOp(const DlRuntimeEffectColorSource* source) + : source(source->runtime_effect(), + source->samplers(), + source->uniform_data()) {} + + const DlRuntimeEffectColorSource source; + + void dispatch(Dispatcher& dispatcher) const { + dispatcher.setColorSource(&source); + } + + DisplayListCompare equals(const SetRuntimeEffectColorSourceOp* other) const { + return (source == other->source) ? DisplayListCompare::kEqual + : DisplayListCompare::kNotEqual; + } +}; + // 4 byte header + 16 byte payload uses 24 total bytes (4 bytes unused) struct SetSharedImageFilterOp : DLOp { static const auto kType = DisplayListOpType::kSetSharedImageFilter; diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index d39d508734c0b..b7dd47e48d99e 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -7,12 +7,12 @@ namespace flutter { -ShaderMaskLayer::ShaderMaskLayer(sk_sp shader, +ShaderMaskLayer::ShaderMaskLayer(std::shared_ptr shader, const SkRect& mask_rect, - SkBlendMode blend_mode) + DlBlendMode blend_mode) : CacheableContainerLayer( RasterCacheUtil::kMinimumRendersBeforeCachingFilterLayer), - shader_(shader), + shader_(std::move(shader)), mask_rect_(mask_rect), blend_mode_(blend_mode) {} @@ -60,8 +60,10 @@ void ShaderMaskLayer::Paint(PaintContext& context) const { PaintChildren(context); SkPaint paint; - paint.setBlendMode(blend_mode_); - paint.setShader(shader_); + paint.setBlendMode(ToSk(blend_mode_)); + if (shader_) { + paint.setShader(shader_->skia_object()); + } context.leaf_nodes_canvas->translate(mask_rect_.left(), mask_rect_.top()); context.leaf_nodes_canvas->drawRect( SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()), paint); diff --git a/flow/layers/shader_mask_layer.h b/flow/layers/shader_mask_layer.h index 0dd44e3dedec7..63ac4421d633e 100644 --- a/flow/layers/shader_mask_layer.h +++ b/flow/layers/shader_mask_layer.h @@ -5,16 +5,16 @@ #ifndef FLUTTER_FLOW_LAYERS_SHADER_MASK_LAYER_H_ #define FLUTTER_FLOW_LAYERS_SHADER_MASK_LAYER_H_ +#include "flutter/display_list/display_list_color_source.h" #include "flutter/flow/layers/cacheable_layer.h" -#include "third_party/skia/include/core/SkShader.h" namespace flutter { class ShaderMaskLayer : public CacheableContainerLayer { public: - ShaderMaskLayer(sk_sp shader, + ShaderMaskLayer(std::shared_ptr shader, const SkRect& mask_rect, - SkBlendMode blend_mode); + DlBlendMode blend_mode); void Diff(DiffContext* context, const Layer* old_layer) override; @@ -23,9 +23,9 @@ class ShaderMaskLayer : public CacheableContainerLayer { void Paint(PaintContext& context) const override; private: - sk_sp shader_; + std::shared_ptr shader_; SkRect mask_rect_; - SkBlendMode blend_mode_; + DlBlendMode blend_mode_; FML_DISALLOW_COPY_AND_ASSIGN(ShaderMaskLayer); }; diff --git a/flow/layers/shader_mask_layer_unittests.cc b/flow/layers/shader_mask_layer_unittests.cc index d57a2753d4bea..5f6c38b76a0f1 100644 --- a/flow/layers/shader_mask_layer_unittests.cc +++ b/flow/layers/shader_mask_layer_unittests.cc @@ -23,7 +23,7 @@ using ShaderMaskLayerTest = LayerTest; #ifndef NDEBUG TEST_F(ShaderMaskLayerTest, PaintingEmptyLayerDies) { auto layer = - std::make_shared(nullptr, kEmptyRect, SkBlendMode::kSrc); + std::make_shared(nullptr, kEmptyRect, DlBlendMode::kSrc); layer->Preroll(preroll_context(), SkMatrix()); EXPECT_EQ(layer->paint_bounds(), kEmptyRect); @@ -39,7 +39,7 @@ TEST_F(ShaderMaskLayerTest, PaintBeforePrerollDies) { const SkPath child_path = SkPath().addRect(child_bounds); auto mock_layer = std::make_shared(child_path); auto layer = - std::make_shared(nullptr, kEmptyRect, SkBlendMode::kSrc); + std::make_shared(nullptr, kEmptyRect, DlBlendMode::kSrc); layer->Add(mock_layer); EXPECT_EQ(layer->paint_bounds(), kEmptyRect); @@ -57,7 +57,7 @@ TEST_F(ShaderMaskLayerTest, EmptyFilter) { const SkPaint child_paint = SkPaint(SkColors::kYellow); auto mock_layer = std::make_shared(child_path, child_paint); auto layer = std::make_shared(nullptr, layer_bounds, - SkBlendMode::kSrc); + DlBlendMode::kSrc); layer->Add(mock_layer); layer->Preroll(preroll_context(), initial_transform); @@ -98,9 +98,10 @@ TEST_F(ShaderMaskLayerTest, SimpleFilter) { const SkPaint child_paint = SkPaint(SkColors::kYellow); auto layer_filter = SkPerlinNoiseShader::MakeFractalNoise(1.0f, 1.0f, 1, 1.0f); + auto dl_filter = DlColorSource::From(layer_filter); auto mock_layer = std::make_shared(child_path, child_paint); - auto layer = std::make_shared(layer_filter, layer_bounds, - SkBlendMode::kSrc); + auto layer = std::make_shared(dl_filter, layer_bounds, + DlBlendMode::kSrc); layer->Add(mock_layer); layer->Preroll(preroll_context(), initial_transform); @@ -142,10 +143,11 @@ TEST_F(ShaderMaskLayerTest, MultipleChildren) { const SkPaint child_paint2 = SkPaint(SkColors::kCyan); auto layer_filter = SkPerlinNoiseShader::MakeFractalNoise(1.0f, 1.0f, 1, 1.0f); + auto dl_filter = DlColorSource::From(layer_filter); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); - auto layer = std::make_shared(layer_filter, layer_bounds, - SkBlendMode::kSrc); + auto layer = std::make_shared(dl_filter, layer_bounds, + DlBlendMode::kSrc); layer->Add(mock_layer1); layer->Add(mock_layer2); @@ -197,14 +199,16 @@ TEST_F(ShaderMaskLayerTest, Nested) { const SkPaint child_paint2 = SkPaint(SkColors::kCyan); auto layer_filter1 = SkPerlinNoiseShader::MakeFractalNoise(1.0f, 1.0f, 1, 1.0f); + auto dl_filter1 = DlColorSource::From(layer_filter1); auto layer_filter2 = SkPerlinNoiseShader::MakeFractalNoise(2.0f, 2.0f, 2, 2.0f); + auto dl_filter2 = DlColorSource::From(layer_filter2); auto mock_layer1 = std::make_shared(child_path1, child_paint1); auto mock_layer2 = std::make_shared(child_path2, child_paint2); - auto layer1 = std::make_shared(layer_filter1, layer_bounds, - SkBlendMode::kSrc); - auto layer2 = std::make_shared(layer_filter2, layer_bounds, - SkBlendMode::kSrc); + auto layer1 = std::make_shared(dl_filter1, layer_bounds, + DlBlendMode::kSrc); + auto layer2 = std::make_shared(dl_filter2, layer_bounds, + DlBlendMode::kSrc); layer2->Add(mock_layer2); layer1->Add(mock_layer1); layer1->Add(layer2); @@ -269,8 +273,9 @@ TEST_F(ShaderMaskLayerTest, Readback) { const SkRect layer_bounds = SkRect::MakeLTRB(2.0f, 4.0f, 20.5f, 20.5f); auto layer_filter = SkPerlinNoiseShader::MakeFractalNoise(1.0f, 1.0f, 1, 1.0f); - auto layer = std::make_shared(layer_filter, layer_bounds, - SkBlendMode::kSrc); + auto dl_filter = DlColorSource::From(layer_filter); + auto layer = std::make_shared(dl_filter, layer_bounds, + DlBlendMode::kSrc); // ShaderMaskLayer does not read from surface preroll_context()->surface_needs_readback = false; @@ -289,13 +294,14 @@ TEST_F(ShaderMaskLayerTest, Readback) { TEST_F(ShaderMaskLayerTest, LayerCached) { auto layer_filter = SkPerlinNoiseShader::MakeFractalNoise(1.0f, 1.0f, 1, 1.0f); + auto dl_filter = DlColorSource::From(layer_filter); SkPaint paint; const SkRect layer_bounds = SkRect::MakeLTRB(2.0f, 4.0f, 20.5f, 20.5f); auto initial_transform = SkMatrix::Translate(50.0, 25.5); const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f)); auto mock_layer = std::make_shared(child_path); - auto layer = std::make_shared(layer_filter, layer_bounds, - SkBlendMode::kSrc); + auto layer = std::make_shared(dl_filter, layer_bounds, + DlBlendMode::kSrc); layer->Add(mock_layer); SkMatrix cache_ctm = initial_transform; @@ -344,7 +350,7 @@ TEST_F(ShaderMaskLayerTest, OpacityInheritance) { auto mock_layer = MockLayer::Make(child_path); const SkRect mask_rect = SkRect::MakeLTRB(10, 10, 20, 20); auto shader_mask_layer = - std::make_shared(nullptr, mask_rect, SkBlendMode::kSrc); + std::make_shared(nullptr, mask_rect, DlBlendMode::kSrc); shader_mask_layer->Add(mock_layer); // ShaderMaskLayers can always support opacity despite incompatible children diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index f483856b6a4dc..0fbd95d891b24 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -397,6 +397,7 @@ void DisplayListDispatcher::setColorSource( return; } case flutter::DlColorSourceType::kConicalGradient: + case flutter::DlColorSourceType::kRuntimeEffect: case flutter::DlColorSourceType::kUnknown: UNIMPLEMENTED; break; diff --git a/impeller/display_list/display_list_image_impeller.cc b/impeller/display_list/display_list_image_impeller.cc index b4627c0da6776..f964010b9ae90 100644 --- a/impeller/display_list/display_list_image_impeller.cc +++ b/impeller/display_list/display_list_image_impeller.cc @@ -29,6 +29,12 @@ std::shared_ptr DlImageImpeller::impeller_texture() const { return texture_; } +// |DlImage| +bool DlImageImpeller::isOpaque() const { + // Impeller doesn't currently implement opaque alpha types. + return false; +} + // |DlImage| bool DlImageImpeller::isTextureBacked() const { // Impeller textures are always ... textures :/ diff --git a/impeller/display_list/display_list_image_impeller.h b/impeller/display_list/display_list_image_impeller.h index 652b861f85c77..cf7ae7501eb69 100644 --- a/impeller/display_list/display_list_image_impeller.h +++ b/impeller/display_list/display_list_image_impeller.h @@ -23,6 +23,9 @@ class DlImageImpeller final : public flutter::DlImage { // |DlImage| std::shared_ptr impeller_texture() const override; + // |DlImage| + bool isOpaque() const override; + // |DlImage| bool isTextureBacked() const override; diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 3967c20088d9b..9a543c284a18a 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -189,8 +189,7 @@ void SceneBuilder::pushShaderMask(Dart_Handle layer_handle, maskRectBottom); auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); auto layer = std::make_shared( - shader->shader(sampling)->skia_object(), rect, - static_cast(blendMode)); + shader->shader(sampling), rect, static_cast(blendMode)); PushLayer(layer); EngineLayer::MakeRetained(layer_handle, layer); diff --git a/lib/ui/painting/display_list_deferred_image_gpu.cc b/lib/ui/painting/display_list_deferred_image_gpu.cc index 4580fe9801e2c..beeb0ccf80404 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.cc +++ b/lib/ui/painting/display_list_deferred_image_gpu.cc @@ -51,6 +51,11 @@ std::shared_ptr DlDeferredImageGPU::impeller_texture() return nullptr; } +// |DlImage| +bool DlDeferredImageGPU::isOpaque() const { + return image_wrapper_ ? image_wrapper_->image_info().isOpaque() : false; +} + // |DlImage| bool DlDeferredImageGPU::isTextureBacked() const { return image_wrapper_ ? image_wrapper_->isTextureBacked() : false; diff --git a/lib/ui/painting/display_list_deferred_image_gpu.h b/lib/ui/painting/display_list_deferred_image_gpu.h index a98f4feaa4236..429dcd873a101 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.h +++ b/lib/ui/painting/display_list_deferred_image_gpu.h @@ -41,6 +41,9 @@ class DlDeferredImageGPU final : public DlImage { // |DlImage| std::shared_ptr impeller_texture() const override; + // |DlImage| + bool isOpaque() const override; + // |DlImage| bool isTextureBacked() const override; diff --git a/lib/ui/painting/display_list_image_gpu.cc b/lib/ui/painting/display_list_image_gpu.cc index a9e209a9e14eb..ff52840568cf1 100644 --- a/lib/ui/painting/display_list_image_gpu.cc +++ b/lib/ui/painting/display_list_image_gpu.cc @@ -29,6 +29,14 @@ std::shared_ptr DlImageGPU::impeller_texture() const { return nullptr; } +// |DlImage| +bool DlImageGPU::isOpaque() const { + if (auto image = skia_image()) { + return image->isOpaque(); + } + return false; +} + // |DlImage| bool DlImageGPU::isTextureBacked() const { if (auto image = skia_image()) { diff --git a/lib/ui/painting/display_list_image_gpu.h b/lib/ui/painting/display_list_image_gpu.h index 9631a333c0473..dbc7febc465ce 100644 --- a/lib/ui/painting/display_list_image_gpu.h +++ b/lib/ui/painting/display_list_image_gpu.h @@ -24,6 +24,9 @@ class DlImageGPU final : public DlImage { // |DlImage| std::shared_ptr impeller_texture() const override; + // |DlImage| + bool isOpaque() const override; + // |DlImage| bool isTextureBacked() const override; diff --git a/lib/ui/painting/fragment_program.cc b/lib/ui/painting/fragment_program.cc index bcd2626d28b33..e55c09f3eac94 100644 --- a/lib/ui/painting/fragment_program.cc +++ b/lib/ui/painting/fragment_program.cc @@ -112,7 +112,8 @@ fml::RefPtr FragmentProgram::shader(Dart_Handle shader, uniform_floats[i] = uniforms[i]; } uniforms.Release(); - std::vector> sk_samplers(sampler_shaders.size()); + std::vector> dl_samplers( + sampler_shaders.size()); for (size_t i = 0; i < sampler_shaders.size(); i++) { DlImageSampling sampling = DlImageSampling::kNearestNeighbor; ImageShader* image_shader = sampler_shaders[i]; @@ -122,13 +123,14 @@ fml::RefPtr FragmentProgram::shader(Dart_Handle shader, // 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. - sk_samplers[i] = image_shader->shader(sampling)->skia_object(); + dl_samplers[i] = image_shader->shader(sampling); uniform_floats[uniform_count + 2 * i] = image_shader->width(); uniform_floats[uniform_count + 2 * i + 1] = image_shader->height(); } - auto sk_shader = runtime_effect_->makeShader( - std::move(uniform_data), sk_samplers.data(), sk_samplers.size()); - return FragmentShader::Create(shader, std::move(sk_shader)); + return FragmentShader::Create( + shader, + DlColorSource::MakeRuntimeEffect(runtime_effect_, std::move(dl_samplers), + std::move(uniform_data))); } void FragmentProgram::Create(Dart_Handle wrapper) { diff --git a/lib/ui/painting/fragment_shader.cc b/lib/ui/painting/fragment_shader.cc index c7fa991bf07e1..39cee53482bed 100644 --- a/lib/ui/painting/fragment_shader.cc +++ b/lib/ui/painting/fragment_shader.cc @@ -34,15 +34,17 @@ std::shared_ptr FragmentShader::shader( return source_; } -fml::RefPtr FragmentShader::Create(Dart_Handle dart_handle, - sk_sp shader) { +fml::RefPtr FragmentShader::Create( + Dart_Handle dart_handle, + std::shared_ptr shader) { auto fragment_shader = fml::MakeRefCounted(std::move(shader)); fragment_shader->AssociateWithDartWrapper(dart_handle); return fragment_shader; } -FragmentShader::FragmentShader(sk_sp shader) - : source_(DlColorSource::From(shader)) {} +FragmentShader::FragmentShader( + std::shared_ptr shader) + : source_(std::move(shader)) {} FragmentShader::~FragmentShader() = default; diff --git a/lib/ui/painting/fragment_shader.h b/lib/ui/painting/fragment_shader.h index 3936f4475300f..f3aa48a156577 100644 --- a/lib/ui/painting/fragment_shader.h +++ b/lib/ui/painting/fragment_shader.h @@ -25,15 +25,16 @@ class FragmentShader : public Shader { public: ~FragmentShader() override; - static fml::RefPtr Create(Dart_Handle dart_handle, - sk_sp shader); + static fml::RefPtr Create( + Dart_Handle dart_handle, + std::shared_ptr shader); std::shared_ptr shader(DlImageSampling) override; private: - explicit FragmentShader(sk_sp shader); + explicit FragmentShader(std::shared_ptr shader); - std::shared_ptr source_; + std::shared_ptr source_; }; } // namespace flutter diff --git a/lib/ui/painting/image_shader.cc b/lib/ui/painting/image_shader.cc index 4567e016056a1..c7416bc86652c 100644 --- a/lib/ui/painting/image_shader.cc +++ b/lib/ui/painting/image_shader.cc @@ -32,12 +32,6 @@ Dart_Handle ImageShader::initWithImage(CanvasImage* image, return ToDart("ImageShader constructor called with non-genuine Image."); } - if (image->image()->owning_context() != DlImage::OwningContext::kIO) { - // TODO(dnfield): it should be possible to support this - // https://github.com/flutter/flutter/issues/105085 - return ToDart("ImageShader constructor with GPU image is not supported."); - } - image_ = image->image(); tonic::Float64List matrix4(matrix_handle); SkMatrix local_matrix = ToSkMatrix(matrix4); diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index 23b07b25d51bb..ccf0d11117367 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -98,7 +98,14 @@ const SkPaint* Paint::paint(SkPaint& paint) const { Shader* decoded = tonic::DartConverter::FromDart(shader); auto sampling = ImageFilter::SamplingFromIndex(uint_data[kFilterQualityIndex]); - paint.setShader(decoded->shader(sampling)->skia_object()); + auto color_source = decoded->shader(sampling); + // TODO(dnfield): Remove this restriction. + // This currently is only used by paragraph code. Once SkParagraph does + // not need to take an SkPaint, we won't be restricted in this way because + // we will not need to access the shader on the UI task runner. + if (color_source->owning_context() != DlImage::OwningContext::kRaster) { + paint.setShader(color_source->skia_object()); + } } Dart_Handle color_filter = values[kColorFilterIndex]; diff --git a/testing/dart/fragment_shader_test.dart b/testing/dart/fragment_shader_test.dart index 7fdcdf2742654..5fcc63f3ad328 100644 --- a/testing/dart/fragment_shader_test.dart +++ b/testing/dart/fragment_shader_test.dart @@ -36,8 +36,25 @@ void main() async { samplerUniforms: [imageShader], ); await _expectShaderRendersGreen(shader); + blueGreenImage.dispose(); }); + test('blue-green image renders green - GPU image', () async { + final FragmentProgram program = await FragmentProgram.fromAsset( + 'blue_green_sampler.frag.iplr', + ); + final Image blueGreenImage = _createBlueGreenImageSync(); + final ImageShader imageShader = ImageShader( + blueGreenImage, TileMode.clamp, TileMode.clamp, _identityMatrix); + final Shader shader = program.shader( + floatUniforms: Float32List.fromList([]), + samplerUniforms: [imageShader], + ); + await _expectShaderRendersGreen(shader); + blueGreenImage.dispose(); + }); + + test('shader with uniforms renders correctly', () async { final FragmentProgram program = await FragmentProgram.fromAsset( 'uniforms.frag.iplr', @@ -318,6 +335,21 @@ Future _createBlueGreenImage() async { return frame.image; } +// A 10x10 image where the left half is blue and the right half is green. +Image _createBlueGreenImageSync() { + final PictureRecorder recorder = PictureRecorder(); + final Canvas canvas = Canvas(recorder); + canvas.drawRect(const Rect.fromLTWH(0, 0, 5, 10), Paint()..color = const Color(0xFF0000FF)); + canvas.drawRect(const Rect.fromLTWH(5, 0, 5, 10), Paint()..color = const Color(0xFF00FF00)); + final Picture picture = recorder.endRecording(); + try { + return picture.toImageSync(10, 10); + } finally { + picture.dispose(); + } +} + + final Float64List _identityMatrix = Float64List.fromList([ 1, 0, 0, 0, 0, 1, 0, 0, diff --git a/testing/dart/image_shader_test.dart b/testing/dart/image_shader_test.dart index 56c502b132596..25b8b2dafb4f5 100644 --- a/testing/dart/image_shader_test.dart +++ b/testing/dart/image_shader_test.dart @@ -25,11 +25,9 @@ void main() { final Image image = picture.toImageSync(50, 50); picture.dispose(); - // TODO(dnfield): this should not throw once - // https://github.com/flutter/flutter/issues/105085 is fixed. - expect( - () => ImageShader(image, TileMode.clamp, TileMode.clamp, Float64List(16)), - throwsException, - ); + final ImageShader shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Float64List(16)); + final Paint paint = Paint()..shader=shader; + const Rect rect = Rect.fromLTRB(0, 0, 100, 100); + testCanvas((Canvas canvas) => canvas.drawRect(rect, paint)); }); } From deda4364e92f9add54f4de91fc8085a53b3b99fb Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Thu, 18 Aug 2022 17:26:52 -0700 Subject: [PATCH 408/558] Upgrade Android SDK to 33 Tiramisu (#35415) --- DEPS | 4 +-- .../localization/LocalizationPlugin.java | 5 +++- .../platform/android/test_runner/build.gradle | 2 +- .../android/app/build.gradle | 6 ++--- testing/scenario_app/android/app/build.gradle | 6 ++--- tools/android_lint/bin/main.dart | 4 +-- tools/android_lint/project.xml | 2 +- tools/android_sdk/create_cipd_packages.sh | 26 ++++++++++++++----- tools/android_sdk/packages.txt | 6 ++--- .../android_embedding_bundle/build.gradle | 2 +- tools/javadoc/gen_javadoc.py | 2 +- 11 files changed, 40 insertions(+), 25 deletions(-) diff --git a/DEPS b/DEPS index 0cb2b837bae5a..dac84661608a8 100644 --- a/DEPS +++ b/DEPS @@ -102,7 +102,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + '4dfab138e7dcc4d174ad0032c102d0f9055ba904', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '25e5fd0200ff0bbf4761f3e73cab67a16e928955', # Fuchsia compatibility # @@ -546,7 +546,7 @@ deps = { 'packages': [ { 'package': 'flutter/android/sdk/all/${{platform}}', - 'version': 'version:32v1' + 'version': 'version:33v6' } ], 'condition': 'download_android_deps', diff --git a/shell/platform/android/io/flutter/plugin/localization/LocalizationPlugin.java b/shell/platform/android/io/flutter/plugin/localization/LocalizationPlugin.java index 38dc780ed79fe..acb1e904ca629 100644 --- a/shell/platform/android/io/flutter/plugin/localization/LocalizationPlugin.java +++ b/shell/platform/android/io/flutter/plugin/localization/LocalizationPlugin.java @@ -23,7 +23,10 @@ public class LocalizationPlugin { @NonNull private final LocalizationChannel localizationChannel; @NonNull private final Context context; - @SuppressLint("AppBundleLocaleChanges") // This is optionally turned on by apps. + @SuppressLint({ + "AppBundleLocaleChanges", + "DiscouragedApi" + }) // This is optionally turned on by apps. @VisibleForTesting final LocalizationChannel.LocalizationMessageHandler localizationMessageHandler = new LocalizationChannel.LocalizationMessageHandler() { diff --git a/shell/platform/android/test_runner/build.gradle b/shell/platform/android/test_runner/build.gradle index 5d6aca1b8dfe5..dfdf361aeeae0 100644 --- a/shell/platform/android/test_runner/build.gradle +++ b/shell/platform/android/test_runner/build.gradle @@ -33,7 +33,7 @@ println "AVAILABLE PROCESSORS: $availableProcessors" println "==========================================" android { - compileSdkVersion 32 + compileSdkVersion 33 defaultConfig { minSdkVersion 16 diff --git a/testing/android_background_image/android/app/build.gradle b/testing/android_background_image/android/app/build.gradle index cfa8d98bedf23..c7346c23e8422 100644 --- a/testing/android_background_image/android/app/build.gradle +++ b/testing/android_background_image/android/app/build.gradle @@ -16,8 +16,8 @@ android { // The others are irrelevant for a test application. disable 'UnpackedNativeCode','MissingApplicationIcon','GoogleAppIndexingApiWarning','GoogleAppIndexingWarning','GradleDependency','NewerVersionAvailable' } - buildToolsVersion = '33.0.0-rc4' - compileSdkVersion 32 + buildToolsVersion = '33.0.0' + compileSdkVersion 33 compileOptions { sourceCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11 @@ -25,7 +25,7 @@ android { defaultConfig { applicationId 'dev.flutter.android_background_image' minSdkVersion 16 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName '1.0' } diff --git a/testing/scenario_app/android/app/build.gradle b/testing/scenario_app/android/app/build.gradle index d36ff250c7383..5f2a94523b996 100644 --- a/testing/scenario_app/android/app/build.gradle +++ b/testing/scenario_app/android/app/build.gradle @@ -18,8 +18,8 @@ android { // The others are irrelevant for a test application. disable 'UnpackedNativeCode','MissingApplicationIcon','GoogleAppIndexingApiWarning','GoogleAppIndexingWarning','GradleDependency','NewerVersionAvailable','Registered' } - buildToolsVersion = '33.0.0-rc4' - compileSdkVersion 32 + buildToolsVersion = '33.0.0' + compileSdkVersion 33 compileOptions { sourceCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11 @@ -27,7 +27,7 @@ android { defaultConfig { applicationId 'dev.flutter.scenarios' minSdkVersion 18 - targetSdkVersion 32 + targetSdkVersion 33 versionCode 1 versionName '1.0' testInstrumentationRunner 'dev.flutter.TestRunner' diff --git a/tools/android_lint/bin/main.dart b/tools/android_lint/bin/main.dart index e304caa158da5..88cfd040e231b 100644 --- a/tools/android_lint/bin/main.dart +++ b/tools/android_lint/bin/main.dart @@ -73,7 +73,7 @@ Future runLint(ArgParser argParser, ArgResults argResults) async { - + '''); for (final FileSystemEntity entity in androidDir.listSync(recursive: true)) { @@ -95,7 +95,7 @@ Future runLint(ArgParser argParser, ArgResults argResults) async { final List lintArgs = [ path.join(androidSdkDir.path, 'cmdline-tools', 'latest', 'bin', 'lint'), '--project', projectXmlPath, - '--compile-sdk-version', '31', + '--compile-sdk-version', '33', '--showall', '--exitcode', // Set non-zero exit code on errors '-Wall', diff --git a/tools/android_lint/project.xml b/tools/android_lint/project.xml index 1b1c2d514f6ef..af48aa0b7c75c 100644 --- a/tools/android_lint/project.xml +++ b/tools/android_lint/project.xml @@ -2,7 +2,7 @@ - + diff --git a/tools/android_sdk/create_cipd_packages.sh b/tools/android_sdk/create_cipd_packages.sh index b3bbb3184e8b5..c618ddeb025b8 100755 --- a/tools/android_sdk/create_cipd_packages.sh +++ b/tools/android_sdk/create_cipd_packages.sh @@ -3,11 +3,14 @@ # This script requires depot_tools to be on path. print_usage () { - echo "Usage: create_cipd_united_package.sh [PATH_TO_SDK_DIR]" - echo " where:" - echo " - VERSION_TAG is the tag of the cipd packages, e.g. 28r6 or 31v1" - echo " - PATH_TO_SDK_DIR is the path to the sdk folder. If omitted, this defaults to" + echo "Usage:" + echo " ./create_cipd_united_package.sh [PATH_TO_SDK_DIR]" + echo " Downloads, packages, and uploads Android SDK packages where:" + echo " - VERSION_TAG is the tag of the cipd packages, e.g. 28r6 or 31v1" + echo " - PATH_TO_SDK_DIR is the path to the sdk folder. If omitted, this defaults to" echo " your ANDROID_SDK_ROOT environment variable." + echo " ./create_cipd_united_package.sh list" + echo " Lists the available packages for use in 'packages.txt'" echo "" echo "This script downloads the packages specified in packages.txt and uploads" echo "them to CIPD for linux, mac, and windows." @@ -69,10 +72,16 @@ while [ ! -f "$sdkmanager_path" ]; do ((i++)) done +# list available packages +if [ $version_tag == "list" ]; then + $sdkmanager_path --list --include_obsolete + exit 0 +fi + # We create a new temporary SDK directory because the default working directory # tends to not update/re-download packages if they are being used. This guarantees # a clean install of Android SDK. -temp_dir=`mktemp -d -t android_sdk` +temp_dir=`mktemp -d -t android_sdkXXXX` for platform in "${platforms[@]}"; do sdk_root="$temp_dir/sdk_$platform" @@ -99,8 +108,11 @@ for platform in "${platforms[@]}"; do done # Special treatment for NDK to move to expected directory. - mv $upload_dir/sdk/ndk-bundle $upload_dir - mv $upload_dir/ndk-bundle $upload_dir/ndk + mv $upload_dir/sdk/ndk $upload_dir/ndk-bundle + ndk_sub_paths=`find $upload_dir/ndk-bundle -maxdepth 1 -type d` + ndk_sub_paths_arr=($ndk_sub_paths) + mv ${ndk_sub_paths_arr[1]} $upload_dir/ndk + rm -rf $upload_dir/ndk-bundle # Accept all licenses to ensure they are generated and uploaded. yes "y" | $sdkmanager_path --licenses --sdk_root=$sdk_root diff --git a/tools/android_sdk/packages.txt b/tools/android_sdk/packages.txt index c0961a9c7fe65..b257101a496af 100644 --- a/tools/android_sdk/packages.txt +++ b/tools/android_sdk/packages.txt @@ -1,6 +1,6 @@ -platforms;android-32:platforms +platforms;android-33:platforms cmdline-tools;latest:cmdline-tools -build-tools;33.0.0-rc4:build-tools +build-tools;33.0.0:build-tools platform-tools:platform-tools tools:tools -ndk-bundle:ndk-bundle \ No newline at end of file +ndk;22.1.7171670:ndk \ No newline at end of file diff --git a/tools/cipd/android_embedding_bundle/build.gradle b/tools/cipd/android_embedding_bundle/build.gradle index 66d2dfbc9aeb8..93c76e84fd384 100644 --- a/tools/cipd/android_embedding_bundle/build.gradle +++ b/tools/cipd/android_embedding_bundle/build.gradle @@ -29,7 +29,7 @@ allprojects { apply plugin: "com.android.application" android { - compileSdkVersion 32 + compileSdkVersion 33 } configurations { diff --git a/tools/javadoc/gen_javadoc.py b/tools/javadoc/gen_javadoc.py index e10a046cb051c..92b49ad77118d 100755 --- a/tools/javadoc/gen_javadoc.py +++ b/tools/javadoc/gen_javadoc.py @@ -58,7 +58,7 @@ def main(): classpath = [ args.android_source_root, os.path.join( - args.third_party, 'android_tools/sdk/platforms/android-32/android.jar' + args.third_party, 'android_tools/sdk/platforms/android-33/android.jar' ), os.path.join( args.third_party, 'android_embedding_dependencies', 'lib', '*' From f846d5f2ce9eff13b61d15f172dd5a6e391d4209 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Thu, 18 Aug 2022 17:30:34 -0700 Subject: [PATCH 409/558] Backfilled unit tests for IncomingMessageDispatcher. (#35139) * Backfilled unit tests for IncomingMessageDispatcher. * added license golden --- ci/licenses_golden/licenses_flutter | 1 + shell/platform/common/BUILD.gn | 1 + .../incoming_message_dispatcher_unittests.cc | 91 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 shell/platform/common/incoming_message_dispatcher_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index dfa73e2f41a3f..e32f53958103f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1686,6 +1686,7 @@ FILE: ../../../flutter/shell/platform/common/geometry.h FILE: ../../../flutter/shell/platform/common/geometry_unittests.cc FILE: ../../../flutter/shell/platform/common/incoming_message_dispatcher.cc FILE: ../../../flutter/shell/platform/common/incoming_message_dispatcher.h +FILE: ../../../flutter/shell/platform/common/incoming_message_dispatcher_unittests.cc FILE: ../../../flutter/shell/platform/common/json_message_codec.cc FILE: ../../../flutter/shell/platform/common/json_message_codec.h FILE: ../../../flutter/shell/platform/common/json_message_codec_unittests.cc diff --git a/shell/platform/common/BUILD.gn b/shell/platform/common/BUILD.gn index 571ee50765d17..a1a1817939202 100644 --- a/shell/platform/common/BUILD.gn +++ b/shell/platform/common/BUILD.gn @@ -174,6 +174,7 @@ if (enable_unittests) { sources = [ "engine_switches_unittests.cc", "geometry_unittests.cc", + "incoming_message_dispatcher_unittests.cc", "json_message_codec_unittests.cc", "json_method_codec_unittests.cc", "text_editing_delta_unittests.cc", diff --git a/shell/platform/common/incoming_message_dispatcher_unittests.cc b/shell/platform/common/incoming_message_dispatcher_unittests.cc new file mode 100644 index 0000000000000..55d69ed369218 --- /dev/null +++ b/shell/platform/common/incoming_message_dispatcher_unittests.cc @@ -0,0 +1,91 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/common/incoming_message_dispatcher.h" + +#include "gtest/gtest.h" + +namespace flutter { +TEST(IncomingMessageDispatcher, SetHandle) { + FlutterDesktopMessengerRef messenger = + reinterpret_cast(0xfeedface); + const uint8_t* message_data = reinterpret_cast(0xcafebabe); + auto dispatcher = std::make_unique(messenger); + bool did_call = false; + dispatcher->SetMessageCallback( + "hello", + [](FlutterDesktopMessengerRef messenger, + const FlutterDesktopMessage* message, void* user_data) { + EXPECT_EQ(messenger, + reinterpret_cast(0xfeedface)); + EXPECT_EQ(message->message, + reinterpret_cast(0xcafebabe)); + EXPECT_EQ(message->message_size, 123u); + *reinterpret_cast(user_data) = true; + }, + &did_call); + FlutterDesktopMessage message = { + .struct_size = sizeof(FlutterDesktopMessage), + .channel = "hello", + .message = message_data, + .message_size = 123, + .response_handle = nullptr, + }; + dispatcher->HandleMessage(message); + EXPECT_TRUE(did_call); +} + +TEST(IncomingMessageDispatcher, BlockInputFalse) { + FlutterDesktopMessengerRef messenger = nullptr; + auto dispatcher = std::make_unique(messenger); + bool did_call[3] = {false, false, false}; + dispatcher->SetMessageCallback( + "hello", + [](FlutterDesktopMessengerRef messenger, + const FlutterDesktopMessage* message, + void* user_data) { reinterpret_cast(user_data)[0] = true; }, + &did_call); + FlutterDesktopMessage message = { + .struct_size = sizeof(FlutterDesktopMessage), + .channel = "hello", + .message = nullptr, + .message_size = 0, + .response_handle = nullptr, + }; + dispatcher->HandleMessage( + message, [&did_call] { did_call[1] = true; }, + [&did_call] { did_call[2] = true; }); + EXPECT_TRUE(did_call[0]); + EXPECT_FALSE(did_call[1]); + EXPECT_FALSE(did_call[2]); +} + +TEST(IncomingMessageDispatcher, BlockInputTrue) { + FlutterDesktopMessengerRef messenger = nullptr; + auto dispatcher = std::make_unique(messenger); + static int counter = 0; + int did_call[3] = {-1, -1, -1}; + dispatcher->EnableInputBlockingForChannel("hello"); + dispatcher->SetMessageCallback( + "hello", + [](FlutterDesktopMessengerRef messenger, + const FlutterDesktopMessage* message, + void* user_data) { reinterpret_cast(user_data)[counter++] = 1; }, + &did_call); + FlutterDesktopMessage message = { + .struct_size = sizeof(FlutterDesktopMessage), + .channel = "hello", + .message = nullptr, + .message_size = 0, + .response_handle = nullptr, + }; + dispatcher->HandleMessage( + message, [&did_call] { did_call[counter++] = 0; }, + [&did_call] { did_call[counter++] = 2; }); + EXPECT_EQ(did_call[0], 0); + EXPECT_EQ(did_call[1], 1); + EXPECT_EQ(did_call[2], 2); +} + +} // namespace flutter From 5ccc5c48d0b6a68cfd6ae00b1236442e18121f6a Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Thu, 18 Aug 2022 17:34:25 -0700 Subject: [PATCH 410/558] [Impeller] Render Gaussian blurs into smaller textures and scale up with linear sampling (#35491) --- .../filters/gaussian_blur_filter_contents.cc | 85 +++++++++++++------ 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index 9c3034ff36449..a9f2ceed5ba9f 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -4,6 +4,7 @@ #include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" +#include #include #include "impeller/base/validation.h" @@ -90,7 +91,7 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( return std::nullopt; } - // Input 0 snapshot and UV mapping. + // Input 0 snapshot. auto input_snapshot = inputs[0]->GetSnapshot(renderer, entity); if (!input_snapshot.has_value()) { @@ -101,24 +102,51 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( return input_snapshot.value(); // No blur to render. } - auto maybe_input_uvs = input_snapshot->GetCoverageUVs(coverage); - if (!maybe_input_uvs.has_value()) { - return std::nullopt; - } - auto input_uvs = maybe_input_uvs.value(); + auto radius = Radius{blur_sigma_}.radius; + + auto transformed_blur_radius = + entity.GetTransformation().TransformDirection(blur_direction_ * radius); + + auto transformed_blur_radius_length = transformed_blur_radius.GetLength(); + + // A matrix that rotates the snapshot space such that the blur direction is + // +X. + auto texture_rotate = Matrix::MakeRotationZ( + transformed_blur_radius.Normalize().AngleTo({1, 0})); - // Source override snapshot and UV mapping. + // Converts local pass space to screen space. This is just the snapshot space + // rotated such that the blur direction is +X. + auto pass_transform = texture_rotate * input_snapshot->transform; + + // The pass texture coverage, but rotated such that the blur is in the +X + // direction, and expanded to include the blur radius. This is used for UV + // projection and as a source for the pass size. Note that it doesn't matter + // which direction the space is rotated in when grabbing the pass size. + auto pass_texture_rect = Rect::MakeSize(input_snapshot->texture->GetSize()) + .TransformBounds(pass_transform); + pass_texture_rect.origin.x -= transformed_blur_radius_length; + pass_texture_rect.size.width += transformed_blur_radius_length * 2; + + // Source override snapshot. auto source = source_override_ ? source_override_ : inputs[0]; auto source_snapshot = source->GetSnapshot(renderer, entity); if (!source_snapshot.has_value()) { return std::nullopt; } - auto maybe_source_uvs = source_snapshot->GetCoverageUVs(coverage); - if (!maybe_source_uvs.has_value()) { - return std::nullopt; - } - auto source_uvs = maybe_source_uvs.value(); + + // UV mapping. + + auto pass_uv_project = [&texture_rotate, + &pass_texture_rect](Snapshot& input) { + auto uv_matrix = Matrix::MakeScale(1 / Vector2(input.texture->GetSize())) * + (texture_rotate * input.transform).Invert(); + return pass_texture_rect.GetTransformedPoints(uv_matrix); + }; + + auto input_uvs = pass_uv_project(input_snapshot.value()); + + auto source_uvs = pass_uv_project(source_snapshot.value()); //---------------------------------------------------------------------------- /// Render to texture. @@ -139,9 +167,6 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( }); auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); - auto transformed_blur = entity.GetTransformation().TransformDirection( - blur_direction_ * blur_sigma_.sigma); - VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); @@ -150,11 +175,15 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( input_snapshot->texture->GetYCoordScale(); frag_info.alpha_mask_sampler_y_coord_scale = source_snapshot->texture->GetYCoordScale(); - frag_info.blur_sigma = transformed_blur.GetLength(); - frag_info.blur_radius = Radius{Sigma{frag_info.blur_sigma}}.radius; - frag_info.blur_direction = input_snapshot->transform.Invert() - .TransformDirection(transformed_blur) - .Normalize(); + + auto radius = Radius{transformed_blur_radius_length}; + frag_info.blur_sigma = Sigma{radius}.sigma; + frag_info.blur_radius = radius.radius; + + // The blur direction is in input UV space. + frag_info.blur_direction = + pass_transform.Invert().TransformDirection(Vector2(1, 0)).Normalize(); + frag_info.tile_mode = static_cast(tile_mode_); frag_info.src_factor = src_color_factor_; frag_info.inner_blur_factor = inner_blur_factor_; @@ -182,7 +211,12 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( return pass.AddCommand(cmd); }; - auto out_texture = renderer.MakeSubpass(ISize(coverage.size), callback); + Scalar x_scale = + std::min(1.0, 1.0 / std::ceil(std::log2(transformed_blur_radius_length))); + auto out_texture = + renderer.MakeSubpass(ISize(pass_texture_rect.size.width * x_scale, + pass_texture_rect.size.height), + callback); if (!out_texture) { return std::nullopt; } @@ -192,9 +226,12 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( sampler_desc.min_filter = MinMagFilter::kLinear; sampler_desc.mag_filter = MinMagFilter::kLinear; - return Snapshot{.texture = out_texture, - .transform = Matrix::MakeTranslation(coverage.origin), - .sampler_descriptor = sampler_desc}; + return Snapshot{ + .texture = out_texture, + .transform = texture_rotate.Invert() * + Matrix::MakeTranslation(pass_texture_rect.origin) * + Matrix::MakeScale(Vector2(1 / x_scale, 1)), + .sampler_descriptor = sampler_desc}; } std::optional DirectionalGaussianBlurFilterContents::GetFilterCoverage( From b1970a0c3839629e851b4ffa590a10265a3cc94b Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 18 Aug 2022 18:00:48 -0700 Subject: [PATCH 411/558] Use `MakeWebGLSurface` in `toImageSync` (#35276) --- .../src/engine/canvaskit/canvaskit_api.dart | 1 + .../lib/src/engine/canvaskit/picture.dart | 22 +++++++- .../test/canvaskit/canvaskit_api_test.dart | 6 ++- .../test/canvaskit/image_golden_test.dart | 51 ++++++++++++++++++- lib/web_ui/test/canvaskit/picture_test.dart | 6 ++- lib/web_ui/test/canvaskit/scene_test.dart | 3 +- 6 files changed, 81 insertions(+), 8 deletions(-) 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 3ef9ed6de0b28..c9b4135b804bf 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -107,6 +107,7 @@ extension CanvasKitExtension on CanvasKit { external SkParagraphStyle ParagraphStyle( SkParagraphStyleProperties properties); external SkTextStyle TextStyle(SkTextStyleProperties properties); + external SkSurface MakeWebGLCanvasSurface(DomCanvasElement canvas); external SkSurface MakeSurface( int width, int height, diff --git a/lib/web_ui/lib/src/engine/canvaskit/picture.dart b/lib/web_ui/lib/src/engine/canvaskit/picture.dart index 0e55fe8f8634e..fa5a7c263f852 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/picture.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/picture.dart @@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:typed_data'; + import 'package:ui/ui.dart' as ui; +import '../dom.dart'; import '../profiler.dart'; import '../util.dart'; import 'canvas.dart'; @@ -97,12 +100,27 @@ class CkPicture extends ManagedSkiaObject implements ui.Picture { @override ui.Image toImageSync(int width, int height) { assert(debugCheckNotDisposed('Cannot convert picture to image.')); - final SkSurface skSurface = canvasKit.MakeSurface(width, height); + final DomCanvasElement tempCanvas = + createDomCanvasElement(width: width, height: height); + final SkSurface skSurface = canvasKit.MakeWebGLCanvasSurface(tempCanvas); final SkCanvas skCanvas = skSurface.getCanvas(); skCanvas.drawPicture(skiaObject); final SkImage skImage = skSurface.makeImageSnapshot(); + final SkImageInfo imageInfo = SkImageInfo( + alphaType: canvasKit.AlphaType.Premul, + colorType: canvasKit.ColorType.RGBA_8888, + colorSpace: SkColorSpaceSRGB, + width: width, + height: height, + ); + final Uint8List pixels = skImage.readPixels(0, 0, imageInfo); + final SkImage? rasterImage = canvasKit.MakeImage(imageInfo, pixels, 4 * width); skSurface.dispose(); - return CkImage(skImage); + tempCanvas.remove(); + if (rasterImage == null) { + throw StateError('Unable to convert image pixels into SkImage.'); + } + return CkImage(rasterImage); } @override diff --git a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart index 8418965a164da..eae7a3bee5730 100644 --- a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart +++ b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart @@ -692,7 +692,8 @@ void _matrix4x4CompositionTests() { final bool areEqual = await fuzzyCompareImages(incrementalMatrixImage, combinedMatrixImage); expect(areEqual, true); - }); + // TODO(hterkelsen): https://github.com/flutter/flutter/issues/109265 + }, skip: isFirefox); } void _toSkRectTests() { @@ -1370,7 +1371,8 @@ void _canvasTests() { final ByteData pngData = await image.toByteData(format: ui.ImageByteFormat.png); expect(pngData.lengthInBytes, greaterThan(0)); - }); + // TODO(hterkelsen): https://github.com/flutter/flutter/issues/109265 + }, skip: isFirefox); } void _textStyleTests() { diff --git a/lib/web_ui/test/canvaskit/image_golden_test.dart b/lib/web_ui/test/canvaskit/image_golden_test.dart index afcd198e7e714..19528b2370e79 100644 --- a/lib/web_ui/test/canvaskit/image_golden_test.dart +++ b/lib/web_ui/test/canvaskit/image_golden_test.dart @@ -521,7 +521,8 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { image.dispose(); codec.dispose(); - }); + // TODO(hterkelsen): https://github.com/flutter/flutter/issues/109265 + }, skip: isFirefox || isSafari); // This is a regression test for the issues with transferring textures from // one GL context to another, such as: @@ -575,6 +576,54 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { await disposePlatformView(0); }); + test('toImageSync with texture-backed image', () async { + final DomResponse imageResponse = await httpFetch('/test_images/mandrill_128.png'); + final Uint8List imageData = (await imageResponse.arrayBuffer() as ByteBuffer).asUint8List(); + final ui.Codec codec = await skiaInstantiateImageCodec(imageData); + final ui.FrameInfo frame = await codec.getNextFrame(); + final CkImage mandrill = frame.image as CkImage; + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final ui.Canvas canvas = ui.Canvas(recorder); + canvas.drawImageRect( + mandrill, + const ui.Rect.fromLTWH(0, 0, 128, 128), + const ui.Rect.fromLTWH(0, 0, 128, 128), + ui.Paint(), + ); + final ui.Picture picture = recorder.endRecording(); + final ui.Image image = picture.toImageSync(50, 50); + + expect(image.width, 50); + expect(image.height, 50); + + final ByteData? data = await image.toByteData(); + expect(data, isNotNull); + expect(data!.lengthInBytes, 50 * 50 * 4); + expect(data.buffer.asUint32List().any((int byte) => byte != 0), isTrue); + + final LayerSceneBuilder sb = LayerSceneBuilder(); + sb.pushOffset(0, 0); + { + final CkPictureRecorder recorder = CkPictureRecorder(); + final CkCanvas canvas = recorder.beginRecording(ui.Rect.largest); + canvas.save(); + canvas.drawImage(image as CkImage, ui.Offset.zero, CkPaint()); + canvas.restore(); + sb.addPicture(ui.Offset.zero, recorder.endRecording()); + } + final EnginePlatformDispatcher dispatcher = + ui.window.platformDispatcher as EnginePlatformDispatcher; + dispatcher.rasterizer!.draw(sb.build().layerTree); + await matchGoldenFile( + 'canvaskit_picture_texture_toimage', + region: const ui.Rect.fromLTRB(0, 0, 128, 128), + maxDiffRatePercent: 0, + ); + mandrill.dispose(); + codec.dispose(); + // TODO(hterkelsen): https://github.com/flutter/flutter/issues/109265 + }, skip: isFirefox || isSafari); + test('can detect JPEG from just magic number', () async { expect( detectContentType( diff --git a/lib/web_ui/test/canvaskit/picture_test.dart b/lib/web_ui/test/canvaskit/picture_test.dart index 5ed13acc1edcf..213d0dc4bad31 100644 --- a/lib/web_ui/test/canvaskit/picture_test.dart +++ b/lib/web_ui/test/canvaskit/picture_test.dart @@ -101,6 +101,8 @@ void testMain() { expect(data, isNotNull); expect(data!.lengthInBytes, 10 * 15 * 4); expect(data.buffer.asUint32List().first, color.value); - }); - }); + // TODO(hterkelsen): https://github.com/flutter/flutter/issues/109265 + }, skip: isFirefox || isSafari); + // TODO(hterkelsen): https://github.com/flutter/flutter/issues/60040 + }, skip: isIosSafari); } diff --git a/lib/web_ui/test/canvaskit/scene_test.dart b/lib/web_ui/test/canvaskit/scene_test.dart index 9395c067bb3d7..422e9622f9cac 100644 --- a/lib/web_ui/test/canvaskit/scene_test.dart +++ b/lib/web_ui/test/canvaskit/scene_test.dart @@ -45,7 +45,8 @@ void testMain() { final ui.Image sceneImage = await scene.toImage(100, 100); expect(sceneImage, isA()); - }); + // TODO(hterkelsen): https://github.com/flutter/flutter/issues/109265 + }, skip: isFirefox || isSafari); test('pushColorFilter does not throw', () async { final ui.SceneBuilder builder = ui.SceneBuilder(); From 5c30ead197b9b7e008c6a8bed12a92d29391772d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 21:15:10 -0400 Subject: [PATCH 412/558] Roll Skia from 9a51e6deb112 to 79633dd54c6f (16 revisions) (#35521) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index dac84661608a8..d3c0d5c950aa1 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': '9a51e6deb112a113ca133c48a3be12ed3c5a9a0a', + 'skia_revision': '79633dd54c6fa17b311dbb94fd3390394edb0bac', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 070c15872de74..59321ab83dabe 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 1008dd7e91b37ffa0192d2cf9c12bfcf +Signature: 0b72c565b4a6025f947e1b9dbb482ed2 UNUSED LICENSES: @@ -5545,6 +5545,8 @@ FILE: ../../../third_party/skia/src/gpu/AtlasTypes.h FILE: ../../../third_party/skia/src/gpu/RefCntedCallback.h FILE: ../../../third_party/skia/src/gpu/ganesh/GrBufferTransferRenderTask.cpp 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/tessellate/PathTessellator.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/tessellate/PathTessellator.h @@ -5627,7 +5629,6 @@ FILE: ../../../third_party/skia/src/gpu/tessellate/LinearTolerances.h FILE: ../../../third_party/skia/src/shaders/SkEmptyShader.cpp FILE: ../../../third_party/skia/src/shaders/gradients/SkGradientShaderBase.cpp FILE: ../../../third_party/skia/src/sksl/analysis/SkSLFinalizationChecks.cpp -FILE: ../../../third_party/skia/src/sksl/analysis/SkSLGetComputeShaderMainParams.cpp FILE: ../../../third_party/skia/src/sksl/analysis/SkSLIsSameExpressionTree.cpp FILE: ../../../third_party/skia/src/sksl/analysis/SkSLIsTrivialExpression.cpp FILE: ../../../third_party/skia/src/sksl/analysis/SkSLNoOpErrorReporter.h From 3e9fcf4f4a74a03ee81cd7ff0e8a2c3a36e0003c Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Thu, 18 Aug 2022 19:00:34 -0700 Subject: [PATCH 413/558] [canvaskit] Generate fallback font data file (#34729) --- ci/licenses_golden/licenses_flutter | 2 + lib/web_ui/README.md | 13 + lib/web_ui/dev/felt.dart | 2 + .../dev/generate_fallback_font_data.dart | 289 +++++++++ lib/web_ui/lib/src/engine.dart | 2 + .../engine/canvaskit/font_fallback_data.dart | 151 +++++ .../src/engine/canvaskit/font_fallbacks.dart | 599 ++---------------- .../src/engine/canvaskit/interval_tree.dart | 2 +- .../lib/src/engine/canvaskit/noto_font.dart | 98 +++ .../test/canvaskit/canvas_golden_test.dart | 5 +- .../canvaskit/fallback_fonts_golden_test.dart | 278 +++++--- 11 files changed, 797 insertions(+), 644 deletions(-) create mode 100644 lib/web_ui/dev/generate_fallback_font_data.dart create mode 100644 lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart create mode 100644 lib/web_ui/lib/src/engine/canvaskit/noto_font.dart diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e32f53958103f..03a7ee396ef44 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1135,6 +1135,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/color_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views_diff.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/fonts.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -1148,6 +1149,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.d FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/mask_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/n_way_canvas.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/painting.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path_metrics.dart diff --git a/lib/web_ui/README.md b/lib/web_ui/README.md index d13e1ee6b145d..f4e87cb31c6eb 100644 --- a/lib/web_ui/README.md +++ b/lib/web_ui/README.md @@ -205,6 +205,19 @@ directly), follow these steps to roll to the new version: If you have questions, contact the Flutter Web team on Flutter Discord on the #hackers-web-🌍 channel. +### Rolling Noto Font Data + +In order to generate new data for the Noto fallback fonts, you will need +a GoogleFonts API key. Once you have one, run: + +``` +./dev/felt generate-fallback-font-data --key= +``` + +This will generate the file `lib/src/engine/canvaskit/font_fallback_data.dart` with +the latest data from GoogleFonts. This generated file should then be rolled in with +a PR to the engine. + ### Configuration files `browser_lock.yaml` contains the version of browsers we use to test Flutter for diff --git a/lib/web_ui/dev/felt.dart b/lib/web_ui/dev/felt.dart index 1048c8bdcf3a6..2e6e6d156cf46 100644 --- a/lib/web_ui/dev/felt.dart +++ b/lib/web_ui/dev/felt.dart @@ -9,6 +9,7 @@ import 'package:args/command_runner.dart'; import 'build.dart'; import 'clean.dart'; import 'exceptions.dart'; +import 'generate_fallback_font_data.dart'; import 'licenses.dart'; import 'run.dart'; import 'test_runner.dart'; @@ -20,6 +21,7 @@ CommandRunner runner = CommandRunner( ) ..addCommand(BuildCommand()) ..addCommand(CleanCommand()) + ..addCommand(GenerateFallbackFontDataCommand()) ..addCommand(LicensesCommand()) ..addCommand(RunCommand()) ..addCommand(TestCommand()); diff --git a/lib/web_ui/dev/generate_fallback_font_data.dart b/lib/web_ui/dev/generate_fallback_font_data.dart new file mode 100644 index 0000000000000..7ae4aae65eb8c --- /dev/null +++ b/lib/web_ui/dev/generate_fallback_font_data.dart @@ -0,0 +1,289 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert' show jsonDecode; +import 'dart:io' as io; + +import 'package:args/command_runner.dart'; +import 'package:http/http.dart' as http; +import 'package:path/path.dart' as path; + +import 'environment.dart'; +import 'exceptions.dart'; +import 'utils.dart'; + +class GenerateFallbackFontDataCommand extends Command + with ArgUtils { + GenerateFallbackFontDataCommand() { + argParser.addOption( + 'key', + defaultsTo: '', + help: 'The Google Fonts API key. Used to get data about fonts hosted on ' + 'Google Fonts.', + ); + argParser.addFlag( + 'download-test-fonts', + defaultsTo: true, + help: 'Whether to download the Noto fonts into a local folder to use in' + 'tests.', + ); + } + + @override + final String name = 'generate-fallback-font-data'; + + @override + final String description = 'Generate fallback font data from GoogleFonts'; + + String get apiKey => stringArg('key'); + + bool get downloadTestFonts => boolArg('download-test-fonts'); + + @override + Future run() async { + await _generateFallbackFontData(); + return true; + } + + Future _generateFallbackFontData() async { + if (apiKey.isEmpty) { + throw UsageException('No Google Fonts API key provided', argParser.usage); + } + final http.Client client = http.Client(); + final http.Response response = await client.get(Uri.parse( + 'https://www.googleapis.com/webfonts/v1/webfonts?key=$apiKey')); + if (response.statusCode != 200) { + throw ToolExit('Failed to download Google Fonts list.'); + } + final Map googleFontsResult = + jsonDecode(response.body) as Map; + final List> fontDatas = + (googleFontsResult['items'] as List) + .cast>(); + final Map urlForFamily = {}; + for (final Map fontData in fontDatas) { + if (fallbackFonts.contains(fontData['family'])) { + final Uri uri = Uri.parse(fontData['files']['regular'] as String); + urlForFamily[fontData['family'] as String] = uri; + } + } + final Map charsetForFamily = {}; + final io.Directory fontDir = downloadTestFonts + ? await io.Directory(path.join( + environment.webUiBuildDir.path, + 'assets', + 'noto', + )).create(recursive: true) + : await io.Directory.systemTemp.createTemp('fonts'); + // Delete old fonts in the font directory. + await for (final io.FileSystemEntity file in fontDir.list()) { + await file.delete(); + } + for (final String family in fallbackFonts) { + print('Downloading $family...'); + final Uri uri = urlForFamily[family]!; + final http.Response fontResponse = await client.get(uri); + if (fontResponse.statusCode != 200) { + throw ToolExit('Failed to download font for $family'); + } + final io.File fontFile = + io.File(path.join(fontDir.path, path.basename(uri.path))); + await fontFile.writeAsBytes(fontResponse.bodyBytes); + final io.ProcessResult fcQueryResult = + await io.Process.run('fc-query', [ + '--format=%{charset}', + '--', + fontFile.path, + ]); + final String encodedCharset = fcQueryResult.stdout as String; + charsetForFamily[family] = encodedCharset; + } + + final StringBuffer sb = StringBuffer(); + + sb.writeln('// Copyright 2013 The Flutter Authors. All rights reserved.'); + sb.writeln('// Use of this source code is governed by a BSD-style license ' + 'that can be'); + sb.writeln('// found in the LICENSE file.'); + sb.writeln(); + sb.writeln('// DO NOT EDIT! This file is generated. See:'); + sb.writeln('// dev/generate_fallback_font_data.dart'); + sb.writeln("import 'noto_font.dart';"); + sb.writeln(); + sb.writeln('final List fallbackFonts = ['); + for (final String family in fallbackFonts) { + sb.write(" NotoFont.fromFlatRanges('$family', '${urlForFamily[family]!}', " + '['); + for (final String range in charsetForFamily[family]!.split(' ')) { + String? start; + String? end; + final List parts = range.split('-'); + if (parts.length == 1) { + start = parts[0]; + end = parts[0]; + } else { + start = parts[0]; + end = parts[1]; + } + sb.write('0x$start,0x$end,'); + } + sb.writeln(']),'); + } + sb.writeln('];'); + + final io.File fontDataFile = io.File(path.join( + environment.webUiRootDir.path, + 'lib', + 'src', + 'engine', + 'canvaskit', + 'font_fallback_data.dart', + )); + await fontDataFile.writeAsString(sb.toString()); + } +} + +const List fallbackFonts = [ + 'Noto Sans', + 'Noto Emoji', + 'Noto Sans Symbols', + 'Noto Sans Symbols 2', + 'Noto Sans Adlam', + 'Noto Sans Anatolian Hieroglyphs', + 'Noto Sans Arabic', + 'Noto Sans Armenian', + 'Noto Sans Avestan', + 'Noto Sans Balinese', + 'Noto Sans Bamum', + 'Noto Sans Bassa Vah', + 'Noto Sans Batak', + 'Noto Sans Bengali', + 'Noto Sans Bhaiksuki', + 'Noto Sans Brahmi', + 'Noto Sans Buginese', + 'Noto Sans Buhid', + 'Noto Sans Canadian Aboriginal', + 'Noto Sans Carian', + 'Noto Sans Caucasian Albanian', + 'Noto Sans Chakma', + 'Noto Sans Cham', + 'Noto Sans Cherokee', + 'Noto Sans Coptic', + 'Noto Sans Cuneiform', + 'Noto Sans Cypriot', + 'Noto Sans Deseret', + 'Noto Sans Devanagari', + 'Noto Sans Duployan', + 'Noto Sans Egyptian Hieroglyphs', + 'Noto Sans Elbasan', + 'Noto Sans Elymaic', + 'Noto Sans Georgian', + 'Noto Sans Glagolitic', + 'Noto Sans Gothic', + 'Noto Sans Grantha', + 'Noto Sans Gujarati', + 'Noto Sans Gunjala Gondi', + 'Noto Sans Gurmukhi', + 'Noto Sans HK', + 'Noto Sans Hanunoo', + 'Noto Sans Hatran', + 'Noto Sans Hebrew', + 'Noto Sans Imperial Aramaic', + 'Noto Sans Indic Siyaq Numbers', + 'Noto Sans Inscriptional Pahlavi', + 'Noto Sans Inscriptional Parthian', + 'Noto Sans JP', + 'Noto Sans Javanese', + 'Noto Sans KR', + 'Noto Sans Kaithi', + 'Noto Sans Kannada', + 'Noto Sans Kayah Li', + 'Noto Sans Kharoshthi', + 'Noto Sans Khmer', + 'Noto Sans Khojki', + 'Noto Sans Khudawadi', + 'Noto Sans Lao', + 'Noto Sans Lepcha', + 'Noto Sans Limbu', + 'Noto Sans Linear A', + 'Noto Sans Linear B', + 'Noto Sans Lisu', + 'Noto Sans Lycian', + 'Noto Sans Lydian', + 'Noto Sans Mahajani', + 'Noto Sans Malayalam', + 'Noto Sans Mandaic', + 'Noto Sans Manichaean', + 'Noto Sans Marchen', + 'Noto Sans Masaram Gondi', + 'Noto Sans Math', + 'Noto Sans Mayan Numerals', + 'Noto Sans Medefaidrin', + 'Noto Sans Meetei Mayek', + 'Noto Sans Meroitic', + 'Noto Sans Miao', + 'Noto Sans Modi', + 'Noto Sans Mongolian', + 'Noto Sans Mro', + 'Noto Sans Multani', + 'Noto Sans Myanmar', + 'Noto Sans N Ko', + 'Noto Sans Nabataean', + 'Noto Sans New Tai Lue', + 'Noto Sans Newa', + 'Noto Sans Nushu', + 'Noto Sans Ogham', + 'Noto Sans Ol Chiki', + 'Noto Sans Old Hungarian', + 'Noto Sans Old Italic', + 'Noto Sans Old North Arabian', + 'Noto Sans Old Permic', + 'Noto Sans Old Persian', + 'Noto Sans Old Sogdian', + 'Noto Sans Old South Arabian', + 'Noto Sans Old Turkic', + 'Noto Sans Oriya', + 'Noto Sans Osage', + 'Noto Sans Osmanya', + 'Noto Sans Pahawh Hmong', + 'Noto Sans Palmyrene', + 'Noto Sans Pau Cin Hau', + 'Noto Sans Phags Pa', + 'Noto Sans Phoenician', + 'Noto Sans Psalter Pahlavi', + 'Noto Sans Rejang', + 'Noto Sans Runic', + 'Noto Sans SC', + 'Noto Sans Saurashtra', + 'Noto Sans Sharada', + 'Noto Sans Shavian', + 'Noto Sans Siddham', + 'Noto Sans Sinhala', + 'Noto Sans Sogdian', + 'Noto Sans Sora Sompeng', + 'Noto Sans Soyombo', + 'Noto Sans Sundanese', + 'Noto Sans Syloti Nagri', + 'Noto Sans Syriac', + 'Noto Sans TC', + 'Noto Sans Tagalog', + 'Noto Sans Tagbanwa', + 'Noto Sans Tai Le', + 'Noto Sans Tai Tham', + 'Noto Sans Tai Viet', + 'Noto Sans Takri', + 'Noto Sans Tamil', + 'Noto Sans Tamil Supplement', + 'Noto Sans Telugu', + 'Noto Sans Thaana', + 'Noto Sans Thai', + 'Noto Sans Tifinagh', + 'Noto Sans Tirhuta', + 'Noto Sans Ugaritic', + 'Noto Sans Vai', + 'Noto Sans Wancho', + 'Noto Sans Warang Citi', + 'Noto Sans Yi', + 'Noto Sans Zanabazar Square', +]; diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 166f78ffac659..592f364c3cbee 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -26,6 +26,7 @@ export 'engine/canvaskit/canvaskit_canvas.dart'; export 'engine/canvaskit/color_filter.dart'; export 'engine/canvaskit/embedded_views.dart'; export 'engine/canvaskit/embedded_views_diff.dart'; +export 'engine/canvaskit/font_fallback_data.dart'; export 'engine/canvaskit/font_fallbacks.dart'; export 'engine/canvaskit/fonts.dart'; export 'engine/canvaskit/image.dart'; @@ -39,6 +40,7 @@ export 'engine/canvaskit/layer_scene_builder.dart'; export 'engine/canvaskit/layer_tree.dart'; export 'engine/canvaskit/mask_filter.dart'; export 'engine/canvaskit/n_way_canvas.dart'; +export 'engine/canvaskit/noto_font.dart'; export 'engine/canvaskit/painting.dart'; export 'engine/canvaskit/path.dart'; export 'engine/canvaskit/path_metrics.dart'; diff --git a/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart b/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart new file mode 100644 index 0000000000000..41c64cf61c7c6 --- /dev/null +++ b/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart @@ -0,0 +1,151 @@ +// 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. + +// DO NOT EDIT! This file is generated. See: +// dev/generate_fallback_font_data.dart +import 'noto_font.dart'; + +final List fallbackFonts = [ + NotoFont.fromFlatRanges('Noto Sans', 'http://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNb4j5Ba_2c7A.ttf', [0x20,0x7e,0xa0,0x377,0x37a,0x37f,0x384,0x38a,0x38c,0x38c,0x38e,0x3a1,0x3a3,0x3e1,0x3f0,0x52f,0x900,0x97f,0x1ab0,0x1ac0,0x1c80,0x1c88,0x1cd0,0x1cf6,0x1cf8,0x1cf9,0x1d00,0x1df9,0x1dfb,0x1f15,0x1f18,0x1f1d,0x1f20,0x1f45,0x1f48,0x1f4d,0x1f50,0x1f57,0x1f59,0x1f59,0x1f5b,0x1f5b,0x1f5d,0x1f5d,0x1f5f,0x1f7d,0x1f80,0x1fb4,0x1fb6,0x1fc4,0x1fc6,0x1fd3,0x1fd6,0x1fdb,0x1fdd,0x1fef,0x1ff2,0x1ff4,0x1ff6,0x1ffe,0x2000,0x2064,0x2066,0x2071,0x2074,0x208e,0x2090,0x209c,0x20a0,0x20bf,0x20f0,0x20f0,0x2100,0x215f,0x2184,0x2184,0x2189,0x2189,0x2212,0x2212,0x2215,0x2215,0x25cc,0x25cc,0x2c60,0x2c7f,0x2de0,0x2e52,0xa640,0xa69f,0xa700,0xa7bf,0xa7c2,0xa7ca,0xa7f5,0xa7ff,0xa830,0xa839,0xa8e0,0xa8ff,0xa92e,0xa92e,0xab30,0xab6b,0xfb00,0xfb06,0xfe00,0xfe00,0xfe20,0xfe2f,0xfeff,0xfeff,0xfffc,0xfffd,]), + NotoFont.fromFlatRanges('Noto Emoji', 'http://fonts.gstatic.com/s/notoemoji/v26/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-r0jwvS-FGJCMY.ttf', [0x20,0x20,0x23,0x23,0x2a,0x2a,0x30,0x39,0xa9,0xa9,0xae,0xae,0x200d,0x200d,0x203c,0x203c,0x2049,0x2049,0x20e3,0x20e3,0x2122,0x2122,0x2139,0x2139,0x2194,0x2199,0x21a9,0x21aa,0x231a,0x231b,0x2328,0x2328,0x23cf,0x23cf,0x23e9,0x23f3,0x23f8,0x23fa,0x24c2,0x24c2,0x25aa,0x25ab,0x25b6,0x25b6,0x25c0,0x25c0,0x25fb,0x25fe,0x2600,0x2604,0x260e,0x260e,0x2611,0x2611,0x2614,0x2615,0x2618,0x2618,0x261d,0x261d,0x2620,0x2620,0x2622,0x2623,0x2626,0x2626,0x262a,0x262a,0x262e,0x262f,0x2638,0x263a,0x2640,0x2640,0x2642,0x2642,0x2648,0x2653,0x265f,0x2660,0x2663,0x2663,0x2665,0x2666,0x2668,0x2668,0x267b,0x267b,0x267e,0x267f,0x2692,0x2697,0x2699,0x2699,0x269b,0x269c,0x26a0,0x26a1,0x26a7,0x26a7,0x26aa,0x26ab,0x26b0,0x26b1,0x26bd,0x26be,0x26c4,0x26c5,0x26c8,0x26c8,0x26ce,0x26cf,0x26d1,0x26d1,0x26d3,0x26d4,0x26e9,0x26ea,0x26f0,0x26f5,0x26f7,0x26fa,0x26fd,0x26fd,0x2702,0x2702,0x2705,0x2705,0x2708,0x270d,0x270f,0x270f,0x2712,0x2712,0x2714,0x2714,0x2716,0x2716,0x271d,0x271d,0x2721,0x2721,0x2728,0x2728,0x2733,0x2734,0x2744,0x2744,0x2747,0x2747,0x274c,0x274c,0x274e,0x274e,0x2753,0x2755,0x2757,0x2757,0x2763,0x2764,0x2795,0x2797,0x27a1,0x27a1,0x27b0,0x27b0,0x27bf,0x27bf,0x2934,0x2935,0x2b05,0x2b07,0x2b1b,0x2b1c,0x2b50,0x2b50,0x2b55,0x2b55,0x3030,0x3030,0x303d,0x303d,0x3297,0x3297,0x3299,0x3299,0xfe0e,0xfe0f,0x1f004,0x1f004,0x1f0cf,0x1f0cf,0x1f170,0x1f171,0x1f17e,0x1f17f,0x1f18e,0x1f18e,0x1f191,0x1f19a,0x1f1e6,0x1f1ff,0x1f201,0x1f202,0x1f21a,0x1f21a,0x1f22f,0x1f22f,0x1f232,0x1f23a,0x1f250,0x1f251,0x1f300,0x1f321,0x1f324,0x1f393,0x1f396,0x1f397,0x1f399,0x1f39b,0x1f39e,0x1f3f0,0x1f3f3,0x1f3f5,0x1f3f7,0x1f4fd,0x1f4ff,0x1f53d,0x1f549,0x1f54e,0x1f550,0x1f567,0x1f56f,0x1f570,0x1f573,0x1f57a,0x1f587,0x1f587,0x1f58a,0x1f58d,0x1f590,0x1f590,0x1f595,0x1f596,0x1f5a4,0x1f5a5,0x1f5a8,0x1f5a8,0x1f5b1,0x1f5b2,0x1f5bc,0x1f5bc,0x1f5c2,0x1f5c4,0x1f5d1,0x1f5d3,0x1f5dc,0x1f5de,0x1f5e1,0x1f5e1,0x1f5e3,0x1f5e3,0x1f5e8,0x1f5e8,0x1f5ef,0x1f5ef,0x1f5f3,0x1f5f3,0x1f5fa,0x1f64f,0x1f680,0x1f6c5,0x1f6cb,0x1f6d2,0x1f6d5,0x1f6d7,0x1f6dd,0x1f6e5,0x1f6e9,0x1f6e9,0x1f6eb,0x1f6ec,0x1f6f0,0x1f6f0,0x1f6f3,0x1f6fc,0x1f7e0,0x1f7eb,0x1f7f0,0x1f7f0,0x1f90c,0x1f93a,0x1f93c,0x1f945,0x1f947,0x1f9ff,0x1fa70,0x1fa74,0x1fa78,0x1fa7c,0x1fa80,0x1fa86,0x1fa90,0x1faac,0x1fab0,0x1faba,0x1fac0,0x1fac5,0x1fad0,0x1fad9,0x1fae0,0x1fae7,0x1faf0,0x1faf6,0xe0030,0xe0039,0xe0061,0xe007a,0xe007f,0xe007f,0xfe4e5,0xfe4ee,0xfe82c,0xfe82c,0xfe82e,0xfe837,]), + NotoFont.fromFlatRanges('Noto Sans Symbols', 'http://fonts.gstatic.com/s/notosanssymbols/v34/rP2up3q65FkAtHfwd-eIS2brbDN6gxP34F9jRRCe4W3gfQ8gavVFRkzrbQ.ttf', [0x20,0x20,0x30,0x39,0x41,0x5a,0x61,0x7a,0xa0,0xa0,0x20dd,0x20e0,0x20e2,0x20e4,0x2160,0x2183,0x2185,0x2188,0x218a,0x218b,0x2190,0x2199,0x2300,0x230f,0x2311,0x2315,0x2317,0x2317,0x231c,0x231f,0x2322,0x2323,0x2329,0x232a,0x232c,0x2335,0x237c,0x237c,0x2380,0x2394,0x2396,0x239a,0x23af,0x23af,0x23be,0x23cd,0x23d0,0x23db,0x23e2,0x23e8,0x2460,0x24ff,0x25cc,0x25cc,0x260a,0x260d,0x2613,0x2613,0x2624,0x262f,0x2638,0x263b,0x263d,0x2653,0x2669,0x267e,0x2690,0x269d,0x26a2,0x26a9,0x26ad,0x26bc,0x26ce,0x26ce,0x26e2,0x26ff,0x271d,0x2721,0x2776,0x2793,0x2921,0x2922,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f190,0x1f19b,0x1f1ac,0x1f546,0x1f549,0x1f54f,0x1f54f,0x1f610,0x1f610,0x1f700,0x1f773,]), + NotoFont.fromFlatRanges('Noto Sans Symbols 2', 'http://fonts.gstatic.com/s/notosanssymbols2/v15/I_uyMoGduATTei9eI8daxVHDyfisHr71ypPqfX71-AI.ttf', [0x20,0x20,0x23,0x23,0x2a,0x2a,0x30,0x39,0x7f,0xa0,0x2022,0x2022,0x20e2,0x20e3,0x21af,0x21af,0x21e6,0x21f0,0x21f3,0x21f3,0x2218,0x2219,0x2299,0x2299,0x22c4,0x22c6,0x2316,0x2316,0x2318,0x2318,0x231a,0x231b,0x2324,0x2328,0x232b,0x232b,0x237b,0x237b,0x237d,0x237f,0x2394,0x2394,0x23ce,0x23cf,0x23e9,0x23ea,0x23ed,0x23ef,0x23f1,0x2426,0x2440,0x244a,0x25a0,0x2609,0x260e,0x2612,0x2614,0x2623,0x2630,0x2637,0x263c,0x263c,0x2654,0x2668,0x267f,0x268f,0x269e,0x26a1,0x26aa,0x26ac,0x26bd,0x26cd,0x26cf,0x26e1,0x2700,0x2704,0x2706,0x2709,0x270b,0x271c,0x2722,0x2727,0x2729,0x274b,0x274d,0x274d,0x274f,0x2753,0x2756,0x2775,0x2794,0x2794,0x2798,0x27af,0x27b1,0x27be,0x2800,0x28ff,0x2981,0x2981,0x29bf,0x29bf,0x29eb,0x29eb,0x2b00,0x2b0d,0x2b12,0x2b2f,0x2b4d,0x2b73,0x2b76,0x2b95,0x2b97,0x2bfd,0x2bff,0x2bff,0x4dc0,0x4dff,0xfff9,0xfffb,0x10140,0x1018e,0x10190,0x1019c,0x101a0,0x101a0,0x101d0,0x101fd,0x102e0,0x102fb,0x10e60,0x10e7e,0x1d2e0,0x1d2f3,0x1d300,0x1d356,0x1d360,0x1d378,0x1f000,0x1f02b,0x1f030,0x1f093,0x1f0a0,0x1f0ae,0x1f0b1,0x1f0bf,0x1f0c1,0x1f0cf,0x1f0d1,0x1f0f5,0x1f30d,0x1f30f,0x1f315,0x1f315,0x1f31c,0x1f31c,0x1f321,0x1f32c,0x1f336,0x1f336,0x1f378,0x1f378,0x1f37d,0x1f37d,0x1f393,0x1f39f,0x1f3a7,0x1f3a7,0x1f3ac,0x1f3ae,0x1f3c2,0x1f3c2,0x1f3c4,0x1f3c4,0x1f3c6,0x1f3c6,0x1f3ca,0x1f3ce,0x1f3d4,0x1f3e0,0x1f3ed,0x1f3ed,0x1f3f1,0x1f3f3,0x1f3f5,0x1f3f7,0x1f408,0x1f408,0x1f415,0x1f415,0x1f41f,0x1f41f,0x1f426,0x1f426,0x1f43f,0x1f43f,0x1f441,0x1f442,0x1f446,0x1f449,0x1f44c,0x1f44e,0x1f453,0x1f453,0x1f46a,0x1f46a,0x1f47d,0x1f47d,0x1f4a3,0x1f4a3,0x1f4b0,0x1f4b0,0x1f4b3,0x1f4b3,0x1f4b9,0x1f4b9,0x1f4bb,0x1f4bb,0x1f4bf,0x1f4bf,0x1f4c8,0x1f4cb,0x1f4da,0x1f4da,0x1f4df,0x1f4df,0x1f4e4,0x1f4e6,0x1f4ea,0x1f4ed,0x1f4f7,0x1f4f7,0x1f4f9,0x1f4fb,0x1f4fd,0x1f4fe,0x1f503,0x1f503,0x1f507,0x1f50a,0x1f50d,0x1f50d,0x1f512,0x1f513,0x1f53e,0x1f545,0x1f54a,0x1f54a,0x1f550,0x1f579,0x1f57b,0x1f594,0x1f597,0x1f5a3,0x1f5a5,0x1f5fa,0x1f650,0x1f67f,0x1f687,0x1f687,0x1f68d,0x1f68d,0x1f691,0x1f691,0x1f694,0x1f694,0x1f698,0x1f698,0x1f6ad,0x1f6ad,0x1f6b2,0x1f6b2,0x1f6b9,0x1f6ba,0x1f6bc,0x1f6bc,0x1f6c6,0x1f6cb,0x1f6cd,0x1f6cf,0x1f6d3,0x1f6d7,0x1f6e0,0x1f6ea,0x1f6f0,0x1f6f3,0x1f6f7,0x1f6fc,0x1f780,0x1f7d8,0x1f7e0,0x1f7eb,0x1f800,0x1f80b,0x1f810,0x1f847,0x1f850,0x1f859,0x1f860,0x1f887,0x1f890,0x1f8ad,0x1f8b0,0x1f8b1,0x1f93b,0x1f93b,0x1f946,0x1f946,0x1fa00,0x1fa53,0x1fa60,0x1fa6d,0x1fa70,0x1fa74,0x1fa78,0x1fa7a,0x1fa80,0x1fa86,0x1fa90,0x1faa8,0x1fab0,0x1fab6,0x1fac0,0x1fac2,0x1fad0,0x1fad6,0x1fb00,0x1fb92,0x1fb94,0x1fbca,0x1fbf0,0x1fbf9,]), + NotoFont.fromFlatRanges('Noto Sans Adlam', 'http://fonts.gstatic.com/s/notosansadlam/v19/neIczCCpqp0s5pPusPamd81eMfjPonvqdbYxxpgufnv0TGnBZLwhuvk.ttf', [0x20,0x2f,0x3a,0x40,0x5b,0x5f,0x7b,0x7d,0xa0,0xa0,0xab,0xab,0xbb,0xbb,0x61f,0x61f,0x640,0x640,0x2013,0x2015,0x2018,0x201e,0x2020,0x2022,0x2026,0x2026,0x2030,0x2030,0x2039,0x203a,0x2044,0x2044,0x204f,0x204f,0x25cc,0x25cc,0x2e28,0x2e29,0x2e41,0x2e41,0x1e900,0x1e94b,0x1e950,0x1e959,0x1e95e,0x1e95f,]), + NotoFont.fromFlatRanges('Noto Sans Anatolian Hieroglyphs', 'http://fonts.gstatic.com/s/notosansanatolianhieroglyphs/v14/ijw9s4roRME5LLRxjsRb8A0gKPSWq4BbDmHHu6j2pEtUJzZWXybIymc5QYo.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200b,0x14400,0x14646,]), + NotoFont.fromFlatRanges('Noto Sans Arabic', 'http://fonts.gstatic.com/s/notosansarabic/v18/nwpxtLGrOAZMl5nJ_wfgRg3DrWFZWsnVBJ_sS6tlqHHFlhQ5l3sQWIHPqzCfyGyvu3CBFQLaig.ttf', [0x20,0x21,0x2c,0x2e,0x30,0x3a,0xa0,0xa0,0xab,0xab,0xbb,0xbb,0x34f,0x34f,0x600,0x61c,0x61e,0x6ff,0x750,0x77f,0x8a0,0x8b4,0x8b6,0x8be,0x8d3,0x8ff,0x200b,0x2011,0x204f,0x204f,0x25cc,0x25cc,0x2e41,0x2e41,0xfb50,0xfbc1,0xfbd3,0xfd3f,0xfd50,0xfd8f,0xfd92,0xfdc7,0xfdf0,0xfdfd,0xfe70,0xfe74,0xfe76,0xfefc,]), + NotoFont.fromFlatRanges('Noto Sans Armenian', 'http://fonts.gstatic.com/s/notosansarmenian/v32/ZgN0jOZKPa7CHqq0h37c7ReDUubm2SEdFXp7ig73qtTY5idb74R9UdM3y2nZLorxb60iYy6zF3Eg.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x308,0x308,0x531,0x556,0x559,0x58a,0x58d,0x58f,0x2010,0x2010,0x25cc,0x25cc,0xfb13,0xfb17,]), + NotoFont.fromFlatRanges('Noto Sans Avestan', 'http://fonts.gstatic.com/s/notosansavestan/v17/bWti7ejKfBziStx7lIzKOLQZKhIJkyu9SASLji8U.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200c,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x2e30,0x2e31,0x10b00,0x10b35,0x10b39,0x10b3f,]), + NotoFont.fromFlatRanges('Noto Sans Balinese', 'http://fonts.gstatic.com/s/notosansbalinese/v18/NaPwcYvSBuhTirw6IaFn6UrRDaqje-lpbbRtYf-Fwu2Ov7fdhE5Vd222PPY.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1b00,0x1b4b,0x1b50,0x1b7c,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Bamum', 'http://fonts.gstatic.com/s/notosansbamum/v18/uk-0EGK3o6EruUbnwovcbBTkkklK_Ya_PBHfNGTPEddO-_gLykxEkxA.ttf', [0x20,0x20,0xa0,0xa0,0xa6a0,0xa6f7,0x16800,0x16a38,]), + NotoFont.fromFlatRanges('Noto Sans Bassa Vah', 'http://fonts.gstatic.com/s/notosansbassavah/v15/PN_sRee-r3f7LnqsD5sax12gjZn7mBpL_4c2VNUQptE.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x16ad0,0x16aed,0x16af0,0x16af5,]), + NotoFont.fromFlatRanges('Noto Sans Batak', 'http://fonts.gstatic.com/s/notosansbatak/v15/gok2H6TwAEdtF9N8-mdTCQvT-Zdgo4_PHuk74A.ttf', [0x20,0x20,0xa0,0xa0,0x1bc0,0x1bf3,0x1bfc,0x1bff,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Bengali', 'http://fonts.gstatic.com/s/notosansbengali/v20/Cn-SJsCGWQxOjaGwMQ6fIiMywrNJIky6nvd8BjzVMvJx2mcSPVFpVEqE-6KmsolLudCk8izI0lc.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0x980,0x983,0x985,0x98c,0x98f,0x990,0x993,0x9a8,0x9aa,0x9b0,0x9b2,0x9b2,0x9b6,0x9b9,0x9bc,0x9c4,0x9c7,0x9c8,0x9cb,0x9ce,0x9d7,0x9d7,0x9dc,0x9dd,0x9df,0x9e3,0x9e6,0x9fe,0x1cd0,0x1cd0,0x1cd2,0x1cd2,0x1cd5,0x1cd6,0x1cd8,0x1cd8,0x1ce1,0x1ce1,0x1cea,0x1cea,0x1ced,0x1ced,0x1cf2,0x1cf2,0x1cf5,0x1cf7,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa8f1,0xa8f1,]), + NotoFont.fromFlatRanges('Noto Sans Bhaiksuki', 'http://fonts.gstatic.com/s/notosansbhaiksuki/v15/UcC63EosKniBH4iELXATsSBWdvUHXxhj8rLUdU4wh9U.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200b,0x25cc,0x25cc,0x11c00,0x11c08,0x11c0a,0x11c36,0x11c38,0x11c45,0x11c50,0x11c6c,]), + NotoFont.fromFlatRanges('Noto Sans Brahmi', 'http://fonts.gstatic.com/s/notosansbrahmi/v15/vEFK2-VODB8RrNDvZSUmQQIIByV18tK1W77HtMo.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0x11000,0x1104d,0x11052,0x1106f,0x1107f,0x1107f,]), + NotoFont.fromFlatRanges('Noto Sans Buginese', 'http://fonts.gstatic.com/s/notosansbuginese/v15/esDM30ldNv-KYGGJpKGk18phe_7Da6_gtfuEXLmNtw.ttf', [0x20,0x20,0xa0,0xa0,0x1a00,0x1a1b,0x1a1e,0x1a1f,0x200b,0x200d,0x25cc,0x25cc,0xa9cf,0xa9cf,]), + NotoFont.fromFlatRanges('Noto Sans Buhid', 'http://fonts.gstatic.com/s/notosansbuhid/v17/Dxxy8jiXMW75w3OmoDXVWJD7YwzAe6tgnaFoGA.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1735,0x1736,0x1740,0x1753,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Canadian Aboriginal', 'http://fonts.gstatic.com/s/notosanscanadianaboriginal/v19/4C_TLjTuEqPj-8J01CwaGkiZ9os0iGVkezM1mUT-j_Lmlzda6uH_nnX1bzigWLn_yAsg0q0uhQ.ttf', [0x20,0x20,0xa0,0xa0,0x131,0x131,0x2c7,0x2c7,0x2d8,0x2db,0x307,0x307,0x1400,0x167f,0x18b0,0x18f5,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Carian', 'http://fonts.gstatic.com/s/notosanscarian/v15/LDIpaoiONgYwA9Yc6f0gUILeMIOgs7ob9yGLmfI.ttf', [0x20,0x20,0xa0,0xa0,0x102a0,0x102d0,]), + NotoFont.fromFlatRanges('Noto Sans Caucasian Albanian', 'http://fonts.gstatic.com/s/notosanscaucasianalbanian/v16/nKKA-HM_FYFRJvXzVXaANsU0VzsAc46QGOkWytlTs-TXrYDmoVmRSZo.ttf', [0x20,0x20,0xa0,0xa0,0x304,0x304,0x331,0x331,0x25cc,0x25cc,0xfe20,0xfe2f,0x10530,0x10563,0x1056f,0x1056f,]), + NotoFont.fromFlatRanges('Noto Sans Chakma', 'http://fonts.gstatic.com/s/notosanschakma/v15/Y4GQYbJ8VTEp4t3MKJSMjg5OIzhi4JjTQhYBeYo.ttf', [0x20,0x20,0xa0,0xa0,0x9e6,0x9ef,0x1040,0x1049,0x200c,0x200d,0x25cc,0x25cc,0x11100,0x11134,0x11136,0x11146,]), + NotoFont.fromFlatRanges('Noto Sans Cham', 'http://fonts.gstatic.com/s/notosanscham/v19/pe06MIySN5pO62Z5YkFyQb_bbuRhe6D4yip43qfcERwcv7GykboaLg.ttf', [0x20,0x22,0x27,0x29,0x2c,0x2f,0x3a,0x3b,0x3f,0x3f,0xa0,0xa0,0xad,0xad,0x200c,0x200d,0x2010,0x2010,0x25cc,0x25cc,0xaa00,0xaa36,0xaa40,0xaa4d,0xaa50,0xaa59,0xaa5c,0xaa5f,]), + NotoFont.fromFlatRanges('Noto Sans Cherokee', 'http://fonts.gstatic.com/s/notosanscherokee/v17/KFOPCm6Yu8uF-29fiz9vQF9YWK6Z8O10cHNA0cSkZCHYWi5PDkm5rAffjl0.ttf', [0x20,0x20,0xa0,0xa0,0x300,0x302,0x304,0x304,0x30b,0x30c,0x323,0x324,0x330,0x331,0x13a0,0x13f5,0x13f8,0x13fd,0xab70,0xabbf,]), + NotoFont.fromFlatRanges('Noto Sans Coptic', 'http://fonts.gstatic.com/s/notosanscoptic/v15/iJWfBWmUZi_OHPqn4wq6kgqumOEd78u_VG0xR4Y.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x300,0x302,0x304,0x305,0x307,0x308,0x323,0x323,0x33f,0x33f,0x361,0x361,0x374,0x375,0x3e2,0x3ef,0x1dcd,0x1dcd,0x2010,0x2010,0x25cc,0x25cc,0x2c80,0x2cf3,0x2cf9,0x2cff,0xfe24,0xfe26,0x102e0,0x102fb,]), + NotoFont.fromFlatRanges('Noto Sans Cuneiform', 'http://fonts.gstatic.com/s/notosanscuneiform/v15/bMrrmTWK7YY-MF22aHGGd7H8PhJtvBDWgb9JlRQueeQ.ttf', [0x20,0x20,0xa0,0xa0,0x12000,0x12399,0x12400,0x1246e,0x12470,0x12474,0x12480,0x12543,]), + NotoFont.fromFlatRanges('Noto Sans Cypriot', 'http://fonts.gstatic.com/s/notosanscypriot/v15/8AtzGta9PYqQDjyp79a6f8Cj-3a3cxIsK5MPpahF.ttf', [0x20,0x20,0xa0,0xa0,0x10800,0x10805,0x10808,0x10808,0x1080a,0x10835,0x10837,0x10838,0x1083c,0x1083c,0x1083f,0x1083f,]), + NotoFont.fromFlatRanges('Noto Sans Deseret', 'http://fonts.gstatic.com/s/notosansdeseret/v15/MwQsbgPp1eKH6QsAVuFb9AZM6MMr2Vq9ZnJSZtQG.ttf', [0x20,0x20,0xa0,0xa0,0x10400,0x1044f,]), + NotoFont.fromFlatRanges('Noto Sans Devanagari', 'http://fonts.gstatic.com/s/notosansdevanagari/v19/TuGoUUFzXI5FBtUq5a8bjKYTZjtRU6Sgv3NaV_SNmI0b8QQCQmHn6B2OHjbL_08AlXQly-AzoFoW4Ow.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x900,0x97f,0x1cd0,0x1cf6,0x1cf8,0x1cf9,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x20f0,0x20f0,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa839,0xa8e0,0xa8ff,]), + NotoFont.fromFlatRanges('Noto Sans Duployan', 'http://fonts.gstatic.com/s/notosansduployan/v16/gokzH7nwAEdtF9N8-mdTDx_X9JM5wsvrFsIn6WYDvA.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x1bc00,0x1bc6a,0x1bc70,0x1bc7c,0x1bc80,0x1bc88,0x1bc90,0x1bc99,0x1bc9c,0x1bca3,]), + NotoFont.fromFlatRanges('Noto Sans Egyptian Hieroglyphs', 'http://fonts.gstatic.com/s/notosansegyptianhieroglyphs/v26/vEF42-tODB8RrNDvZSUmRhcQHzx1s7y_F9-j3qSzEcbEYindSVK8xRg7iw.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x13000,0x1342e,]), + NotoFont.fromFlatRanges('Noto Sans Elbasan', 'http://fonts.gstatic.com/s/notosanselbasan/v15/-F6rfiZqLzI2JPCgQBnw400qp1trvHdlre4dFcFh.ttf', [0x20,0x20,0xa0,0xa0,0xb7,0xb7,0x305,0x305,0x391,0x3a1,0x3a3,0x3a9,0x3da,0x3da,0x3dc,0x3dc,0x3de,0x3de,0x25cc,0x25cc,0x10500,0x10527,]), + NotoFont.fromFlatRanges('Noto Sans Elymaic', 'http://fonts.gstatic.com/s/notosanselymaic/v15/UqyKK9YTJW5liNMhTMqe9vUFP65ZD4AjWOT0zi2V.ttf', [0x20,0x20,0xa0,0xa0,0x10fe0,0x10ff6,]), + NotoFont.fromFlatRanges('Noto Sans Georgian', 'http://fonts.gstatic.com/s/notosansgeorgian/v36/PlIaFke5O6RzLfvNNVSitxkr76PRHBC4Ytyq-Gof7PUs4S7zWn-8YDB09HFNdpvnzFj-f5WK0OQV.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x589,0x589,0x10a0,0x10c5,0x10c7,0x10c7,0x10cd,0x10cd,0x10d0,0x10ff,0x1c90,0x1cba,0x1cbd,0x1cbf,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20be,0x20be,0x2122,0x2122,0x2212,0x2212,0x2d00,0x2d25,0x2d27,0x2d27,0x2d2d,0x2d2d,]), + NotoFont.fromFlatRanges('Noto Sans Glagolitic', 'http://fonts.gstatic.com/s/notosansglagolitic/v15/1q2ZY4-BBFBst88SU_tOj4J-4yuNF_HI4ERK4Amu7nM1.ttf', [0x20,0x20,0xa0,0xa0,0x303,0x303,0x305,0x305,0x484,0x484,0x487,0x487,0x2c00,0x2c2e,0x2c30,0x2c5e,0xa66f,0xa66f,0x1e000,0x1e006,0x1e008,0x1e018,0x1e01b,0x1e021,0x1e023,0x1e024,0x1e026,0x1e02a,]), + NotoFont.fromFlatRanges('Noto Sans Gothic', 'http://fonts.gstatic.com/s/notosansgothic/v15/TuGKUUVzXI5FBtUq5a8bj6wRbzxTFMX40kFQRx0.ttf', [0x20,0x20,0xa0,0xa0,0x304,0x305,0x308,0x308,0x331,0x331,0x10330,0x1034a,]), + NotoFont.fromFlatRanges('Noto Sans Grantha', 'http://fonts.gstatic.com/s/notosansgrantha/v15/3y976akwcCjmsU8NDyrKo3IQfQ4o-r8cFeulHc6N.ttf', [0x20,0x20,0xa0,0xa0,0x951,0x952,0x964,0x965,0xbaa,0xbaa,0xbb5,0xbb5,0xbe6,0xbf2,0x1cd0,0x1cd0,0x1cd2,0x1cd3,0x1cf2,0x1cf4,0x1cf8,0x1cf9,0x200c,0x200d,0x20f0,0x20f0,0x25cc,0x25cc,0x11300,0x11303,0x11305,0x1130c,0x1130f,0x11310,0x11313,0x11328,0x1132a,0x11330,0x11332,0x11333,0x11335,0x11339,0x1133b,0x11344,0x11347,0x11348,0x1134b,0x1134d,0x11350,0x11350,0x11357,0x11357,0x1135d,0x11363,0x11366,0x1136c,0x11370,0x11374,]), + NotoFont.fromFlatRanges('Noto Sans Gujarati', 'http://fonts.gstatic.com/s/notosansgujarati/v19/wlpWgx_HC1ti5ViekvcxnhMlCVo3f5pv17ivlzsUB14gg1TMR2Gw4VceEl7MA_ypFwPM_OdiEH0s.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xa81,0xa83,0xa85,0xa8d,0xa8f,0xa91,0xa93,0xaa8,0xaaa,0xab0,0xab2,0xab3,0xab5,0xab9,0xabc,0xac5,0xac7,0xac9,0xacb,0xacd,0xad0,0xad0,0xae0,0xae3,0xae6,0xaf1,0xaf9,0xaff,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa839,]), + NotoFont.fromFlatRanges('Noto Sans Gunjala Gondi', 'http://fonts.gstatic.com/s/notosansgunjalagondi/v15/bWto7e7KfBziStx7lIzKPrcSMwcEnCv6DW7n5hcVXYMTK4q1.ttf', [0x20,0x21,0x25,0x25,0x27,0x2f,0x3a,0x3a,0x3c,0x3f,0xa0,0xa0,0xd7,0xd7,0xf7,0xf7,0x200c,0x200d,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x2212,0x2212,0x25cc,0x25cc,0x11d60,0x11d65,0x11d67,0x11d68,0x11d6a,0x11d8e,0x11d90,0x11d91,0x11d93,0x11d98,0x11da0,0x11da9,]), + NotoFont.fromFlatRanges('Noto Sans Gurmukhi', 'http://fonts.gstatic.com/s/notosansgurmukhi/v18/w8g9H3EvQP81sInb43inmyN9zZ7hb7ATbSWo4q8dJ74a3cVrYFQ_bogT0-gPeG1OenbxZ_trdp7h.ttf', [0x20,0x23,0x25,0x25,0x27,0x3f,0x5b,0x5f,0x7b,0x7e,0xa0,0xa0,0xad,0xad,0xd7,0xd7,0xf7,0xf7,0x951,0x952,0x964,0x965,0xa01,0xa03,0xa05,0xa0a,0xa0f,0xa10,0xa13,0xa28,0xa2a,0xa30,0xa32,0xa33,0xa35,0xa36,0xa38,0xa39,0xa3c,0xa3c,0xa3e,0xa42,0xa47,0xa48,0xa4b,0xa4d,0xa51,0xa51,0xa59,0xa5c,0xa5e,0xa5e,0xa66,0xa76,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x20b9,0x20b9,0x2212,0x2212,0x25cc,0x25cc,0x262c,0x262c,0xa830,0xa839,]), + NotoFont.fromFlatRanges('Noto Sans HK', 'http://fonts.gstatic.com/s/notosanshk/v21/nKKQ-GM_FYFRJvXzVXaAPe9hMnB3Eu7mOQ.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x3435,0x3435,0x3440,0x3440,0x344a,0x344a,0x344c,0x344c,0x3464,0x3464,0x3473,0x3473,0x347a,0x347a,0x347d,0x347e,0x3493,0x3493,0x3496,0x3496,0x34a5,0x34a5,0x34af,0x34af,0x34bc,0x34bc,0x34c1,0x34c1,0x34c8,0x34c8,0x34df,0x34df,0x34e4,0x34e4,0x34e6,0x34e6,0x34fb,0x34fb,0x3506,0x3506,0x353e,0x353e,0x3551,0x3551,0x3553,0x3553,0x3559,0x3559,0x3561,0x3561,0x356d,0x356d,0x3570,0x3570,0x3572,0x3572,0x3577,0x3578,0x3584,0x3584,0x3597,0x3598,0x35a1,0x35a1,0x35a5,0x35a5,0x35ad,0x35ad,0x35bf,0x35bf,0x35c1,0x35c1,0x35c5,0x35c5,0x35c7,0x35c7,0x35ca,0x35ca,0x35ce,0x35ce,0x35d2,0x35d2,0x35d6,0x35d6,0x35db,0x35db,0x35dd,0x35dd,0x35f1,0x35f3,0x35fb,0x35fb,0x35fe,0x35fe,0x3609,0x3609,0x3618,0x3618,0x361a,0x361a,0x3623,0x3623,0x3625,0x3625,0x362d,0x362d,0x3635,0x3635,0x3639,0x3639,0x363e,0x363e,0x3647,0x3649,0x364e,0x364e,0x365f,0x365f,0x3661,0x3661,0x367a,0x367a,0x3681,0x3681,0x369a,0x369a,0x36a5,0x36a5,0x36aa,0x36aa,0x36ac,0x36ac,0x36b0,0x36b1,0x36b5,0x36b5,0x36b9,0x36b9,0x36bc,0x36bc,0x36c1,0x36c1,0x36c3,0x36c5,0x36c7,0x36c8,0x36d3,0x36d4,0x36d6,0x36d6,0x36dd,0x36dd,0x36e1,0x36e2,0x36e5,0x36e6,0x36f5,0x36f5,0x3701,0x3701,0x3703,0x3703,0x3708,0x3708,0x370a,0x370a,0x370d,0x370d,0x371c,0x371c,0x3722,0x3723,0x3725,0x3725,0x372c,0x372d,0x3730,0x3730,0x3732,0x3733,0x373a,0x373a,0x3740,0x3740,0x3743,0x3743,0x3762,0x3762,0x376f,0x376f,0x3797,0x3797,0x37a0,0x37a0,0x37b9,0x37b9,0x37be,0x37be,0x37d6,0x37d6,0x37f2,0x37f2,0x37f8,0x37f8,0x37fb,0x37fb,0x380f,0x380f,0x3819,0x3819,0x3820,0x3820,0x382d,0x382d,0x3836,0x3836,0x3838,0x3838,0x3863,0x3863,0x3875,0x3875,0x38a0,0x38a0,0x38c3,0x38c3,0x38cc,0x38cc,0x38d1,0x38d1,0x38d4,0x38d4,0x38fa,0x38fa,0x3908,0x3908,0x3914,0x3914,0x3927,0x3927,0x3932,0x3932,0x393f,0x393f,0x394d,0x394d,0x3963,0x3963,0x3978,0x3978,0x3980,0x3980,0x3989,0x398a,0x3992,0x3992,0x3999,0x3999,0x399b,0x399b,0x39a1,0x39a1,0x39a4,0x39a4,0x39b8,0x39b8,0x39dc,0x39dc,0x39e2,0x39e2,0x39e5,0x39e5,0x39ec,0x39ec,0x39f8,0x39f8,0x39fb,0x39fb,0x39fe,0x39fe,0x3a01,0x3a01,0x3a03,0x3a03,0x3a06,0x3a06,0x3a17,0x3a18,0x3a29,0x3a2a,0x3a34,0x3a34,0x3a4b,0x3a4b,0x3a52,0x3a52,0x3a57,0x3a57,0x3a5c,0x3a5c,0x3a5e,0x3a5e,0x3a66,0x3a67,0x3a97,0x3a97,0x3aab,0x3aab,0x3abd,0x3abd,0x3ade,0x3ade,0x3ae0,0x3ae0,0x3af0,0x3af0,0x3af2,0x3af2,0x3af5,0x3af5,0x3afb,0x3afb,0x3b0e,0x3b0e,0x3b19,0x3b19,0x3b22,0x3b22,0x3b2b,0x3b2b,0x3b39,0x3b39,0x3b42,0x3b42,0x3b58,0x3b58,0x3b60,0x3b60,0x3b71,0x3b72,0x3b7b,0x3b7c,0x3b80,0x3b80,0x3b95,0x3b96,0x3b99,0x3b99,0x3ba1,0x3ba1,0x3bbc,0x3bbc,0x3bbe,0x3bbe,0x3bc2,0x3bc2,0x3bc4,0x3bc4,0x3bd7,0x3bd7,0x3bdd,0x3bdd,0x3bec,0x3bec,0x3bf2,0x3bf4,0x3c0d,0x3c0d,0x3c11,0x3c11,0x3c15,0x3c15,0x3c18,0x3c18,0x3c54,0x3c54,0x3c8b,0x3c8b,0x3ccb,0x3ccb,0x3ccd,0x3ccd,0x3cd1,0x3cd1,0x3cd6,0x3cd6,0x3cdc,0x3cdc,0x3ceb,0x3ceb,0x3cef,0x3cef,0x3d12,0x3d13,0x3d1d,0x3d1d,0x3d32,0x3d32,0x3d3b,0x3d3b,0x3d46,0x3d46,0x3d4c,0x3d4c,0x3d4e,0x3d4e,0x3d51,0x3d51,0x3d5f,0x3d5f,0x3d62,0x3d62,0x3d69,0x3d6a,0x3d6f,0x3d6f,0x3d75,0x3d75,0x3d7d,0x3d7d,0x3d85,0x3d85,0x3d88,0x3d88,0x3d8a,0x3d8a,0x3d8f,0x3d8f,0x3d91,0x3d91,0x3da5,0x3da5,0x3dad,0x3dad,0x3db4,0x3db4,0x3dbf,0x3dbf,0x3dc6,0x3dc7,0x3dc9,0x3dc9,0x3dcc,0x3dcd,0x3dd3,0x3dd3,0x3ddb,0x3ddb,0x3de7,0x3de8,0x3deb,0x3deb,0x3df3,0x3df4,0x3df7,0x3df7,0x3dfc,0x3dfd,0x3e06,0x3e06,0x3e40,0x3e40,0x3e43,0x3e43,0x3e48,0x3e48,0x3e55,0x3e55,0x3e74,0x3e74,0x3ea8,0x3eaa,0x3ead,0x3ead,0x3eb1,0x3eb1,0x3eb8,0x3eb8,0x3ebf,0x3ebf,0x3ec2,0x3ec2,0x3ec7,0x3ec7,0x3eca,0x3eca,0x3ecc,0x3ecc,0x3ed0,0x3ed1,0x3ed6,0x3ed7,0x3eda,0x3edb,0x3ede,0x3ede,0x3ee1,0x3ee2,0x3ee7,0x3ee7,0x3ee9,0x3ee9,0x3eeb,0x3eec,0x3ef0,0x3ef0,0x3ef3,0x3ef4,0x3efa,0x3efa,0x3efc,0x3efc,0x3eff,0x3f00,0x3f04,0x3f04,0x3f06,0x3f07,0x3f0e,0x3f0e,0x3f53,0x3f53,0x3f58,0x3f59,0x3f63,0x3f63,0x3f7c,0x3f7c,0x3f93,0x3f93,0x3fc0,0x3fc0,0x3fc8,0x3fc8,0x3fd7,0x3fd7,0x3fdc,0x3fdc,0x3fe5,0x3fe5,0x3fed,0x3fed,0x3ff9,0x3ffa,0x4004,0x4004,0x4009,0x4009,0x401d,0x401d,0x4039,0x4039,0x4045,0x4045,0x4053,0x4053,0x4057,0x4057,0x4062,0x4062,0x4065,0x4065,0x406a,0x406a,0x406f,0x406f,0x4071,0x4071,0x40a8,0x40a8,0x40b4,0x40b4,0x40bb,0x40bb,0x40bf,0x40bf,0x40c8,0x40c8,0x40d8,0x40d8,0x40df,0x40df,0x40f8,0x40f8,0x40fa,0x40fa,0x4102,0x4104,0x4109,0x4109,0x410e,0x410e,0x4131,0x4132,0x4167,0x4167,0x416c,0x416c,0x416e,0x416e,0x417c,0x417c,0x417f,0x417f,0x4181,0x4181,0x4190,0x4190,0x41b2,0x41b2,0x41c4,0x41c4,0x41ca,0x41ca,0x41cf,0x41cf,0x41db,0x41db,0x41ed,0x41ed,0x41ef,0x41ef,0x41f9,0x41f9,0x4211,0x4211,0x4223,0x4223,0x4240,0x4240,0x4260,0x4260,0x426a,0x426a,0x4276,0x4276,0x427a,0x427a,0x428c,0x428c,0x4294,0x4294,0x42a2,0x42a2,0x42b5,0x42b5,0x42b9,0x42b9,0x42bc,0x42bc,0x42f4,0x42f4,0x42fb,0x42fc,0x430a,0x430a,0x432b,0x432b,0x436e,0x436e,0x4397,0x4397,0x439a,0x439a,0x43ba,0x43ba,0x43c1,0x43c1,0x43d9,0x43d9,0x43df,0x43df,0x43ed,0x43ed,0x43f0,0x43f0,0x43f2,0x43f2,0x4401,0x4402,0x4413,0x4413,0x4425,0x4425,0x442d,0x442d,0x447a,0x447a,0x448f,0x448f,0x4491,0x4491,0x449f,0x44a0,0x44a2,0x44a2,0x44b0,0x44b0,0x44b7,0x44b7,0x44bd,0x44bd,0x44c0,0x44c0,0x44c3,0x44c3,0x44c5,0x44c5,0x44ce,0x44ce,0x44dd,0x44df,0x44e1,0x44e1,0x44e4,0x44e4,0x44e9,0x44ec,0x44f4,0x44f4,0x4503,0x4504,0x4509,0x4509,0x450b,0x450b,0x4516,0x4516,0x451b,0x451b,0x451d,0x451d,0x4527,0x4527,0x452e,0x452e,0x4533,0x4533,0x4536,0x4536,0x453b,0x453b,0x453d,0x453d,0x453f,0x453f,0x4543,0x4543,0x4551,0x4552,0x4555,0x4555,0x4558,0x4558,0x455c,0x455c,0x4561,0x4562,0x456a,0x456a,0x456d,0x456d,0x4577,0x4578,0x4585,0x4585,0x45a6,0x45a6,0x45b3,0x45b3,0x45da,0x45da,0x45e9,0x45ea,0x4603,0x4603,0x4606,0x4606,0x460f,0x460f,0x4615,0x4615,0x4617,0x4617,0x465b,0x465b,0x467a,0x467a,0x4680,0x4680,0x46a1,0x46a1,0x46ae,0x46ae,0x46bb,0x46bb,0x46cf,0x46d0,0x46f5,0x46f5,0x46f7,0x46f7,0x4713,0x4713,0x4718,0x4718,0x4736,0x4736,0x4744,0x4744,0x474e,0x474f,0x477c,0x477c,0x4798,0x4798,0x47a6,0x47a6,0x47d5,0x47d5,0x47ed,0x47ed,0x47f4,0x47f4,0x4800,0x4800,0x480b,0x480b,0x4837,0x4837,0x485d,0x485d,0x4871,0x4871,0x489b,0x489b,0x48ad,0x48ae,0x48d0,0x48d0,0x48dd,0x48dd,0x48ed,0x48ed,0x48f3,0x48f3,0x48fa,0x48fa,0x4906,0x4906,0x4911,0x4911,0x491e,0x491e,0x4925,0x4925,0x492a,0x492a,0x492d,0x492d,0x492f,0x4930,0x4935,0x4935,0x493c,0x493c,0x493e,0x493e,0x4945,0x4945,0x4951,0x4951,0x4953,0x4953,0x4965,0x4965,0x496a,0x496a,0x4972,0x4972,0x4989,0x4989,0x49a1,0x49a1,0x49a7,0x49a7,0x49df,0x49df,0x49e5,0x49e5,0x49e7,0x49e7,0x4a0f,0x4a0f,0x4a1d,0x4a1d,0x4a24,0x4a24,0x4a35,0x4a35,0x4a96,0x4a96,0x4aa4,0x4aa4,0x4ab4,0x4ab4,0x4ab8,0x4ab8,0x4ad1,0x4ad1,0x4ae4,0x4ae4,0x4aff,0x4aff,0x4b10,0x4b10,0x4b19,0x4b19,0x4b20,0x4b20,0x4b2c,0x4b2c,0x4b37,0x4b37,0x4b6f,0x4b70,0x4b72,0x4b72,0x4b7b,0x4b7b,0x4b7e,0x4b7e,0x4b8e,0x4b8e,0x4b90,0x4b90,0x4b93,0x4b93,0x4b96,0x4b97,0x4b9d,0x4b9d,0x4bbd,0x4bbe,0x4bc0,0x4bc0,0x4c04,0x4c04,0x4c07,0x4c07,0x4c0e,0x4c0e,0x4c32,0x4c32,0x4c3b,0x4c3b,0x4c3e,0x4c3e,0x4c40,0x4c40,0x4c47,0x4c47,0x4c57,0x4c57,0x4c5b,0x4c5b,0x4c6d,0x4c6d,0x4c77,0x4c77,0x4c7b,0x4c7b,0x4c7d,0x4c7d,0x4c81,0x4c81,0x4c85,0x4c85,0x4ca4,0x4ca4,0x4cae,0x4cae,0x4cb0,0x4cb0,0x4cb7,0x4cb7,0x4ccd,0x4ccd,0x4ce1,0x4ce2,0x4ced,0x4ced,0x4d07,0x4d07,0x4d09,0x4d09,0x4d10,0x4d10,0x4d34,0x4d34,0x4d76,0x4d77,0x4d89,0x4d89,0x4d91,0x4d91,0x4d9c,0x4d9c,0x4e00,0x4e01,0x4e03,0x4e04,0x4e07,0x4e11,0x4e14,0x4e16,0x4e18,0x4e1a,0x4e1c,0x4e1c,0x4e1e,0x4e1f,0x4e21,0x4e22,0x4e24,0x4e24,0x4e26,0x4e26,0x4e28,0x4e28,0x4e2a,0x4e33,0x4e36,0x4e39,0x4e3b,0x4e3d,0x4e3f,0x4e3f,0x4e42,0x4e43,0x4e45,0x4e45,0x4e47,0x4e49,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e52,0x4e53,0x4e56,0x4e56,0x4e58,0x4e5f,0x4e69,0x4e6a,0x4e73,0x4e73,0x4e78,0x4e78,0x4e7e,0x4e89,0x4e8b,0x4e8e,0x4e91,0x4e95,0x4e98,0x4e9b,0x4e9e,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eae,0x4eb3,0x4eb3,0x4eb6,0x4eb7,0x4eb9,0x4ebc,0x4ebf,0x4ec4,0x4ec6,0x4ecb,0x4ecd,0x4ece,0x4ed4,0x4eda,0x4edc,0x4edf,0x4ee1,0x4ee1,0x4ee3,0x4ee5,0x4ee8,0x4eeb,0x4eee,0x4eee,0x4ef0,0x4ef8,0x4efb,0x4efb,0x4efd,0x4efd,0x4eff,0x4f05,0x4f08,0x4f0b,0x4f0d,0x4f15,0x4f17,0x4f1a,0x4f1d,0x4f1d,0x4f22,0x4f22,0x4f28,0x4f29,0x4f2c,0x4f2d,0x4f2f,0x4f30,0x4f32,0x4f34,0x4f36,0x4f3f,0x4f41,0x4f43,0x4f45,0x4f49,0x4f4b,0x4f64,0x4f67,0x4f67,0x4f69,0x4f6c,0x4f6e,0x4f70,0x4f72,0x4f8b,0x4f8d,0x4f8d,0x4f8f,0x4f92,0x4f94,0x4f98,0x4f9a,0x4f9e,0x4fa2,0x4fa2,0x4fa8,0x4fa8,0x4fab,0x4fab,0x4fae,0x4fb0,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbd,0x4fbd,0x4fbf,0x4fc5,0x4fc7,0x4fd1,0x4fd3,0x4fd4,0x4fd6,0x4fe1,0x4fe4,0x4fe5,0x4fec,0x4fec,0x4fee,0x4ffa,0x4ffd,0x4ffe,0x5000,0x5000,0x5003,0x5003,0x5005,0x5009,0x500b,0x500f,0x5011,0x501c,0x501e,0x5023,0x5025,0x5031,0x5033,0x5035,0x5037,0x5037,0x503b,0x503c,0x5040,0x5041,0x5043,0x5043,0x5045,0x504f,0x5051,0x5051,0x5053,0x5053,0x5055,0x5058,0x505a,0x5066,0x5068,0x5070,0x5072,0x5077,0x507a,0x507a,0x507d,0x507d,0x5080,0x5083,0x5085,0x5085,0x5087,0x5088,0x508b,0x508e,0x5090,0x5092,0x5094,0x5096,0x5098,0x509e,0x50a2,0x50a3,0x50a6,0x50a6,0x50ac,0x50b8,0x50ba,0x50bf,0x50c1,0x50c2,0x50c4,0x50cb,0x50cd,0x50d1,0x50d3,0x50d7,0x50d9,0x50db,0x50dd,0x50dd,0x50df,0x50e1,0x50e3,0x50ea,0x50ec,0x50f1,0x50f3,0x50f6,0x50f8,0x50f9,0x50fb,0x510e,0x5110,0x5115,0x5117,0x5118,0x511a,0x511a,0x511c,0x511c,0x511f,0x5122,0x5124,0x5126,0x5129,0x512b,0x512d,0x512e,0x5130,0x5135,0x5137,0x513d,0x513f,0x5141,0x5143,0x5149,0x514b,0x514d,0x5151,0x5152,0x5154,0x5157,0x5159,0x5163,0x5165,0x5165,0x5167,0x516e,0x5171,0x5171,0x5174,0x5179,0x517c,0x517c,0x5180,0x5180,0x5182,0x5182,0x5186,0x518a,0x518d,0x518d,0x518f,0x518f,0x5191,0x5198,0x519a,0x519a,0x519c,0x519c,0x519e,0x519e,0x51a0,0x51a0,0x51a2,0x51a2,0x51a4,0x51a5,0x51a7,0x51a8,0x51aa,0x51ac,0x51ae,0x51ae,0x51b0,0x51b9,0x51bc,0x51be,0x51c3,0x51d4,0x51d7,0x51d8,0x51db,0x51e2,0x51e4,0x51e4,0x51ed,0x51ed,0x51f0,0x51f1,0x51f3,0x51f6,0x51f8,0x51fa,0x51fc,0x51fe,0x5200,0x5203,0x5205,0x520c,0x520e,0x520e,0x5210,0x5213,0x5216,0x5217,0x521c,0x5221,0x5224,0x522a,0x522e,0x522e,0x5230,0x5238,0x523a,0x523c,0x5241,0x5241,0x5243,0x5244,0x5246,0x5247,0x5249,0x524f,0x5252,0x5252,0x5254,0x5257,0x5259,0x5262,0x5268,0x526f,0x5272,0x5275,0x5277,0x527d,0x527f,0x5284,0x5287,0x528d,0x528f,0x5291,0x5293,0x5294,0x5296,0x529b,0x529f,0x52a1,0x52a3,0x52a4,0x52a6,0x52a6,0x52a8,0x52ae,0x52b5,0x52b5,0x52b9,0x52b9,0x52bb,0x52bc,0x52be,0x52be,0x52c0,0x52c3,0x52c5,0x52c5,0x52c7,0x52c7,0x52c9,0x52c9,0x52cc,0x52cd,0x52d0,0x52d3,0x52d5,0x52d9,0x52db,0x52db,0x52dd,0x52e4,0x52e6,0x52e6,0x52e9,0x52e9,0x52eb,0x52eb,0x52ef,0x52f1,0x52f3,0x52f5,0x52f7,0x52fc,0x52fe,0x52ff,0x5301,0x5301,0x5305,0x5306,0x5308,0x530b,0x530d,0x5312,0x5315,0x5317,0x5319,0x531a,0x531c,0x531d,0x531f,0x5324,0x5327,0x5327,0x532a,0x532a,0x532c,0x532d,0x532f,0x5334,0x5337,0x5339,0x533b,0x5345,0x5347,0x534a,0x534c,0x534e,0x5351,0x5354,0x5357,0x5357,0x535a,0x535a,0x535c,0x5361,0x5363,0x5364,0x5366,0x5367,0x5369,0x5369,0x536c,0x5375,0x5377,0x5379,0x537b,0x537f,0x5382,0x5382,0x5384,0x5384,0x538a,0x538a,0x538e,0x538f,0x5392,0x5394,0x5396,0x539a,0x539c,0x53a0,0x53a2,0x53a2,0x53a4,0x53ae,0x53b0,0x53b0,0x53b2,0x53b2,0x53b4,0x53b4,0x53b6,0x53b6,0x53b9,0x53b9,0x53bb,0x53bb,0x53c1,0x53c3,0x53c5,0x53c5,0x53c8,0x53cd,0x53d0,0x53d2,0x53d4,0x53d4,0x53d6,0x53db,0x53df,0x53e6,0x53e8,0x53f3,0x53f5,0x53f8,0x53fb,0x53fc,0x53fe,0x53fe,0x5401,0x5401,0x5403,0x5404,0x5406,0x5414,0x5416,0x5416,0x5418,0x5421,0x5423,0x5439,0x543b,0x5443,0x5445,0x5448,0x544a,0x544f,0x5454,0x5454,0x5460,0x546d,0x546f,0x5478,0x547a,0x5482,0x5484,0x5488,0x548b,0x5498,0x549a,0x549a,0x549c,0x549c,0x549e,0x549e,0x54a0,0x54b4,0x54b6,0x54c9,0x54cb,0x54d0,0x54d6,0x54d6,0x54da,0x54da,0x54de,0x54de,0x54e0,0x54eb,0x54ed,0x54ef,0x54f1,0x54f3,0x54f7,0x54f8,0x54fa,0x54fd,0x54ff,0x54ff,0x5501,0x5514,0x5517,0x5518,0x551a,0x551a,0x551e,0x551e,0x5523,0x5523,0x5525,0x5528,0x552a,0x5539,0x553b,0x553c,0x553e,0x5541,0x5543,0x554b,0x554d,0x5553,0x5555,0x5557,0x555c,0x555f,0x5561,0x5566,0x5569,0x556b,0x5571,0x5573,0x5575,0x5577,0x5579,0x5579,0x557b,0x5584,0x5586,0x5595,0x5598,0x559a,0x559c,0x559d,0x559f,0x559f,0x55a1,0x55ae,0x55b0,0x55b5,0x55b9,0x55bc,0x55bf,0x55df,0x55e1,0x55ea,0x55ec,0x55ec,0x55ee,0x55f2,0x55f5,0x55f7,0x55f9,0x5602,0x5604,0x5606,0x5608,0x5609,0x560c,0x5617,0x561b,0x5623,0x5625,0x5625,0x5627,0x5627,0x5629,0x562a,0x562c,0x5630,0x5632,0x563b,0x563d,0x5643,0x5645,0x5646,0x5648,0x564a,0x564c,0x5650,0x5652,0x5654,0x5657,0x565a,0x565d,0x565e,0x5660,0x5666,0x5668,0x5674,0x5676,0x567c,0x567e,0x5687,0x5689,0x5690,0x5692,0x5693,0x5695,0x5695,0x5697,0x569a,0x569c,0x569f,0x56a1,0x56a1,0x56a4,0x56a8,0x56aa,0x56af,0x56b1,0x56b7,0x56b9,0x56b9,0x56bc,0x56c3,0x56c5,0x56c6,0x56c8,0x56cd,0x56d1,0x56d1,0x56d3,0x56d4,0x56d6,0x56d7,0x56da,0x56db,0x56dd,0x56e2,0x56e4,0x56e5,0x56e7,0x56e7,0x56ea,0x56eb,0x56ed,0x56f1,0x56f7,0x56f7,0x56f9,0x56fb,0x56fd,0x56fd,0x56ff,0x5704,0x5707,0x570d,0x5712,0x5716,0x5718,0x5718,0x571a,0x5720,0x5722,0x5723,0x5728,0x572a,0x572c,0x5730,0x5732,0x5734,0x573b,0x573b,0x573d,0x5743,0x5745,0x5747,0x5749,0x5752,0x5754,0x5754,0x5757,0x5757,0x575b,0x575b,0x575f,0x575f,0x5761,0x5762,0x5764,0x5764,0x5766,0x576b,0x576d,0x576d,0x576f,0x5777,0x577a,0x5780,0x5782,0x5783,0x5788,0x5788,0x578a,0x578d,0x578f,0x5790,0x5793,0x5795,0x5797,0x57a5,0x57a7,0x57a7,0x57aa,0x57aa,0x57ae,0x57ae,0x57b3,0x57b6,0x57b8,0x57bf,0x57c1,0x57c4,0x57c6,0x57c8,0x57cb,0x57cc,0x57ce,0x57d0,0x57d2,0x57d2,0x57d4,0x57d5,0x57d7,0x57d7,0x57dc,0x57e7,0x57e9,0x57e9,0x57ec,0x57fe,0x5800,0x580e,0x5810,0x5810,0x5812,0x5812,0x5814,0x5814,0x5818,0x5819,0x581b,0x581e,0x5820,0x582a,0x582c,0x583b,0x583d,0x583d,0x583f,0x5840,0x5844,0x5844,0x5847,0x584f,0x5851,0x5855,0x5857,0x585f,0x5862,0x5865,0x5868,0x5869,0x586b,0x586d,0x586f,0x586f,0x5871,0x5876,0x5879,0x5883,0x5885,0x588b,0x588e,0x5894,0x5896,0x5896,0x5898,0x589a,0x589c,0x58a1,0x58a3,0x58a3,0x58a5,0x58ac,0x58ae,0x58b1,0x58b3,0x58b3,0x58b5,0x58b6,0x58ba,0x58bf,0x58c1,0x58c2,0x58c5,0x58c9,0x58cb,0x58cb,0x58ce,0x58d6,0x58d8,0x58e0,0x58e2,0x58e4,0x58e7,0x58e9,0x58eb,0x58ec,0x58ef,0x58f0,0x58f2,0x58f4,0x58f9,0x58ff,0x5902,0x5907,0x590a,0x590a,0x590c,0x590f,0x5911,0x5912,0x5914,0x5917,0x5919,0x591a,0x591c,0x591d,0x591f,0x5920,0x5922,0x5922,0x5924,0x5925,0x5927,0x5927,0x5929,0x592f,0x5931,0x5932,0x5934,0x5934,0x5937,0x5938,0x593c,0x593c,0x593e,0x593e,0x5940,0x5940,0x5944,0x5945,0x5947,0x594a,0x594e,0x5951,0x5953,0x5955,0x5957,0x5958,0x595a,0x595a,0x595c,0x595c,0x5960,0x5962,0x5965,0x5965,0x5967,0x5967,0x5969,0x596e,0x5970,0x5979,0x597b,0x5985,0x5989,0x598a,0x598d,0x5990,0x5992,0x5994,0x5996,0x599a,0x599d,0x59a8,0x59ac,0x59ac,0x59ae,0x59c1,0x59c3,0x59d4,0x59d6,0x59d6,0x59d8,0x59de,0x59e0,0x59e1,0x59e3,0x59e6,0x59e8,0x5a03,0x5a09,0x5a0d,0x5a0f,0x5a0f,0x5a11,0x5a13,0x5a15,0x5a1c,0x5a1e,0x5a21,0x5a23,0x5a25,0x5a27,0x5a27,0x5a29,0x5a2e,0x5a33,0x5a33,0x5a35,0x5a39,0x5a3c,0x5a3e,0x5a40,0x5a4a,0x5a4c,0x5a4d,0x5a50,0x5a6e,0x5a70,0x5a71,0x5a77,0x5a7f,0x5a81,0x5a84,0x5a86,0x5a86,0x5a88,0x5a88,0x5a8a,0x5a8c,0x5a8e,0x5a97,0x5a99,0x5aa2,0x5aa4,0x5aa7,0x5aa9,0x5aac,0x5aae,0x5ac4,0x5ac6,0x5acf,0x5ad1,0x5ad1,0x5ad3,0x5ad3,0x5ad5,0x5ae6,0x5ae8,0x5aee,0x5af0,0x5af0,0x5af2,0x5afb,0x5afd,0x5aff,0x5b01,0x5b03,0x5b05,0x5b05,0x5b07,0x5b09,0x5b0b,0x5b0d,0x5b0f,0x5b11,0x5b13,0x5b17,0x5b19,0x5b1b,0x5b1d,0x5b21,0x5b23,0x5b28,0x5b2a,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b38,0x5b38,0x5b3c,0x5b41,0x5b43,0x5b48,0x5b4a,0x5b51,0x5b53,0x5b58,0x5b5a,0x5b5d,0x5b5f,0x5b5f,0x5b62,0x5b66,0x5b68,0x5b69,0x5b6b,0x5b6e,0x5b70,0x5b78,0x5b7a,0x5b7d,0x5b7f,0x5b85,0x5b87,0x5b89,0x5b8b,0x5b8c,0x5b8e,0x5b90,0x5b92,0x5b93,0x5b95,0x5b9f,0x5ba2,0x5ba8,0x5baa,0x5baa,0x5bac,0x5bae,0x5bb0,0x5bb0,0x5bb3,0x5bb9,0x5bbf,0x5bc7,0x5bca,0x5bce,0x5bd0,0x5bd9,0x5bdb,0x5bdb,0x5bde,0x5bec,0x5bee,0x5bf3,0x5bf5,0x5bf6,0x5bf8,0x5bf8,0x5bfa,0x5bfa,0x5bff,0x5bff,0x5c01,0x5c01,0x5c03,0x5c05,0x5c07,0x5c16,0x5c1a,0x5c1a,0x5c1c,0x5c1c,0x5c1e,0x5c20,0x5c22,0x5c25,0x5c28,0x5c28,0x5c2a,0x5c2a,0x5c2c,0x5c2c,0x5c30,0x5c31,0x5c33,0x5c33,0x5c37,0x5c3c,0x5c3e,0x5c41,0x5c44,0x5c51,0x5c53,0x5c56,0x5c58,0x5c59,0x5c5c,0x5c5e,0x5c60,0x5c60,0x5c62,0x5c65,0x5c67,0x5c6a,0x5c6c,0x5c6f,0x5c71,0x5c71,0x5c73,0x5c74,0x5c78,0x5c7c,0x5c7e,0x5c7e,0x5c83,0x5c83,0x5c85,0x5c86,0x5c88,0x5c8d,0x5c8f,0x5c95,0x5c99,0x5c9a,0x5c9c,0x5cb1,0x5cb3,0x5cb3,0x5cb5,0x5cb8,0x5cba,0x5cba,0x5cc1,0x5cc2,0x5cc6,0x5ccc,0x5cce,0x5cdb,0x5cde,0x5cdf,0x5ce5,0x5ce5,0x5ce8,0x5cea,0x5cec,0x5cf1,0x5cf4,0x5cf9,0x5cfb,0x5cfd,0x5cff,0x5d01,0x5d06,0x5d07,0x5d0b,0x5d12,0x5d14,0x5d1b,0x5d1d,0x5d20,0x5d22,0x5d29,0x5d2c,0x5d2c,0x5d2e,0x5d3a,0x5d3c,0x5d43,0x5d45,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d52,0x5d55,0x5d57,0x5d59,0x5d59,0x5d5b,0x5d5b,0x5d5e,0x5d5e,0x5d62,0x5d63,0x5d65,0x5d65,0x5d67,0x5d69,0x5d6b,0x5d6c,0x5d6f,0x5d72,0x5d74,0x5d74,0x5d77,0x5d82,0x5d84,0x5d8b,0x5d8d,0x5d8e,0x5d92,0x5d95,0x5d97,0x5d97,0x5d99,0x5d9a,0x5d9c,0x5da2,0x5da4,0x5da4,0x5da7,0x5db2,0x5db4,0x5dba,0x5dbc,0x5dbd,0x5dc0,0x5dc3,0x5dc6,0x5dc7,0x5dc9,0x5dc9,0x5dcb,0x5dcb,0x5dcd,0x5dcd,0x5dcf,0x5dcf,0x5dd1,0x5dd2,0x5dd4,0x5dd8,0x5ddb,0x5ddb,0x5ddd,0x5de2,0x5de5,0x5de8,0x5deb,0x5deb,0x5dee,0x5dee,0x5df0,0x5df5,0x5df7,0x5df7,0x5df9,0x5df9,0x5dfd,0x5dff,0x5e02,0x5e04,0x5e06,0x5e06,0x5e09,0x5e0c,0x5e0e,0x5e0e,0x5e11,0x5e12,0x5e14,0x5e1b,0x5e1d,0x5e1d,0x5e1f,0x5e25,0x5e28,0x5e29,0x5e2b,0x5e2b,0x5e2d,0x5e2e,0x5e33,0x5e34,0x5e36,0x5e38,0x5e3d,0x5e3e,0x5e40,0x5e45,0x5e48,0x5e48,0x5e4a,0x5e4f,0x5e53,0x5e55,0x5e57,0x5e59,0x5e5b,0x5e63,0x5e66,0x5e70,0x5e72,0x5e76,0x5e78,0x5e80,0x5e82,0x5e84,0x5e86,0x5e8d,0x5e8f,0x5e8f,0x5e92,0x5e92,0x5e95,0x5e97,0x5e99,0x5e9c,0x5ea0,0x5ea0,0x5ea2,0x5ea8,0x5eaa,0x5eae,0x5eb0,0x5eb9,0x5ebd,0x5ebe,0x5ec1,0x5ec2,0x5ec4,0x5ece,0x5ed0,0x5ee3,0x5ee5,0x5ee9,0x5eec,0x5eec,0x5eee,0x5eef,0x5ef1,0x5ef4,0x5ef6,0x5efc,0x5efe,0x5eff,0x5f01,0x5f02,0x5f04,0x5f05,0x5f07,0x5f08,0x5f0a,0x5f0f,0x5f12,0x5f15,0x5f17,0x5f18,0x5f1a,0x5f1b,0x5f1d,0x5f1d,0x5f1f,0x5f1f,0x5f22,0x5f29,0x5f2d,0x5f2e,0x5f30,0x5f31,0x5f33,0x5f33,0x5f35,0x5f38,0x5f3a,0x5f3c,0x5f40,0x5f40,0x5f43,0x5f46,0x5f48,0x5f51,0x5f54,0x5f54,0x5f56,0x5f59,0x5f5c,0x5f5e,0x5f61,0x5f65,0x5f67,0x5f67,0x5f69,0x5f6d,0x5f6f,0x5f74,0x5f76,0x5f79,0x5f7b,0x5f83,0x5f85,0x5f8c,0x5f90,0x5f92,0x5f96,0x5f99,0x5f9b,0x5f9c,0x5f9e,0x5fa1,0x5fa4,0x5faf,0x5fb1,0x5fb2,0x5fb5,0x5fb7,0x5fb9,0x5fc5,0x5fc9,0x5fc9,0x5fcc,0x5fcd,0x5fcf,0x5fd2,0x5fd4,0x5fd9,0x5fdb,0x5fdb,0x5fdd,0x5fe1,0x5fe3,0x5fe5,0x5fe8,0x5fe8,0x5fea,0x5feb,0x5fed,0x5fef,0x5ff1,0x5ff1,0x5ff3,0x5ff5,0x5ff7,0x5ff8,0x5ffa,0x5ffb,0x5ffd,0x5ffd,0x5fff,0x6000,0x6009,0x6017,0x6019,0x601e,0x6020,0x602f,0x6031,0x6035,0x6037,0x6037,0x6039,0x6039,0x603b,0x603b,0x6040,0x6047,0x6049,0x604d,0x6050,0x6050,0x6052,0x6055,0x6058,0x605b,0x605d,0x605f,0x6062,0x6070,0x6072,0x6072,0x6075,0x6075,0x6077,0x6077,0x607e,0x6081,0x6083,0x608a,0x608c,0x608e,0x6090,0x6090,0x6092,0x6092,0x6094,0x6097,0x609a,0x60a0,0x60a2,0x60a4,0x60a6,0x60a8,0x60b0,0x60c1,0x60c3,0x60cf,0x60d1,0x60d1,0x60d3,0x60d5,0x60d7,0x60e4,0x60e6,0x60e9,0x60f0,0x6101,0x6103,0x6110,0x6112,0x6116,0x6118,0x611d,0x611f,0x6120,0x6122,0x6123,0x6127,0x6129,0x612b,0x612c,0x612e,0x6130,0x6132,0x6132,0x6134,0x6134,0x6136,0x6137,0x613b,0x613b,0x613d,0x6142,0x6144,0x6150,0x6152,0x6156,0x6158,0x6168,0x616a,0x616c,0x616e,0x6177,0x6179,0x617a,0x617c,0x617e,0x6180,0x6183,0x6187,0x6187,0x6189,0x618e,0x6190,0x6196,0x6198,0x619d,0x619f,0x619f,0x61a1,0x61a2,0x61a4,0x61a4,0x61a7,0x61ba,0x61bc,0x61bc,0x61be,0x61c3,0x61c5,0x61cd,0x61cf,0x61d0,0x61d3,0x61d3,0x61d6,0x61d6,0x61d8,0x61d8,0x61da,0x61da,0x61de,0x61e0,0x61e2,0x61eb,0x61ed,0x61ee,0x61f0,0x61f2,0x61f5,0x6201,0x6203,0x6204,0x6207,0x620a,0x620c,0x620e,0x6210,0x6212,0x6214,0x6216,0x6219,0x621b,0x621f,0x6225,0x6227,0x6227,0x6229,0x622e,0x6230,0x6230,0x6232,0x6234,0x6236,0x6237,0x6239,0x623a,0x623d,0x6243,0x6246,0x624e,0x6250,0x6254,0x6258,0x625c,0x625e,0x625e,0x6260,0x6266,0x6268,0x6268,0x626d,0x6274,0x6276,0x6277,0x6279,0x628a,0x628c,0x628c,0x628e,0x6298,0x629d,0x629d,0x62a4,0x62a4,0x62a6,0x62a6,0x62a8,0x62b1,0x62b3,0x62b6,0x62b8,0x62b9,0x62bb,0x62bf,0x62c1,0x62dc,0x62df,0x62df,0x62e5,0x62e5,0x62eb,0x6303,0x6307,0x6309,0x630b,0x6311,0x6313,0x6316,0x6318,0x6318,0x6328,0x632f,0x6331,0x633e,0x6340,0x6351,0x6354,0x635a,0x635d,0x635d,0x6364,0x6365,0x6367,0x6369,0x636b,0x6372,0x6375,0x637d,0x637f,0x6385,0x6387,0x6392,0x6394,0x6394,0x6396,0x6399,0x639b,0x63a5,0x63a7,0x63b1,0x63b9,0x63b9,0x63bd,0x63be,0x63c0,0x63d3,0x63d5,0x63eb,0x63ed,0x63f6,0x63f8,0x63f9,0x63fb,0x63fc,0x63fe,0x63fe,0x6406,0x6407,0x6409,0x6410,0x6412,0x6418,0x641a,0x641c,0x641e,0x6428,0x642a,0x6430,0x6432,0x643b,0x643d,0x6441,0x6443,0x6443,0x644b,0x644b,0x644d,0x644e,0x6450,0x6454,0x6458,0x6461,0x6465,0x6469,0x646b,0x647d,0x647f,0x647f,0x6482,0x6482,0x6485,0x6485,0x6487,0x648d,0x648f,0x6493,0x6495,0x649a,0x649c,0x64a0,0x64a2,0x64a6,0x64a9,0x64a9,0x64ab,0x64b4,0x64b6,0x64b6,0x64bb,0x64c5,0x64c7,0x64c7,0x64c9,0x64cb,0x64cd,0x64d0,0x64d2,0x64d4,0x64d6,0x64db,0x64dd,0x64dd,0x64e0,0x64ed,0x64ef,0x64f4,0x64f7,0x64f8,0x64fa,0x6501,0x6503,0x6504,0x6506,0x6507,0x6509,0x650a,0x650c,0x6511,0x6513,0x6519,0x651b,0x6526,0x6529,0x6530,0x6532,0x6539,0x653b,0x653b,0x653d,0x653f,0x6541,0x6541,0x6543,0x6543,0x6545,0x6546,0x6548,0x654a,0x654d,0x654d,0x654f,0x654f,0x6551,0x6551,0x6553,0x655a,0x655c,0x655f,0x6562,0x6568,0x656a,0x656d,0x656f,0x656f,0x6572,0x657c,0x657f,0x6589,0x658b,0x658c,0x6590,0x6592,0x6594,0x6597,0x6599,0x6599,0x659b,0x65a2,0x65a4,0x65a5,0x65a7,0x65a8,0x65aa,0x65ac,0x65ae,0x65b0,0x65b2,0x65b3,0x65b5,0x65b9,0x65bb,0x65bf,0x65c1,0x65c6,0x65cb,0x65d4,0x65d6,0x65d7,0x65da,0x65db,0x65dd,0x65e3,0x65e5,0x65e6,0x65e8,0x65e9,0x65ec,0x65f5,0x65fa,0x65fd,0x65ff,0x6600,0x6602,0x6615,0x6618,0x6618,0x661c,0x6628,0x662b,0x662b,0x662d,0x6636,0x6639,0x663a,0x6641,0x6645,0x6647,0x664d,0x664f,0x664f,0x6651,0x6653,0x6657,0x6657,0x6659,0x6668,0x666a,0x666c,0x666e,0x6674,0x6676,0x667e,0x6680,0x6680,0x6684,0x668e,0x6690,0x6692,0x6694,0x669a,0x669d,0x669d,0x669f,0x66a2,0x66a4,0x66a4,0x66a8,0x66ab,0x66ad,0x66bb,0x66bd,0x66c0,0x66c4,0x66c4,0x66c6,0x66cf,0x66d2,0x66d2,0x66d6,0x66d6,0x66d8,0x66de,0x66e0,0x66e0,0x66e3,0x66e4,0x66e6,0x66e9,0x66eb,0x66ee,0x66f0,0x66f4,0x66f6,0x66f9,0x66fc,0x66fc,0x66fe,0x6705,0x6708,0x6710,0x6712,0x6719,0x671b,0x671b,0x671d,0x6723,0x6725,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6736,0x6738,0x673f,0x6744,0x6749,0x674b,0x6751,0x6753,0x6753,0x6755,0x6757,0x6759,0x675a,0x675c,0x6762,0x6767,0x6767,0x676a,0x677f,0x6781,0x6787,0x6789,0x6789,0x678b,0x6795,0x6797,0x679a,0x679c,0x679d,0x679f,0x67a0,0x67a4,0x67a4,0x67ac,0x67ac,0x67ae,0x67bb,0x67bf,0x67c6,0x67c8,0x67d4,0x67d6,0x67df,0x67e2,0x67e7,0x67e9,0x67fa,0x67fc,0x67fc,0x67fe,0x6804,0x680d,0x680d,0x6810,0x6810,0x6812,0x6814,0x6816,0x6818,0x681a,0x6822,0x6825,0x6826,0x6828,0x682b,0x682d,0x682f,0x6831,0x683e,0x6840,0x6851,0x6853,0x6856,0x685d,0x685d,0x6865,0x6865,0x686b,0x686b,0x686d,0x686f,0x6871,0x6872,0x6874,0x6879,0x687b,0x688c,0x688f,0x6894,0x6896,0x6898,0x689b,0x689d,0x689f,0x68a4,0x68a6,0x68b6,0x68b9,0x68b9,0x68bd,0x68bd,0x68c1,0x68c1,0x68c3,0x68ce,0x68d0,0x68d8,0x68da,0x68da,0x68dc,0x68e1,0x68e3,0x68e4,0x68e6,0x68ec,0x68ee,0x68fd,0x6900,0x6915,0x6917,0x691b,0x6925,0x6925,0x692a,0x692a,0x692c,0x692c,0x692f,0x6930,0x6932,0x6939,0x693b,0x6946,0x6948,0x694c,0x694e,0x694f,0x6951,0x697b,0x6980,0x6980,0x6982,0x6983,0x6985,0x6986,0x698a,0x698a,0x698d,0x698e,0x6990,0x6991,0x6993,0x699c,0x699e,0x69b7,0x69b9,0x69b9,0x69bb,0x69c4,0x69c6,0x69c6,0x69c9,0x69d1,0x69d3,0x69d6,0x69d9,0x69d9,0x69e1,0x69e2,0x69e4,0x69e9,0x69eb,0x69ee,0x69f1,0x69f4,0x69f6,0x6a0d,0x6a0f,0x6a0f,0x6a11,0x6a11,0x6a13,0x6a21,0x6a23,0x6a23,0x6a25,0x6a29,0x6a2b,0x6a2d,0x6a32,0x6a35,0x6a38,0x6a41,0x6a43,0x6a49,0x6a4b,0x6a5b,0x6a5d,0x6a6b,0x6a6d,0x6a6d,0x6a6f,0x6a6f,0x6a71,0x6a71,0x6a74,0x6a74,0x6a76,0x6a76,0x6a7a,0x6a7a,0x6a7e,0x6a85,0x6a87,0x6a87,0x6a89,0x6a8a,0x6a8c,0x6a97,0x6a99,0x6aa8,0x6aab,0x6aaf,0x6ab1,0x6abb,0x6abd,0x6abe,0x6ac2,0x6ac3,0x6ac5,0x6acd,0x6acf,0x6ad1,0x6ad3,0x6ad4,0x6ad8,0x6ae1,0x6ae5,0x6ae5,0x6ae7,0x6ae8,0x6aea,0x6aec,0x6aee,0x6af1,0x6af3,0x6af3,0x6af6,0x6af6,0x6af8,0x6afc,0x6b00,0x6b00,0x6b02,0x6b05,0x6b08,0x6b0b,0x6b0f,0x6b13,0x6b16,0x6b1a,0x6b1d,0x6b1e,0x6b20,0x6b21,0x6b23,0x6b23,0x6b25,0x6b25,0x6b28,0x6b28,0x6b2c,0x6b2d,0x6b2f,0x6b2f,0x6b31,0x6b3f,0x6b41,0x6b43,0x6b45,0x6b4e,0x6b50,0x6b52,0x6b54,0x6b57,0x6b59,0x6b59,0x6b5b,0x6b5c,0x6b5e,0x6b67,0x6b6a,0x6b6a,0x6b6d,0x6b6d,0x6b6f,0x6b6f,0x6b72,0x6b72,0x6b74,0x6b74,0x6b76,0x6b7b,0x6b7e,0x6b84,0x6b86,0x6b86,0x6b88,0x6b8a,0x6b8c,0x6b8f,0x6b91,0x6b91,0x6b94,0x6b99,0x6b9b,0x6b9b,0x6b9e,0x6ba0,0x6ba2,0x6ba7,0x6baa,0x6bab,0x6bad,0x6bb0,0x6bb2,0x6bb3,0x6bb5,0x6bb7,0x6bba,0x6bba,0x6bbc,0x6bbd,0x6bbf,0x6bc1,0x6bc3,0x6bcd,0x6bcf,0x6bd0,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdc,0x6bde,0x6bde,0x6be0,0x6be4,0x6be6,0x6be8,0x6bea,0x6bec,0x6bef,0x6bf0,0x6bf2,0x6bf3,0x6bf7,0x6c06,0x6c08,0x6c09,0x6c0b,0x6c0d,0x6c0f,0x6c11,0x6c13,0x6c16,0x6c18,0x6c1d,0x6c1f,0x6c21,0x6c23,0x6c28,0x6c2a,0x6c2c,0x6c2e,0x6c3b,0x6c3d,0x6c43,0x6c46,0x6c46,0x6c49,0x6c50,0x6c52,0x6c52,0x6c54,0x6c55,0x6c57,0x6c61,0x6c65,0x6c6b,0x6c6d,0x6c76,0x6c78,0x6c7b,0x6c7d,0x6c90,0x6c92,0x6c96,0x6c98,0x6c9d,0x6c9f,0x6c9f,0x6ca2,0x6ca2,0x6caa,0x6cb4,0x6cb6,0x6cc7,0x6cc9,0x6cd7,0x6cd9,0x6ce3,0x6ce5,0x6ce5,0x6ce7,0x6cf3,0x6cf5,0x6cf5,0x6cf9,0x6cf9,0x6cff,0x6d12,0x6d16,0x6d1b,0x6d1d,0x6d20,0x6d22,0x6d22,0x6d24,0x6d42,0x6d4e,0x6d4e,0x6d57,0x6d5c,0x6d5e,0x6d6a,0x6d6c,0x6d72,0x6d74,0x6d98,0x6d9a,0x6d9a,0x6da4,0x6da5,0x6daa,0x6dac,0x6dae,0x6daf,0x6db1,0x6db5,0x6db7,0x6dc0,0x6dc2,0x6dc2,0x6dc4,0x6dcd,0x6dcf,0x6de6,0x6de8,0x6df7,0x6df9,0x6dfe,0x6e00,0x6e00,0x6e02,0x6e05,0x6e0a,0x6e0a,0x6e0f,0x6e0f,0x6e15,0x6e15,0x6e18,0x6e1d,0x6e1f,0x6e36,0x6e38,0x6e41,0x6e43,0x6e47,0x6e49,0x6e4b,0x6e4d,0x6e69,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e71,0x6e74,0x6e76,0x6e79,0x6e7c,0x6e7c,0x6e86,0x6e86,0x6e88,0x6e89,0x6e8b,0x6e8b,0x6e8d,0x6e90,0x6e92,0x6e94,0x6e96,0x6ea7,0x6eaa,0x6eab,0x6eae,0x6ed6,0x6ed8,0x6edd,0x6ee2,0x6ee2,0x6ee8,0x6ee9,0x6eeb,0x6eef,0x6ef1,0x6ef2,0x6ef4,0x6f0f,0x6f12,0x6f1a,0x6f1c,0x6f1c,0x6f1e,0x6f27,0x6f29,0x6f41,0x6f43,0x6f44,0x6f4e,0x6f58,0x6f5a,0x6f64,0x6f66,0x6f67,0x6f69,0x6f70,0x6f72,0x6f74,0x6f76,0x6f82,0x6f84,0x6f8e,0x6f90,0x6f90,0x6f92,0x6f97,0x6f9d,0x6fb6,0x6fb8,0x6fc4,0x6fc6,0x6fcf,0x6fd3,0x6fd5,0x6fd8,0x6fe4,0x6fe6,0x6fe9,0x6feb,0x6ff2,0x6ff4,0x6ff4,0x6ff6,0x6ff8,0x6ffa,0x6ffc,0x6ffe,0x7001,0x7003,0x7007,0x7009,0x700f,0x7011,0x7011,0x7014,0x7024,0x7026,0x702c,0x702f,0x7035,0x7037,0x703c,0x703e,0x7046,0x7048,0x704d,0x7050,0x7052,0x7054,0x7058,0x705a,0x706c,0x706e,0x7071,0x7074,0x707a,0x707c,0x707f,0x7081,0x7086,0x7089,0x708b,0x708e,0x708f,0x7091,0x7096,0x7098,0x709a,0x709f,0x70a1,0x70a3,0x70a7,0x70a9,0x70a9,0x70ab,0x70b1,0x70b3,0x70b5,0x70b7,0x70be,0x70c0,0x70c0,0x70c4,0x70c8,0x70ca,0x70da,0x70dc,0x70e2,0x70e4,0x70e4,0x70ef,0x70f1,0x70f3,0x7100,0x7102,0x7102,0x7104,0x7106,0x7109,0x710e,0x7110,0x7110,0x7113,0x7113,0x7117,0x7117,0x7119,0x7123,0x7125,0x7126,0x7128,0x7129,0x712b,0x712c,0x712e,0x7136,0x713a,0x713b,0x713e,0x713e,0x7140,0x7147,0x7149,0x7154,0x7156,0x715a,0x715c,0x716c,0x716e,0x716e,0x7170,0x7178,0x717a,0x717e,0x7180,0x7182,0x7184,0x718a,0x718c,0x718c,0x718e,0x7192,0x7194,0x7194,0x7196,0x71a5,0x71a7,0x71aa,0x71ac,0x71ad,0x71af,0x71b5,0x71b7,0x71ba,0x71bc,0x71cb,0x71ce,0x71d2,0x71d4,0x71d6,0x71d8,0x71dd,0x71df,0x71e2,0x71e4,0x71e8,0x71eb,0x71ee,0x71f0,0x71f2,0x71f4,0x71f6,0x71f8,0x71f9,0x71fb,0x7203,0x7205,0x7207,0x7209,0x720a,0x720c,0x7210,0x7213,0x7217,0x7219,0x721b,0x721d,0x721f,0x7222,0x722e,0x7230,0x7230,0x7235,0x7236,0x7238,0x723b,0x723d,0x7242,0x7244,0x7244,0x7246,0x724c,0x724f,0x7250,0x7252,0x7253,0x7255,0x7263,0x7266,0x7267,0x7269,0x726a,0x726c,0x726c,0x726e,0x7270,0x7272,0x7274,0x7276,0x7279,0x727b,0x7282,0x7284,0x7289,0x728b,0x7298,0x729a,0x729b,0x729d,0x729f,0x72a1,0x72aa,0x72ac,0x72b0,0x72b2,0x72b2,0x72b4,0x72b5,0x72ba,0x72ba,0x72bd,0x72bd,0x72bf,0x72c6,0x72c9,0x72ce,0x72d0,0x72d2,0x72d4,0x72d4,0x72d6,0x72da,0x72dc,0x72dc,0x72df,0x72e4,0x72e6,0x72e6,0x72e8,0x72eb,0x72f3,0x72f4,0x72f6,0x7302,0x7304,0x7304,0x7307,0x7308,0x730a,0x730c,0x730f,0x7313,0x7316,0x7319,0x731b,0x731e,0x7322,0x7323,0x7325,0x732e,0x7330,0x733c,0x733e,0x7345,0x7348,0x734a,0x734c,0x7352,0x7357,0x735b,0x735d,0x7362,0x7365,0x736c,0x736e,0x7378,0x737a,0x738c,0x738e,0x738f,0x7392,0x7398,0x739c,0x73a2,0x73a4,0x73ad,0x73b2,0x73bc,0x73be,0x73c0,0x73c2,0x73d0,0x73d2,0x73de,0x73e0,0x73eb,0x73ed,0x73ef,0x73f3,0x740d,0x7411,0x7412,0x7414,0x7417,0x7419,0x7426,0x7428,0x743a,0x743c,0x743c,0x743f,0x7457,0x7459,0x7465,0x7467,0x7476,0x7479,0x747a,0x747c,0x7483,0x7485,0x748d,0x7490,0x7490,0x7492,0x7492,0x7494,0x7495,0x7497,0x74a1,0x74a3,0x74ab,0x74ad,0x74ad,0x74af,0x74b2,0x74b4,0x74bb,0x74bd,0x74c3,0x74c5,0x74c6,0x74c8,0x74c8,0x74ca,0x74cc,0x74cf,0x74d0,0x74d3,0x74e9,0x74ec,0x74ec,0x74ee,0x74ee,0x74f0,0x74f2,0x74f4,0x74f8,0x74fb,0x74fb,0x74fd,0x7500,0x7502,0x7505,0x7507,0x7508,0x750b,0x751a,0x751c,0x751f,0x7521,0x7522,0x7525,0x7526,0x7528,0x7535,0x7537,0x753b,0x753d,0x7540,0x7542,0x7542,0x7546,0x7548,0x754a,0x754f,0x7551,0x7551,0x7553,0x7555,0x7559,0x755d,0x755f,0x7560,0x7562,0x7567,0x756a,0x7570,0x7572,0x7572,0x7576,0x757a,0x757d,0x7580,0x7583,0x7584,0x7586,0x7587,0x758a,0x7592,0x7594,0x7595,0x7598,0x759a,0x759d,0x759e,0x75a2,0x75a5,0x75a7,0x75a7,0x75aa,0x75ab,0x75b0,0x75b6,0x75b8,0x75c5,0x75c7,0x75c8,0x75ca,0x75d2,0x75d4,0x75d5,0x75d7,0x75e4,0x75e6,0x75e7,0x75ed,0x75ed,0x75ef,0x7603,0x7607,0x760d,0x760f,0x7611,0x7613,0x7616,0x7619,0x7629,0x762c,0x762d,0x762f,0x7635,0x7638,0x7638,0x763a,0x763d,0x7640,0x7640,0x7642,0x7643,0x7646,0x7649,0x764c,0x7654,0x7656,0x765a,0x765c,0x765c,0x765f,0x7662,0x7664,0x7667,0x7669,0x766a,0x766c,0x7676,0x7678,0x767f,0x7681,0x7682,0x7684,0x7684,0x7686,0x768b,0x768e,0x7690,0x7692,0x7693,0x7695,0x7696,0x7699,0x769e,0x76a1,0x76a1,0x76a4,0x76a6,0x76aa,0x76ab,0x76ad,0x76b0,0x76b4,0x76b5,0x76b7,0x76b8,0x76ba,0x76bb,0x76bd,0x76bf,0x76c2,0x76c6,0x76c8,0x76ca,0x76cc,0x76ce,0x76d2,0x76d4,0x76d6,0x76d6,0x76d9,0x76df,0x76e1,0x76e1,0x76e3,0x76e7,0x76e9,0x76ea,0x76ec,0x76f5,0x76f7,0x76fc,0x76fe,0x76fe,0x7701,0x7701,0x7703,0x7705,0x7707,0x770c,0x770e,0x7713,0x7715,0x7715,0x7719,0x771b,0x771d,0x7720,0x7722,0x7729,0x772b,0x772b,0x772d,0x772d,0x772f,0x772f,0x7731,0x773e,0x7740,0x7740,0x7743,0x7747,0x774a,0x774f,0x7752,0x7752,0x7754,0x7756,0x7758,0x775c,0x775e,0x7763,0x7765,0x776f,0x7772,0x7772,0x7777,0x7785,0x7787,0x7789,0x778b,0x778f,0x7791,0x7791,0x7793,0x7793,0x7795,0x7795,0x7797,0x77a3,0x77a5,0x77a5,0x77a7,0x77a8,0x77aa,0x77ad,0x77af,0x77b7,0x77b9,0x77bf,0x77c2,0x77c5,0x77c7,0x77c7,0x77c9,0x77d0,0x77d3,0x77d5,0x77d7,0x77de,0x77e0,0x77e0,0x77e2,0x77e3,0x77e5,0x77e9,0x77ec,0x77f4,0x77f7,0x77fe,0x7802,0x7803,0x7805,0x7806,0x7808,0x7809,0x780c,0x7814,0x7818,0x7818,0x781c,0x7823,0x7825,0x7835,0x7837,0x7839,0x783c,0x783d,0x7842,0x7845,0x7847,0x784e,0x7850,0x7854,0x785c,0x785e,0x7860,0x7860,0x7862,0x7862,0x7864,0x7866,0x7868,0x7871,0x7879,0x787c,0x787e,0x7881,0x7883,0x7889,0x788c,0x788f,0x7891,0x7891,0x7893,0x789a,0x789e,0x78a5,0x78a7,0x78ad,0x78af,0x78b4,0x78b6,0x78b6,0x78b8,0x78bc,0x78be,0x78be,0x78c1,0x78c1,0x78c3,0x78c5,0x78c7,0x78d5,0x78d7,0x78d8,0x78da,0x78db,0x78dd,0x78e5,0x78e7,0x78ea,0x78ec,0x78f5,0x78f7,0x78f7,0x78f9,0x78ff,0x7901,0x7902,0x7904,0x7906,0x7909,0x7909,0x790c,0x790c,0x790e,0x790e,0x7910,0x7914,0x7917,0x7917,0x7919,0x7919,0x791b,0x791e,0x7921,0x7921,0x7923,0x792f,0x7931,0x7936,0x7938,0x7942,0x7944,0x794c,0x794f,0x7965,0x7967,0x796b,0x796d,0x796d,0x7970,0x7974,0x7979,0x797a,0x797c,0x7983,0x7986,0x7988,0x798a,0x798b,0x798d,0x799d,0x799f,0x79a2,0x79a4,0x79ae,0x79b0,0x79b4,0x79b6,0x79bb,0x79bd,0x79c1,0x79c4,0x79c6,0x79c8,0x79d2,0x79d4,0x79d6,0x79d8,0x79d8,0x79dc,0x79e0,0x79e2,0x79e4,0x79e6,0x79e7,0x79e9,0x79ee,0x79f1,0x79f1,0x79f4,0x79f4,0x79f6,0x79f8,0x79fa,0x79fb,0x7a00,0x7a00,0x7a02,0x7a06,0x7a08,0x7a08,0x7a0a,0x7a0e,0x7a10,0x7a15,0x7a17,0x7a1c,0x7a1e,0x7a20,0x7a22,0x7a22,0x7a26,0x7a26,0x7a28,0x7a28,0x7a2a,0x7a32,0x7a37,0x7a37,0x7a39,0x7a40,0x7a43,0x7a4e,0x7a54,0x7a54,0x7a56,0x7a58,0x7a5a,0x7a5c,0x7a5f,0x7a62,0x7a65,0x7a65,0x7a67,0x7a69,0x7a6b,0x7a6e,0x7a70,0x7a72,0x7a74,0x7a76,0x7a78,0x7a7b,0x7a7d,0x7a81,0x7a83,0x7a8c,0x7a8f,0x7a99,0x7a9e,0x7aa0,0x7aa2,0x7aa3,0x7aa8,0x7aac,0x7aae,0x7ab8,0x7aba,0x7abc,0x7abe,0x7ac5,0x7ac7,0x7acb,0x7acf,0x7acf,0x7ad1,0x7ad1,0x7ad3,0x7ad3,0x7ad8,0x7add,0x7adf,0x7ae0,0x7ae2,0x7ae7,0x7ae9,0x7aeb,0x7aed,0x7aef,0x7af6,0x7af7,0x7af9,0x7b01,0x7b04,0x7b06,0x7b08,0x7b0c,0x7b0e,0x7b14,0x7b18,0x7b1b,0x7b1d,0x7b20,0x7b22,0x7b35,0x7b38,0x7b39,0x7b3b,0x7b3b,0x7b40,0x7b40,0x7b42,0x7b52,0x7b54,0x7b56,0x7b58,0x7b58,0x7b60,0x7b67,0x7b69,0x7b69,0x7b6c,0x7b78,0x7b7b,0x7b7b,0x7b82,0x7b82,0x7b84,0x7b85,0x7b87,0x7b88,0x7b8a,0x7b92,0x7b94,0x7b9d,0x7ba0,0x7ba4,0x7bac,0x7baf,0x7bb1,0x7bb2,0x7bb4,0x7bb5,0x7bb7,0x7bb9,0x7bbe,0x7bbe,0x7bc0,0x7bc1,0x7bc4,0x7bc7,0x7bc9,0x7bcc,0x7bce,0x7bd0,0x7bd4,0x7bd5,0x7bd8,0x7bec,0x7bf0,0x7bf4,0x7bf7,0x7c03,0x7c05,0x7c07,0x7c09,0x7c12,0x7c15,0x7c15,0x7c19,0x7c19,0x7c1b,0x7c23,0x7c25,0x7c2d,0x7c30,0x7c30,0x7c33,0x7c33,0x7c35,0x7c35,0x7c37,0x7c39,0x7c3b,0x7c40,0x7c42,0x7c45,0x7c47,0x7c4a,0x7c4c,0x7c4d,0x7c50,0x7c51,0x7c53,0x7c54,0x7c56,0x7c57,0x7c59,0x7c5d,0x7c5f,0x7c60,0x7c63,0x7c67,0x7c69,0x7c70,0x7c72,0x7c75,0x7c78,0x7c81,0x7c83,0x7c86,0x7c88,0x7c8a,0x7c8c,0x7c8e,0x7c91,0x7c92,0x7c94,0x7c98,0x7c9c,0x7c9c,0x7c9e,0x7c9f,0x7ca1,0x7ca3,0x7ca5,0x7ca8,0x7cac,0x7cac,0x7cae,0x7caf,0x7cb1,0x7cb5,0x7cb8,0x7cbf,0x7cc2,0x7cc3,0x7cc5,0x7cc5,0x7cc7,0x7cce,0x7cd0,0x7cd7,0x7cd9,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce6,0x7ce8,0x7cea,0x7cea,0x7cec,0x7cf9,0x7cfb,0x7cfe,0x7d00,0x7d22,0x7d25,0x7d25,0x7d28,0x7d29,0x7d2b,0x7d2c,0x7d2e,0x7d33,0x7d35,0x7d36,0x7d38,0x7d47,0x7d4a,0x7d4a,0x7d4d,0x7d56,0x7d58,0x7d58,0x7d5a,0x7d5f,0x7d61,0x7d63,0x7d66,0x7d6b,0x7d6d,0x7d73,0x7d79,0x7d7d,0x7d7f,0x7d81,0x7d83,0x7d86,0x7d88,0x7d89,0x7d8b,0x7d8f,0x7d91,0x7d97,0x7d9c,0x7da4,0x7da6,0x7db5,0x7db7,0x7dc2,0x7dc4,0x7dc7,0x7dc9,0x7dd0,0x7dd2,0x7dd4,0x7dd7,0x7de1,0x7de3,0x7dea,0x7dec,0x7dec,0x7dee,0x7df7,0x7df9,0x7dfe,0x7e03,0x7e03,0x7e07,0x7e17,0x7e1a,0x7e25,0x7e27,0x7e27,0x7e29,0x7e2b,0x7e2d,0x7e49,0x7e4c,0x7e4c,0x7e50,0x7e5c,0x7e5e,0x7e63,0x7e65,0x7e65,0x7e67,0x7e70,0x7e72,0x7e82,0x7e86,0x7e88,0x7e8a,0x7e8f,0x7e91,0x7e9c,0x7e9f,0x7e9f,0x7ea4,0x7ea4,0x7eac,0x7eac,0x7eba,0x7eba,0x7ec7,0x7ec7,0x7ecf,0x7ecf,0x7edf,0x7edf,0x7f06,0x7f06,0x7f36,0x7f3a,0x7f3d,0x7f41,0x7f43,0x7f45,0x7f47,0x7f55,0x7f58,0x7f58,0x7f5b,0x7f61,0x7f63,0x7f63,0x7f65,0x7f6e,0x7f70,0x7f73,0x7f75,0x7f7f,0x7f83,0x7f83,0x7f85,0x7f8f,0x7f91,0x7f97,0x7f9a,0x7f9e,0x7fa0,0x7fa9,0x7fac,0x7fc3,0x7fc5,0x7fc5,0x7fc7,0x7fc7,0x7fc9,0x7fd2,0x7fd4,0x7fd5,0x7fd7,0x7fd7,0x7fdb,0x7fe3,0x7fe5,0x7ff5,0x7ff7,0x8008,0x800b,0x8012,0x8014,0x8019,0x801b,0x8021,0x8024,0x8026,0x8028,0x802a,0x802c,0x802c,0x802e,0x8031,0x8033,0x8037,0x8039,0x8039,0x803b,0x803f,0x8043,0x8043,0x8046,0x8048,0x804a,0x804a,0x804f,0x8052,0x8054,0x8054,0x8056,0x8056,0x8058,0x8058,0x805a,0x805e,0x8061,0x8064,0x8066,0x8067,0x806c,0x806c,0x806f,0x8073,0x8075,0x8079,0x807d,0x8080,0x8082,0x8082,0x8084,0x8087,0x8089,0x808c,0x808f,0x8090,0x8092,0x8093,0x8095,0x8096,0x8098,0x809d,0x809f,0x809f,0x80a1,0x80a3,0x80a5,0x80a5,0x80a7,0x80a7,0x80a9,0x80ab,0x80ad,0x80af,0x80b1,0x80b2,0x80b4,0x80b8,0x80ba,0x80ba,0x80bc,0x80bd,0x80c2,0x80ca,0x80cc,0x80d1,0x80d4,0x80de,0x80e0,0x80e1,0x80e3,0x80e6,0x80e9,0x80e9,0x80ec,0x80ed,0x80ef,0x80f6,0x80f8,0x80fe,0x8100,0x8103,0x8105,0x810a,0x810c,0x810c,0x810e,0x810e,0x8112,0x8112,0x8114,0x811b,0x811d,0x811f,0x8121,0x8125,0x8127,0x8127,0x8129,0x812d,0x812f,0x8132,0x8134,0x8134,0x8137,0x8137,0x8139,0x813a,0x813d,0x813e,0x8142,0x8144,0x8146,0x8148,0x814a,0x8156,0x8159,0x815c,0x815e,0x815e,0x8160,0x8162,0x8164,0x8167,0x8169,0x8169,0x816b,0x8174,0x8176,0x817a,0x817c,0x817d,0x817f,0x8180,0x8182,0x8184,0x8186,0x818d,0x818f,0x818f,0x8193,0x8193,0x8195,0x8195,0x8197,0x81a0,0x81a2,0x81a3,0x81a5,0x81ac,0x81ae,0x81ae,0x81b0,0x81b7,0x81b9,0x81ca,0x81cc,0x81cd,0x81cf,0x81d2,0x81d5,0x81d5,0x81d7,0x81db,0x81dd,0x81ea,0x81ec,0x81ef,0x81f2,0x81f4,0x81f6,0x81fc,0x81fe,0x8202,0x8204,0x8205,0x8207,0x820d,0x8210,0x8212,0x8214,0x8216,0x8218,0x8218,0x821a,0x8222,0x8225,0x8226,0x8228,0x822d,0x822f,0x822f,0x8232,0x823a,0x823c,0x8240,0x8242,0x8242,0x8244,0x8245,0x8247,0x8247,0x8249,0x8249,0x824b,0x824b,0x824e,0x825c,0x825e,0x825f,0x8261,0x8266,0x8268,0x8269,0x826b,0x826f,0x8271,0x8272,0x8274,0x8280,0x8283,0x8285,0x8287,0x8287,0x828a,0x828b,0x828d,0x8294,0x8298,0x829b,0x829d,0x82b1,0x82b3,0x82c0,0x82c2,0x82c4,0x82ca,0x82ca,0x82cf,0x82d9,0x82db,0x82dc,0x82de,0x82e8,0x82ea,0x8309,0x830b,0x830d,0x8316,0x831e,0x8320,0x8320,0x8322,0x8322,0x8324,0x832d,0x832f,0x832f,0x8331,0x833d,0x833f,0x8345,0x8347,0x8354,0x8356,0x8357,0x8362,0x8363,0x8366,0x8366,0x836f,0x836f,0x8373,0x8378,0x837a,0x837f,0x8381,0x8381,0x8383,0x8383,0x8385,0x839e,0x83a0,0x83a0,0x83a2,0x83ac,0x83ae,0x83b0,0x83b9,0x83b9,0x83bd,0x83cf,0x83d1,0x83d1,0x83d3,0x83d9,0x83db,0x83e5,0x83e7,0x83f6,0x83f8,0x83ff,0x8401,0x8401,0x8403,0x8407,0x8409,0x8414,0x8416,0x8416,0x8418,0x8418,0x841b,0x841c,0x8420,0x8421,0x8423,0x8424,0x8426,0x8426,0x8429,0x8429,0x842b,0x8440,0x8442,0x844e,0x8450,0x8469,0x846b,0x847a,0x847d,0x8480,0x8482,0x8482,0x8484,0x8484,0x8486,0x8486,0x8488,0x8488,0x848d,0x8494,0x8496,0x84a4,0x84a7,0x84b2,0x84b4,0x84b4,0x84b6,0x84b6,0x84b8,0x84c2,0x84c4,0x84c7,0x84c9,0x84d4,0x84d6,0x84d7,0x84da,0x84db,0x84de,0x84de,0x84e1,0x84e2,0x84e4,0x84e5,0x84e7,0x84ec,0x84ee,0x84f4,0x84f6,0x8500,0x8502,0x851a,0x851c,0x8521,0x8523,0x8531,0x8533,0x8534,0x8538,0x8538,0x853b,0x853b,0x853d,0x853e,0x8540,0x854e,0x8551,0x855b,0x855d,0x8571,0x8573,0x8573,0x8575,0x857c,0x857e,0x857e,0x8580,0x8591,0x8593,0x85a4,0x85a6,0x85aa,0x85af,0x85b1,0x85b3,0x85ba,0x85bd,0x85c9,0x85cb,0x85cb,0x85cd,0x85d2,0x85d5,0x85da,0x85dc,0x85e6,0x85e8,0x85f2,0x85f4,0x85f4,0x85f6,0x8602,0x8604,0x8607,0x8609,0x860d,0x860f,0x8611,0x8613,0x8614,0x8616,0x861c,0x861e,0x862a,0x862c,0x862f,0x8631,0x8636,0x8638,0x863c,0x863e,0x8640,0x8642,0x8643,0x8645,0x8648,0x864b,0x864e,0x8650,0x8650,0x8652,0x8656,0x8659,0x8659,0x865b,0x865c,0x865e,0x865f,0x8661,0x8665,0x8667,0x8674,0x8677,0x8677,0x8679,0x867c,0x867e,0x867e,0x8685,0x8687,0x868a,0x868e,0x8690,0x869a,0x869c,0x869e,0x86a0,0x86a5,0x86a7,0x86aa,0x86ad,0x86ad,0x86af,0x86c9,0x86cb,0x86cc,0x86d0,0x86d1,0x86d3,0x86d4,0x86d6,0x86df,0x86e2,0x86e4,0x86e6,0x86e6,0x86e8,0x86ed,0x86ef,0x86ef,0x86f5,0x86fb,0x86fe,0x86fe,0x8700,0x870e,0x8711,0x8713,0x8715,0x8715,0x8718,0x871c,0x871e,0x871e,0x8720,0x872a,0x872c,0x872e,0x8730,0x8735,0x8737,0x8738,0x873a,0x873c,0x873e,0x8743,0x8746,0x8746,0x874c,0x8771,0x8773,0x877b,0x877d,0x877d,0x8781,0x8789,0x878b,0x878d,0x878f,0x8794,0x8796,0x8798,0x879a,0x879f,0x87a2,0x87a5,0x87a9,0x87c6,0x87c8,0x87cc,0x87ce,0x87ce,0x87d1,0x87d4,0x87d6,0x87e8,0x87ea,0x87ef,0x87f2,0x87f7,0x87f9,0x87fc,0x87fe,0x8806,0x8808,0x880d,0x880f,0x8811,0x8813,0x8819,0x881b,0x881d,0x881f,0x8833,0x8835,0x8839,0x883b,0x8846,0x8848,0x8848,0x884a,0x884f,0x8852,0x8853,0x8855,0x8857,0x8859,0x885b,0x885d,0x885e,0x8860,0x8865,0x8867,0x886b,0x886d,0x8872,0x8874,0x8877,0x8879,0x8879,0x887c,0x8884,0x8887,0x8889,0x888b,0x8893,0x8895,0x88a2,0x88a4,0x88a4,0x88a7,0x88a8,0x88aa,0x88ac,0x88ae,0x88ae,0x88b1,0x88b2,0x88b4,0x88ba,0x88bc,0x88c2,0x88c5,0x88c5,0x88c7,0x88c7,0x88c9,0x88d0,0x88d2,0x88d2,0x88d4,0x88df,0x88e1,0x88e1,0x88e6,0x88e8,0x88eb,0x88ec,0x88ee,0x8902,0x8905,0x8907,0x8909,0x890c,0x890e,0x890e,0x8910,0x891a,0x891e,0x891f,0x8921,0x8927,0x8929,0x8933,0x8935,0x8938,0x893b,0x893e,0x8941,0x8944,0x8946,0x8947,0x8949,0x8949,0x894b,0x894d,0x894f,0x8954,0x8956,0x8966,0x8969,0x896f,0x8971,0x8974,0x8976,0x8977,0x8979,0x897c,0x897e,0x8983,0x8985,0x898b,0x898f,0x898f,0x8991,0x8991,0x8993,0x8998,0x899b,0x899f,0x89a1,0x89a7,0x89a9,0x89aa,0x89ac,0x89af,0x89b2,0x89b2,0x89b6,0x89b7,0x89b9,0x89ba,0x89bc,0x89c1,0x89c6,0x89c6,0x89d2,0x89d6,0x89d9,0x89dd,0x89df,0x89e9,0x89eb,0x89ed,0x89f0,0x89f4,0x89f6,0x89f8,0x89fa,0x89fc,0x89fe,0x8a00,0x8a02,0x8a04,0x8a07,0x8a08,0x8a0a,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a13,0x8a15,0x8a18,0x8a1b,0x8a1f,0x8a22,0x8a23,0x8a25,0x8a25,0x8a27,0x8a27,0x8a29,0x8a2d,0x8a30,0x8a31,0x8a34,0x8a34,0x8a36,0x8a36,0x8a38,0x8a41,0x8a44,0x8a46,0x8a48,0x8a4a,0x8a4c,0x8a52,0x8a54,0x8a59,0x8a5b,0x8a5b,0x8a5e,0x8a5e,0x8a60,0x8a63,0x8a66,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a77,0x8a79,0x8a7c,0x8a7e,0x8a7f,0x8a81,0x8a87,0x8a8b,0x8a8d,0x8a8f,0x8a96,0x8a98,0x8a9a,0x8a9c,0x8a9c,0x8a9e,0x8a9e,0x8aa0,0x8aa1,0x8aa3,0x8aac,0x8aaf,0x8ab0,0x8ab2,0x8ab2,0x8ab4,0x8ab4,0x8ab6,0x8ab6,0x8ab8,0x8ac0,0x8ac2,0x8ac9,0x8acb,0x8acd,0x8acf,0x8acf,0x8ad1,0x8ae2,0x8ae4,0x8ae4,0x8ae6,0x8ae8,0x8aea,0x8aeb,0x8aed,0x8afc,0x8afe,0x8b02,0x8b04,0x8b08,0x8b0a,0x8b20,0x8b22,0x8b28,0x8b2a,0x8b31,0x8b33,0x8b33,0x8b35,0x8b37,0x8b39,0x8b43,0x8b45,0x8b5a,0x8b5c,0x8b60,0x8b62,0x8b63,0x8b65,0x8b6d,0x8b6f,0x8b70,0x8b74,0x8b74,0x8b77,0x8b7b,0x8b7d,0x8b86,0x8b88,0x8b88,0x8b8a,0x8b8c,0x8b8e,0x8b90,0x8b92,0x8b96,0x8b98,0x8b9c,0x8b9e,0x8ba0,0x8bbe,0x8bbe,0x8be2,0x8be2,0x8c37,0x8c37,0x8c39,0x8c39,0x8c3b,0x8c3f,0x8c41,0x8c43,0x8c45,0x8c51,0x8c54,0x8c57,0x8c5a,0x8c5a,0x8c5c,0x8c5d,0x8c5f,0x8c5f,0x8c61,0x8c62,0x8c64,0x8c66,0x8c68,0x8c6d,0x8c6f,0x8c73,0x8c75,0x8c7b,0x8c7d,0x8c7d,0x8c80,0x8c82,0x8c84,0x8c86,0x8c89,0x8c8a,0x8c8c,0x8c8d,0x8c8f,0x8c95,0x8c97,0x8ca5,0x8ca7,0x8cad,0x8caf,0x8cb0,0x8cb2,0x8cc5,0x8cc7,0x8cc8,0x8cca,0x8cca,0x8ccc,0x8ccd,0x8ccf,0x8ccf,0x8cd1,0x8cd7,0x8cd9,0x8cee,0x8cf0,0x8cf5,0x8cf7,0x8cfe,0x8d00,0x8d00,0x8d02,0x8d0d,0x8d0f,0x8d19,0x8d1b,0x8d1d,0x8d64,0x8d64,0x8d66,0x8d69,0x8d6b,0x8d70,0x8d72,0x8d74,0x8d76,0x8d7b,0x8d7d,0x8d7d,0x8d80,0x8d82,0x8d84,0x8d85,0x8d89,0x8d8a,0x8d8c,0x8d96,0x8d99,0x8d99,0x8d9b,0x8d9c,0x8d9f,0x8da1,0x8da3,0x8da3,0x8da5,0x8daf,0x8db2,0x8db7,0x8db9,0x8dba,0x8dbc,0x8dbc,0x8dbe,0x8dc3,0x8dc5,0x8dc8,0x8dcb,0x8dd1,0x8dd3,0x8ddd,0x8ddf,0x8de4,0x8de6,0x8dec,0x8dee,0x8df4,0x8dfa,0x8dfa,0x8dfc,0x8e07,0x8e09,0x8e0a,0x8e0d,0x8e2b,0x8e2d,0x8e2e,0x8e30,0x8e31,0x8e33,0x8e36,0x8e38,0x8e3a,0x8e3c,0x8e42,0x8e44,0x8e50,0x8e53,0x8e57,0x8e59,0x8e6a,0x8e6c,0x8e6d,0x8e6f,0x8e6f,0x8e71,0x8e78,0x8e7a,0x8e7c,0x8e7e,0x8e7e,0x8e80,0x8e82,0x8e84,0x8e8e,0x8e90,0x8e98,0x8e9a,0x8e9a,0x8e9d,0x8ea1,0x8ea3,0x8ead,0x8eb0,0x8eb0,0x8eb2,0x8eb2,0x8eb6,0x8eb6,0x8eb9,0x8eba,0x8ebc,0x8ebd,0x8ec0,0x8ec0,0x8ec2,0x8ec3,0x8ec9,0x8ecf,0x8ed1,0x8ed4,0x8ed7,0x8ed8,0x8eda,0x8ee2,0x8ee4,0x8ee9,0x8eeb,0x8eef,0x8ef1,0x8ef2,0x8ef4,0x8efc,0x8efe,0x8f03,0x8f05,0x8f0b,0x8f0d,0x8f0e,0x8f10,0x8f20,0x8f23,0x8f26,0x8f29,0x8f2a,0x8f2c,0x8f30,0x8f32,0x8f39,0x8f3b,0x8f3c,0x8f3e,0x8f4b,0x8f4d,0x8f64,0x8f66,0x8f67,0x8f6e,0x8f6e,0x8f93,0x8f93,0x8f9b,0x8f9c,0x8f9f,0x8fa0,0x8fa3,0x8fa3,0x8fa5,0x8fa8,0x8fad,0x8fbc,0x8fbe,0x8fbf,0x8fc1,0x8fc2,0x8fc4,0x8fc6,0x8fc9,0x8fd7,0x8fda,0x8fda,0x8fe0,0x8fe6,0x8fe8,0x8fe8,0x8fea,0x8feb,0x8fed,0x8fee,0x8ff0,0x8ff0,0x8ff4,0x9006,0x9008,0x9008,0x900b,0x900d,0x900f,0x9012,0x9014,0x9017,0x9019,0x9024,0x902d,0x902f,0x9031,0x9038,0x903c,0x903f,0x9041,0x9042,0x9044,0x9044,0x9046,0x9047,0x9049,0x9056,0x9058,0x9059,0x905b,0x905e,0x9060,0x9064,0x9067,0x9069,0x906b,0x9070,0x9072,0x9088,0x908a,0x908b,0x908d,0x908d,0x908f,0x9091,0x9094,0x9095,0x9097,0x9099,0x909b,0x909b,0x909e,0x90a3,0x90a5,0x90a8,0x90aa,0x90aa,0x90ae,0x90b6,0x90b8,0x90b8,0x90bb,0x90bb,0x90bd,0x90bf,0x90c1,0x90c1,0x90c3,0x90c5,0x90c7,0x90c8,0x90ca,0x90cb,0x90ce,0x90ce,0x90d4,0x90dd,0x90df,0x90e5,0x90e8,0x90ed,0x90ef,0x90f5,0x90f9,0x9109,0x910b,0x910b,0x910d,0x9112,0x9114,0x9114,0x9116,0x9124,0x9126,0x9136,0x9138,0x913b,0x913e,0x9141,0x9143,0x9153,0x9155,0x915a,0x915c,0x915c,0x915e,0x9165,0x9167,0x916a,0x916c,0x916c,0x916e,0x9170,0x9172,0x917a,0x917c,0x917c,0x9180,0x9187,0x9189,0x9193,0x9196,0x9196,0x9199,0x91a3,0x91a5,0x91a5,0x91a7,0x91b7,0x91b9,0x91be,0x91c0,0x91c7,0x91c9,0x91c9,0x91cb,0x91d1,0x91d3,0x91da,0x91dc,0x91dd,0x91df,0x91df,0x91e2,0x91ee,0x91f1,0x91f1,0x91f3,0x91fa,0x91fd,0x920a,0x920c,0x921a,0x921c,0x921c,0x921e,0x921e,0x9221,0x9221,0x9223,0x9228,0x922a,0x922b,0x922d,0x922e,0x9230,0x923a,0x923c,0x9241,0x9244,0x9246,0x9248,0x9258,0x925a,0x925b,0x925d,0x9267,0x926b,0x9270,0x9272,0x9272,0x9276,0x928f,0x9291,0x9291,0x9293,0x929d,0x92a0,0x92ac,0x92ae,0x92ae,0x92b1,0x92b7,0x92b9,0x92bc,0x92be,0x92d5,0x92d7,0x92d9,0x92db,0x92db,0x92dd,0x92e1,0x92e3,0x92f4,0x92f6,0x9304,0x9306,0x9309,0x930b,0x9310,0x9312,0x9316,0x9318,0x931b,0x931d,0x9331,0x9333,0x9336,0x9338,0x9339,0x933c,0x933c,0x9340,0x9352,0x9354,0x935c,0x935e,0x936e,0x9370,0x9371,0x9373,0x937e,0x9380,0x938a,0x938c,0x9392,0x9394,0x93aa,0x93ac,0x93b5,0x93b7,0x93b8,0x93bb,0x93bb,0x93bd,0x93bd,0x93bf,0x93c0,0x93c2,0x93c4,0x93c6,0x93c8,0x93ca,0x93e4,0x93e6,0x93e8,0x93ec,0x93ec,0x93ee,0x93ee,0x93f0,0x93f1,0x93f3,0x9401,0x9403,0x9404,0x9406,0x9419,0x941b,0x941b,0x941d,0x941d,0x9420,0x9420,0x9424,0x9433,0x9435,0x9440,0x9442,0x944d,0x944f,0x9452,0x9454,0x9455,0x9457,0x9458,0x945b,0x945b,0x945d,0x945e,0x9460,0x9460,0x9462,0x9465,0x9467,0x9479,0x947b,0x9483,0x9485,0x9485,0x949f,0x949f,0x94a2,0x94a2,0x94c1,0x94c1,0x94c3,0x94c3,0x94dc,0x94dc,0x94f6,0x94f6,0x952d,0x952d,0x9547,0x9547,0x9577,0x9578,0x957a,0x957d,0x957f,0x9580,0x9582,0x9583,0x9585,0x9586,0x9588,0x9589,0x958b,0x9594,0x9596,0x9599,0x959b,0x959c,0x959e,0x95ae,0x95b0,0x95b2,0x95b5,0x95b7,0x95b9,0x95c0,0x95c3,0x95c3,0x95c5,0x95cd,0x95d0,0x95d6,0x95da,0x95dc,0x95de,0x95e5,0x95e8,0x95e8,0x95f4,0x95f4,0x961c,0x961e,0x9620,0x9624,0x9628,0x9628,0x962a,0x962a,0x962c,0x9633,0x9638,0x963d,0x963f,0x9645,0x964a,0x9651,0x9653,0x9654,0x9656,0x9656,0x9658,0x9658,0x965b,0x965f,0x9661,0x9664,0x9669,0x966d,0x966f,0x9678,0x967b,0x967e,0x9680,0x9681,0x9683,0x968b,0x968d,0x968f,0x9691,0x9699,0x969b,0x969c,0x969e,0x969e,0x96a1,0x96a5,0x96a7,0x96aa,0x96ac,0x96ac,0x96ae,0x96ae,0x96b0,0x96b1,0x96b3,0x96b4,0x96b6,0x96b6,0x96b8,0x96b9,0x96bb,0x96bd,0x96bf,0x96ce,0x96d2,0x96df,0x96e1,0x96e3,0x96e5,0x96e5,0x96e8,0x96ea,0x96ef,0x96f2,0x96f4,0x96fb,0x96fd,0x96fd,0x96ff,0x9700,0x9702,0x9709,0x970b,0x970b,0x970d,0x9713,0x9716,0x9716,0x9718,0x9719,0x971b,0x972c,0x972e,0x9732,0x9734,0x9736,0x9738,0x973a,0x973d,0x9744,0x9746,0x974b,0x9751,0x9752,0x9755,0x9758,0x975a,0x9762,0x9766,0x9766,0x9768,0x976a,0x976c,0x976e,0x9770,0x9774,0x9776,0x9778,0x977a,0x9785,0x9787,0x978b,0x978d,0x978f,0x9794,0x9794,0x9797,0x97a6,0x97a8,0x97a8,0x97aa,0x97ae,0x97b1,0x97b4,0x97b6,0x97bb,0x97bd,0x97c9,0x97cb,0x97d0,0x97d2,0x97d9,0x97dc,0x97e1,0x97e3,0x97e3,0x97e5,0x97e6,0x97ed,0x97ee,0x97f0,0x97f3,0x97f5,0x97f6,0x97f8,0x97fb,0x97fd,0x9808,0x980a,0x980a,0x980c,0x9818,0x981b,0x9821,0x9823,0x9824,0x9826,0x9829,0x982b,0x982b,0x982d,0x9830,0x9832,0x9835,0x9837,0x9839,0x983b,0x983b,0x9841,0x9841,0x9843,0x9853,0x9856,0x9859,0x985b,0x9860,0x9862,0x986c,0x986f,0x9875,0x98a8,0x98a9,0x98ac,0x98af,0x98b1,0x98b4,0x98b6,0x98c4,0x98c6,0x98cc,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e3,0x98e5,0x98e7,0x98e9,0x98ed,0x98ef,0x98ef,0x98f1,0x98f2,0x98f4,0x98f6,0x98f9,0x98fa,0x98fc,0x98fe,0x9900,0x9900,0x9902,0x9903,0x9905,0x9905,0x9907,0x990a,0x990c,0x990c,0x990e,0x990e,0x9910,0x991c,0x991e,0x991f,0x9921,0x9921,0x9924,0x9925,0x9927,0x9933,0x9935,0x9935,0x9937,0x9943,0x9945,0x9945,0x9947,0x994e,0x9950,0x9959,0x995b,0x995f,0x9961,0x9963,0x9996,0x9999,0x999b,0x999e,0x99a1,0x99a1,0x99a3,0x99a8,0x99aa,0x99b5,0x99b8,0x99bd,0x99c1,0x99c5,0x99c7,0x99c7,0x99c9,0x99c9,0x99cb,0x99dd,0x99df,0x99e7,0x99e9,0x99ea,0x99ec,0x99ee,0x99f0,0x99f1,0x99f4,0x99ff,0x9a01,0x9a07,0x9a09,0x9a11,0x9a14,0x9a16,0x9a19,0x9a27,0x9a29,0x9a32,0x9a34,0x9a46,0x9a48,0x9a4a,0x9a4c,0x9a50,0x9a52,0x9a5c,0x9a5e,0x9a60,0x9a62,0x9a6c,0x9a8f,0x9a8f,0x9aa8,0x9aa8,0x9aab,0x9aab,0x9aad,0x9aad,0x9aaf,0x9ab4,0x9ab6,0x9ac2,0x9ac6,0x9ac7,0x9aca,0x9aca,0x9acd,0x9acd,0x9acf,0x9ad8,0x9adc,0x9adc,0x9adf,0x9ae3,0x9ae6,0x9ae7,0x9aeb,0x9aef,0x9af1,0x9af4,0x9af6,0x9af7,0x9af9,0x9aff,0x9b01,0x9b06,0x9b08,0x9b12,0x9b14,0x9b1a,0x9b1e,0x9b20,0x9b22,0x9b25,0x9b27,0x9b2b,0x9b2d,0x9b2f,0x9b31,0x9b35,0x9b37,0x9b37,0x9b39,0x9b3c,0x9b3e,0x9b46,0x9b48,0x9b48,0x9b4a,0x9b52,0x9b54,0x9b56,0x9b58,0x9b5b,0x9b5f,0x9b61,0x9b64,0x9b64,0x9b66,0x9b69,0x9b6c,0x9b6c,0x9b6f,0x9b71,0x9b74,0x9b77,0x9b7a,0x9b83,0x9b85,0x9b88,0x9b8b,0x9b8b,0x9b8d,0x9b93,0x9b95,0x9b95,0x9b97,0x9b97,0x9b9a,0x9b9b,0x9b9d,0x9ba2,0x9ba4,0x9ba6,0x9ba8,0x9ba8,0x9baa,0x9bab,0x9bad,0x9bb0,0x9bb5,0x9bb6,0x9bb8,0x9bb9,0x9bbd,0x9bbd,0x9bbf,0x9bc1,0x9bc3,0x9bc4,0x9bc6,0x9bca,0x9bcf,0x9bcf,0x9bd3,0x9bd7,0x9bd9,0x9bde,0x9be0,0x9be2,0x9be4,0x9bed,0x9bf0,0x9bf1,0x9bf4,0x9bf4,0x9bf7,0x9bf8,0x9bfd,0x9bfd,0x9bff,0x9bff,0x9c02,0x9c02,0x9c05,0x9c0e,0x9c10,0x9c10,0x9c12,0x9c15,0x9c17,0x9c17,0x9c1b,0x9c1d,0x9c1f,0x9c21,0x9c23,0x9c26,0x9c28,0x9c29,0x9c2b,0x9c2d,0x9c2f,0x9c2f,0x9c31,0x9c37,0x9c39,0x9c41,0x9c44,0x9c50,0x9c52,0x9c59,0x9c5d,0x9c60,0x9c62,0x9c63,0x9c66,0x9c68,0x9c6d,0x9c6e,0x9c71,0x9c75,0x9c77,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9cea,0x9ced,0x9ced,0x9cf1,0x9cf7,0x9cf9,0x9cfd,0x9cff,0x9d00,0x9d02,0x9d09,0x9d0c,0x9d0c,0x9d10,0x9d10,0x9d12,0x9d12,0x9d14,0x9d19,0x9d1b,0x9d1b,0x9d1d,0x9d23,0x9d25,0x9d26,0x9d28,0x9d29,0x9d2d,0x9d31,0x9d33,0x9d34,0x9d36,0x9d39,0x9d3b,0x9d3b,0x9d3d,0x9d45,0x9d49,0x9d4c,0x9d4e,0x9d54,0x9d56,0x9d61,0x9d67,0x9d75,0x9d77,0x9d79,0x9d7b,0x9d8c,0x9d90,0x9d90,0x9d92,0x9d94,0x9d96,0x9dad,0x9daf,0x9daf,0x9db1,0x9dc5,0x9dc7,0x9ddf,0x9de1,0x9de6,0x9de8,0x9de9,0x9deb,0x9df0,0x9df2,0x9e07,0x9e09,0x9e15,0x9e17,0x9e1f,0x9e75,0x9e75,0x9e79,0x9e7d,0x9e7f,0x9e8e,0x9e90,0x9ea2,0x9ea4,0x9eb1,0x9eb4,0x9eb7,0x9ebb,0x9ec4,0x9ec6,0x9ec8,0x9ecc,0x9ed1,0x9ed3,0x9ed6,0x9ed8,0x9ed8,0x9eda,0x9ee0,0x9ee2,0x9ee2,0x9ee4,0x9ee8,0x9eeb,0x9eeb,0x9eed,0x9f02,0x9f06,0x9f0a,0x9f0e,0x9f10,0x9f12,0x9f13,0x9f15,0x9f1c,0x9f1e,0x9f1e,0x9f20,0x9f20,0x9f22,0x9f39,0x9f3b,0x9f3b,0x9f3d,0x9f3e,0x9f40,0x9f50,0x9f52,0x9f67,0x9f69,0x9f6c,0x9f6e,0x9f72,0x9f74,0x9f7b,0x9f7e,0x9f7f,0x9f8d,0x9f8e,0x9f90,0x9f92,0x9f94,0x9f99,0x9f9c,0x9f9c,0x9f9f,0x9fa0,0x9fa2,0x9fa2,0x9fa4,0x9fb3,0x9fc7,0x9fcb,0x9fd0,0x9fd0,0xf900,0xf908,0xf90b,0xf90d,0xf915,0xf915,0xf917,0xf917,0xf91a,0xf91a,0xf922,0xf922,0xf92d,0xf92d,0xf934,0xf934,0xf937,0xf937,0xf93a,0xf93a,0xf943,0xf943,0xf947,0xf948,0xf94a,0xf94a,0xf952,0xf952,0xf95e,0xf95e,0xf962,0xf962,0xf965,0xf965,0xf967,0xf967,0xf96d,0xf96d,0xf972,0xf972,0xf976,0xf976,0xf978,0xf979,0xf97b,0xf97b,0xf97e,0xf97e,0xf980,0xf980,0xf986,0xf986,0xf98a,0xf98a,0xf98e,0xf98e,0xf995,0xf995,0xf99c,0xf99d,0xf99f,0xf99f,0xf9b5,0xf9b5,0xf9bb,0xf9bb,0xf9bd,0xf9be,0xf9c5,0xf9c6,0xf9c8,0xf9c8,0xf9d0,0xf9d0,0xf9d8,0xf9d9,0xf9dc,0xf9de,0xf9e0,0xf9e0,0xf9e2,0xf9e4,0xf9e7,0xf9e7,0xf9e9,0xf9e9,0xf9f4,0xf9f5,0xf9fa,0xf9fa,0xf9fd,0xf9fd,0xf9ff,0xf9ff,0xfa02,0xfa02,0xfa05,0xfa08,0xfa0a,0xfa0a,0xfa0c,0xfa0d,0xfa33,0xfa35,0xfa3a,0xfa3a,0xfa49,0xfa49,0xfa4b,0xfa4b,0xfa5d,0xfa5e,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x20021,0x20021,0x2003e,0x2003e,0x20046,0x20046,0x2004e,0x2004e,0x20068,0x20068,0x20086,0x20087,0x2008a,0x2008a,0x20094,0x20094,0x200ca,0x200cd,0x200d1,0x200d1,0x200ee,0x200ee,0x2010c,0x2010c,0x2010e,0x2010e,0x20118,0x20118,0x201a4,0x201a4,0x201a9,0x201a9,0x201ab,0x201ab,0x201c1,0x201c1,0x201d4,0x201d4,0x201f2,0x201f2,0x20204,0x20204,0x2020c,0x2020c,0x20214,0x20214,0x20239,0x20239,0x2025b,0x2025b,0x20274,0x20275,0x20299,0x20299,0x2029e,0x2029e,0x202a0,0x202a0,0x202b7,0x202b7,0x202bf,0x202c0,0x202e5,0x202e5,0x2030a,0x2030a,0x20325,0x20325,0x20341,0x20341,0x20345,0x20347,0x2037e,0x20380,0x203a0,0x203a0,0x203a7,0x203a7,0x203b5,0x203b5,0x203c9,0x203c9,0x203cb,0x203cb,0x203f5,0x203f5,0x203fc,0x203fc,0x20413,0x20414,0x2041f,0x2041f,0x20465,0x20465,0x20487,0x20487,0x2048e,0x2048e,0x20491,0x20492,0x204a3,0x204a3,0x204d7,0x204d7,0x204fc,0x204fc,0x204fe,0x204fe,0x20547,0x20547,0x2058e,0x2058e,0x205a5,0x205a5,0x205b3,0x205b3,0x205c3,0x205c3,0x205ca,0x205ca,0x205d0,0x205d0,0x205d5,0x205d5,0x205df,0x205e0,0x205eb,0x205eb,0x20611,0x20611,0x20615,0x20615,0x20619,0x2061a,0x20628,0x20628,0x20630,0x20630,0x20656,0x20656,0x20676,0x20676,0x2070e,0x2070e,0x20731,0x20731,0x20779,0x20779,0x2082c,0x2082c,0x20873,0x20873,0x208d5,0x208d5,0x20916,0x20916,0x20923,0x20923,0x20954,0x20954,0x20979,0x20979,0x209e7,0x209e7,0x20a11,0x20a11,0x20a50,0x20a50,0x20a6f,0x20a6f,0x20a8a,0x20a8a,0x20ab4,0x20ab4,0x20ac2,0x20ac2,0x20acd,0x20acd,0x20b0d,0x20b0d,0x20b8f,0x20b8f,0x20b9f,0x20b9f,0x20ba8,0x20ba9,0x20bbf,0x20bbf,0x20bc6,0x20bc6,0x20bcb,0x20bcb,0x20be2,0x20be2,0x20beb,0x20beb,0x20bfb,0x20bfb,0x20bff,0x20bff,0x20c0b,0x20c0b,0x20c0d,0x20c0d,0x20c20,0x20c20,0x20c34,0x20c34,0x20c3a,0x20c3b,0x20c41,0x20c43,0x20c53,0x20c53,0x20c65,0x20c65,0x20c77,0x20c78,0x20c7c,0x20c7c,0x20c8d,0x20c8d,0x20c96,0x20c96,0x20c9c,0x20c9c,0x20cb5,0x20cb5,0x20cb8,0x20cb8,0x20ccf,0x20ccf,0x20cd3,0x20cd6,0x20cdd,0x20cdd,0x20ced,0x20ced,0x20cff,0x20cff,0x20d15,0x20d15,0x20d28,0x20d28,0x20d31,0x20d32,0x20d46,0x20d49,0x20d4c,0x20d4e,0x20d6f,0x20d6f,0x20d71,0x20d71,0x20d74,0x20d74,0x20d7c,0x20d7c,0x20d7e,0x20d7f,0x20d96,0x20d96,0x20d9c,0x20d9c,0x20da7,0x20da7,0x20db2,0x20db2,0x20dc8,0x20dc8,0x20e04,0x20e04,0x20e09,0x20e0a,0x20e0d,0x20e11,0x20e16,0x20e16,0x20e1d,0x20e1d,0x20e4c,0x20e4c,0x20e6d,0x20e6d,0x20e73,0x20e73,0x20e75,0x20e7b,0x20e8c,0x20e8c,0x20e96,0x20e96,0x20e98,0x20e98,0x20e9d,0x20e9d,0x20ea2,0x20ea2,0x20eaa,0x20eac,0x20eb6,0x20eb6,0x20ed7,0x20ed8,0x20edd,0x20edd,0x20ef8,0x20efb,0x20f1d,0x20f1d,0x20f26,0x20f26,0x20f2d,0x20f2e,0x20f30,0x20f31,0x20f3b,0x20f3b,0x20f4c,0x20f4c,0x20f64,0x20f64,0x20f8d,0x20f8d,0x20f90,0x20f90,0x20fad,0x20fad,0x20fb4,0x20fb6,0x20fbc,0x20fbc,0x20fdf,0x20fdf,0x20fea,0x20fed,0x21014,0x21014,0x2101d,0x2101e,0x2104f,0x2104f,0x2105c,0x2105c,0x2106f,0x2106f,0x21075,0x21078,0x2107b,0x2107b,0x21088,0x21088,0x21096,0x21096,0x2109d,0x2109d,0x210b4,0x210b4,0x210bf,0x210c1,0x210c7,0x210c9,0x210cf,0x210cf,0x210d3,0x210d3,0x210e4,0x210e4,0x210f4,0x210f6,0x2112f,0x2112f,0x2113b,0x2113b,0x2113d,0x2113d,0x21145,0x21145,0x21148,0x21148,0x2114f,0x2114f,0x21180,0x21180,0x21187,0x21187,0x211d9,0x211d9,0x2123c,0x2123c,0x2124f,0x2124f,0x2127c,0x2127c,0x212a8,0x212a9,0x212b0,0x212b0,0x212e3,0x212e3,0x212fe,0x212fe,0x21302,0x21305,0x21336,0x21336,0x2133a,0x2133a,0x21375,0x21376,0x2138e,0x2138e,0x21398,0x21398,0x2139c,0x2139c,0x213c5,0x213c6,0x213ed,0x213ed,0x213fe,0x213fe,0x21413,0x21413,0x21416,0x21416,0x21424,0x21424,0x2143f,0x2143f,0x21452,0x21452,0x21454,0x21455,0x2148a,0x2148a,0x21497,0x21497,0x214b6,0x214b6,0x214e8,0x214e8,0x214fd,0x214fd,0x21577,0x21577,0x21582,0x21582,0x21596,0x21596,0x2160a,0x2160a,0x21613,0x21613,0x21619,0x21619,0x2163e,0x2163e,0x21661,0x21661,0x21692,0x21692,0x216b8,0x216b8,0x216ba,0x216ba,0x216c0,0x216c2,0x216d3,0x216d3,0x216d5,0x216d5,0x216df,0x216df,0x216e6,0x216e8,0x216fa,0x216fc,0x216fe,0x216fe,0x2170d,0x2170d,0x21710,0x21710,0x21726,0x21726,0x2173a,0x2173c,0x21757,0x21757,0x2176c,0x21771,0x21773,0x21774,0x217ab,0x217ab,0x217b0,0x217b5,0x217c3,0x217c3,0x217c7,0x217c7,0x217d9,0x217dc,0x217df,0x217df,0x217ef,0x217ef,0x217f5,0x217f6,0x217f8,0x217fc,0x21820,0x21820,0x21828,0x2182a,0x2182d,0x2182d,0x21839,0x2183b,0x21840,0x21840,0x21845,0x21845,0x21852,0x21852,0x2185e,0x2185e,0x21861,0x21864,0x21877,0x21877,0x2187b,0x2187b,0x21883,0x21885,0x2189e,0x218a2,0x218be,0x218bf,0x218d1,0x218d1,0x218d6,0x218d9,0x218fa,0x218fa,0x21903,0x21905,0x21910,0x21912,0x21915,0x21915,0x2191c,0x2191c,0x21922,0x21922,0x21927,0x21927,0x2193b,0x2193b,0x21944,0x21944,0x21958,0x21958,0x2196a,0x2196a,0x2197c,0x2197c,0x21980,0x21980,0x21983,0x21983,0x21988,0x21988,0x21996,0x21996,0x219db,0x219db,0x219f3,0x219f3,0x21a2d,0x21a2d,0x21a34,0x21a34,0x21a45,0x21a45,0x21a4b,0x21a4b,0x21a63,0x21a63,0x21b44,0x21b44,0x21bc1,0x21bc2,0x21c2a,0x21c2a,0x21c70,0x21c70,0x21ca2,0x21ca2,0x21ca5,0x21ca5,0x21cac,0x21cac,0x21d46,0x21d46,0x21d53,0x21d53,0x21d5e,0x21d5e,0x21d90,0x21d90,0x21db6,0x21db6,0x21dba,0x21dba,0x21dca,0x21dca,0x21dd1,0x21dd1,0x21deb,0x21deb,0x21df9,0x21df9,0x21e1c,0x21e1c,0x21e23,0x21e23,0x21e37,0x21e37,0x21e3d,0x21e3d,0x21e89,0x21e89,0x21ea4,0x21ea4,0x21ea8,0x21ea8,0x21ec8,0x21ec8,0x21ed5,0x21ed5,0x21f0f,0x21f0f,0x21f15,0x21f15,0x21f6a,0x21f6a,0x21f9e,0x21f9e,0x21fa1,0x21fa1,0x21fe8,0x21fe8,0x22045,0x22045,0x22049,0x22049,0x2207e,0x2207e,0x2209a,0x2209a,0x220c7,0x220c7,0x220fc,0x220fc,0x2212a,0x2212a,0x2215b,0x2215b,0x22173,0x22173,0x2217a,0x2217a,0x221a1,0x221a1,0x221c1,0x221c1,0x221c3,0x221c3,0x22208,0x22208,0x2227c,0x2227c,0x22321,0x22321,0x22325,0x22325,0x223bd,0x223bd,0x223d0,0x223d0,0x223d7,0x223d7,0x223fa,0x223fa,0x22465,0x22465,0x22471,0x22471,0x2248b,0x2248b,0x22491,0x22491,0x224b0,0x224b0,0x224bc,0x224bc,0x224c1,0x224c1,0x224c9,0x224c9,0x224cc,0x224cc,0x224ed,0x224ed,0x22513,0x22513,0x2251b,0x2251b,0x22530,0x22530,0x22554,0x22554,0x2258d,0x2258d,0x225af,0x225af,0x225be,0x225be,0x2261b,0x2261c,0x2262b,0x2262b,0x22668,0x22668,0x2267a,0x2267a,0x22696,0x22696,0x22698,0x22698,0x226f4,0x226f6,0x22712,0x22712,0x22714,0x22714,0x2271b,0x2271b,0x2271f,0x2271f,0x2272a,0x2272a,0x22775,0x22775,0x22781,0x22781,0x22796,0x22796,0x227b4,0x227b5,0x227cd,0x227cd,0x22803,0x22803,0x2285f,0x22860,0x22871,0x22871,0x228ad,0x228ad,0x228c1,0x228c1,0x228f7,0x228f7,0x22926,0x22926,0x22939,0x22939,0x2294f,0x2294f,0x22967,0x22967,0x2296b,0x2296b,0x22980,0x22980,0x22993,0x22993,0x22a66,0x22a66,0x22acf,0x22acf,0x22ad5,0x22ad5,0x22ae6,0x22ae6,0x22ae8,0x22ae8,0x22b0e,0x22b0e,0x22b22,0x22b22,0x22b3f,0x22b3f,0x22b43,0x22b43,0x22b6a,0x22b6a,0x22bca,0x22bca,0x22bce,0x22bce,0x22c26,0x22c27,0x22c38,0x22c38,0x22c4c,0x22c4c,0x22c51,0x22c51,0x22c55,0x22c55,0x22c62,0x22c62,0x22c88,0x22c88,0x22c9b,0x22c9b,0x22ca1,0x22ca1,0x22ca9,0x22ca9,0x22cb2,0x22cb2,0x22cb7,0x22cb7,0x22cc2,0x22cc2,0x22cc6,0x22cc6,0x22cc9,0x22cc9,0x22d07,0x22d08,0x22d12,0x22d12,0x22d44,0x22d44,0x22d4c,0x22d4c,0x22d67,0x22d67,0x22d8d,0x22d8d,0x22d95,0x22d95,0x22da0,0x22da0,0x22da3,0x22da4,0x22db7,0x22db7,0x22dee,0x22dee,0x22e0d,0x22e0d,0x22e36,0x22e36,0x22e42,0x22e42,0x22e78,0x22e78,0x22e8b,0x22e8b,0x22eb3,0x22eb3,0x22eef,0x22eef,0x22f74,0x22f74,0x22fcc,0x22fcc,0x22fe3,0x22fe3,0x23033,0x23033,0x23044,0x23044,0x2304b,0x2304b,0x23066,0x23066,0x2307d,0x2307e,0x2308e,0x2308e,0x230b7,0x230b7,0x230bc,0x230bc,0x230da,0x230da,0x23103,0x23103,0x2313d,0x2313d,0x2317d,0x2317d,0x23182,0x23182,0x231a4,0x231a5,0x231b3,0x231b3,0x231c8,0x231c9,0x231ea,0x231ea,0x231f7,0x231f9,0x2320f,0x2320f,0x23225,0x23225,0x2322f,0x2322f,0x23231,0x23234,0x23256,0x23256,0x2325e,0x2325e,0x23262,0x23262,0x23281,0x23281,0x23289,0x2328a,0x232ab,0x232ad,0x232d2,0x232d2,0x232e0,0x232e1,0x23300,0x23300,0x2330a,0x2330a,0x2331f,0x2331f,0x233b4,0x233b4,0x233cc,0x233cc,0x233de,0x233de,0x233e6,0x233e6,0x233f4,0x233f5,0x233f9,0x233fa,0x233fe,0x233fe,0x23400,0x23400,0x2343f,0x2343f,0x23450,0x23450,0x2346f,0x2346f,0x23472,0x23472,0x234e5,0x234e5,0x23519,0x23519,0x23530,0x23530,0x23551,0x23551,0x2355a,0x2355a,0x23567,0x23567,0x23595,0x23595,0x23599,0x23599,0x2359c,0x2359c,0x235bb,0x235bb,0x235cd,0x235cf,0x235f3,0x235f3,0x23600,0x23600,0x23617,0x23617,0x2361a,0x2361a,0x2363c,0x2363c,0x23640,0x23640,0x23659,0x23659,0x2365f,0x2365f,0x23677,0x23677,0x2368e,0x2368e,0x2369e,0x2369e,0x236a6,0x236a6,0x236ad,0x236ad,0x236ba,0x236ba,0x236df,0x236df,0x236ee,0x236ee,0x23703,0x23703,0x23716,0x23716,0x23720,0x23720,0x2372d,0x2372d,0x2372f,0x2372f,0x2373f,0x2373f,0x23766,0x23766,0x23781,0x23781,0x237a2,0x237a2,0x237bc,0x237bc,0x237c2,0x237c2,0x237d5,0x237d7,0x2383a,0x2383a,0x239c2,0x239c2,0x23aa7,0x23aa7,0x23adb,0x23adb,0x23aee,0x23aee,0x23afa,0x23afa,0x23b1a,0x23b1a,0x23b5a,0x23b5a,0x23c63,0x23c63,0x23c99,0x23c9b,0x23cb5,0x23cb5,0x23cb7,0x23cb7,0x23cc7,0x23cc9,0x23cfc,0x23cff,0x23d40,0x23d40,0x23d5b,0x23d5b,0x23d7e,0x23d7e,0x23d8f,0x23d8f,0x23db6,0x23dbd,0x23de3,0x23de3,0x23df8,0x23df8,0x23e06,0x23e06,0x23e11,0x23e11,0x23e2c,0x23e31,0x23e39,0x23e39,0x23e88,0x23e8b,0x23eb9,0x23eb9,0x23ebf,0x23ebf,0x23ed7,0x23ed7,0x23ef7,0x23efc,0x23f35,0x23f35,0x23f41,0x23f41,0x23f4a,0x23f4a,0x23f61,0x23f61,0x23f7f,0x23f82,0x23f8f,0x23f8f,0x23fb4,0x23fb4,0x23fb7,0x23fb7,0x23fc0,0x23fc0,0x23fc5,0x23fc5,0x23feb,0x23ff0,0x24011,0x24011,0x24039,0x2403d,0x24057,0x24057,0x24085,0x24085,0x2408b,0x2408d,0x24091,0x24091,0x240c9,0x240c9,0x240e1,0x240e1,0x240ec,0x240ec,0x24104,0x24104,0x2410f,0x2410f,0x24119,0x24119,0x2413f,0x24140,0x24144,0x24144,0x2414e,0x2414e,0x24155,0x24157,0x2415c,0x2415c,0x2415f,0x2415f,0x24161,0x24161,0x24177,0x24177,0x2417a,0x2417a,0x241a3,0x241a5,0x241ac,0x241ac,0x241b5,0x241b5,0x241cd,0x241cd,0x241e2,0x241e2,0x241fc,0x241fc,0x2421b,0x2421b,0x2424b,0x2424b,0x24256,0x24256,0x24259,0x24259,0x24276,0x24278,0x24284,0x24284,0x24293,0x24293,0x24295,0x24295,0x242a5,0x242a5,0x242bf,0x242bf,0x242c1,0x242c1,0x242c9,0x242ca,0x242ee,0x242ee,0x242fa,0x242fa,0x2430d,0x2430d,0x2431a,0x2431a,0x24334,0x24334,0x24348,0x24348,0x24362,0x24365,0x2438c,0x2438c,0x24396,0x24396,0x2439c,0x2439c,0x243bd,0x243bd,0x243c1,0x243c1,0x243e9,0x243ea,0x243f2,0x243f2,0x243f8,0x243f8,0x24404,0x24404,0x24435,0x24436,0x2445a,0x2445b,0x24473,0x24473,0x24487,0x24488,0x244b9,0x244b9,0x244bc,0x244bc,0x244ce,0x244ce,0x244d3,0x244d3,0x244d6,0x244d6,0x24505,0x24505,0x24521,0x24521,0x24578,0x24578,0x245c8,0x245c8,0x24618,0x24618,0x2462a,0x2462a,0x24665,0x24665,0x24674,0x24674,0x24697,0x24697,0x246d4,0x246d4,0x24706,0x24706,0x24725,0x24725,0x2472f,0x2472f,0x2478f,0x2478f,0x247e0,0x247e0,0x24812,0x24812,0x24823,0x24823,0x24882,0x24882,0x248e9,0x248e9,0x248f0,0x248f3,0x248fb,0x248fb,0x248ff,0x24901,0x2490c,0x2490c,0x24916,0x24917,0x24919,0x24919,0x2492f,0x2492f,0x24933,0x24934,0x2493e,0x24943,0x24962,0x24963,0x24974,0x24976,0x2497b,0x2497b,0x2497f,0x2497f,0x24982,0x24982,0x24988,0x2498f,0x24994,0x24994,0x249a4,0x249a4,0x249a7,0x249a7,0x249a9,0x249a9,0x249ab,0x249ad,0x249b7,0x249bb,0x249c5,0x249c5,0x249d0,0x249d0,0x249da,0x249da,0x249de,0x249df,0x249e3,0x249e3,0x249e5,0x249e5,0x249ec,0x249ed,0x249f6,0x249f9,0x249fb,0x249fb,0x24a0e,0x24a0e,0x24a12,0x24a13,0x24a15,0x24a15,0x24a21,0x24a2a,0x24a3e,0x24a3e,0x24a42,0x24a42,0x24a45,0x24a45,0x24a4a,0x24a4a,0x24a4e,0x24a51,0x24a5d,0x24a5d,0x24a65,0x24a67,0x24a71,0x24a71,0x24a77,0x24a7a,0x24a8c,0x24a8c,0x24a93,0x24a96,0x24aa4,0x24aa7,0x24ab1,0x24ab3,0x24aba,0x24abc,0x24ac0,0x24ac0,0x24ac7,0x24ac7,0x24aca,0x24aca,0x24ad1,0x24ad1,0x24adf,0x24adf,0x24ae2,0x24ae2,0x24ae9,0x24ae9,0x24b0f,0x24b0f,0x24b6e,0x24b6e,0x24bf5,0x24bf5,0x24c09,0x24c09,0x24c9e,0x24c9f,0x24cc9,0x24cc9,0x24cd9,0x24cd9,0x24d06,0x24d06,0x24d13,0x24d13,0x24db8,0x24db8,0x24dea,0x24deb,0x24e3b,0x24e3b,0x24e50,0x24e50,0x24ea5,0x24ea5,0x24ea7,0x24ea7,0x24f0e,0x24f0e,0x24f5c,0x24f5c,0x24f82,0x24f82,0x24f86,0x24f86,0x24f97,0x24f97,0x24f9a,0x24f9a,0x24fa9,0x24fa9,0x24fb8,0x24fb8,0x24fc2,0x24fc2,0x2502c,0x2502c,0x25052,0x25052,0x2509d,0x2509d,0x2512b,0x2512b,0x25148,0x25148,0x2517d,0x2517e,0x251cd,0x251cd,0x251e3,0x251e3,0x251e6,0x251e7,0x25220,0x25221,0x25250,0x25250,0x25299,0x25299,0x252c7,0x252c7,0x252d8,0x252d8,0x2530e,0x2530e,0x25311,0x25311,0x25313,0x25313,0x25419,0x25419,0x25425,0x25425,0x2542f,0x25430,0x25446,0x25446,0x2546c,0x2546c,0x2546e,0x2546e,0x2549a,0x2549a,0x25531,0x25531,0x25535,0x25535,0x2553f,0x2553f,0x2555b,0x2555e,0x25562,0x25562,0x25565,0x25566,0x25581,0x25581,0x25584,0x25584,0x2558f,0x2558f,0x255b9,0x255b9,0x255d5,0x255d5,0x255db,0x255db,0x255e0,0x255e0,0x25605,0x25605,0x25635,0x25635,0x25651,0x25651,0x25683,0x25683,0x25695,0x25695,0x256e3,0x256e3,0x256f6,0x256f6,0x25706,0x25706,0x2571d,0x2571d,0x25725,0x25725,0x2573d,0x2573d,0x25772,0x25772,0x257c7,0x257c7,0x257df,0x257e1,0x25857,0x25857,0x2585d,0x2585d,0x25872,0x25872,0x258c8,0x258c8,0x258de,0x258de,0x258e1,0x258e1,0x25903,0x25903,0x25946,0x25946,0x25956,0x25956,0x259ac,0x259ac,0x259cc,0x259cc,0x25a54,0x25a54,0x25a95,0x25a95,0x25a9c,0x25a9c,0x25aae,0x25aaf,0x25ad7,0x25ad7,0x25ae9,0x25ae9,0x25b74,0x25b74,0x25b89,0x25b89,0x25bb3,0x25bb4,0x25bc6,0x25bc6,0x25be4,0x25be4,0x25be8,0x25be8,0x25c01,0x25c01,0x25c06,0x25c06,0x25c21,0x25c21,0x25c4a,0x25c4a,0x25c65,0x25c65,0x25c91,0x25c91,0x25ca4,0x25ca4,0x25cc0,0x25cc1,0x25cfe,0x25cfe,0x25d20,0x25d20,0x25d30,0x25d30,0x25d43,0x25d43,0x25d99,0x25d99,0x25db9,0x25db9,0x25e0e,0x25e0e,0x25e49,0x25e49,0x25e81,0x25e83,0x25ea6,0x25ea6,0x25ebc,0x25ebc,0x25ed7,0x25ed8,0x25f1a,0x25f1a,0x25f4b,0x25f4b,0x25fe1,0x25fe2,0x26021,0x26021,0x26029,0x26029,0x26048,0x26048,0x26064,0x26064,0x26083,0x26083,0x26097,0x26097,0x260a4,0x260a5,0x26102,0x26102,0x26121,0x26121,0x26159,0x2615c,0x261ad,0x261ae,0x261b2,0x261b2,0x261dd,0x261dd,0x26258,0x26258,0x26261,0x26261,0x2626a,0x2626b,0x262d0,0x262d0,0x26335,0x26335,0x2634b,0x2634c,0x26351,0x26351,0x263be,0x263be,0x263f5,0x263f5,0x263f8,0x263f8,0x26402,0x26402,0x26410,0x26412,0x2644a,0x2644a,0x26469,0x26469,0x26484,0x26484,0x26488,0x26489,0x2648d,0x2648d,0x26498,0x26498,0x26512,0x26512,0x26572,0x26572,0x265a0,0x265a0,0x265ad,0x265ad,0x265bf,0x265bf,0x26612,0x26612,0x26626,0x26626,0x266af,0x266af,0x266b1,0x266b1,0x266b5,0x266b5,0x266da,0x266da,0x266e8,0x266e8,0x266fc,0x266fc,0x26716,0x26716,0x26741,0x26741,0x26799,0x26799,0x267b3,0x267b4,0x267cc,0x267cc,0x2681c,0x2681c,0x26846,0x26846,0x2685e,0x2685e,0x2686e,0x2686e,0x26888,0x26888,0x2688a,0x2688a,0x26893,0x26893,0x268c7,0x268c7,0x2690e,0x2690e,0x26911,0x26911,0x26926,0x26926,0x26939,0x26939,0x26951,0x26951,0x269a8,0x269a8,0x269b5,0x269b5,0x269f2,0x269f2,0x269fa,0x269fa,0x26a2d,0x26a2e,0x26a34,0x26a34,0x26a42,0x26a42,0x26a51,0x26a52,0x26b05,0x26b05,0x26b0a,0x26b0a,0x26b13,0x26b13,0x26b15,0x26b15,0x26b23,0x26b23,0x26b28,0x26b28,0x26b50,0x26b53,0x26b5b,0x26b5b,0x26b75,0x26b75,0x26b82,0x26b82,0x26b96,0x26b97,0x26b9d,0x26b9d,0x26bb3,0x26bb3,0x26bc0,0x26bc0,0x26bf7,0x26bf7,0x26c21,0x26c21,0x26c40,0x26c41,0x26c46,0x26c46,0x26c7e,0x26c82,0x26ca4,0x26ca4,0x26cb7,0x26cb8,0x26cbd,0x26cbd,0x26cc0,0x26cc0,0x26cc3,0x26cc3,0x26cd1,0x26cd1,0x26d22,0x26d2a,0x26d51,0x26d51,0x26d74,0x26d74,0x26da0,0x26da7,0x26dae,0x26dae,0x26ddc,0x26ddc,0x26dea,0x26deb,0x26df0,0x26df0,0x26e00,0x26e00,0x26e05,0x26e05,0x26e07,0x26e07,0x26e12,0x26e12,0x26e42,0x26e45,0x26e6e,0x26e6e,0x26e72,0x26e72,0x26e77,0x26e77,0x26e84,0x26e84,0x26e88,0x26e88,0x26e8b,0x26e8b,0x26e99,0x26e99,0x26ed0,0x26ed7,0x26f26,0x26f26,0x26f73,0x26f74,0x26f9f,0x26f9f,0x26fa1,0x26fa1,0x26fbe,0x26fbe,0x26fde,0x26fdf,0x2700e,0x2700e,0x2704b,0x2704b,0x27052,0x27053,0x27088,0x27088,0x270ad,0x270af,0x270cd,0x270cd,0x270d2,0x270d2,0x270f0,0x270f0,0x270f8,0x270f8,0x27109,0x27109,0x2710c,0x2710d,0x27126,0x27127,0x27164,0x27165,0x27175,0x27175,0x271cd,0x271cd,0x2721b,0x2721b,0x27267,0x27267,0x27280,0x27280,0x27285,0x27285,0x2728b,0x2728b,0x272b2,0x272b2,0x272b6,0x272b6,0x272e6,0x272e6,0x27352,0x27352,0x2739a,0x2739a,0x273ff,0x273ff,0x27422,0x27422,0x27450,0x27450,0x27484,0x27484,0x27486,0x27486,0x27574,0x27574,0x275a3,0x275a3,0x275e0,0x275e0,0x275e4,0x275e4,0x275fd,0x275fe,0x27607,0x27607,0x2760c,0x2760c,0x27632,0x27632,0x27639,0x27639,0x27655,0x27657,0x27694,0x27694,0x2770f,0x2770f,0x27735,0x27736,0x27741,0x27741,0x2775e,0x2775e,0x27784,0x27785,0x277cc,0x277cc,0x27858,0x27858,0x27870,0x27870,0x2789d,0x2789d,0x278b2,0x278b2,0x278c8,0x278c8,0x27924,0x27924,0x27967,0x27967,0x2797a,0x2797a,0x279a0,0x279a0,0x279dd,0x279dd,0x279fd,0x279fd,0x27a0a,0x27a0a,0x27a0e,0x27a0e,0x27a3e,0x27a3e,0x27a53,0x27a53,0x27a59,0x27a59,0x27a79,0x27a79,0x27a84,0x27a84,0x27abd,0x27abe,0x27af4,0x27af4,0x27b06,0x27b06,0x27b0b,0x27b0b,0x27b18,0x27b18,0x27b38,0x27b3a,0x27b48,0x27b48,0x27b65,0x27b65,0x27bef,0x27bef,0x27bf4,0x27bf4,0x27c12,0x27c12,0x27c6c,0x27c6c,0x27cb1,0x27cb1,0x27cc5,0x27cc5,0x27d2f,0x27d2f,0x27d53,0x27d54,0x27d66,0x27d66,0x27d73,0x27d73,0x27d84,0x27d84,0x27d8f,0x27d8f,0x27d98,0x27d98,0x27dbd,0x27dbd,0x27ddc,0x27ddc,0x27e4d,0x27e4d,0x27e4f,0x27e4f,0x27f2e,0x27f2e,0x27fb7,0x27fb7,0x27ff9,0x27ff9,0x28002,0x28002,0x28009,0x28009,0x2801e,0x2801e,0x28023,0x28024,0x28048,0x28048,0x28083,0x28083,0x28090,0x28090,0x280bd,0x280be,0x280e8,0x280e9,0x280f4,0x280f4,0x2812e,0x2812e,0x2814f,0x2814f,0x2815d,0x2815d,0x2816f,0x2816f,0x28189,0x28189,0x281af,0x281af,0x281bc,0x281bc,0x28207,0x28207,0x28218,0x28218,0x2821a,0x2821a,0x28256,0x28256,0x2827c,0x2827c,0x2829b,0x2829b,0x282cd,0x282cd,0x282e2,0x282e2,0x28306,0x28306,0x28318,0x28318,0x2832f,0x2832f,0x2833a,0x2833a,0x28365,0x28365,0x2836d,0x2836d,0x2837d,0x2837d,0x2838a,0x2838a,0x28412,0x28412,0x28468,0x28468,0x2846c,0x2846c,0x28473,0x28473,0x28482,0x28482,0x28501,0x28501,0x2853c,0x2853d,0x2856c,0x2856c,0x285e8,0x285e8,0x285f4,0x285f4,0x28600,0x28600,0x2860b,0x2860b,0x28625,0x28625,0x2863b,0x2863b,0x286aa,0x286ab,0x286b2,0x286b2,0x286bc,0x286bc,0x286d8,0x286d8,0x286e6,0x286e6,0x2870f,0x2870f,0x28713,0x28713,0x28804,0x28804,0x2882b,0x2882b,0x2890d,0x2890d,0x28933,0x28933,0x28948,0x28949,0x28956,0x28956,0x28964,0x28964,0x28968,0x28968,0x2896c,0x2896d,0x2897e,0x2897e,0x28989,0x28989,0x289a8,0x289a8,0x289aa,0x289ab,0x289b8,0x289b8,0x289bc,0x289bc,0x289c0,0x289c0,0x289dc,0x289dc,0x289de,0x289de,0x289e1,0x289e1,0x289e3,0x289e4,0x289e7,0x289e8,0x289f9,0x289fc,0x28a0f,0x28a0f,0x28a16,0x28a16,0x28a25,0x28a25,0x28a29,0x28a29,0x28a32,0x28a32,0x28a36,0x28a36,0x28a44,0x28a4b,0x28a59,0x28a5a,0x28a81,0x28a83,0x28a9a,0x28a9c,0x28ac0,0x28ac0,0x28ac6,0x28ac6,0x28acb,0x28acc,0x28ace,0x28ace,0x28ade,0x28ae3,0x28ae5,0x28ae5,0x28aea,0x28aea,0x28afc,0x28afc,0x28b0c,0x28b0c,0x28b13,0x28b13,0x28b21,0x28b22,0x28b2b,0x28b2d,0x28b2f,0x28b2f,0x28b46,0x28b46,0x28b4c,0x28b4c,0x28b4e,0x28b4e,0x28b50,0x28b50,0x28b63,0x28b66,0x28b6c,0x28b6c,0x28b8f,0x28b8f,0x28b99,0x28b99,0x28b9c,0x28b9d,0x28bb9,0x28bb9,0x28bc2,0x28bc2,0x28bc5,0x28bc5,0x28bd4,0x28bd4,0x28bd7,0x28bd7,0x28bd9,0x28bda,0x28be7,0x28bec,0x28bf5,0x28bf5,0x28bff,0x28bff,0x28c03,0x28c03,0x28c09,0x28c09,0x28c1c,0x28c1d,0x28c23,0x28c23,0x28c26,0x28c26,0x28c2b,0x28c2b,0x28c30,0x28c30,0x28c39,0x28c39,0x28c3b,0x28c3b,0x28cca,0x28cca,0x28ccd,0x28ccd,0x28cd2,0x28cd2,0x28d34,0x28d34,0x28d99,0x28d99,0x28db9,0x28db9,0x28e0f,0x28e0f,0x28e36,0x28e36,0x28e39,0x28e39,0x28e65,0x28e66,0x28e97,0x28e97,0x28eac,0x28eac,0x28eb2,0x28eb3,0x28ed9,0x28ed9,0x28ee7,0x28ee7,0x28fc5,0x28fc5,0x29079,0x29079,0x29088,0x29088,0x2908b,0x2908b,0x29093,0x29093,0x290af,0x290b1,0x290c0,0x290c0,0x290e4,0x290e5,0x290ec,0x290ed,0x2910d,0x2910d,0x29110,0x29110,0x2913c,0x2913c,0x2914d,0x2914d,0x2915b,0x2915b,0x2915e,0x2915e,0x29170,0x29170,0x2919c,0x2919c,0x291a8,0x291a8,0x291d5,0x291d5,0x291eb,0x291eb,0x2941d,0x2941d,0x29420,0x29420,0x29433,0x29433,0x2943f,0x2943f,0x29448,0x29448,0x294d0,0x294d0,0x294d9,0x294da,0x294e5,0x294e5,0x294e7,0x294e7,0x2959e,0x2959e,0x295b0,0x295b0,0x295b8,0x295b8,0x295d7,0x295d7,0x295e9,0x295e9,0x295f4,0x295f4,0x2967f,0x2967f,0x29720,0x29720,0x29732,0x29732,0x297d4,0x297d4,0x29810,0x29810,0x29857,0x29857,0x298a4,0x298a4,0x298d1,0x298d1,0x298ea,0x298ea,0x298f1,0x298f1,0x298fa,0x298fa,0x29903,0x29903,0x29905,0x29905,0x2992f,0x2992f,0x29945,0x29945,0x29947,0x29949,0x2995d,0x2995d,0x2996a,0x2996a,0x2999d,0x2999d,0x299c3,0x299c3,0x299c9,0x299c9,0x29a28,0x29a28,0x29a4d,0x29a4d,0x29b05,0x29b05,0x29b0e,0x29b0e,0x29bd5,0x29bd5,0x29c73,0x29c73,0x29cad,0x29cad,0x29d3e,0x29d3e,0x29d5a,0x29d5a,0x29d7c,0x29d7c,0x29d98,0x29d98,0x29d9b,0x29d9b,0x29df6,0x29df6,0x29e06,0x29e06,0x29e2d,0x29e2d,0x29e68,0x29e68,0x29eac,0x29eac,0x29eb0,0x29eb0,0x29ec3,0x29ec3,0x29ef8,0x29ef8,0x29f23,0x29f23,0x29f30,0x29f30,0x29fb7,0x29fb7,0x29fde,0x29fde,0x2a014,0x2a014,0x2a087,0x2a087,0x2a0b9,0x2a0b9,0x2a0e1,0x2a0e1,0x2a0ed,0x2a0ed,0x2a0f3,0x2a0f3,0x2a0f8,0x2a0f8,0x2a0fe,0x2a0fe,0x2a107,0x2a107,0x2a123,0x2a123,0x2a133,0x2a134,0x2a150,0x2a150,0x2a192,0x2a193,0x2a1ab,0x2a1ab,0x2a1b4,0x2a1b5,0x2a1df,0x2a1df,0x2a1f5,0x2a1f5,0x2a220,0x2a220,0x2a233,0x2a233,0x2a293,0x2a293,0x2a29f,0x2a29f,0x2a2b2,0x2a2b2,0x2a2b4,0x2a2b4,0x2a2b6,0x2a2b6,0x2a2ba,0x2a2ba,0x2a2bd,0x2a2bd,0x2a2df,0x2a2df,0x2a2ff,0x2a2ff,0x2a351,0x2a351,0x2a3a9,0x2a3a9,0x2a3ed,0x2a3ed,0x2a434,0x2a434,0x2a45b,0x2a45b,0x2a5c6,0x2a5c6,0x2a5cb,0x2a5cb,0x2a601,0x2a601,0x2a632,0x2a632,0x2a64a,0x2a64a,0x2a65b,0x2a65b,0x2a6a9,0x2a6a9,0x2adff,0x2adff,0x2d544,0x2d544,0x2f825,0x2f825,0x2f83b,0x2f83b,0x2f840,0x2f840,0x2f878,0x2f878,0x2f894,0x2f894,0x2f8a6,0x2f8a6,0x2f8cd,0x2f8cd,0x2f8db,0x2f8db,0x2f994,0x2f994,0x2f9b2,0x2f9b2,0x2f9bc,0x2f9bc,0x2f9d4,0x2f9d4,0x30ede,0x30ede,0x3106c,0x3106c,]), + NotoFont.fromFlatRanges('Noto Sans Hanunoo', 'http://fonts.gstatic.com/s/notosanshanunoo/v15/f0Xs0fCv8dxkDWlZSoXOj6CphMloFsEsEpgL_ix2.ttf', [0x20,0x20,0xa0,0xa0,0x1720,0x1736,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Hatran', 'http://fonts.gstatic.com/s/notosanshatran/v15/A2BBn4Ne0RgnVF3Lnko-0sOBIfL_mM83r1nwzDs.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200c,0x108e0,0x108f2,0x108f4,0x108f5,0x108fb,0x108ff,]), + NotoFont.fromFlatRanges('Noto Sans Hebrew', 'http://fonts.gstatic.com/s/notosanshebrew/v38/or3HQ7v33eiDljA1IufXTtVf7V6RvEEdhQlk0LlGxCyaeNKYZC0sqk3xXGiXd4qtoiJltutR2g.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x34f,0x34f,0x591,0x5c7,0x5d0,0x5ea,0x5f0,0x5f4,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200c,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20aa,0x20aa,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xfb1d,0xfb36,0xfb38,0xfb3c,0xfb3e,0xfb3e,0xfb40,0xfb41,0xfb43,0xfb44,0xfb46,0xfb4f,]), + NotoFont.fromFlatRanges('Noto Sans Imperial Aramaic', 'http://fonts.gstatic.com/s/notosansimperialaramaic/v15/a8IMNpjwKmHXpgXbMIsbTc_kvks91LlLetBr5itQrtdml3YfPNno.ttf', [0x20,0x20,0xa0,0xa0,0x10840,0x10855,0x10857,0x1085f,]), + NotoFont.fromFlatRanges('Noto Sans Indic Siyaq Numbers', 'http://fonts.gstatic.com/s/notosansindicsiyaqnumbers/v15/6xK5dTJFKcWIu4bpRBjRZRpsIYHabOeZ8UZLubTzpXNHKx2WPOpVd5Iu.ttf', [0x20,0x20,0xa0,0xa0,0x627,0x627,0x660,0x669,0x6f0,0x6f9,0x1ec71,0x1ecb4,]), + NotoFont.fromFlatRanges('Noto Sans Inscriptional Pahlavi', 'http://fonts.gstatic.com/s/notosansinscriptionalpahlavi/v15/ll8UK3GaVDuxR-TEqFPIbsR79Xxz9WEKbwsjpz7VklYlC7FCVtqVOAYK0QA.ttf', [0x20,0x20,0xa0,0xa0,0x10b60,0x10b72,0x10b78,0x10b7f,]), + NotoFont.fromFlatRanges('Noto Sans Inscriptional Parthian', 'http://fonts.gstatic.com/s/notosansinscriptionalparthian/v15/k3k7o-IMPvpLmixcA63oYi-yStDkgXuXncL7dzfW3P4TAJ2yklBJ2jNkLlLr.ttf', [0x20,0x20,0xa0,0xa0,0x10b40,0x10b55,0x10b58,0x10b5f,]), + NotoFont.fromFlatRanges('Noto Sans JP', 'http://fonts.gstatic.com/s/notosansjp/v42/-F62fjtqLzI2JPCgQBnw7HFowAIO2lZ9hg.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x3402,0x3402,0x3405,0x3406,0x3427,0x3427,0x342c,0x342c,0x342e,0x342e,0x3468,0x3468,0x346a,0x346a,0x3488,0x3488,0x3492,0x3492,0x34b5,0x34b5,0x34bc,0x34bc,0x34c1,0x34c1,0x34c7,0x34c7,0x34db,0x34db,0x351f,0x351f,0x353e,0x353e,0x355d,0x355e,0x3563,0x3563,0x356e,0x356e,0x35a6,0x35a6,0x35a8,0x35a8,0x35c5,0x35c5,0x35da,0x35da,0x35de,0x35de,0x35f4,0x35f4,0x3605,0x3605,0x3614,0x3614,0x364a,0x364a,0x3691,0x3691,0x3696,0x3696,0x3699,0x3699,0x36cf,0x36cf,0x3761,0x3762,0x376b,0x376c,0x3775,0x3775,0x378d,0x378d,0x37c1,0x37c1,0x37e2,0x37e2,0x37e8,0x37e8,0x37f4,0x37f4,0x37fd,0x37fd,0x3800,0x3800,0x382f,0x382f,0x3836,0x3836,0x3840,0x3840,0x385c,0x385c,0x3861,0x3861,0x38a1,0x38a1,0x38ad,0x38ad,0x38fa,0x38fa,0x3917,0x3917,0x391a,0x391a,0x396f,0x396f,0x39a4,0x39a4,0x39b8,0x39b8,0x3a5c,0x3a5c,0x3a6e,0x3a6e,0x3a73,0x3a73,0x3a85,0x3a85,0x3ac4,0x3ac4,0x3acb,0x3acb,0x3ad6,0x3ad7,0x3aea,0x3aea,0x3af3,0x3af3,0x3b0e,0x3b0e,0x3b1a,0x3b1a,0x3b1c,0x3b1c,0x3b22,0x3b22,0x3b35,0x3b35,0x3b6d,0x3b6d,0x3b77,0x3b77,0x3b87,0x3b88,0x3b8d,0x3b8d,0x3ba4,0x3ba4,0x3bb6,0x3bb6,0x3bc3,0x3bc3,0x3bcd,0x3bcd,0x3bf0,0x3bf0,0x3bf3,0x3bf3,0x3c0f,0x3c0f,0x3c26,0x3c26,0x3cc3,0x3cc3,0x3cd2,0x3cd2,0x3d11,0x3d11,0x3d1e,0x3d1e,0x3d31,0x3d31,0x3d4e,0x3d4e,0x3d64,0x3d64,0x3d9a,0x3d9a,0x3dc0,0x3dc0,0x3dcc,0x3dcc,0x3dd4,0x3dd4,0x3e05,0x3e05,0x3e3f,0x3e40,0x3e60,0x3e60,0x3e66,0x3e66,0x3e68,0x3e68,0x3e83,0x3e83,0x3e8a,0x3e8a,0x3e94,0x3e94,0x3eda,0x3eda,0x3f57,0x3f57,0x3f72,0x3f72,0x3f75,0x3f75,0x3f77,0x3f77,0x3fae,0x3fae,0x3fb1,0x3fb1,0x3fc9,0x3fc9,0x3fd7,0x3fd7,0x3fdc,0x3fdc,0x4039,0x4039,0x4058,0x4058,0x4093,0x4093,0x4103,0x4103,0x4105,0x4105,0x4148,0x4148,0x414f,0x414f,0x4163,0x4163,0x41b4,0x41b4,0x41bf,0x41bf,0x41e6,0x41e6,0x41ee,0x41ee,0x41f3,0x41f3,0x4207,0x4207,0x420e,0x420e,0x4264,0x4264,0x4293,0x4293,0x42c6,0x42c6,0x42d6,0x42d6,0x42dd,0x42dd,0x4302,0x4302,0x432b,0x432b,0x4343,0x4343,0x43ee,0x43ee,0x43f0,0x43f0,0x4408,0x4408,0x440c,0x440c,0x4417,0x4417,0x441c,0x441c,0x4422,0x4422,0x4453,0x4453,0x445b,0x445b,0x4476,0x4476,0x447a,0x447a,0x4491,0x4491,0x44b3,0x44b3,0x44be,0x44be,0x44d4,0x44d4,0x4508,0x4508,0x450d,0x450d,0x4525,0x4525,0x4543,0x4543,0x457a,0x457a,0x459d,0x459d,0x45b8,0x45b8,0x45be,0x45be,0x45e5,0x45e5,0x45ea,0x45ea,0x460f,0x4610,0x4641,0x4641,0x4665,0x4665,0x46a1,0x46a1,0x46ae,0x46af,0x470c,0x470c,0x471f,0x471f,0x4764,0x4764,0x47e6,0x47e6,0x47fd,0x47fd,0x4816,0x4816,0x481e,0x481e,0x4844,0x4844,0x484e,0x484e,0x48b5,0x48b5,0x49b0,0x49b0,0x49e7,0x49e7,0x49fa,0x49fa,0x4a04,0x4a04,0x4a29,0x4a29,0x4abc,0x4abc,0x4b38,0x4b38,0x4b3b,0x4b3b,0x4b7e,0x4b7e,0x4bc2,0x4bc2,0x4bca,0x4bca,0x4bd2,0x4bd2,0x4be8,0x4be8,0x4c17,0x4c17,0x4c20,0x4c20,0x4c38,0x4c38,0x4cc4,0x4cc4,0x4cd1,0x4cd1,0x4ce1,0x4ce1,0x4d07,0x4d07,0x4d77,0x4d77,0x4e00,0x4e05,0x4e07,0x4e12,0x4e14,0x4e19,0x4e1e,0x4e1f,0x4e21,0x4e21,0x4e23,0x4e24,0x4e26,0x4e26,0x4e28,0x4e32,0x4e35,0x4e39,0x4e3b,0x4e3c,0x4e3f,0x4e45,0x4e47,0x4e48,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e51,0x4e51,0x4e55,0x4e5f,0x4e62,0x4e63,0x4e68,0x4e69,0x4e71,0x4e71,0x4e73,0x4e75,0x4e79,0x4e79,0x4e7e,0x4e80,0x4e82,0x4e82,0x4e85,0x4e86,0x4e88,0x4e8e,0x4e91,0x4e92,0x4e94,0x4e99,0x4e9b,0x4ea2,0x4ea4,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eb0,0x4eb3,0x4eb3,0x4eb6,0x4eb6,0x4eb9,0x4ebc,0x4ec0,0x4ec4,0x4ec6,0x4ec8,0x4eca,0x4ecb,0x4ecd,0x4ed0,0x4ed4,0x4edb,0x4edd,0x4ee5,0x4ee8,0x4ee8,0x4eeb,0x4eeb,0x4eed,0x4ef3,0x4ef5,0x4ef7,0x4efb,0x4f03,0x4f08,0x4f12,0x4f15,0x4f17,0x4f19,0x4f1a,0x4f1c,0x4f1d,0x4f2b,0x4f2b,0x4f2e,0x4f31,0x4f33,0x4f3e,0x4f40,0x4f40,0x4f42,0x4f43,0x4f46,0x4f49,0x4f4b,0x4f60,0x4f63,0x4f64,0x4f69,0x4f6a,0x4f6c,0x4f6c,0x4f6e,0x4f71,0x4f73,0x4f73,0x4f75,0x4f7f,0x4f81,0x4f86,0x4f88,0x4f94,0x4f96,0x4f9b,0x4f9d,0x4fa1,0x4fab,0x4fab,0x4fad,0x4faf,0x4fb2,0x4fb2,0x4fb5,0x4fb7,0x4fb9,0x4fb9,0x4fbb,0x4fc6,0x4fc8,0x4fd4,0x4fd7,0x4fd8,0x4fda,0x4fdd,0x4fdf,0x4fe6,0x4fee,0x4ff3,0x4ff5,0x4ff6,0x4ff8,0x4ff8,0x4ffa,0x4ffa,0x4ffc,0x5002,0x5004,0x5007,0x5009,0x5014,0x5016,0x501f,0x5021,0x502e,0x5030,0x5030,0x5032,0x5033,0x5035,0x5036,0x5039,0x5039,0x503b,0x503b,0x5040,0x5043,0x5045,0x504a,0x504c,0x504c,0x504e,0x5053,0x5055,0x5057,0x5059,0x505a,0x505c,0x505c,0x505f,0x5060,0x5062,0x5063,0x5065,0x5067,0x506a,0x506a,0x506c,0x506d,0x5070,0x5072,0x5074,0x5078,0x507d,0x507d,0x5080,0x5081,0x5083,0x5086,0x5088,0x5088,0x508a,0x508a,0x508d,0x5096,0x5098,0x509c,0x509e,0x50a3,0x50aa,0x50aa,0x50ac,0x50ad,0x50af,0x50b5,0x50b7,0x50b7,0x50b9,0x50bb,0x50bd,0x50be,0x50c0,0x50c0,0x50c2,0x50c5,0x50c7,0x50c7,0x50c9,0x50ca,0x50cc,0x50d1,0x50d3,0x50d6,0x50d8,0x50da,0x50dc,0x50df,0x50e1,0x50e9,0x50ed,0x50f6,0x50f9,0x50fb,0x50fe,0x50fe,0x5100,0x5104,0x5106,0x5109,0x510b,0x510e,0x5110,0x5110,0x5112,0x5112,0x5114,0x511f,0x5121,0x5121,0x5123,0x5123,0x5127,0x5128,0x512a,0x512a,0x512c,0x512d,0x512f,0x512f,0x5131,0x5135,0x5137,0x513c,0x513f,0x5150,0x5152,0x5155,0x5157,0x5158,0x515a,0x515a,0x515c,0x515c,0x515f,0x5160,0x5162,0x5162,0x5164,0x516e,0x5171,0x5171,0x5173,0x5179,0x517b,0x517c,0x517e,0x517e,0x5180,0x5180,0x5182,0x5186,0x5189,0x5193,0x5195,0x5199,0x519d,0x519d,0x51a0,0x51a6,0x51a8,0x51ad,0x51b0,0x51b8,0x51ba,0x51ba,0x51bc,0x51bf,0x51c2,0x51c6,0x51c8,0x51cd,0x51cf,0x51cf,0x51d1,0x51d6,0x51d8,0x51d8,0x51db,0x51e2,0x51e5,0x51e7,0x51e9,0x51ea,0x51ec,0x51ee,0x51f0,0x51fa,0x51fd,0x51fe,0x5200,0x5208,0x520a,0x520b,0x520e,0x520e,0x5211,0x5218,0x521d,0x521d,0x5222,0x5222,0x5224,0x522b,0x522e,0x522e,0x5230,0x5233,0x5235,0x523c,0x5243,0x5245,0x5247,0x5247,0x5249,0x524d,0x524f,0x524f,0x5254,0x5258,0x525a,0x5261,0x5263,0x5266,0x5269,0x526a,0x526c,0x526c,0x526e,0x5275,0x5277,0x5279,0x527d,0x527d,0x527f,0x5280,0x5282,0x5285,0x5287,0x528a,0x528c,0x528d,0x5291,0x5298,0x529a,0x529c,0x529f,0x52a0,0x52a3,0x52a7,0x52a9,0x52ad,0x52af,0x52b1,0x52b4,0x52be,0x52c0,0x52c1,0x52c3,0x52ca,0x52cc,0x52cd,0x52cf,0x52d2,0x52d4,0x52d9,0x52db,0x52ea,0x52ec,0x52ec,0x52f0,0x52fb,0x52fe,0x5303,0x5305,0x5308,0x530a,0x530d,0x530f,0x5311,0x5313,0x5313,0x5315,0x5321,0x5323,0x5325,0x5327,0x532d,0x532f,0x5333,0x5335,0x5335,0x5338,0x5343,0x5345,0x534d,0x5351,0x5354,0x5357,0x535c,0x535e,0x535e,0x5360,0x5361,0x5363,0x5367,0x5369,0x5369,0x536c,0x5375,0x5377,0x537b,0x537d,0x537f,0x5382,0x5384,0x5387,0x5389,0x538e,0x538e,0x5393,0x5394,0x5396,0x5396,0x5398,0x539a,0x539d,0x539d,0x539f,0x53a1,0x53a4,0x53a6,0x53a8,0x53ab,0x53ad,0x53b0,0x53b2,0x53b8,0x53ba,0x53bb,0x53bd,0x53bd,0x53c0,0x53c5,0x53c8,0x53cf,0x53d2,0x53d7,0x53d9,0x53db,0x53dd,0x53f8,0x53fa,0x53fa,0x5401,0x5404,0x5408,0x5413,0x541a,0x541b,0x541d,0x5421,0x5424,0x5424,0x5426,0x542f,0x5431,0x5431,0x5433,0x5436,0x5438,0x5439,0x543b,0x5440,0x5442,0x5444,0x5446,0x544a,0x544c,0x544f,0x5451,0x5451,0x5455,0x5455,0x545e,0x545f,0x5462,0x5462,0x5464,0x5464,0x5466,0x546e,0x5470,0x5471,0x5473,0x5477,0x547b,0x547d,0x547f,0x5481,0x5483,0x5486,0x5488,0x5492,0x5495,0x5496,0x549c,0x549c,0x549f,0x54a2,0x54a4,0x54af,0x54b1,0x54b3,0x54b7,0x54c4,0x54c6,0x54ca,0x54cd,0x54ce,0x54d8,0x54d8,0x54e0,0x54e2,0x54e5,0x54e6,0x54e8,0x54ea,0x54ec,0x54ef,0x54f1,0x54f3,0x54f6,0x54f6,0x54fa,0x54fa,0x54fc,0x5501,0x5504,0x5509,0x550c,0x5510,0x5514,0x5516,0x5527,0x5527,0x552a,0x552b,0x552e,0x552f,0x5531,0x5533,0x5535,0x5536,0x5538,0x5539,0x553b,0x553e,0x5540,0x5541,0x5544,0x5547,0x5549,0x554a,0x554c,0x554d,0x554f,0x5551,0x5553,0x5553,0x5556,0x5558,0x555a,0x555e,0x5560,0x5561,0x5563,0x5564,0x5566,0x5566,0x557b,0x5584,0x5586,0x558b,0x558e,0x558f,0x5591,0x5594,0x5597,0x559a,0x559c,0x559f,0x55a3,0x55a4,0x55a7,0x55ae,0x55b0,0x55b0,0x55b2,0x55b2,0x55b6,0x55b6,0x55bf,0x55bf,0x55c1,0x55c1,0x55c3,0x55c7,0x55c9,0x55c9,0x55cb,0x55cc,0x55ce,0x55ce,0x55d1,0x55d4,0x55d7,0x55d8,0x55da,0x55df,0x55e2,0x55e4,0x55e9,0x55e9,0x55ec,0x55ec,0x55ee,0x55ee,0x55f1,0x55f1,0x55f6,0x55f9,0x55fd,0x55ff,0x5605,0x560a,0x560d,0x5612,0x5614,0x5614,0x5616,0x5619,0x561b,0x561b,0x5620,0x5620,0x5628,0x5629,0x562c,0x562c,0x562f,0x5639,0x563b,0x563d,0x563f,0x5644,0x5646,0x5647,0x5649,0x5649,0x564b,0x5650,0x5653,0x5654,0x565b,0x565b,0x565e,0x565e,0x5660,0x5664,0x5666,0x5666,0x5668,0x566d,0x566f,0x566f,0x5671,0x5672,0x5674,0x5676,0x5678,0x5678,0x567a,0x567a,0x5680,0x5680,0x5684,0x5688,0x568a,0x568c,0x568f,0x568f,0x5694,0x5695,0x5699,0x569a,0x569d,0x56a0,0x56a2,0x56a2,0x56a5,0x56a9,0x56ab,0x56ae,0x56b1,0x56b4,0x56b6,0x56b7,0x56bc,0x56bc,0x56be,0x56be,0x56c0,0x56c3,0x56c5,0x56c5,0x56c8,0x56d1,0x56d3,0x56d3,0x56d7,0x56e1,0x56e3,0x56e8,0x56eb,0x56eb,0x56ed,0x56ee,0x56f0,0x56f3,0x56f6,0x56f7,0x56f9,0x56fa,0x56fd,0x56fd,0x56ff,0x5704,0x5707,0x570d,0x570f,0x570f,0x5711,0x5713,0x5715,0x5716,0x5718,0x5718,0x571a,0x571d,0x571f,0x572a,0x572c,0x5730,0x5733,0x5734,0x5737,0x5738,0x573b,0x573b,0x573d,0x5740,0x5742,0x5742,0x5745,0x5747,0x574a,0x574a,0x574c,0x5752,0x5759,0x5759,0x575f,0x575f,0x5761,0x5762,0x5764,0x576b,0x576d,0x5771,0x5773,0x5775,0x5777,0x5777,0x5779,0x577c,0x577e,0x577f,0x5781,0x5783,0x5788,0x5789,0x578b,0x578c,0x5793,0x5795,0x5797,0x5797,0x5799,0x579a,0x579c,0x57a4,0x57a7,0x57aa,0x57ac,0x57ac,0x57ae,0x57ae,0x57b0,0x57b0,0x57b3,0x57b3,0x57b8,0x57b8,0x57bd,0x57bd,0x57c0,0x57c0,0x57c3,0x57c3,0x57c6,0x57c8,0x57cb,0x57cc,0x57ce,0x57cf,0x57d2,0x57d7,0x57dc,0x57e1,0x57e3,0x57e4,0x57e6,0x57e7,0x57e9,0x57e9,0x57ed,0x57ed,0x57f0,0x57f0,0x57f4,0x5800,0x5802,0x5806,0x5808,0x580d,0x5815,0x5815,0x5819,0x5819,0x581b,0x581b,0x581d,0x5821,0x5824,0x5824,0x5826,0x5827,0x582a,0x582a,0x582d,0x582d,0x582f,0x5832,0x5834,0x5835,0x5839,0x583a,0x583d,0x583d,0x583f,0x5841,0x5849,0x584d,0x584f,0x5852,0x5854,0x5855,0x5857,0x585a,0x585e,0x585f,0x5861,0x5862,0x5864,0x5864,0x5867,0x5869,0x586b,0x586b,0x586d,0x586d,0x5870,0x5870,0x5872,0x5872,0x5875,0x5875,0x5878,0x5879,0x587c,0x587c,0x587e,0x5881,0x5883,0x5883,0x5885,0x5885,0x5887,0x588d,0x588f,0x5890,0x5893,0x5894,0x5896,0x5898,0x589c,0x58a2,0x58a6,0x58a6,0x58a8,0x58ab,0x58ae,0x58ae,0x58b1,0x58b3,0x58b8,0x58bc,0x58be,0x58be,0x58c1,0x58c5,0x58c7,0x58c8,0x58ca,0x58ca,0x58cc,0x58ce,0x58d0,0x58da,0x58dc,0x58e2,0x58e4,0x58e5,0x58e9,0x58e9,0x58eb,0x58ec,0x58ee,0x58f4,0x58f7,0x58f7,0x58f9,0x58fd,0x5902,0x5902,0x5905,0x5906,0x5909,0x590d,0x590f,0x5910,0x5912,0x5916,0x5918,0x591d,0x591f,0x591f,0x5921,0x5925,0x5927,0x5933,0x5935,0x5939,0x593d,0x593f,0x5943,0x5944,0x5946,0x5949,0x594e,0x5955,0x5957,0x595b,0x595d,0x5963,0x5965,0x5965,0x5967,0x596f,0x5972,0x5976,0x5978,0x5979,0x597b,0x597d,0x5981,0x5984,0x598a,0x598e,0x5992,0x5993,0x5995,0x5997,0x5999,0x5999,0x599b,0x599b,0x599d,0x599d,0x599f,0x599f,0x59a3,0x59a5,0x59a7,0x59a8,0x59ac,0x59b0,0x59b2,0x59b3,0x59b7,0x59b7,0x59b9,0x59bc,0x59be,0x59be,0x59c1,0x59c1,0x59c3,0x59c4,0x59c6,0x59c6,0x59c8,0x59cb,0x59cd,0x59cd,0x59d0,0x59d4,0x59d9,0x59da,0x59dc,0x59df,0x59e3,0x59e8,0x59ea,0x59ec,0x59ee,0x59ef,0x59f1,0x59f2,0x59f4,0x59f4,0x59f6,0x59f8,0x59fb,0x59fb,0x59ff,0x5a01,0x5a03,0x5a04,0x5a09,0x5a09,0x5a0c,0x5a0e,0x5a11,0x5a13,0x5a17,0x5a18,0x5a1a,0x5a1c,0x5a1e,0x5a20,0x5a23,0x5a25,0x5a27,0x5a2a,0x5a2d,0x5a2d,0x5a2f,0x5a30,0x5a35,0x5a36,0x5a3c,0x5a3c,0x5a40,0x5a41,0x5a44,0x5a49,0x5a4c,0x5a4c,0x5a50,0x5a50,0x5a55,0x5a55,0x5a5a,0x5a5a,0x5a5e,0x5a5e,0x5a62,0x5a63,0x5a65,0x5a67,0x5a6a,0x5a6a,0x5a6c,0x5a6d,0x5a77,0x5a77,0x5a7a,0x5a7b,0x5a7e,0x5a7f,0x5a84,0x5a84,0x5a8b,0x5a8b,0x5a90,0x5a90,0x5a92,0x5a93,0x5a96,0x5a96,0x5a99,0x5a9c,0x5a9e,0x5aa0,0x5aa2,0x5aa2,0x5aa7,0x5aa7,0x5aac,0x5aac,0x5ab1,0x5ab3,0x5ab5,0x5ab5,0x5ab8,0x5ab8,0x5aba,0x5abf,0x5ac1,0x5ac2,0x5ac4,0x5ac4,0x5ac6,0x5ac6,0x5ac8,0x5ac9,0x5acb,0x5acc,0x5acf,0x5ad0,0x5ad6,0x5ad7,0x5ada,0x5ada,0x5adc,0x5adc,0x5ae0,0x5ae1,0x5ae3,0x5ae3,0x5ae5,0x5ae6,0x5ae9,0x5aea,0x5aee,0x5aee,0x5af0,0x5af0,0x5af5,0x5af6,0x5afa,0x5afb,0x5afd,0x5afd,0x5b00,0x5b01,0x5b08,0x5b09,0x5b0b,0x5b0c,0x5b16,0x5b17,0x5b19,0x5b19,0x5b1b,0x5b1b,0x5b1d,0x5b1d,0x5b21,0x5b22,0x5b25,0x5b25,0x5b2a,0x5b2a,0x5b2c,0x5b2d,0x5b30,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b36,0x5b36,0x5b38,0x5b38,0x5b3e,0x5b3e,0x5b40,0x5b41,0x5b43,0x5b43,0x5b45,0x5b45,0x5b4b,0x5b4c,0x5b50,0x5b52,0x5b54,0x5b58,0x5b5a,0x5b5f,0x5b63,0x5b66,0x5b68,0x5b69,0x5b6b,0x5b6b,0x5b6e,0x5b71,0x5b73,0x5b73,0x5b75,0x5b76,0x5b78,0x5b78,0x5b7a,0x5b7a,0x5b7c,0x5b91,0x5b93,0x5b9d,0x5b9f,0x5b9f,0x5ba2,0x5ba6,0x5ba8,0x5ba9,0x5bac,0x5bba,0x5bbc,0x5bbc,0x5bbf,0x5bc7,0x5bc9,0x5bc9,0x5bcc,0x5bd0,0x5bd2,0x5bd4,0x5bd6,0x5bdb,0x5bdd,0x5be2,0x5be4,0x5be9,0x5beb,0x5bec,0x5bee,0x5bf1,0x5bf3,0x5bf6,0x5bf8,0x5bf8,0x5bfa,0x5bfa,0x5bfd,0x5bff,0x5c01,0x5c0f,0x5c11,0x5c14,0x5c16,0x5c17,0x5c19,0x5c1a,0x5c1e,0x5c20,0x5c22,0x5c24,0x5c26,0x5c26,0x5c28,0x5c2e,0x5c30,0x5c32,0x5c35,0x5c36,0x5c38,0x5c41,0x5c45,0x5c46,0x5c48,0x5c48,0x5c4a,0x5c4b,0x5c4d,0x5c51,0x5c53,0x5c53,0x5c55,0x5c55,0x5c59,0x5c5c,0x5c5e,0x5c65,0x5c67,0x5c69,0x5c6c,0x5c71,0x5c74,0x5c76,0x5c79,0x5c7d,0x5c87,0x5c88,0x5c8a,0x5c8a,0x5c8c,0x5c8c,0x5c8f,0x5c92,0x5c94,0x5c94,0x5c9d,0x5c9d,0x5c9f,0x5ca3,0x5ca6,0x5cad,0x5cb1,0x5cb8,0x5cba,0x5cbc,0x5cbe,0x5cbe,0x5cc5,0x5cc5,0x5cc7,0x5cc7,0x5cc9,0x5cc9,0x5ccb,0x5ccb,0x5cd0,0x5cd0,0x5cd2,0x5cd2,0x5cd7,0x5cd7,0x5cd9,0x5cd9,0x5cdd,0x5cdd,0x5ce0,0x5ce1,0x5ce6,0x5ce6,0x5ce8,0x5cea,0x5ced,0x5cf2,0x5cf4,0x5cf6,0x5cfa,0x5cfb,0x5cfd,0x5cfd,0x5d01,0x5d01,0x5d06,0x5d07,0x5d0b,0x5d0b,0x5d0d,0x5d0e,0x5d10,0x5d12,0x5d14,0x5d1b,0x5d1d,0x5d1d,0x5d1f,0x5d20,0x5d22,0x5d24,0x5d26,0x5d27,0x5d29,0x5d29,0x5d2b,0x5d2b,0x5d31,0x5d31,0x5d34,0x5d34,0x5d39,0x5d39,0x5d3d,0x5d3d,0x5d3f,0x5d3f,0x5d42,0x5d43,0x5d46,0x5d48,0x5d4a,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d53,0x5d55,0x5d55,0x5d59,0x5d59,0x5d5c,0x5d5c,0x5d5f,0x5d62,0x5d64,0x5d64,0x5d69,0x5d6a,0x5d6c,0x5d6d,0x5d6f,0x5d70,0x5d73,0x5d73,0x5d76,0x5d76,0x5d79,0x5d7a,0x5d7e,0x5d7f,0x5d81,0x5d84,0x5d87,0x5d88,0x5d8a,0x5d8c,0x5d90,0x5d90,0x5d92,0x5d95,0x5d97,0x5d97,0x5d99,0x5d99,0x5d9b,0x5d9b,0x5d9d,0x5d9d,0x5d9f,0x5da0,0x5da2,0x5da2,0x5da4,0x5da4,0x5da7,0x5da7,0x5dab,0x5dac,0x5dae,0x5dae,0x5db0,0x5db0,0x5db2,0x5db2,0x5db4,0x5db4,0x5db7,0x5dba,0x5dbc,0x5dbd,0x5dc3,0x5dc3,0x5dc7,0x5dc7,0x5dc9,0x5dc9,0x5dcb,0x5dce,0x5dd0,0x5dd3,0x5dd6,0x5dd9,0x5ddb,0x5ddb,0x5ddd,0x5dde,0x5de0,0x5de9,0x5deb,0x5deb,0x5dee,0x5dee,0x5df1,0x5df5,0x5df7,0x5df9,0x5dfb,0x5dfb,0x5dfd,0x5e00,0x5e02,0x5e03,0x5e06,0x5e07,0x5e0b,0x5e0d,0x5e11,0x5e12,0x5e14,0x5e16,0x5e18,0x5e1b,0x5e1d,0x5e1d,0x5e1f,0x5e20,0x5e25,0x5e25,0x5e28,0x5e28,0x5e2b,0x5e2b,0x5e2d,0x5e30,0x5e32,0x5e33,0x5e35,0x5e38,0x5e3d,0x5e3e,0x5e40,0x5e40,0x5e43,0x5e45,0x5e47,0x5e47,0x5e49,0x5e49,0x5e4b,0x5e4c,0x5e4e,0x5e4e,0x5e50,0x5e51,0x5e54,0x5e58,0x5e5b,0x5e5c,0x5e5e,0x5e5f,0x5e61,0x5e64,0x5e68,0x5e68,0x5e6a,0x5e6e,0x5e70,0x5e70,0x5e72,0x5e81,0x5e83,0x5e84,0x5e87,0x5e87,0x5e8a,0x5e8b,0x5e8e,0x5e8f,0x5e95,0x5e97,0x5e99,0x5e9a,0x5e9c,0x5e9c,0x5ea0,0x5ea0,0x5ea2,0x5ea2,0x5ea4,0x5ea8,0x5eaa,0x5ead,0x5eb1,0x5eb1,0x5eb3,0x5eb3,0x5eb5,0x5eb9,0x5ebd,0x5ebf,0x5ec1,0x5ec3,0x5ec6,0x5ec6,0x5ec8,0x5ecc,0x5ece,0x5ed6,0x5ed9,0x5ee3,0x5ee5,0x5ee5,0x5ee8,0x5ee9,0x5eeb,0x5eec,0x5ef0,0x5ef1,0x5ef3,0x5ef4,0x5ef6,0x5f04,0x5f06,0x5f11,0x5f13,0x5f19,0x5f1b,0x5f1f,0x5f21,0x5f29,0x5f2b,0x5f31,0x5f34,0x5f38,0x5f3a,0x5f41,0x5f44,0x5f45,0x5f47,0x5f48,0x5f4a,0x5f4a,0x5f4c,0x5f4e,0x5f50,0x5f51,0x5f53,0x5f54,0x5f56,0x5f59,0x5f5b,0x5f5d,0x5f60,0x5f67,0x5f69,0x5f6d,0x5f6f,0x5f75,0x5f77,0x5f7a,0x5f7c,0x5f85,0x5f87,0x5f8d,0x5f8f,0x5f93,0x5f96,0x5f99,0x5f9c,0x5f9e,0x5fa0,0x5fa2,0x5fa4,0x5fa4,0x5fa7,0x5fb1,0x5fb3,0x5fb5,0x5fb7,0x5fb9,0x5fbc,0x5fbd,0x5fc3,0x5fc5,0x5fc7,0x5fc9,0x5fcb,0x5fcd,0x5fd0,0x5fd4,0x5fd6,0x5fd9,0x5fdc,0x5fde,0x5fe0,0x5fe2,0x5fe4,0x5fe4,0x5fe8,0x5ff3,0x5ff5,0x5ff6,0x5ff8,0x5ff8,0x5ffa,0x5ffd,0x5fff,0x5fff,0x6007,0x6007,0x600a,0x600a,0x600d,0x6010,0x6012,0x601d,0x601f,0x6022,0x6024,0x602b,0x602d,0x602d,0x602f,0x602f,0x6031,0x6031,0x6033,0x6033,0x6035,0x6035,0x603a,0x603a,0x6040,0x6043,0x6046,0x604d,0x6050,0x6052,0x6054,0x6057,0x6059,0x605a,0x605d,0x605d,0x605f,0x6065,0x6067,0x606d,0x606f,0x6071,0x6075,0x6075,0x6077,0x6077,0x607e,0x607f,0x6081,0x6086,0x6088,0x608e,0x6091,0x6098,0x609a,0x609b,0x609d,0x60a0,0x60a2,0x60aa,0x60b0,0x60b8,0x60bb,0x60be,0x60c2,0x60c2,0x60c4,0x60cb,0x60ce,0x60cf,0x60d1,0x60d1,0x60d3,0x60d5,0x60d8,0x60e3,0x60e5,0x60e5,0x60e7,0x60e8,0x60ee,0x60ee,0x60f0,0x60fd,0x6100,0x6103,0x6106,0x610a,0x610c,0x6117,0x6119,0x611c,0x611e,0x6122,0x6127,0x6128,0x612a,0x612c,0x6130,0x6131,0x6134,0x6137,0x6139,0x613a,0x613c,0x613f,0x6141,0x6142,0x6144,0x614e,0x6153,0x6153,0x6155,0x6155,0x6158,0x615a,0x615d,0x6160,0x6162,0x6165,0x6167,0x6168,0x616b,0x616c,0x616e,0x6178,0x617b,0x6184,0x6187,0x6187,0x618a,0x618b,0x618d,0x618e,0x6190,0x6194,0x6196,0x619a,0x619c,0x619d,0x619f,0x61a0,0x61a4,0x61a5,0x61a7,0x61ae,0x61b2,0x61b2,0x61b6,0x61b6,0x61b8,0x61ba,0x61bc,0x61bc,0x61be,0x61be,0x61c0,0x61c3,0x61c6,0x61d0,0x61d5,0x61d5,0x61dc,0x61df,0x61e1,0x61e3,0x61e5,0x61e9,0x61ec,0x61ed,0x61ef,0x61ef,0x61f2,0x61f2,0x61f4,0x61f8,0x61fa,0x61fa,0x61fc,0x6201,0x6203,0x6204,0x6207,0x620a,0x620c,0x620e,0x6210,0x6216,0x621a,0x6223,0x6226,0x6227,0x6229,0x622b,0x622e,0x6234,0x6236,0x6236,0x6238,0x6239,0x623b,0x623b,0x623d,0x6244,0x6246,0x6249,0x624b,0x624e,0x6250,0x6256,0x6258,0x6258,0x625a,0x625c,0x625e,0x625e,0x6260,0x6261,0x6263,0x6264,0x6268,0x6268,0x626d,0x626f,0x6271,0x6271,0x6273,0x6273,0x6276,0x6276,0x6279,0x6280,0x6282,0x6285,0x6289,0x628a,0x628d,0x6299,0x629b,0x629c,0x629e,0x629e,0x62a6,0x62a6,0x62a8,0x62a8,0x62ab,0x62ac,0x62b1,0x62b1,0x62b3,0x62b3,0x62b5,0x62b7,0x62b9,0x62bf,0x62c2,0x62c2,0x62c4,0x62ca,0x62cc,0x62dd,0x62e0,0x62e1,0x62ea,0x62ea,0x62ec,0x62ef,0x62f1,0x62f7,0x62fc,0x62ff,0x6301,0x6304,0x6307,0x630d,0x6310,0x6311,0x6313,0x6313,0x6316,0x6316,0x6318,0x6319,0x631b,0x631b,0x631f,0x631f,0x6327,0x632b,0x632d,0x632d,0x632f,0x632f,0x6332,0x6332,0x6335,0x6336,0x6339,0x633f,0x6341,0x6344,0x6346,0x6346,0x6349,0x6350,0x6352,0x6355,0x6357,0x6359,0x635b,0x635c,0x6365,0x6369,0x636b,0x636e,0x6371,0x6372,0x6374,0x6378,0x637a,0x637d,0x637f,0x6380,0x6382,0x6384,0x6387,0x638a,0x638c,0x638c,0x638e,0x6390,0x6392,0x6392,0x6394,0x6396,0x6398,0x639b,0x639e,0x63af,0x63b2,0x63b2,0x63b4,0x63b5,0x63bb,0x63bb,0x63bd,0x63be,0x63c0,0x63c1,0x63c3,0x63c6,0x63c8,0x63c9,0x63ce,0x63d6,0x63da,0x63dc,0x63e0,0x63e1,0x63e3,0x63e3,0x63e5,0x63e5,0x63e9,0x63ee,0x63f2,0x63fa,0x6406,0x6406,0x6409,0x640a,0x640d,0x640d,0x640f,0x6410,0x6412,0x6414,0x6416,0x6418,0x641c,0x641c,0x641e,0x641e,0x6420,0x6420,0x6422,0x6422,0x6424,0x6426,0x6428,0x642a,0x642c,0x642d,0x642f,0x6430,0x6434,0x6436,0x643a,0x643a,0x643d,0x643f,0x6442,0x6442,0x644b,0x644b,0x644e,0x644f,0x6451,0x6454,0x6458,0x6458,0x645a,0x645d,0x645f,0x6461,0x6463,0x6463,0x6467,0x6467,0x6469,0x6469,0x646d,0x646d,0x646f,0x646f,0x6473,0x6474,0x6476,0x6476,0x6478,0x647b,0x647d,0x647d,0x6483,0x6483,0x6485,0x6485,0x6487,0x6488,0x648f,0x6493,0x6495,0x6495,0x6498,0x649b,0x649d,0x649f,0x64a1,0x64a1,0x64a3,0x64a6,0x64a8,0x64a9,0x64ab,0x64ae,0x64b0,0x64b0,0x64b2,0x64b3,0x64b9,0x64b9,0x64bb,0x64bf,0x64c1,0x64c2,0x64c4,0x64c5,0x64c7,0x64c7,0x64c9,0x64ce,0x64d0,0x64d2,0x64d4,0x64d5,0x64d7,0x64d8,0x64da,0x64da,0x64e0,0x64e7,0x64e9,0x64ea,0x64ec,0x64ed,0x64ef,0x64f2,0x64f4,0x64f7,0x64fa,0x64fb,0x64fd,0x6501,0x6504,0x6505,0x6508,0x650a,0x650f,0x650f,0x6513,0x6514,0x6516,0x6516,0x6518,0x6519,0x651b,0x651f,0x6522,0x6524,0x6526,0x6526,0x6529,0x652c,0x652e,0x652f,0x6531,0x6532,0x6534,0x653f,0x6543,0x6545,0x6547,0x6549,0x654d,0x6552,0x6554,0x6559,0x655d,0x6560,0x6562,0x6563,0x6566,0x6567,0x656b,0x656c,0x6570,0x6570,0x6572,0x6572,0x6574,0x6575,0x6577,0x6578,0x657a,0x657a,0x657d,0x657d,0x6581,0x6585,0x6587,0x658a,0x658c,0x658c,0x658e,0x658e,0x6590,0x6592,0x6595,0x6595,0x6597,0x6599,0x659b,0x659d,0x659f,0x65a1,0x65a3,0x65a7,0x65ab,0x65b0,0x65b2,0x65b5,0x65b7,0x65b9,0x65bc,0x65bf,0x65c1,0x65c6,0x65c8,0x65c9,0x65cb,0x65cc,0x65ce,0x65d0,0x65d2,0x65d2,0x65d4,0x65d4,0x65d6,0x65d9,0x65db,0x65db,0x65df,0x65e3,0x65e5,0x65e9,0x65ec,0x65ed,0x65f0,0x65f2,0x65f4,0x65f5,0x65f9,0x65fc,0x65fe,0x6600,0x6602,0x6604,0x6606,0x660a,0x660c,0x660f,0x6611,0x6616,0x661c,0x6631,0x6633,0x6637,0x6639,0x663c,0x663f,0x6646,0x6648,0x664c,0x664e,0x664f,0x6651,0x6652,0x6657,0x6670,0x6673,0x667c,0x667e,0x6681,0x6683,0x6684,0x6687,0x6689,0x668b,0x668e,0x6690,0x6692,0x6696,0x669d,0x669f,0x66a0,0x66a2,0x66a2,0x66a4,0x66a4,0x66a6,0x66a6,0x66ab,0x66ab,0x66ad,0x66ae,0x66b1,0x66b5,0x66b8,0x66b9,0x66bb,0x66bc,0x66be,0x66c4,0x66c6,0x66c9,0x66cc,0x66cc,0x66ce,0x66cf,0x66d4,0x66d4,0x66d6,0x66d6,0x66d9,0x66dd,0x66df,0x66e0,0x66e6,0x66e6,0x66e8,0x66e9,0x66eb,0x66ec,0x66ee,0x66ee,0x66f0,0x66f0,0x66f2,0x66f5,0x66f7,0x6701,0x6703,0x6703,0x6705,0x6705,0x6707,0x6709,0x670b,0x6710,0x6712,0x6717,0x6719,0x6719,0x671b,0x6720,0x6722,0x6722,0x6725,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6738,0x673a,0x673a,0x673d,0x673f,0x6741,0x6741,0x6743,0x6743,0x6745,0x6749,0x674c,0x6751,0x6753,0x6756,0x6759,0x6759,0x675c,0x6766,0x676a,0x676a,0x676c,0x6777,0x677b,0x677c,0x677e,0x6781,0x6784,0x6785,0x6787,0x6787,0x6789,0x6789,0x678b,0x678c,0x678e,0x6793,0x6795,0x679d,0x67a0,0x67a2,0x67a4,0x67a4,0x67a6,0x67a6,0x67a9,0x67a9,0x67af,0x67b9,0x67bb,0x67be,0x67c0,0x67c6,0x67c8,0x67ca,0x67ce,0x67d4,0x67d7,0x67de,0x67e1,0x67e2,0x67e4,0x67e4,0x67e6,0x67e7,0x67e9,0x67e9,0x67ec,0x67ec,0x67ee,0x67f7,0x67f9,0x67fc,0x67fe,0x67ff,0x6801,0x6805,0x6810,0x6810,0x6813,0x6814,0x6816,0x6819,0x681d,0x681f,0x6821,0x6822,0x6827,0x682d,0x682f,0x6834,0x6838,0x6839,0x683b,0x6846,0x6848,0x684a,0x684c,0x684e,0x6850,0x6855,0x6857,0x6859,0x685b,0x685d,0x685f,0x685f,0x6863,0x6863,0x6867,0x6867,0x686b,0x686b,0x686e,0x6872,0x6874,0x6877,0x6879,0x687c,0x687e,0x687f,0x6881,0x6886,0x6888,0x6888,0x688d,0x6890,0x6893,0x6894,0x6896,0x689d,0x689f,0x68a3,0x68a5,0x68ab,0x68ad,0x68b6,0x68b9,0x68bc,0x68c3,0x68c6,0x68c8,0x68cd,0x68cf,0x68da,0x68dc,0x68dd,0x68df,0x68e1,0x68e3,0x68e5,0x68e7,0x68e8,0x68ea,0x68f2,0x68f5,0x68f7,0x68f9,0x68fd,0x6900,0x6901,0x6903,0x6913,0x6916,0x6917,0x6919,0x691c,0x6921,0x6923,0x6925,0x6926,0x6928,0x6928,0x692a,0x692a,0x6930,0x6931,0x6933,0x6936,0x6938,0x6939,0x693b,0x693b,0x693d,0x693d,0x693f,0x693f,0x6942,0x6942,0x6945,0x6946,0x6949,0x694a,0x694e,0x694e,0x6953,0x6955,0x6957,0x6957,0x6959,0x695e,0x6960,0x6966,0x6968,0x6975,0x6977,0x6982,0x6986,0x6986,0x698a,0x698a,0x698d,0x698e,0x6991,0x6992,0x6994,0x6996,0x6998,0x6998,0x699b,0x699c,0x69a0,0x69a1,0x69a5,0x69a8,0x69ab,0x69ab,0x69ad,0x69b2,0x69b4,0x69b4,0x69b7,0x69b8,0x69ba,0x69bc,0x69be,0x69c1,0x69c3,0x69c3,0x69c5,0x69c5,0x69c7,0x69c8,0x69ca,0x69d1,0x69d3,0x69d3,0x69d6,0x69d9,0x69dd,0x69de,0x69e2,0x69e3,0x69e5,0x69e5,0x69e7,0x69eb,0x69ed,0x69ef,0x69f1,0x69f6,0x69f9,0x69f9,0x69fb,0x69fb,0x69fd,0x6a03,0x6a05,0x6a05,0x6a0a,0x6a0c,0x6a0f,0x6a0f,0x6a11,0x6a15,0x6a17,0x6a17,0x6a19,0x6a1b,0x6a1d,0x6a24,0x6a28,0x6a2b,0x6a2e,0x6a2e,0x6a30,0x6a30,0x6a32,0x6a3b,0x6a3d,0x6a3f,0x6a44,0x6a4b,0x6a4e,0x6a4e,0x6a50,0x6a52,0x6a54,0x6a56,0x6a58,0x6a59,0x6a5b,0x6a5b,0x6a5f,0x6a5f,0x6a61,0x6a62,0x6a64,0x6a64,0x6a66,0x6a67,0x6a6a,0x6a6b,0x6a71,0x6a73,0x6a78,0x6a78,0x6a7a,0x6a7a,0x6a7e,0x6a81,0x6a83,0x6a84,0x6a86,0x6a87,0x6a89,0x6a89,0x6a8b,0x6a8b,0x6a8d,0x6a8e,0x6a90,0x6a91,0x6a94,0x6a94,0x6a97,0x6a97,0x6a9b,0x6aa3,0x6aa5,0x6aa5,0x6aaa,0x6aac,0x6aae,0x6ab1,0x6ab3,0x6ab4,0x6ab8,0x6ab8,0x6abb,0x6abb,0x6abd,0x6abf,0x6ac1,0x6ac3,0x6ac6,0x6ac6,0x6ac8,0x6ac9,0x6acc,0x6acc,0x6ad0,0x6ad1,0x6ad3,0x6ad6,0x6ada,0x6adf,0x6ae2,0x6ae2,0x6ae4,0x6ae4,0x6ae7,0x6ae8,0x6aea,0x6aea,0x6aec,0x6aec,0x6af0,0x6af3,0x6af8,0x6af8,0x6afa,0x6afd,0x6b02,0x6b07,0x6b09,0x6b0b,0x6b0f,0x6b12,0x6b16,0x6b17,0x6b1b,0x6b1b,0x6b1d,0x6b21,0x6b23,0x6b24,0x6b27,0x6b28,0x6b2b,0x6b2c,0x6b2f,0x6b2f,0x6b32,0x6b32,0x6b35,0x6b3b,0x6b3d,0x6b3f,0x6b43,0x6b43,0x6b46,0x6b47,0x6b49,0x6b4a,0x6b4c,0x6b4e,0x6b50,0x6b50,0x6b52,0x6b54,0x6b56,0x6b56,0x6b58,0x6b59,0x6b5b,0x6b5b,0x6b5d,0x6b5d,0x6b5f,0x6b67,0x6b69,0x6b6c,0x6b6e,0x6b70,0x6b72,0x6b75,0x6b77,0x6b7b,0x6b7d,0x6b86,0x6b89,0x6b8b,0x6b8d,0x6b8d,0x6b95,0x6b98,0x6b9b,0x6b9b,0x6b9e,0x6ba0,0x6ba2,0x6ba4,0x6ba8,0x6bb5,0x6bb7,0x6bc0,0x6bc3,0x6bc9,0x6bcb,0x6bcf,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdb,0x6bdf,0x6bdf,0x6be1,0x6be1,0x6be3,0x6be3,0x6be6,0x6be7,0x6beb,0x6bec,0x6bee,0x6bef,0x6bf1,0x6bf1,0x6bf3,0x6bf3,0x6bf7,0x6bf7,0x6bf9,0x6bf9,0x6bff,0x6bff,0x6c02,0x6c02,0x6c04,0x6c05,0x6c08,0x6c0a,0x6c0d,0x6c14,0x6c17,0x6c17,0x6c19,0x6c19,0x6c1b,0x6c1b,0x6c1f,0x6c1f,0x6c23,0x6c24,0x6c26,0x6c28,0x6c2c,0x6c2c,0x6c2e,0x6c2e,0x6c33,0x6c38,0x6c3a,0x6c3b,0x6c3e,0x6c42,0x6c4a,0x6c4b,0x6c4d,0x6c50,0x6c52,0x6c52,0x6c54,0x6c55,0x6c57,0x6c57,0x6c59,0x6c60,0x6c62,0x6c62,0x6c67,0x6c68,0x6c6a,0x6c6b,0x6c6d,0x6c6d,0x6c6f,0x6c70,0x6c72,0x6c74,0x6c76,0x6c76,0x6c78,0x6c7b,0x6c7d,0x6c7e,0x6c81,0x6c89,0x6c8c,0x6c8d,0x6c90,0x6c90,0x6c92,0x6c9c,0x6c9f,0x6c9f,0x6ca1,0x6ca2,0x6caa,0x6cae,0x6cb0,0x6cb4,0x6cb8,0x6cbf,0x6cc1,0x6cc2,0x6cc4,0x6cc6,0x6cc9,0x6cca,0x6ccc,0x6ccd,0x6ccf,0x6cd7,0x6cd9,0x6cdd,0x6ce0,0x6ce3,0x6ce5,0x6ce5,0x6ce7,0x6cf4,0x6cfb,0x6cfb,0x6d00,0x6d01,0x6d04,0x6d04,0x6d07,0x6d07,0x6d0a,0x6d0c,0x6d0e,0x6d0f,0x6d11,0x6d13,0x6d17,0x6d17,0x6d19,0x6d1b,0x6d1e,0x6d1f,0x6d24,0x6d2b,0x6d2e,0x6d2f,0x6d31,0x6d36,0x6d38,0x6d39,0x6d3b,0x6d3f,0x6d41,0x6d41,0x6d44,0x6d45,0x6d57,0x6d5c,0x6d5e,0x6d61,0x6d63,0x6d67,0x6d69,0x6d6a,0x6d6c,0x6d6c,0x6d6e,0x6d70,0x6d74,0x6d74,0x6d77,0x6d79,0x6d7c,0x6d7c,0x6d80,0x6d82,0x6d85,0x6d85,0x6d87,0x6d8a,0x6d8c,0x6d8e,0x6d91,0x6d99,0x6d9b,0x6d9c,0x6daa,0x6dac,0x6dae,0x6daf,0x6db2,0x6db2,0x6db4,0x6db5,0x6db7,0x6db9,0x6dbc,0x6dbd,0x6dbf,0x6dc0,0x6dc2,0x6dc2,0x6dc4,0x6dc8,0x6dca,0x6dcc,0x6dce,0x6dd2,0x6dd5,0x6dd6,0x6dd8,0x6ddb,0x6ddd,0x6de2,0x6de4,0x6de6,0x6de8,0x6dec,0x6dee,0x6dfc,0x6e00,0x6e00,0x6e04,0x6e05,0x6e07,0x6e0b,0x6e13,0x6e13,0x6e15,0x6e15,0x6e17,0x6e17,0x6e19,0x6e1b,0x6e1d,0x6e27,0x6e29,0x6e29,0x6e2b,0x6e2f,0x6e32,0x6e32,0x6e34,0x6e34,0x6e36,0x6e36,0x6e38,0x6e3c,0x6e3e,0x6e3e,0x6e42,0x6e45,0x6e48,0x6e4f,0x6e51,0x6e54,0x6e56,0x6e58,0x6e5b,0x6e5f,0x6e62,0x6e63,0x6e67,0x6e68,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e72,0x6e73,0x6e76,0x6e76,0x6e7b,0x6e7b,0x6e7d,0x6e80,0x6e82,0x6e82,0x6e89,0x6e89,0x6e8c,0x6e8d,0x6e8f,0x6e90,0x6e93,0x6e93,0x6e96,0x6e96,0x6e98,0x6e99,0x6e9c,0x6e9d,0x6e9f,0x6ea0,0x6ea2,0x6ea2,0x6ea5,0x6ea5,0x6ea7,0x6ea7,0x6eaa,0x6eab,0x6ead,0x6eaf,0x6eb1,0x6eb4,0x6eb6,0x6eb7,0x6eba,0x6ebd,0x6ebf,0x6ec5,0x6ec7,0x6ecf,0x6ed1,0x6ed1,0x6ed3,0x6ed5,0x6ed9,0x6edb,0x6edd,0x6ede,0x6ee6,0x6ee6,0x6eeb,0x6eef,0x6ef2,0x6ef2,0x6ef4,0x6ef4,0x6ef7,0x6ef9,0x6efb,0x6efb,0x6efd,0x6eff,0x6f01,0x6f02,0x6f04,0x6f04,0x6f06,0x6f06,0x6f08,0x6f0a,0x6f0c,0x6f0d,0x6f0f,0x6f11,0x6f13,0x6f16,0x6f18,0x6f18,0x6f1a,0x6f1b,0x6f20,0x6f20,0x6f22,0x6f23,0x6f25,0x6f26,0x6f29,0x6f2d,0x6f2f,0x6f33,0x6f35,0x6f36,0x6f38,0x6f38,0x6f3b,0x6f3c,0x6f3e,0x6f3f,0x6f41,0x6f41,0x6f45,0x6f45,0x6f4f,0x6f4f,0x6f51,0x6f54,0x6f57,0x6f62,0x6f64,0x6f64,0x6f66,0x6f66,0x6f68,0x6f68,0x6f6c,0x6f70,0x6f74,0x6f74,0x6f78,0x6f78,0x6f7a,0x6f7a,0x6f7c,0x6f7e,0x6f80,0x6f84,0x6f86,0x6f88,0x6f8b,0x6f8e,0x6f90,0x6f94,0x6f96,0x6f98,0x6f9a,0x6f9a,0x6f9d,0x6f9d,0x6f9f,0x6fa1,0x6fa3,0x6fa8,0x6faa,0x6faa,0x6fae,0x6fb1,0x6fb3,0x6fb3,0x6fb5,0x6fb7,0x6fb9,0x6fb9,0x6fbc,0x6fbc,0x6fbe,0x6fbe,0x6fc0,0x6fc3,0x6fc5,0x6fca,0x6fd4,0x6fd5,0x6fd8,0x6fd8,0x6fda,0x6fdb,0x6fde,0x6fe1,0x6fe4,0x6fe4,0x6fe8,0x6fe9,0x6feb,0x6fec,0x6fee,0x6ff1,0x6ff3,0x6ff3,0x6ff5,0x6ff6,0x6ff9,0x6ffa,0x6ffc,0x6ffe,0x7000,0x7001,0x7005,0x7007,0x7009,0x700b,0x700d,0x700d,0x700f,0x700f,0x7011,0x7011,0x7015,0x7015,0x7017,0x7018,0x701a,0x701b,0x701d,0x7020,0x7023,0x7023,0x7026,0x7028,0x702c,0x702c,0x702f,0x7030,0x7032,0x7032,0x7034,0x7034,0x7037,0x7037,0x7039,0x703a,0x703c,0x703c,0x703e,0x703e,0x7043,0x7044,0x7047,0x704c,0x704e,0x704e,0x7051,0x7051,0x7054,0x7055,0x7058,0x7058,0x705d,0x705e,0x7063,0x7065,0x7069,0x7069,0x706b,0x706c,0x706e,0x7070,0x7075,0x7076,0x7078,0x7078,0x707c,0x707e,0x7081,0x7081,0x7085,0x7086,0x7089,0x708a,0x708e,0x708e,0x7092,0x7092,0x7094,0x7099,0x709b,0x709b,0x709f,0x709f,0x70a4,0x70a4,0x70ab,0x70b1,0x70b3,0x70b4,0x70b7,0x70bb,0x70c8,0x70c8,0x70ca,0x70cb,0x70cf,0x70cf,0x70d1,0x70d1,0x70d3,0x70d6,0x70d8,0x70d9,0x70dc,0x70dd,0x70df,0x70df,0x70e4,0x70e4,0x70ec,0x70ec,0x70f1,0x70f1,0x70f9,0x70fa,0x70fd,0x70fd,0x7103,0x7109,0x710b,0x710c,0x710f,0x710f,0x7114,0x7114,0x7119,0x711a,0x711c,0x711c,0x711e,0x711e,0x7120,0x7121,0x7126,0x7126,0x712b,0x712b,0x712d,0x7131,0x7136,0x7136,0x7138,0x7138,0x713c,0x713c,0x7141,0x7141,0x7145,0x7147,0x7149,0x714c,0x714e,0x714e,0x7150,0x7153,0x7155,0x7157,0x7159,0x715a,0x715c,0x715c,0x715e,0x715e,0x7160,0x7160,0x7162,0x7162,0x7164,0x7169,0x716c,0x716c,0x716e,0x716e,0x7179,0x7179,0x717d,0x717d,0x7180,0x7180,0x7184,0x7185,0x7187,0x7188,0x718a,0x718a,0x718c,0x718c,0x718f,0x718f,0x7192,0x7192,0x7194,0x7196,0x7199,0x719b,0x719f,0x71a0,0x71a2,0x71a2,0x71a8,0x71a8,0x71ac,0x71ac,0x71ae,0x71b3,0x71b9,0x71ba,0x71be,0x71c1,0x71c3,0x71c4,0x71c8,0x71c9,0x71cb,0x71cc,0x71ce,0x71ce,0x71d0,0x71d0,0x71d2,0x71d7,0x71d9,0x71da,0x71dc,0x71dc,0x71df,0x71e0,0x71e5,0x71e7,0x71ec,0x71ee,0x71f4,0x71f5,0x71f8,0x71f9,0x71fb,0x71fc,0x71fe,0x7200,0x7206,0x7209,0x720d,0x720d,0x7210,0x7210,0x7213,0x7213,0x7215,0x7215,0x7217,0x7217,0x721a,0x721b,0x721d,0x721d,0x721f,0x721f,0x7224,0x7224,0x7228,0x7228,0x722a,0x722d,0x722f,0x7230,0x7232,0x7232,0x7234,0x7236,0x7238,0x7243,0x7245,0x7248,0x724b,0x724c,0x724e,0x7250,0x7252,0x7253,0x7255,0x7263,0x7267,0x7269,0x726b,0x726b,0x726e,0x726f,0x7271,0x7272,0x7274,0x7274,0x7277,0x7279,0x727b,0x7282,0x7284,0x7284,0x7287,0x7287,0x7289,0x7289,0x728d,0x728e,0x7292,0x7293,0x7296,0x7296,0x729b,0x729b,0x72a0,0x72a0,0x72a2,0x72a2,0x72a7,0x72a8,0x72ac,0x72b2,0x72b4,0x72b4,0x72b6,0x72b6,0x72b9,0x72b9,0x72be,0x72be,0x72c0,0x72c4,0x72c6,0x72c7,0x72c9,0x72c9,0x72cc,0x72cc,0x72ce,0x72ce,0x72d0,0x72d0,0x72d2,0x72d2,0x72d5,0x72d9,0x72db,0x72db,0x72df,0x72e2,0x72e5,0x72e5,0x72e9,0x72e9,0x72ec,0x72ed,0x72f3,0x72f4,0x72f7,0x72fe,0x7302,0x7302,0x7304,0x7305,0x7307,0x7307,0x730a,0x730b,0x730d,0x730d,0x7312,0x7313,0x7316,0x7319,0x731b,0x731f,0x7322,0x7322,0x7324,0x7325,0x7327,0x732c,0x732e,0x732f,0x7331,0x7337,0x7339,0x733b,0x733d,0x733f,0x7343,0x7345,0x734d,0x7350,0x7352,0x7352,0x7356,0x7358,0x735d,0x7360,0x7363,0x7363,0x7366,0x736c,0x736e,0x7372,0x7375,0x7375,0x7377,0x737c,0x7380,0x7381,0x7383,0x7387,0x7389,0x738b,0x738e,0x738e,0x7390,0x7390,0x7393,0x7398,0x739c,0x739c,0x739e,0x73a0,0x73a2,0x73a2,0x73a5,0x73a6,0x73a8,0x73ab,0x73ad,0x73ad,0x73b2,0x73b3,0x73b5,0x73b5,0x73b7,0x73b7,0x73b9,0x73bd,0x73bf,0x73c0,0x73c2,0x73c2,0x73c5,0x73c6,0x73c8,0x73cf,0x73d2,0x73d3,0x73d6,0x73d6,0x73d9,0x73d9,0x73dd,0x73de,0x73e0,0x73e1,0x73e3,0x73e7,0x73e9,0x73ea,0x73ed,0x73ee,0x73f1,0x73f1,0x73f4,0x73f5,0x73f7,0x73fb,0x73fd,0x7401,0x7403,0x7407,0x7409,0x740a,0x7411,0x7411,0x7413,0x7413,0x741a,0x741b,0x7421,0x7422,0x7424,0x7426,0x7428,0x7436,0x7439,0x743a,0x743f,0x7441,0x7443,0x7444,0x7446,0x7447,0x744b,0x744b,0x744d,0x744d,0x7451,0x7453,0x7455,0x7455,0x7457,0x7457,0x7459,0x7460,0x7462,0x7464,0x7466,0x746b,0x746d,0x7473,0x7476,0x7476,0x747e,0x747e,0x7480,0x7481,0x7483,0x7483,0x7485,0x7489,0x748b,0x748b,0x748f,0x7492,0x7497,0x749a,0x749c,0x749c,0x749e,0x74a3,0x74a5,0x74ab,0x74ae,0x74b2,0x74b5,0x74b5,0x74b9,0x74bb,0x74bd,0x74bd,0x74bf,0x74bf,0x74c8,0x74ca,0x74cc,0x74cc,0x74cf,0x74d0,0x74d3,0x74d4,0x74d6,0x74d6,0x74d8,0x74d8,0x74da,0x74dc,0x74de,0x74e0,0x74e2,0x74e4,0x74e6,0x74eb,0x74ee,0x74f2,0x74f4,0x74f4,0x74f6,0x74f8,0x74fa,0x74fc,0x74ff,0x74ff,0x7501,0x7501,0x7503,0x7506,0x750c,0x750e,0x7511,0x7513,0x7515,0x7518,0x751a,0x751a,0x751c,0x751c,0x751e,0x752c,0x752f,0x7533,0x7536,0x7540,0x7543,0x7544,0x7546,0x7552,0x7554,0x7554,0x7557,0x7557,0x7559,0x7562,0x7564,0x7567,0x7569,0x756d,0x756f,0x757f,0x7581,0x7582,0x7585,0x7587,0x7589,0x758c,0x758e,0x7595,0x7599,0x759a,0x759c,0x759d,0x75a2,0x75a5,0x75ab,0x75ab,0x75b0,0x75b5,0x75b7,0x75ba,0x75bc,0x75c7,0x75ca,0x75ca,0x75cc,0x75cf,0x75d2,0x75d5,0x75d7,0x75d9,0x75db,0x75e4,0x75e7,0x75e7,0x75e9,0x75e9,0x75ec,0x75ec,0x75ee,0x75f4,0x75f9,0x75fa,0x75fc,0x75fc,0x75fe,0x7604,0x7607,0x760d,0x760f,0x760f,0x7612,0x7613,0x7615,0x7616,0x7618,0x7619,0x761b,0x7629,0x762d,0x762d,0x7630,0x7630,0x7632,0x7635,0x7638,0x763c,0x7640,0x764c,0x764e,0x764e,0x7652,0x7652,0x7655,0x7656,0x7658,0x7659,0x765c,0x765c,0x765f,0x765f,0x7661,0x7662,0x7664,0x7665,0x7667,0x766a,0x766c,0x7672,0x7674,0x7674,0x7676,0x7676,0x7678,0x7678,0x767a,0x767e,0x7680,0x7688,0x768b,0x768e,0x7690,0x7690,0x7693,0x7693,0x7695,0x7696,0x7699,0x76a8,0x76aa,0x76aa,0x76ad,0x76b0,0x76b4,0x76b4,0x76b6,0x76ba,0x76bd,0x76bd,0x76bf,0x76bf,0x76c1,0x76c3,0x76c5,0x76c6,0x76c8,0x76ce,0x76d2,0x76d2,0x76d4,0x76d4,0x76d6,0x76d7,0x76d9,0x76d9,0x76db,0x76dc,0x76de,0x76e1,0x76e3,0x76e8,0x76ea,0x76ec,0x76ee,0x76ee,0x76f0,0x76f2,0x76f4,0x76f4,0x76f6,0x76f6,0x76f8,0x76f9,0x76fb,0x76fc,0x76fe,0x76fe,0x7700,0x7701,0x7704,0x7704,0x7706,0x770c,0x770e,0x770e,0x7712,0x7712,0x7714,0x7715,0x7717,0x7717,0x7719,0x771c,0x771e,0x7720,0x7722,0x7722,0x7724,0x7726,0x7728,0x7729,0x772d,0x772f,0x7734,0x773a,0x773c,0x773e,0x7740,0x7740,0x7742,0x7742,0x7745,0x7747,0x774a,0x774a,0x774d,0x774f,0x7752,0x7752,0x7756,0x7758,0x775a,0x775c,0x775e,0x7768,0x776a,0x776c,0x7770,0x7770,0x7772,0x7774,0x7779,0x777a,0x777c,0x7780,0x7784,0x7784,0x778b,0x778e,0x7791,0x7791,0x7794,0x7796,0x779a,0x779a,0x779e,0x77a0,0x77a2,0x77a2,0x77a4,0x77a5,0x77a7,0x77a7,0x77a9,0x77aa,0x77ac,0x77b1,0x77b3,0x77b3,0x77b5,0x77b7,0x77b9,0x77b9,0x77bb,0x77bf,0x77c3,0x77c3,0x77c7,0x77c7,0x77c9,0x77c9,0x77cd,0x77cd,0x77d1,0x77d2,0x77d5,0x77d5,0x77d7,0x77d7,0x77d9,0x77dc,0x77de,0x77e0,0x77e2,0x77e7,0x77e9,0x77ea,0x77ec,0x77f1,0x77f3,0x77f4,0x77f8,0x77f8,0x77fb,0x77fc,0x7802,0x7802,0x7805,0x7806,0x7809,0x7809,0x780c,0x780e,0x7811,0x7812,0x7814,0x7815,0x7819,0x7819,0x781d,0x781d,0x7820,0x7823,0x7825,0x7827,0x782c,0x782e,0x7830,0x7830,0x7832,0x7832,0x7834,0x7835,0x7837,0x7837,0x783a,0x783a,0x783f,0x783f,0x7843,0x7845,0x7847,0x7848,0x784c,0x784c,0x784e,0x784f,0x7851,0x7852,0x785c,0x785e,0x7860,0x7861,0x7863,0x7864,0x7868,0x7868,0x786a,0x786c,0x786e,0x786f,0x7872,0x7872,0x7874,0x7874,0x787a,0x787a,0x787c,0x787c,0x787e,0x787e,0x7881,0x7881,0x7886,0x7887,0x788a,0x788a,0x788c,0x788f,0x7891,0x7891,0x7893,0x7895,0x7897,0x7898,0x789a,0x789a,0x789d,0x789f,0x78a1,0x78a1,0x78a3,0x78a4,0x78a7,0x78aa,0x78ac,0x78ad,0x78af,0x78b3,0x78b5,0x78b5,0x78ba,0x78bf,0x78c1,0x78c1,0x78c5,0x78cc,0x78ce,0x78ce,0x78d0,0x78d6,0x78da,0x78db,0x78df,0x78e1,0x78e4,0x78e4,0x78e6,0x78e8,0x78ea,0x78ea,0x78ec,0x78ec,0x78ef,0x78ef,0x78f2,0x78f4,0x78f6,0x78f7,0x78f9,0x78fb,0x78fd,0x7901,0x7906,0x7907,0x790c,0x790c,0x790e,0x790e,0x7910,0x7912,0x7919,0x791c,0x791e,0x7920,0x7925,0x792e,0x7930,0x7931,0x7934,0x7935,0x793a,0x7942,0x7944,0x794b,0x794f,0x7951,0x7953,0x7958,0x795a,0x7960,0x7962,0x7962,0x7965,0x7965,0x7967,0x7969,0x796b,0x796b,0x796d,0x796d,0x7972,0x7972,0x7977,0x7977,0x7979,0x797c,0x797e,0x7981,0x7984,0x7985,0x798a,0x798f,0x7991,0x7991,0x7993,0x7996,0x7998,0x7998,0x799b,0x799d,0x79a1,0x79a1,0x79a6,0x79ab,0x79ae,0x79b1,0x79b3,0x79b4,0x79b8,0x79bb,0x79bd,0x79c2,0x79c4,0x79c4,0x79c7,0x79cd,0x79cf,0x79cf,0x79d1,0x79d2,0x79d4,0x79d6,0x79d8,0x79d8,0x79da,0x79da,0x79dd,0x79e7,0x79e9,0x79ed,0x79f0,0x79f1,0x79f8,0x79f8,0x79fb,0x79fc,0x7a00,0x7a00,0x7a02,0x7a03,0x7a05,0x7a05,0x7a07,0x7a0e,0x7a11,0x7a11,0x7a14,0x7a15,0x7a17,0x7a1c,0x7a1e,0x7a21,0x7a27,0x7a27,0x7a2b,0x7a2b,0x7a2d,0x7a32,0x7a34,0x7a35,0x7a37,0x7a40,0x7a42,0x7a49,0x7a4c,0x7a50,0x7a55,0x7a57,0x7a59,0x7a59,0x7a5c,0x7a5d,0x7a5f,0x7a63,0x7a65,0x7a65,0x7a67,0x7a67,0x7a69,0x7a6b,0x7a6d,0x7a6d,0x7a70,0x7a70,0x7a74,0x7a76,0x7a78,0x7a7a,0x7a7d,0x7a86,0x7a88,0x7a88,0x7a8a,0x7a8b,0x7a90,0x7a98,0x7a9e,0x7aa0,0x7aa3,0x7aa3,0x7aa9,0x7aaa,0x7aac,0x7aac,0x7aae,0x7ab0,0x7ab3,0x7ab3,0x7ab5,0x7ab6,0x7ab9,0x7abf,0x7ac3,0x7acf,0x7ad1,0x7ad3,0x7ad5,0x7ad5,0x7ad9,0x7add,0x7adf,0x7ae3,0x7ae5,0x7aed,0x7aef,0x7af1,0x7af4,0x7af4,0x7af6,0x7af6,0x7af8,0x7afb,0x7afd,0x7aff,0x7b02,0x7b02,0x7b04,0x7b04,0x7b06,0x7b08,0x7b0a,0x7b0b,0x7b0f,0x7b0f,0x7b11,0x7b12,0x7b14,0x7b14,0x7b18,0x7b19,0x7b1b,0x7b1b,0x7b1e,0x7b20,0x7b23,0x7b23,0x7b25,0x7b31,0x7b33,0x7b36,0x7b39,0x7b39,0x7b3b,0x7b3b,0x7b3d,0x7b3d,0x7b3f,0x7b41,0x7b45,0x7b49,0x7b4b,0x7b56,0x7b5d,0x7b5d,0x7b60,0x7b60,0x7b64,0x7b67,0x7b69,0x7b6a,0x7b6c,0x7b75,0x7b77,0x7b77,0x7b79,0x7b7a,0x7b7f,0x7b7f,0x7b84,0x7b84,0x7b86,0x7b87,0x7b89,0x7b89,0x7b8b,0x7b8b,0x7b8d,0x7b92,0x7b94,0x7ba1,0x7ba5,0x7ba5,0x7baa,0x7baa,0x7bac,0x7bad,0x7baf,0x7bb2,0x7bb4,0x7bb6,0x7bb8,0x7bb8,0x7bba,0x7bbd,0x7bc0,0x7bc2,0x7bc4,0x7bcc,0x7bcf,0x7bcf,0x7bd4,0x7bd4,0x7bd6,0x7bd7,0x7bd9,0x7bdb,0x7bdd,0x7bdd,0x7be0,0x7be0,0x7be4,0x7be6,0x7be8,0x7bea,0x7bed,0x7bed,0x7bf0,0x7bf0,0x7bf2,0x7bfa,0x7bfc,0x7bfc,0x7bfe,0x7bfe,0x7c00,0x7c04,0x7c06,0x7c07,0x7c09,0x7c09,0x7c0b,0x7c0f,0x7c11,0x7c14,0x7c17,0x7c17,0x7c19,0x7c19,0x7c1b,0x7c1b,0x7c1e,0x7c21,0x7c23,0x7c23,0x7c25,0x7c28,0x7c2a,0x7c2c,0x7c2f,0x7c2f,0x7c31,0x7c31,0x7c33,0x7c34,0x7c36,0x7c3a,0x7c3d,0x7c40,0x7c42,0x7c43,0x7c45,0x7c46,0x7c4a,0x7c4a,0x7c4c,0x7c4d,0x7c4f,0x7c61,0x7c63,0x7c65,0x7c67,0x7c67,0x7c69,0x7c69,0x7c6c,0x7c70,0x7c72,0x7c73,0x7c75,0x7c75,0x7c79,0x7c79,0x7c7b,0x7c7e,0x7c81,0x7c83,0x7c86,0x7c87,0x7c89,0x7c89,0x7c8b,0x7c8b,0x7c8d,0x7c8d,0x7c8f,0x7c90,0x7c92,0x7c92,0x7c94,0x7c95,0x7c97,0x7c98,0x7c9b,0x7c9b,0x7c9e,0x7ca2,0x7ca4,0x7ca8,0x7cab,0x7cab,0x7cad,0x7cae,0x7cb0,0x7cb3,0x7cb6,0x7cb7,0x7cb9,0x7cc0,0x7cc2,0x7cc2,0x7cc4,0x7cc5,0x7cc7,0x7cca,0x7ccd,0x7ccf,0x7cd2,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce6,0x7ce7,0x7ce9,0x7ce9,0x7ceb,0x7ceb,0x7cef,0x7cef,0x7cf2,0x7cf2,0x7cf4,0x7cf6,0x7cf8,0x7cfb,0x7cfe,0x7cfe,0x7d00,0x7d00,0x7d02,0x7d0b,0x7d0d,0x7d0d,0x7d0f,0x7d1e,0x7d20,0x7d23,0x7d26,0x7d26,0x7d2a,0x7d33,0x7d35,0x7d35,0x7d39,0x7d3a,0x7d3c,0x7d48,0x7d4b,0x7d51,0x7d53,0x7d53,0x7d55,0x7d57,0x7d59,0x7d5e,0x7d61,0x7d63,0x7d65,0x7d68,0x7d6a,0x7d6a,0x7d6e,0x7d6e,0x7d70,0x7d73,0x7d75,0x7d76,0x7d78,0x7d7b,0x7d7d,0x7d7d,0x7d7f,0x7d7f,0x7d81,0x7d83,0x7d85,0x7d86,0x7d88,0x7d89,0x7d8b,0x7d8d,0x7d8f,0x7d8f,0x7d91,0x7d91,0x7d93,0x7d93,0x7d96,0x7d97,0x7d99,0x7da0,0x7da2,0x7da3,0x7da6,0x7da7,0x7daa,0x7dbb,0x7dbd,0x7dc0,0x7dc2,0x7dc7,0x7dca,0x7dd2,0x7dd5,0x7dda,0x7ddc,0x7dde,0x7de0,0x7de6,0x7de8,0x7ded,0x7def,0x7def,0x7df1,0x7df2,0x7df4,0x7df6,0x7df9,0x7dfb,0x7e00,0x7e01,0x7e04,0x7e05,0x7e08,0x7e0b,0x7e10,0x7e12,0x7e15,0x7e15,0x7e17,0x7e17,0x7e1b,0x7e23,0x7e26,0x7e28,0x7e2b,0x7e2f,0x7e31,0x7e33,0x7e35,0x7e37,0x7e39,0x7e3b,0x7e3d,0x7e3f,0x7e41,0x7e41,0x7e43,0x7e48,0x7e4a,0x7e4b,0x7e4d,0x7e4e,0x7e50,0x7e50,0x7e52,0x7e52,0x7e54,0x7e56,0x7e58,0x7e5a,0x7e5d,0x7e5f,0x7e61,0x7e62,0x7e65,0x7e67,0x7e69,0x7e6b,0x7e6d,0x7e70,0x7e73,0x7e73,0x7e75,0x7e75,0x7e78,0x7e79,0x7e7b,0x7e7f,0x7e81,0x7e83,0x7e86,0x7e8a,0x7e8c,0x7e96,0x7e98,0x7e98,0x7e9a,0x7e9f,0x7f36,0x7f36,0x7f38,0x7f38,0x7f3a,0x7f3f,0x7f43,0x7f45,0x7f47,0x7f47,0x7f4c,0x7f55,0x7f58,0x7f58,0x7f5b,0x7f5d,0x7f5f,0x7f61,0x7f63,0x7f6b,0x7f6d,0x7f6e,0x7f70,0x7f72,0x7f75,0x7f75,0x7f77,0x7f79,0x7f7d,0x7f80,0x7f82,0x7f83,0x7f85,0x7f88,0x7f8a,0x7f91,0x7f94,0x7f94,0x7f96,0x7f97,0x7f9a,0x7f9a,0x7f9c,0x7f9e,0x7fa1,0x7fa4,0x7fa6,0x7fa6,0x7fa8,0x7faa,0x7fad,0x7faf,0x7fb2,0x7fb2,0x7fb4,0x7fb4,0x7fb6,0x7fb6,0x7fb8,0x7fb9,0x7fbc,0x7fbd,0x7fbf,0x7fc1,0x7fc3,0x7fc3,0x7fc5,0x7fc6,0x7fc8,0x7fc8,0x7fca,0x7fca,0x7fcc,0x7fcc,0x7fce,0x7fcf,0x7fd2,0x7fd2,0x7fd4,0x7fd5,0x7fdb,0x7fdb,0x7fdf,0x7fe1,0x7fe3,0x7fe3,0x7fe5,0x7fe6,0x7fe8,0x7fe9,0x7feb,0x7fec,0x7fee,0x7ff0,0x7ff2,0x7ff3,0x7ff9,0x8008,0x800a,0x8019,0x801c,0x8021,0x8024,0x8024,0x8026,0x8026,0x8028,0x8028,0x802c,0x802c,0x802e,0x802e,0x8030,0x8030,0x8033,0x8037,0x8039,0x8040,0x8043,0x8044,0x8046,0x8046,0x804a,0x804a,0x8052,0x8052,0x8056,0x8056,0x8058,0x8058,0x805a,0x805a,0x805e,0x8062,0x8064,0x8064,0x8066,0x8066,0x8068,0x8068,0x806d,0x806d,0x806f,0x8077,0x8079,0x8079,0x807b,0x807b,0x807d,0x8081,0x8084,0x8089,0x808b,0x808c,0x808e,0x808e,0x8093,0x8093,0x8096,0x8096,0x8098,0x809e,0x80a1,0x80a2,0x80a4,0x80a7,0x80a9,0x80ad,0x80af,0x80af,0x80b1,0x80b2,0x80b4,0x80b4,0x80b8,0x80ba,0x80c3,0x80c6,0x80c8,0x80c8,0x80ca,0x80ca,0x80cc,0x80cf,0x80d2,0x80d2,0x80d4,0x80db,0x80dd,0x80de,0x80e0,0x80e1,0x80e4,0x80e6,0x80ed,0x80fe,0x8101,0x8103,0x8105,0x810b,0x810d,0x810d,0x8116,0x8118,0x811a,0x811c,0x811e,0x811e,0x8120,0x8120,0x8123,0x8124,0x8127,0x8127,0x8129,0x8129,0x812b,0x812c,0x812f,0x8131,0x8133,0x8133,0x8135,0x8135,0x8139,0x813a,0x813c,0x813e,0x8141,0x8141,0x8145,0x8147,0x814a,0x814c,0x814e,0x814e,0x8150,0x8155,0x8157,0x8157,0x815f,0x8161,0x8165,0x8169,0x816b,0x816b,0x816d,0x8171,0x8173,0x8174,0x8177,0x817a,0x817f,0x8186,0x8188,0x8188,0x818a,0x818b,0x818e,0x8190,0x8193,0x8193,0x8195,0x8196,0x8198,0x8198,0x819a,0x819e,0x81a0,0x81a0,0x81a2,0x81a4,0x81a8,0x81a9,0x81ae,0x81ae,0x81b0,0x81b0,0x81b2,0x81b5,0x81b8,0x81b8,0x81ba,0x81bb,0x81bd,0x81c3,0x81c5,0x81c6,0x81c8,0x81cb,0x81cd,0x81cf,0x81d1,0x81d1,0x81d3,0x81d3,0x81d5,0x81db,0x81dd,0x81e1,0x81e3,0x81e5,0x81e7,0x81e8,0x81ea,0x81ed,0x81ef,0x81f6,0x81f8,0x8205,0x8207,0x8210,0x8212,0x8214,0x8216,0x821f,0x8221,0x8222,0x8228,0x822c,0x822e,0x822e,0x8232,0x823a,0x823c,0x823c,0x8240,0x8240,0x8243,0x8247,0x8249,0x8249,0x824b,0x824b,0x824e,0x824f,0x8251,0x8251,0x8256,0x825a,0x825c,0x825d,0x825f,0x8260,0x8262,0x8264,0x8266,0x8268,0x826a,0x826b,0x826d,0x826f,0x8271,0x8272,0x8274,0x8274,0x8276,0x8279,0x827b,0x827b,0x827d,0x8281,0x8283,0x8284,0x8287,0x8287,0x8289,0x828b,0x828d,0x828e,0x8291,0x8294,0x8296,0x8296,0x8298,0x829b,0x829d,0x829d,0x829f,0x82a1,0x82a3,0x82b4,0x82b7,0x82bf,0x82c5,0x82c6,0x82d0,0x82d5,0x82d7,0x82d7,0x82d9,0x82dc,0x82de,0x82e8,0x82ea,0x82eb,0x82ed,0x82ed,0x82ef,0x82ef,0x82f1,0x82f1,0x82f3,0x82f4,0x82f6,0x82f7,0x82f9,0x82fb,0x82fd,0x82fe,0x8300,0x830c,0x830e,0x830e,0x8316,0x8318,0x831b,0x831f,0x8321,0x8323,0x8328,0x8328,0x832b,0x833a,0x833c,0x833d,0x8340,0x8340,0x8342,0x8347,0x8349,0x834a,0x834d,0x8358,0x835a,0x835a,0x8362,0x8363,0x8370,0x8370,0x8373,0x8373,0x8375,0x8375,0x8377,0x8378,0x837b,0x837d,0x837f,0x8380,0x8382,0x8382,0x8384,0x8387,0x8389,0x838a,0x838d,0x838e,0x8392,0x8396,0x8398,0x83a0,0x83a2,0x83a2,0x83a6,0x83ad,0x83b1,0x83b1,0x83b5,0x83b5,0x83bd,0x83c1,0x83c5,0x83c5,0x83c7,0x83c7,0x83c9,0x83ca,0x83cc,0x83cc,0x83ce,0x83d1,0x83d3,0x83d4,0x83d6,0x83d6,0x83d8,0x83d8,0x83dc,0x83dd,0x83df,0x83e1,0x83e5,0x83e5,0x83e8,0x83eb,0x83ef,0x83f2,0x83f4,0x83f4,0x83f6,0x83f9,0x83fb,0x83fd,0x8401,0x8401,0x8403,0x8404,0x8406,0x8407,0x840a,0x840f,0x8411,0x8411,0x8413,0x8413,0x8415,0x8415,0x8417,0x8417,0x8419,0x8419,0x8420,0x8420,0x8422,0x8422,0x8429,0x842a,0x842c,0x842c,0x842f,0x842f,0x8431,0x8431,0x8435,0x8435,0x8438,0x8439,0x843c,0x843d,0x8445,0x844a,0x844d,0x844f,0x8451,0x8452,0x8456,0x845c,0x845f,0x8467,0x8469,0x8471,0x8473,0x847a,0x847c,0x847d,0x8481,0x8482,0x8484,0x8485,0x848b,0x848b,0x8490,0x8490,0x8492,0x8495,0x8497,0x8497,0x8499,0x8499,0x849c,0x849c,0x849e,0x849f,0x84a1,0x84a1,0x84a6,0x84a6,0x84a8,0x84aa,0x84ad,0x84ad,0x84af,0x84af,0x84b1,0x84b2,0x84b4,0x84b4,0x84b8,0x84c2,0x84c4,0x84c4,0x84c6,0x84d1,0x84d3,0x84d3,0x84d6,0x84d6,0x84d9,0x84da,0x84dc,0x84dc,0x84e7,0x84e7,0x84ea,0x84ea,0x84ec,0x84ec,0x84ee,0x84f2,0x84f4,0x84f4,0x84f7,0x84f7,0x84fa,0x84fd,0x84ff,0x8500,0x8502,0x8503,0x8506,0x8507,0x850c,0x850c,0x850e,0x850e,0x8510,0x8511,0x8513,0x8515,0x8517,0x8518,0x851a,0x851c,0x851e,0x851f,0x8521,0x8527,0x852a,0x852d,0x852f,0x852f,0x8532,0x8536,0x853d,0x8541,0x8543,0x8543,0x8546,0x8546,0x8548,0x854b,0x854e,0x8553,0x8555,0x855a,0x855c,0x8564,0x8568,0x856b,0x856d,0x856d,0x856f,0x856f,0x8577,0x8577,0x8579,0x857b,0x857d,0x8581,0x8584,0x858c,0x858f,0x8591,0x8593,0x8594,0x8597,0x8599,0x859b,0x859d,0x859f,0x85a0,0x85a2,0x85a2,0x85a4,0x85b0,0x85b4,0x85b4,0x85b6,0x85ba,0x85bc,0x85bf,0x85c1,0x85c2,0x85c7,0x85c7,0x85c9,0x85cb,0x85cd,0x85d0,0x85d5,0x85d5,0x85d8,0x85da,0x85dc,0x85dd,0x85df,0x85e1,0x85e4,0x85e6,0x85e8,0x85ea,0x85ed,0x85ed,0x85f3,0x85f4,0x85f6,0x85f7,0x85f9,0x85fc,0x85fe,0x8600,0x8602,0x8602,0x8604,0x8607,0x860a,0x860b,0x860d,0x860e,0x8610,0x8613,0x8616,0x861b,0x861e,0x861e,0x8621,0x8622,0x8624,0x8624,0x8627,0x8627,0x8629,0x8629,0x862d,0x862d,0x862f,0x8630,0x8636,0x8636,0x8638,0x863a,0x863c,0x863d,0x863f,0x8642,0x8646,0x8646,0x864d,0x864e,0x8650,0x8650,0x8652,0x8664,0x8667,0x8667,0x8669,0x8669,0x866b,0x866c,0x866f,0x866f,0x8671,0x8671,0x8675,0x8677,0x8679,0x867b,0x867d,0x867d,0x8687,0x868d,0x8691,0x8691,0x8693,0x8693,0x8695,0x8696,0x8698,0x8698,0x869a,0x869a,0x869c,0x869d,0x86a1,0x86a1,0x86a3,0x86a4,0x86a6,0x86ab,0x86ad,0x86ad,0x86af,0x86b1,0x86b3,0x86b9,0x86bf,0x86c1,0x86c3,0x86c7,0x86c9,0x86c9,0x86cb,0x86cb,0x86cd,0x86ce,0x86d1,0x86d2,0x86d4,0x86d5,0x86d7,0x86d7,0x86d9,0x86dc,0x86de,0x86e0,0x86e3,0x86e7,0x86e9,0x86e9,0x86ec,0x86ef,0x86f8,0x86fe,0x8700,0x8700,0x8702,0x870b,0x870d,0x8714,0x8718,0x871a,0x871c,0x871c,0x871e,0x871f,0x8721,0x8723,0x8725,0x8725,0x8728,0x8729,0x872e,0x872f,0x8731,0x8732,0x8734,0x8734,0x8737,0x8737,0x8739,0x8740,0x8743,0x8743,0x8745,0x8745,0x8749,0x8749,0x874b,0x874e,0x8751,0x8751,0x8753,0x8753,0x8755,0x8755,0x8757,0x8759,0x875d,0x875d,0x875f,0x8761,0x8763,0x8766,0x8768,0x8768,0x876a,0x876a,0x876e,0x876f,0x8771,0x8772,0x8774,0x8774,0x8776,0x8776,0x8778,0x8778,0x877b,0x877c,0x877f,0x877f,0x8782,0x8789,0x878b,0x878e,0x8790,0x8790,0x8793,0x8793,0x8795,0x8795,0x8797,0x8799,0x879e,0x87a0,0x87a2,0x87a3,0x87a7,0x87a7,0x87ab,0x87af,0x87b1,0x87b1,0x87b3,0x87b3,0x87b5,0x87b5,0x87ba,0x87bb,0x87bd,0x87c1,0x87c4,0x87c4,0x87c6,0x87cb,0x87ce,0x87ce,0x87d0,0x87d0,0x87d2,0x87d2,0x87d5,0x87d6,0x87d9,0x87da,0x87dc,0x87dc,0x87df,0x87e0,0x87e2,0x87e6,0x87ea,0x87ed,0x87ef,0x87ef,0x87f1,0x87f3,0x87f5,0x87fb,0x87fe,0x87ff,0x8801,0x8801,0x8803,0x8803,0x8805,0x8807,0x8809,0x880b,0x880d,0x8816,0x8818,0x881c,0x881e,0x881f,0x8821,0x8823,0x8827,0x8828,0x882d,0x882e,0x8830,0x8832,0x8835,0x8836,0x8839,0x883c,0x8840,0x8846,0x8848,0x884e,0x8851,0x8853,0x8855,0x8864,0x8868,0x8869,0x886b,0x886b,0x886e,0x8872,0x8875,0x8875,0x8877,0x8877,0x8879,0x8879,0x887b,0x887b,0x887d,0x8882,0x8888,0x8888,0x888b,0x888b,0x888d,0x888d,0x8892,0x8892,0x8896,0x889c,0x889e,0x88a0,0x88a2,0x88a2,0x88a4,0x88a4,0x88a8,0x88a8,0x88aa,0x88ab,0x88ae,0x88ae,0x88b0,0x88b1,0x88b4,0x88b5,0x88b7,0x88b7,0x88ba,0x88ba,0x88bc,0x88c6,0x88ca,0x88cf,0x88d1,0x88d5,0x88d8,0x88d9,0x88db,0x88e1,0x88e7,0x88e8,0x88ef,0x88f5,0x88f7,0x88f9,0x88fc,0x88fe,0x8901,0x8902,0x8904,0x8904,0x8906,0x8907,0x890a,0x890a,0x890c,0x8910,0x8912,0x8913,0x8915,0x8916,0x8918,0x891a,0x891c,0x891e,0x8920,0x8920,0x8925,0x8928,0x892a,0x892b,0x8930,0x8932,0x8935,0x893b,0x893e,0x893e,0x8940,0x8946,0x8949,0x8949,0x894c,0x894d,0x894f,0x894f,0x8952,0x8952,0x8956,0x8957,0x895a,0x895c,0x895e,0x8964,0x8966,0x8966,0x896a,0x896b,0x896d,0x8970,0x8972,0x8975,0x8977,0x8977,0x897a,0x8981,0x8983,0x8983,0x8986,0x898b,0x898d,0x898d,0x898f,0x8990,0x8993,0x8998,0x899a,0x899c,0x899f,0x89a1,0x89a5,0x89a7,0x89a9,0x89aa,0x89ac,0x89ac,0x89af,0x89b0,0x89b2,0x89b7,0x89ba,0x89ba,0x89bc,0x89bd,0x89bf,0x89c1,0x89d2,0x89d2,0x89d4,0x89d8,0x89da,0x89da,0x89dc,0x89dd,0x89e3,0x89e3,0x89e5,0x89e7,0x89e9,0x89e9,0x89eb,0x89eb,0x89ed,0x89ed,0x89f1,0x89f1,0x89f3,0x89f4,0x89f6,0x89f6,0x89f8,0x89f9,0x89fd,0x89fd,0x89ff,0x8a05,0x8a07,0x8a08,0x8a0a,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a18,0x8a1b,0x8a1b,0x8a1d,0x8a26,0x8a2a,0x8a2d,0x8a2f,0x8a2f,0x8a31,0x8a31,0x8a33,0x8a37,0x8a3a,0x8a3e,0x8a40,0x8a41,0x8a43,0x8a43,0x8a45,0x8a49,0x8a4d,0x8a4e,0x8a50,0x8a58,0x8a5b,0x8a5e,0x8a60,0x8a63,0x8a65,0x8a67,0x8a69,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a73,0x8a75,0x8a77,0x8a79,0x8a7c,0x8a7e,0x8a80,0x8a82,0x8a87,0x8a89,0x8a89,0x8a8b,0x8a8d,0x8a8f,0x8a93,0x8a95,0x8a9a,0x8a9e,0x8aa1,0x8aa3,0x8aaa,0x8aac,0x8ab0,0x8ab2,0x8ab3,0x8ab6,0x8ab7,0x8ab9,0x8ab9,0x8abb,0x8abc,0x8abe,0x8abf,0x8ac2,0x8ac4,0x8ac6,0x8acd,0x8acf,0x8ad7,0x8ada,0x8ae2,0x8ae4,0x8ae4,0x8ae6,0x8ae7,0x8aeb,0x8aee,0x8af0,0x8af1,0x8af3,0x8af8,0x8afa,0x8afa,0x8afc,0x8afc,0x8afe,0x8b02,0x8b04,0x8b07,0x8b0a,0x8b11,0x8b14,0x8b14,0x8b16,0x8b17,0x8b19,0x8b21,0x8b26,0x8b26,0x8b28,0x8b28,0x8b2b,0x8b2d,0x8b30,0x8b30,0x8b33,0x8b33,0x8b37,0x8b37,0x8b39,0x8b39,0x8b3c,0x8b3c,0x8b3e,0x8b3e,0x8b41,0x8b46,0x8b48,0x8b49,0x8b4c,0x8b4f,0x8b51,0x8b54,0x8b56,0x8b56,0x8b58,0x8b5c,0x8b5e,0x8b5f,0x8b63,0x8b63,0x8b66,0x8b66,0x8b69,0x8b69,0x8b6b,0x8b6d,0x8b6f,0x8b72,0x8b74,0x8b74,0x8b76,0x8b79,0x8b7c,0x8b81,0x8b83,0x8b85,0x8b8a,0x8b90,0x8b92,0x8b96,0x8b99,0x8b9a,0x8b9c,0x8ba0,0x8c37,0x8c3a,0x8c3d,0x8c3f,0x8c41,0x8c41,0x8c45,0x8c4c,0x8c4e,0x8c51,0x8c53,0x8c55,0x8c57,0x8c5b,0x8c5d,0x8c5d,0x8c61,0x8c64,0x8c66,0x8c66,0x8c68,0x8c6d,0x8c73,0x8c73,0x8c75,0x8c76,0x8c78,0x8c7c,0x8c7e,0x8c7e,0x8c82,0x8c82,0x8c85,0x8c87,0x8c89,0x8c8e,0x8c90,0x8c90,0x8c92,0x8c94,0x8c98,0x8c99,0x8c9b,0x8ca2,0x8ca4,0x8ca4,0x8ca7,0x8cb0,0x8cb2,0x8cb4,0x8cb6,0x8cbd,0x8cbf,0x8ccb,0x8ccd,0x8ccf,0x8cd1,0x8cd3,0x8cd5,0x8cd6,0x8cd9,0x8cde,0x8ce0,0x8ce4,0x8ce6,0x8ce6,0x8ce8,0x8ce8,0x8cea,0x8cea,0x8cec,0x8ced,0x8cef,0x8cf2,0x8cf4,0x8cf5,0x8cf7,0x8cf8,0x8cfa,0x8cff,0x8d01,0x8d01,0x8d03,0x8d05,0x8d07,0x8d0b,0x8d0d,0x8d10,0x8d12,0x8d14,0x8d16,0x8d17,0x8d1b,0x8d1d,0x8d64,0x8d67,0x8d69,0x8d69,0x8d6b,0x8d6e,0x8d70,0x8d71,0x8d73,0x8d74,0x8d76,0x8d77,0x8d7f,0x8d7f,0x8d81,0x8d82,0x8d84,0x8d85,0x8d88,0x8d88,0x8d8a,0x8d8a,0x8d8d,0x8d8d,0x8d90,0x8d91,0x8d95,0x8d95,0x8d99,0x8d99,0x8d9e,0x8da0,0x8da3,0x8da3,0x8da6,0x8da6,0x8da8,0x8da8,0x8dab,0x8dac,0x8daf,0x8daf,0x8db2,0x8db3,0x8db5,0x8db5,0x8db7,0x8db7,0x8db9,0x8dbc,0x8dbe,0x8dbe,0x8dc0,0x8dc0,0x8dc2,0x8dc2,0x8dc5,0x8dc8,0x8dca,0x8dcc,0x8dce,0x8dcf,0x8dd1,0x8dd1,0x8dd4,0x8dd7,0x8dd9,0x8ddb,0x8ddd,0x8ddd,0x8ddf,0x8ddf,0x8de1,0x8de1,0x8de3,0x8de5,0x8de7,0x8de8,0x8dea,0x8dec,0x8def,0x8df5,0x8dfc,0x8dfd,0x8dff,0x8dff,0x8e01,0x8e01,0x8e04,0x8e06,0x8e08,0x8e0c,0x8e0f,0x8e11,0x8e14,0x8e14,0x8e16,0x8e16,0x8e1d,0x8e23,0x8e26,0x8e27,0x8e2a,0x8e2a,0x8e30,0x8e31,0x8e33,0x8e39,0x8e3d,0x8e3d,0x8e40,0x8e42,0x8e44,0x8e44,0x8e47,0x8e50,0x8e54,0x8e55,0x8e59,0x8e59,0x8e5b,0x8e64,0x8e69,0x8e69,0x8e6c,0x8e6d,0x8e6f,0x8e72,0x8e74,0x8e77,0x8e79,0x8e7c,0x8e81,0x8e85,0x8e87,0x8e87,0x8e89,0x8e8b,0x8e8d,0x8e8d,0x8e90,0x8e95,0x8e98,0x8e9b,0x8e9d,0x8e9e,0x8ea1,0x8ea2,0x8ea7,0x8ea7,0x8ea9,0x8eb1,0x8eb3,0x8eb3,0x8eb5,0x8eb6,0x8eba,0x8ebb,0x8ebe,0x8ebe,0x8ec0,0x8ec1,0x8ec3,0x8ec8,0x8eca,0x8ecd,0x8ecf,0x8ecf,0x8ed1,0x8ed2,0x8ed4,0x8ed4,0x8edb,0x8edc,0x8edf,0x8edf,0x8ee2,0x8ee3,0x8ee8,0x8ee8,0x8eeb,0x8eeb,0x8eed,0x8eee,0x8ef0,0x8ef1,0x8ef7,0x8efe,0x8f00,0x8f00,0x8f02,0x8f03,0x8f05,0x8f05,0x8f07,0x8f0a,0x8f0c,0x8f0c,0x8f0f,0x8f10,0x8f12,0x8f19,0x8f1b,0x8f21,0x8f23,0x8f23,0x8f25,0x8f2f,0x8f33,0x8f3b,0x8f3e,0x8f47,0x8f49,0x8f4a,0x8f4c,0x8f4f,0x8f51,0x8f55,0x8f57,0x8f58,0x8f5c,0x8f5f,0x8f61,0x8f66,0x8f9b,0x8fa8,0x8fad,0x8fb2,0x8fb4,0x8fb8,0x8fba,0x8fbc,0x8fbe,0x8fc2,0x8fc4,0x8fc6,0x8fc8,0x8fc8,0x8fca,0x8fcb,0x8fcd,0x8fce,0x8fd0,0x8fd5,0x8fda,0x8fda,0x8fe0,0x8fe0,0x8fe2,0x8fe6,0x8fe8,0x8feb,0x8fed,0x8ff1,0x8ff4,0x8ffb,0x8ffd,0x8ffe,0x9000,0x9006,0x9008,0x9008,0x900b,0x9011,0x9013,0x901b,0x901d,0x9023,0x9027,0x902a,0x902c,0x902f,0x9031,0x9039,0x903c,0x903c,0x903e,0x903f,0x9041,0x9045,0x9047,0x9047,0x9049,0x9056,0x9058,0x9059,0x905b,0x905e,0x9060,0x9063,0x9065,0x9069,0x906c,0x9070,0x9072,0x9072,0x9074,0x907a,0x907c,0x907d,0x907f,0x9085,0x9087,0x908c,0x908e,0x9091,0x9095,0x9095,0x9097,0x9099,0x909b,0x909b,0x90a0,0x90a3,0x90a5,0x90a6,0x90a8,0x90a8,0x90aa,0x90aa,0x90af,0x90b6,0x90b8,0x90b8,0x90bd,0x90be,0x90c1,0x90c1,0x90c3,0x90c5,0x90c7,0x90ca,0x90cc,0x90cc,0x90ce,0x90ce,0x90d2,0x90d2,0x90d5,0x90d5,0x90d7,0x90d9,0x90db,0x90df,0x90e1,0x90e2,0x90e4,0x90e5,0x90e8,0x90e8,0x90eb,0x90eb,0x90ed,0x90ed,0x90ef,0x90f0,0x90f2,0x90f2,0x90f4,0x90f7,0x90fd,0x9100,0x9102,0x9102,0x9104,0x9106,0x9108,0x9108,0x910d,0x910d,0x9110,0x9110,0x9112,0x9112,0x9114,0x911a,0x911c,0x911c,0x911e,0x911e,0x9120,0x9120,0x9122,0x9123,0x9125,0x9125,0x9127,0x9127,0x9129,0x9129,0x912d,0x9132,0x9134,0x9134,0x9136,0x9137,0x9139,0x913a,0x913c,0x913d,0x9143,0x9143,0x9146,0x914f,0x9152,0x9154,0x9156,0x915b,0x9161,0x9165,0x9167,0x9167,0x9169,0x916a,0x916c,0x916d,0x9172,0x9175,0x9177,0x917b,0x9181,0x9183,0x9185,0x9187,0x9189,0x918b,0x918d,0x918e,0x9190,0x9195,0x9197,0x9198,0x919c,0x919c,0x919e,0x919e,0x91a1,0x91a2,0x91a4,0x91a4,0x91a6,0x91a6,0x91a8,0x91a8,0x91aa,0x91b6,0x91b8,0x91b8,0x91ba,0x91bd,0x91bf,0x91c9,0x91cb,0x91d1,0x91d3,0x91d4,0x91d6,0x91df,0x91e1,0x91e1,0x91e3,0x91e7,0x91e9,0x91ea,0x91ec,0x91f1,0x91f5,0x91f7,0x91f9,0x91f9,0x91fb,0x91fd,0x91ff,0x9201,0x9204,0x9207,0x9209,0x920a,0x920c,0x920e,0x9210,0x9218,0x921c,0x921e,0x9223,0x9226,0x9228,0x9229,0x922c,0x922c,0x922e,0x9230,0x9233,0x923a,0x923c,0x923c,0x923e,0x9240,0x9242,0x924b,0x924d,0x9251,0x9256,0x925e,0x9260,0x9262,0x9264,0x9269,0x926e,0x9271,0x9275,0x9279,0x927b,0x9280,0x9283,0x9283,0x9285,0x9285,0x9288,0x928a,0x928d,0x928e,0x9291,0x9293,0x9295,0x929c,0x929f,0x92a0,0x92a4,0x92a5,0x92a7,0x92a8,0x92ab,0x92ab,0x92ad,0x92ad,0x92af,0x92af,0x92b2,0x92b3,0x92b6,0x92bd,0x92bf,0x92c3,0x92c5,0x92c8,0x92cb,0x92d0,0x92d2,0x92d3,0x92d5,0x92d5,0x92d7,0x92d9,0x92dc,0x92dd,0x92df,0x92e1,0x92e3,0x92e5,0x92e7,0x92ea,0x92ec,0x92ee,0x92f0,0x92f0,0x92f2,0x92f3,0x92f7,0x92fc,0x92ff,0x9300,0x9302,0x9302,0x9304,0x9304,0x9306,0x9306,0x9308,0x9308,0x930d,0x930d,0x930f,0x9311,0x9314,0x9315,0x9318,0x931a,0x931c,0x932c,0x932e,0x932f,0x9332,0x9337,0x933a,0x933b,0x9344,0x9344,0x9347,0x934b,0x934d,0x934d,0x9350,0x9352,0x9354,0x9358,0x935a,0x935c,0x935e,0x935e,0x9360,0x9360,0x9364,0x9365,0x9367,0x9367,0x9369,0x9371,0x9373,0x9376,0x937a,0x937a,0x937c,0x9382,0x9388,0x9388,0x938a,0x938d,0x938f,0x938f,0x9392,0x9392,0x9394,0x9398,0x939a,0x939b,0x939e,0x939e,0x93a1,0x93a1,0x93a3,0x93a4,0x93a6,0x93a9,0x93ab,0x93ae,0x93b0,0x93b0,0x93b4,0x93b6,0x93b9,0x93bb,0x93c1,0x93c1,0x93c3,0x93cd,0x93d0,0x93d1,0x93d3,0x93d3,0x93d6,0x93d9,0x93dc,0x93df,0x93e1,0x93e2,0x93e4,0x93e8,0x93f1,0x93f1,0x93f5,0x93f5,0x93f7,0x93fb,0x93fd,0x93fd,0x9401,0x9404,0x9407,0x9409,0x940d,0x9410,0x9413,0x941a,0x941f,0x941f,0x9421,0x9421,0x942b,0x942b,0x942e,0x942f,0x9431,0x9436,0x9438,0x9438,0x943a,0x943b,0x943d,0x943d,0x943f,0x943f,0x9441,0x9441,0x9443,0x9445,0x9448,0x9448,0x944a,0x944a,0x944c,0x944c,0x9451,0x9453,0x9455,0x9455,0x9459,0x945c,0x945e,0x9463,0x9468,0x9468,0x946a,0x946b,0x946d,0x9472,0x9475,0x9475,0x9477,0x9477,0x947c,0x947f,0x9481,0x9481,0x9483,0x9485,0x9577,0x9579,0x957e,0x9580,0x9582,0x9584,0x9586,0x958f,0x9591,0x9594,0x9596,0x9596,0x9598,0x9599,0x959d,0x95a9,0x95ab,0x95ad,0x95b1,0x95b2,0x95b4,0x95b4,0x95b6,0x95b6,0x95b9,0x95bf,0x95c3,0x95c3,0x95c6,0x95cd,0x95d0,0x95d6,0x95d8,0x95da,0x95dc,0x95e2,0x95e4,0x95e6,0x95e8,0x95e8,0x961c,0x961e,0x9621,0x9622,0x9624,0x9626,0x9628,0x9628,0x962a,0x962a,0x962c,0x962c,0x962e,0x962f,0x9631,0x9634,0x9637,0x963d,0x963f,0x9642,0x9644,0x9644,0x964b,0x964d,0x964f,0x9650,0x9652,0x9652,0x9654,0x9654,0x9656,0x9658,0x965b,0x965f,0x9661,0x9666,0x966a,0x966a,0x966c,0x966c,0x966e,0x966e,0x9670,0x9670,0x9672,0x9678,0x967a,0x967f,0x9681,0x9686,0x9688,0x968b,0x968d,0x968f,0x9691,0x9691,0x9694,0x969d,0x969f,0x96a0,0x96a3,0x96aa,0x96ae,0x96b4,0x96b6,0x96bd,0x96c0,0x96c1,0x96c4,0x96c7,0x96c9,0x96ce,0x96d1,0x96d2,0x96d5,0x96d6,0x96d8,0x96df,0x96e2,0x96e3,0x96e8,0x96eb,0x96ef,0x96f2,0x96f6,0x96f7,0x96f9,0x96fb,0x9700,0x9700,0x9702,0x970a,0x970d,0x970f,0x9711,0x9711,0x9713,0x9714,0x9716,0x9716,0x9719,0x971e,0x9721,0x9724,0x9727,0x9728,0x972a,0x972a,0x9730,0x9733,0x9736,0x9736,0x9738,0x9739,0x973b,0x973b,0x973d,0x973e,0x9741,0x9744,0x9746,0x974a,0x974d,0x974f,0x9751,0x9752,0x9755,0x975c,0x975e,0x975e,0x9760,0x9764,0x9766,0x976b,0x976d,0x976e,0x9771,0x9771,0x9773,0x9774,0x9776,0x977d,0x977f,0x9781,0x9784,0x9786,0x9789,0x9789,0x978b,0x978b,0x978d,0x978d,0x978f,0x9790,0x9795,0x979a,0x979c,0x979c,0x979e,0x97a0,0x97a2,0x97a3,0x97a6,0x97a6,0x97a8,0x97a8,0x97ab,0x97ae,0x97b1,0x97b6,0x97b8,0x97ba,0x97bc,0x97bc,0x97be,0x97bf,0x97c1,0x97c1,0x97c3,0x97ce,0x97d0,0x97d1,0x97d3,0x97d4,0x97d7,0x97d9,0x97db,0x97de,0x97e0,0x97e1,0x97e4,0x97e4,0x97e6,0x97e6,0x97ed,0x97ef,0x97f1,0x97f8,0x97fa,0x97fb,0x97ff,0x97ff,0x9801,0x9808,0x980a,0x980a,0x980c,0x9814,0x9816,0x981a,0x981c,0x981c,0x981e,0x981e,0x9820,0x9821,0x9823,0x9826,0x982b,0x9830,0x9832,0x9835,0x9837,0x9839,0x983b,0x983e,0x9844,0x9844,0x9846,0x9847,0x984a,0x984f,0x9851,0x985b,0x985e,0x985e,0x9862,0x9863,0x9865,0x9867,0x986a,0x986c,0x986f,0x9871,0x9873,0x9875,0x98a8,0x98a8,0x98aa,0x98ab,0x98ad,0x98b1,0x98b4,0x98b4,0x98b6,0x98b8,0x98ba,0x98bc,0x98bf,0x98bf,0x98c2,0x98c8,0x98cb,0x98cc,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e3,0x98e5,0x98e7,0x98e9,0x98eb,0x98ed,0x98f4,0x98f6,0x98f6,0x98fc,0x98fe,0x9902,0x9903,0x9905,0x9905,0x9907,0x990a,0x990c,0x990c,0x9910,0x9918,0x991a,0x9922,0x9924,0x9924,0x9926,0x9928,0x992b,0x992c,0x992e,0x992e,0x9931,0x9935,0x9939,0x993e,0x9940,0x9942,0x9945,0x9949,0x994b,0x994e,0x9950,0x9952,0x9954,0x9955,0x9957,0x9959,0x995b,0x995c,0x995e,0x9960,0x9963,0x9963,0x9996,0x9999,0x999b,0x999b,0x999d,0x999f,0x99a3,0x99a3,0x99a5,0x99a6,0x99a8,0x99a8,0x99ac,0x99ae,0x99b0,0x99b5,0x99b9,0x99ba,0x99bc,0x99bd,0x99bf,0x99bf,0x99c1,0x99c1,0x99c3,0x99c6,0x99c8,0x99c9,0x99d0,0x99d5,0x99d8,0x99df,0x99e1,0x99e2,0x99e7,0x99e7,0x99ea,0x99ee,0x99f0,0x99f2,0x99f4,0x99f5,0x99f8,0x99f9,0x99fb,0x99ff,0x9a01,0x9a05,0x9a08,0x9a08,0x9a0a,0x9a0c,0x9a0e,0x9a13,0x9a16,0x9a16,0x9a19,0x9a1a,0x9a1e,0x9a1e,0x9a20,0x9a20,0x9a22,0x9a24,0x9a27,0x9a28,0x9a2b,0x9a2b,0x9a2d,0x9a2e,0x9a30,0x9a31,0x9a33,0x9a33,0x9a35,0x9a38,0x9a3e,0x9a3e,0x9a40,0x9a45,0x9a47,0x9a47,0x9a4a,0x9a4e,0x9a51,0x9a52,0x9a54,0x9a58,0x9a5a,0x9a5b,0x9a5d,0x9a5d,0x9a5f,0x9a5f,0x9a62,0x9a62,0x9a64,0x9a65,0x9a69,0x9a6c,0x9aa8,0x9aa8,0x9aaa,0x9aaa,0x9aac,0x9ab0,0x9ab2,0x9ab2,0x9ab4,0x9ab9,0x9abb,0x9ac1,0x9ac3,0x9ac4,0x9ac6,0x9ac6,0x9ac8,0x9ac8,0x9ace,0x9ad9,0x9adb,0x9adc,0x9ade,0x9ae0,0x9ae2,0x9ae7,0x9ae9,0x9aef,0x9af1,0x9af5,0x9af7,0x9af7,0x9af9,0x9afb,0x9afd,0x9afd,0x9aff,0x9b06,0x9b08,0x9b09,0x9b0b,0x9b0e,0x9b10,0x9b10,0x9b12,0x9b12,0x9b16,0x9b16,0x9b18,0x9b1d,0x9b1f,0x9b20,0x9b22,0x9b23,0x9b25,0x9b2f,0x9b31,0x9b35,0x9b37,0x9b37,0x9b39,0x9b3d,0x9b41,0x9b45,0x9b48,0x9b48,0x9b4b,0x9b4f,0x9b51,0x9b51,0x9b54,0x9b58,0x9b5a,0x9b5b,0x9b5e,0x9b5e,0x9b61,0x9b61,0x9b63,0x9b63,0x9b65,0x9b66,0x9b68,0x9b68,0x9b6a,0x9b6f,0x9b72,0x9b79,0x9b7f,0x9b80,0x9b83,0x9b87,0x9b89,0x9b8b,0x9b8d,0x9b94,0x9b96,0x9b97,0x9b9a,0x9b9a,0x9b9d,0x9ba0,0x9ba6,0x9bae,0x9bb0,0x9bb2,0x9bb4,0x9bb4,0x9bb7,0x9bb9,0x9bbb,0x9bbc,0x9bbe,0x9bc1,0x9bc6,0x9bca,0x9bce,0x9bd2,0x9bd4,0x9bd4,0x9bd6,0x9bd8,0x9bdb,0x9bdb,0x9bdd,0x9bdd,0x9bdf,0x9bdf,0x9be1,0x9be5,0x9be7,0x9be8,0x9bea,0x9beb,0x9bee,0x9bf3,0x9bf5,0x9bf5,0x9bf7,0x9bfa,0x9bfd,0x9bfd,0x9bff,0x9c00,0x9c02,0x9c02,0x9c04,0x9c04,0x9c06,0x9c06,0x9c08,0x9c0d,0x9c0f,0x9c16,0x9c18,0x9c1e,0x9c21,0x9c2a,0x9c2d,0x9c32,0x9c35,0x9c37,0x9c39,0x9c3b,0x9c3d,0x9c3e,0x9c41,0x9c41,0x9c43,0x9c4a,0x9c4e,0x9c50,0x9c52,0x9c54,0x9c56,0x9c58,0x9c5a,0x9c61,0x9c63,0x9c63,0x9c65,0x9c65,0x9c67,0x9c6b,0x9c6d,0x9c6e,0x9c70,0x9c70,0x9c72,0x9c72,0x9c75,0x9c78,0x9c7a,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9ce9,0x9ceb,0x9cec,0x9cf0,0x9cf0,0x9cf2,0x9cf4,0x9cf6,0x9cf7,0x9cf9,0x9cf9,0x9d02,0x9d03,0x9d06,0x9d09,0x9d0b,0x9d0b,0x9d0e,0x9d0e,0x9d11,0x9d12,0x9d15,0x9d15,0x9d17,0x9d18,0x9d1b,0x9d1f,0x9d23,0x9d23,0x9d26,0x9d26,0x9d28,0x9d28,0x9d2a,0x9d2c,0x9d2f,0x9d30,0x9d32,0x9d34,0x9d3a,0x9d3f,0x9d41,0x9d48,0x9d4a,0x9d4a,0x9d50,0x9d54,0x9d59,0x9d59,0x9d5c,0x9d65,0x9d69,0x9d6c,0x9d6f,0x9d70,0x9d72,0x9d73,0x9d76,0x9d77,0x9d7a,0x9d7c,0x9d7e,0x9d7e,0x9d83,0x9d84,0x9d86,0x9d87,0x9d89,0x9d8a,0x9d8d,0x9d8f,0x9d92,0x9d93,0x9d95,0x9d9a,0x9da1,0x9da1,0x9da4,0x9da4,0x9da9,0x9dac,0x9dae,0x9daf,0x9db1,0x9db2,0x9db4,0x9db5,0x9db8,0x9dbd,0x9dbf,0x9dc4,0x9dc6,0x9dc7,0x9dc9,0x9dca,0x9dcf,0x9dcf,0x9dd3,0x9dd7,0x9dd9,0x9dda,0x9dde,0x9de0,0x9de3,0x9de3,0x9de5,0x9de7,0x9de9,0x9de9,0x9deb,0x9deb,0x9ded,0x9df0,0x9df2,0x9df4,0x9df8,0x9dfa,0x9dfd,0x9dfe,0x9e02,0x9e02,0x9e07,0x9e07,0x9e0a,0x9e0a,0x9e0d,0x9e0e,0x9e10,0x9e12,0x9e15,0x9e16,0x9e19,0x9e1f,0x9e75,0x9e75,0x9e78,0x9e7d,0x9e7f,0x9e85,0x9e87,0x9e88,0x9e8b,0x9e8c,0x9e8e,0x9e8f,0x9e91,0x9e93,0x9e95,0x9e98,0x9e9b,0x9e9b,0x9e9d,0x9e9f,0x9ea4,0x9ea6,0x9ea8,0x9eaa,0x9eac,0x9eb0,0x9eb3,0x9eb5,0x9eb8,0x9ebf,0x9ec3,0x9ec4,0x9ec6,0x9ec6,0x9ec8,0x9ec8,0x9ecb,0x9ed2,0x9ed4,0x9ed5,0x9ed8,0x9ed9,0x9edb,0x9ee0,0x9ee4,0x9ee5,0x9ee7,0x9ee8,0x9eec,0x9ef2,0x9ef4,0x9ef9,0x9efb,0x9eff,0x9f02,0x9f03,0x9f07,0x9f09,0x9f0e,0x9f17,0x9f19,0x9f1b,0x9f1f,0x9f22,0x9f26,0x9f26,0x9f2a,0x9f2c,0x9f2f,0x9f2f,0x9f31,0x9f32,0x9f34,0x9f34,0x9f37,0x9f37,0x9f39,0x9f3f,0x9f41,0x9f41,0x9f43,0x9f47,0x9f4a,0x9f4b,0x9f4e,0x9f50,0x9f52,0x9f58,0x9f5a,0x9f5a,0x9f5d,0x9f63,0x9f66,0x9f6a,0x9f6c,0x9f73,0x9f75,0x9f77,0x9f7a,0x9f7a,0x9f7d,0x9f7d,0x9f7f,0x9f7f,0x9f8d,0x9f8d,0x9f8f,0x9f92,0x9f94,0x9f97,0x9f99,0x9f99,0x9f9c,0x9fa3,0x9fa5,0x9fa5,0x9fb4,0x9fb4,0x9fbc,0x9fc2,0x9fc4,0x9fc4,0x9fc6,0x9fc6,0x9fcc,0x9fcc,0xf900,0xf959,0xf95b,0xf9f2,0xf9f4,0xfa0b,0xfa0e,0xfa6d,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x2000b,0x2000b,0x20089,0x2008a,0x200a2,0x200a2,0x200a4,0x200a4,0x200b0,0x200b0,0x200f5,0x200f5,0x20158,0x20158,0x201a2,0x201a2,0x20213,0x20213,0x2032b,0x2032b,0x20371,0x20371,0x20381,0x20381,0x203f9,0x203f9,0x2044a,0x2044a,0x20509,0x20509,0x2053f,0x2053f,0x205b1,0x205b1,0x205d6,0x205d6,0x20611,0x20611,0x20628,0x20628,0x206ec,0x206ec,0x2074f,0x2074f,0x207c8,0x207c8,0x20807,0x20807,0x2083a,0x2083a,0x208b9,0x208b9,0x2090e,0x2090e,0x2097c,0x2097c,0x20984,0x20984,0x2099d,0x2099d,0x20a64,0x20a64,0x20ad3,0x20ad3,0x20b1d,0x20b1d,0x20b9f,0x20b9f,0x20bb7,0x20bb7,0x20d45,0x20d45,0x20d58,0x20d58,0x20de1,0x20de1,0x20e64,0x20e64,0x20e6d,0x20e6d,0x20e95,0x20e95,0x20f5f,0x20f5f,0x21201,0x21201,0x2123d,0x2123d,0x21255,0x21255,0x21274,0x21274,0x2127b,0x2127b,0x212d7,0x212d7,0x212e4,0x212e4,0x212fd,0x212fd,0x2131b,0x2131b,0x21336,0x21336,0x21344,0x21344,0x213c4,0x213c4,0x2146d,0x2146e,0x215d7,0x215d7,0x21647,0x21647,0x216b4,0x216b4,0x21706,0x21706,0x21742,0x21742,0x218bd,0x218bd,0x219c3,0x219c3,0x21a1a,0x21a1a,0x21c56,0x21c56,0x21d2d,0x21d2d,0x21d45,0x21d45,0x21d62,0x21d62,0x21d78,0x21d78,0x21d92,0x21d92,0x21d9c,0x21d9c,0x21da1,0x21da1,0x21db7,0x21db7,0x21de0,0x21de0,0x21e33,0x21e34,0x21f1e,0x21f1e,0x21f76,0x21f76,0x21ffa,0x21ffa,0x2217b,0x2217b,0x22218,0x22218,0x2231e,0x2231e,0x223ad,0x223ad,0x22609,0x22609,0x226f3,0x226f3,0x2285b,0x2285b,0x228ab,0x228ab,0x2298f,0x2298f,0x22ab8,0x22ab8,0x22b46,0x22b46,0x22b4f,0x22b50,0x22ba6,0x22ba6,0x22c1d,0x22c1d,0x22c24,0x22c24,0x22de1,0x22de1,0x22e42,0x22e42,0x22feb,0x22feb,0x231b6,0x231b6,0x231c3,0x231c4,0x231f5,0x231f5,0x23372,0x23372,0x233cc,0x233cc,0x233d0,0x233d0,0x233d2,0x233d3,0x233d5,0x233d5,0x233da,0x233da,0x233df,0x233df,0x233e4,0x233e4,0x233fe,0x233fe,0x2344a,0x2344b,0x23451,0x23451,0x23465,0x23465,0x234e4,0x234e4,0x2355a,0x2355a,0x23594,0x23594,0x235c4,0x235c4,0x23638,0x2363a,0x23647,0x23647,0x2370c,0x2370c,0x2371c,0x2371c,0x2373f,0x2373f,0x23763,0x23764,0x237e7,0x237e7,0x237f1,0x237f1,0x237ff,0x237ff,0x23824,0x23824,0x2383d,0x2383d,0x23a98,0x23a98,0x23c7f,0x23c7f,0x23cbe,0x23cbe,0x23cfe,0x23cfe,0x23d00,0x23d00,0x23d0e,0x23d0e,0x23d40,0x23d40,0x23dd3,0x23dd3,0x23df9,0x23dfa,0x23f7e,0x23f7e,0x2404b,0x2404b,0x24096,0x24096,0x24103,0x24103,0x241c6,0x241c6,0x241fe,0x241fe,0x242ee,0x242ee,0x243bc,0x243bc,0x243d0,0x243d0,0x24629,0x24629,0x246a5,0x246a5,0x247f1,0x247f1,0x24896,0x24896,0x248e9,0x248e9,0x24a4d,0x24a4d,0x24b56,0x24b56,0x24b6f,0x24b6f,0x24c16,0x24c16,0x24d14,0x24d14,0x24e04,0x24e04,0x24e0e,0x24e0e,0x24e37,0x24e37,0x24e6a,0x24e6a,0x24e8b,0x24e8b,0x24ff2,0x24ff2,0x2504a,0x2504a,0x25055,0x25055,0x25122,0x25122,0x251a9,0x251a9,0x251cd,0x251cd,0x251e5,0x251e5,0x2521e,0x2521e,0x2524c,0x2524c,0x2542e,0x2542e,0x2548e,0x2548e,0x254d9,0x254d9,0x2550e,0x2550e,0x255a7,0x255a7,0x2567f,0x2567f,0x25771,0x25771,0x257a9,0x257a9,0x257b4,0x257b4,0x25874,0x25874,0x259c4,0x259c4,0x259cc,0x259cc,0x259d4,0x259d4,0x25ad7,0x25ad7,0x25ae3,0x25ae4,0x25af1,0x25af1,0x25bb2,0x25bb2,0x25c4b,0x25c4b,0x25c64,0x25c64,0x25da1,0x25da1,0x25e2e,0x25e2e,0x25e56,0x25e56,0x25e62,0x25e62,0x25e65,0x25e65,0x25ec2,0x25ec2,0x25ed8,0x25ed8,0x25ee8,0x25ee8,0x25f23,0x25f23,0x25f5c,0x25f5c,0x25fd4,0x25fd4,0x25fe0,0x25fe0,0x25ffb,0x25ffb,0x2600c,0x2600c,0x26017,0x26017,0x26060,0x26060,0x260ed,0x260ed,0x26222,0x26222,0x2626a,0x2626a,0x26270,0x26270,0x26286,0x26286,0x2634c,0x2634c,0x26402,0x26402,0x2667e,0x2667e,0x266b0,0x266b0,0x2671d,0x2671d,0x268dd,0x268dd,0x268ea,0x268ea,0x26951,0x26951,0x2696f,0x2696f,0x26999,0x26999,0x269dd,0x269dd,0x26a1e,0x26a1e,0x26a58,0x26a58,0x26a8c,0x26a8c,0x26ab7,0x26ab7,0x26aff,0x26aff,0x26c29,0x26c29,0x26c73,0x26c73,0x26c9e,0x26c9e,0x26cdd,0x26cdd,0x26e40,0x26e40,0x26e65,0x26e65,0x26f94,0x26f94,0x26ff6,0x26ff8,0x270f4,0x270f4,0x2710d,0x2710d,0x27139,0x27139,0x273da,0x273db,0x273fe,0x273fe,0x27410,0x27410,0x27449,0x27449,0x27614,0x27615,0x27631,0x27631,0x27684,0x27684,0x27693,0x27693,0x2770e,0x2770e,0x27723,0x27723,0x27752,0x27752,0x278b2,0x278b2,0x27985,0x27985,0x279b4,0x279b4,0x27a84,0x27a84,0x27bb3,0x27bb3,0x27bbe,0x27bbe,0x27bc7,0x27bc7,0x27c3c,0x27c3c,0x27cb8,0x27cb8,0x27d73,0x27d73,0x27da0,0x27da0,0x27e10,0x27e10,0x27eaf,0x27eaf,0x27fb7,0x27fb7,0x2808a,0x2808a,0x280bb,0x280bb,0x28277,0x28277,0x28282,0x28282,0x282f3,0x282f3,0x283cd,0x283cd,0x2840c,0x2840c,0x28455,0x28455,0x284dc,0x284dc,0x2856b,0x2856b,0x285c8,0x285c9,0x286d7,0x286d7,0x286fa,0x286fa,0x28946,0x28946,0x28949,0x28949,0x2896b,0x2896b,0x28987,0x28988,0x289ba,0x289bb,0x28a1e,0x28a1e,0x28a29,0x28a29,0x28a43,0x28a43,0x28a71,0x28a71,0x28a99,0x28a99,0x28acd,0x28acd,0x28add,0x28add,0x28ae4,0x28ae4,0x28bc1,0x28bc1,0x28bef,0x28bef,0x28cdd,0x28cdd,0x28d10,0x28d10,0x28d71,0x28d71,0x28dfb,0x28dfb,0x28e0f,0x28e0f,0x28e17,0x28e17,0x28e1f,0x28e1f,0x28e36,0x28e36,0x28e89,0x28e89,0x28eeb,0x28eeb,0x28ef6,0x28ef6,0x28f32,0x28f32,0x28ff8,0x28ff8,0x292a0,0x292a0,0x292b1,0x292b1,0x29490,0x29490,0x295cf,0x295cf,0x2967f,0x2967f,0x296f0,0x296f0,0x29719,0x29719,0x29750,0x29750,0x29810,0x29810,0x298c6,0x298c6,0x29a72,0x29a72,0x29d4b,0x29d4b,0x29ddb,0x29ddb,0x29e15,0x29e15,0x29e3d,0x29e3d,0x29e49,0x29e49,0x29e8a,0x29e8a,0x29ec4,0x29ec4,0x29edb,0x29edb,0x29ee9,0x29ee9,0x29fce,0x29fce,0x29fd7,0x29fd7,0x2a01a,0x2a01a,0x2a02f,0x2a02f,0x2a082,0x2a082,0x2a0f9,0x2a0f9,0x2a190,0x2a190,0x2a2b2,0x2a2b2,0x2a38c,0x2a38c,0x2a437,0x2a437,0x2a5f1,0x2a5f1,0x2a602,0x2a602,0x2a61a,0x2a61a,0x2a6b2,0x2a6b2,0x2a9e6,0x2a9e6,0x2b746,0x2b746,0x2b751,0x2b751,0x2b753,0x2b753,0x2b75a,0x2b75a,0x2b75c,0x2b75c,0x2b765,0x2b765,0x2b776,0x2b777,0x2b77c,0x2b77c,0x2b782,0x2b782,0x2b789,0x2b789,0x2b78b,0x2b78b,0x2b78e,0x2b78e,0x2b794,0x2b794,0x2b7ac,0x2b7ac,0x2b7af,0x2b7af,0x2b7bd,0x2b7bd,0x2b7c9,0x2b7c9,0x2b7cf,0x2b7cf,0x2b7d2,0x2b7d2,0x2b7d8,0x2b7d8,0x2b7f0,0x2b7f0,0x2b80d,0x2b80d,0x2b817,0x2b817,0x2b81a,0x2b81a,0x2d544,0x2d544,0x2e278,0x2e278,0x2e569,0x2e569,0x2e6ea,0x2e6ea,0x2f804,0x2f804,0x2f80f,0x2f80f,0x2f815,0x2f815,0x2f818,0x2f818,0x2f81a,0x2f81a,0x2f822,0x2f822,0x2f828,0x2f828,0x2f82c,0x2f82c,0x2f833,0x2f833,0x2f83f,0x2f83f,0x2f846,0x2f846,0x2f852,0x2f852,0x2f862,0x2f862,0x2f86d,0x2f86d,0x2f873,0x2f873,0x2f877,0x2f877,0x2f884,0x2f884,0x2f899,0x2f89a,0x2f8a6,0x2f8a6,0x2f8ac,0x2f8ac,0x2f8b2,0x2f8b2,0x2f8b6,0x2f8b6,0x2f8d3,0x2f8d3,0x2f8db,0x2f8dc,0x2f8e1,0x2f8e1,0x2f8e5,0x2f8e5,0x2f8ea,0x2f8ea,0x2f8ed,0x2f8ed,0x2f8fc,0x2f8fc,0x2f903,0x2f903,0x2f90b,0x2f90b,0x2f90f,0x2f90f,0x2f91a,0x2f91a,0x2f920,0x2f921,0x2f945,0x2f945,0x2f947,0x2f947,0x2f96c,0x2f96c,0x2f995,0x2f995,0x2f9d0,0x2f9d0,0x2f9de,0x2f9df,0x2f9f4,0x2f9f4,0x30ede,0x30ede,0x3106c,0x3106c,]), + NotoFont.fromFlatRanges('Noto Sans Javanese', 'http://fonts.gstatic.com/s/notosansjavanese/v15/2V0AKJkDAIA6Hp4zoSScDjV0Y-eoHAHJ8r88Rp29eA.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa980,0xa9cd,0xa9cf,0xa9d9,0xa9de,0xa9df,]), + NotoFont.fromFlatRanges('Noto Sans KR', 'http://fonts.gstatic.com/s/notosanskr/v27/PbykFmXiEBPT4ITbgNA5Cgm20HTs4JMMuA.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1100,0x11ff,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x349a,0x349a,0x34d7,0x34d7,0x3515,0x3515,0x3521,0x3521,0x353e,0x353e,0x35ff,0x35ff,0x366f,0x366f,0x36c3,0x36c5,0x36e6,0x36e6,0x3723,0x3723,0x372f,0x372f,0x373a,0x373a,0x37bc,0x37bc,0x380c,0x380c,0x3818,0x3818,0x3883,0x3883,0x38ba,0x38ba,0x38e7,0x38e7,0x38fd,0x38fd,0x3960,0x3960,0x3965,0x3965,0x3983,0x3983,0x3990,0x3990,0x39a5,0x39a5,0x39b6,0x39b6,0x3a39,0x3a39,0x3aa4,0x3aa4,0x3adc,0x3adc,0x3af6,0x3af6,0x3b03,0x3b03,0x3b23,0x3b23,0x3b79,0x3b79,0x3bf3,0x3bf3,0x3c14,0x3c14,0x3c24,0x3c24,0x3c2d,0x3c2d,0x3cbd,0x3cbe,0x3cfc,0x3cfc,0x3d17,0x3d17,0x3d5f,0x3d5f,0x3dbc,0x3dbc,0x3dc2,0x3dc2,0x3ec4,0x3ec4,0x3eed,0x3eed,0x3efd,0x3efd,0x3f04,0x3f04,0x402f,0x402f,0x4034,0x4034,0x4062,0x4062,0x40a9,0x40a9,0x40c9,0x40c9,0x4137,0x4137,0x41ac,0x41ac,0x4259,0x4259,0x43bb,0x43bb,0x43c7,0x43c7,0x43e7,0x43e7,0x43ea,0x43ea,0x4450,0x4450,0x4512,0x4512,0x45f2,0x45f2,0x4618,0x4618,0x46b7,0x46b7,0x46be,0x46be,0x46d4,0x46d4,0x46d8,0x46d8,0x46dd,0x46dd,0x472d,0x472d,0x476c,0x476c,0x477d,0x477d,0x479f,0x479f,0x4863,0x4863,0x4883,0x4883,0x4896,0x4896,0x48a6,0x48a6,0x4925,0x4925,0x499e,0x499e,0x49a5,0x49a5,0x49cb,0x49cb,0x4a12,0x4a12,0x4a2d,0x4a2d,0x4ab8,0x4ab8,0x4adf,0x4adf,0x4ae8,0x4ae8,0x4afb,0x4afb,0x4b53,0x4b53,0x4b71,0x4b71,0x4cdf,0x4ce0,0x4d1b,0x4d1b,0x4e00,0x4e01,0x4e03,0x4e03,0x4e07,0x4e0b,0x4e0d,0x4e0e,0x4e11,0x4e11,0x4e14,0x4e16,0x4e18,0x4e19,0x4e1e,0x4e1f,0x4e24,0x4e24,0x4e26,0x4e26,0x4e28,0x4e28,0x4e2b,0x4e2d,0x4e30,0x4e32,0x4e36,0x4e36,0x4e38,0x4e39,0x4e3b,0x4e3b,0x4e3f,0x4e3f,0x4e42,0x4e43,0x4e45,0x4e45,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e56,0x4e5b,0x4e5d,0x4e5f,0x4e67,0x4e67,0x4e6b,0x4e6d,0x4e71,0x4e71,0x4e73,0x4e73,0x4e76,0x4e77,0x4e7a,0x4e7c,0x4e7e,0x4e7e,0x4e80,0x4e80,0x4e82,0x4e82,0x4e85,0x4e86,0x4e88,0x4e89,0x4e8b,0x4e8c,0x4e8e,0x4e92,0x4e94,0x4e95,0x4e98,0x4e99,0x4e9b,0x4e9c,0x4e9e,0x4ea2,0x4ea4,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eae,0x4eb0,0x4eb0,0x4eb3,0x4eb4,0x4eb6,0x4eb6,0x4eb9,0x4ebb,0x4ec0,0x4ec1,0x4ec4,0x4ec4,0x4ec6,0x4ec7,0x4eca,0x4ecb,0x4ecd,0x4ecd,0x4ed4,0x4ed9,0x4edd,0x4edf,0x4ee1,0x4ee1,0x4ee3,0x4ee5,0x4eee,0x4eee,0x4ef0,0x4ef0,0x4ef2,0x4ef3,0x4ef5,0x4ef7,0x4efb,0x4efb,0x4efd,0x4efd,0x4eff,0x4f01,0x4f09,0x4f0b,0x4f0d,0x4f11,0x4f1a,0x4f1a,0x4f1d,0x4f1d,0x4f2f,0x4f30,0x4f34,0x4f34,0x4f36,0x4f36,0x4f38,0x4f38,0x4f3a,0x4f3a,0x4f3c,0x4f3e,0x4f42,0x4f43,0x4f46,0x4f49,0x4f4b,0x4f4b,0x4f4d,0x4f51,0x4f53,0x4f57,0x4f59,0x4f5f,0x4f69,0x4f6a,0x4f6f,0x4f70,0x4f73,0x4f74,0x4f76,0x4f76,0x4f78,0x4f81,0x4f83,0x4f84,0x4f86,0x4f86,0x4f88,0x4f8b,0x4f8d,0x4f92,0x4f94,0x4f94,0x4f96,0x4f98,0x4f9a,0x4f9d,0x4fae,0x4faf,0x4fb2,0x4fb2,0x4fb5,0x4fb6,0x4fb9,0x4fb9,0x4fbb,0x4fbb,0x4fbf,0x4fbf,0x4fc1,0x4fc5,0x4fc9,0x4fca,0x4fcc,0x4fd4,0x4fd7,0x4fdb,0x4fdd,0x4fe1,0x4fe3,0x4fe3,0x4fee,0x4ff1,0x4ff3,0x4ff6,0x4ff8,0x4ff8,0x4ffa,0x4ffa,0x4ffe,0x4ffe,0x5000,0x5000,0x5002,0x5002,0x5005,0x5007,0x5009,0x5009,0x500b,0x500b,0x500d,0x500d,0x500f,0x500f,0x5011,0x5014,0x5016,0x5016,0x5018,0x501a,0x501c,0x501c,0x501e,0x501f,0x5021,0x502e,0x5030,0x5030,0x503b,0x503b,0x5043,0x5044,0x5047,0x504a,0x504e,0x504f,0x5053,0x5053,0x5055,0x5056,0x5058,0x505a,0x505c,0x505c,0x5060,0x5060,0x5062,0x5062,0x5065,0x5066,0x506a,0x506a,0x5070,0x5070,0x5072,0x5072,0x5074,0x5076,0x5078,0x5078,0x5080,0x5080,0x5083,0x5083,0x5085,0x5085,0x508b,0x508b,0x508d,0x508d,0x5091,0x5092,0x5094,0x5094,0x5096,0x5096,0x5098,0x509b,0x509d,0x509e,0x50a2,0x50a2,0x50ac,0x50ae,0x50b2,0x50b5,0x50b7,0x50b7,0x50bd,0x50bf,0x50c2,0x50c2,0x50c4,0x50c5,0x50c9,0x50ca,0x50cf,0x50cf,0x50d1,0x50d1,0x50d4,0x50d6,0x50da,0x50db,0x50de,0x50de,0x50e2,0x50e2,0x50e5,0x50e7,0x50e9,0x50e9,0x50ec,0x50ee,0x50f5,0x50f5,0x50f9,0x50f9,0x50fb,0x50fb,0x50fe,0x5104,0x5106,0x5107,0x5109,0x5109,0x510b,0x510c,0x5110,0x5110,0x5112,0x5115,0x5117,0x5118,0x511a,0x511c,0x511f,0x511f,0x5121,0x5122,0x5124,0x5125,0x5127,0x5127,0x512a,0x512b,0x5131,0x5133,0x5135,0x5135,0x5137,0x513c,0x513f,0x5141,0x5143,0x5149,0x514b,0x514e,0x5150,0x5150,0x5152,0x5152,0x5154,0x5157,0x515a,0x515a,0x515c,0x515c,0x5162,0x5162,0x5165,0x5165,0x5167,0x516e,0x5171,0x5171,0x5175,0x5178,0x517c,0x517c,0x5180,0x5180,0x5182,0x5182,0x5186,0x5186,0x5189,0x518a,0x518c,0x518d,0x518f,0x518f,0x5191,0x5193,0x5195,0x5199,0x519e,0x519e,0x51a0,0x51a0,0x51a2,0x51a5,0x51aa,0x51ac,0x51b0,0x51b2,0x51b6,0x51b7,0x51bd,0x51be,0x51c4,0x51c6,0x51c9,0x51cd,0x51d2,0x51d2,0x51d4,0x51d4,0x51d6,0x51d6,0x51db,0x51de,0x51e0,0x51e1,0x51e9,0x51e9,0x51ed,0x51ed,0x51f0,0x51f1,0x51f3,0x51f6,0x51f8,0x51fa,0x51fd,0x51fd,0x5200,0x5203,0x5206,0x5208,0x520a,0x520a,0x520e,0x520e,0x5211,0x5211,0x5213,0x5213,0x5216,0x5217,0x521d,0x521d,0x5224,0x5227,0x5229,0x522a,0x522e,0x522e,0x5230,0x5233,0x5236,0x523b,0x5243,0x5244,0x5246,0x5247,0x5249,0x524d,0x5254,0x5257,0x525a,0x525b,0x525d,0x525f,0x5261,0x5261,0x5269,0x526a,0x526f,0x526f,0x5272,0x5272,0x5274,0x5275,0x5277,0x5277,0x527a,0x527a,0x527d,0x527d,0x527f,0x527f,0x5282,0x5283,0x5287,0x5289,0x528d,0x528d,0x5291,0x5293,0x5297,0x5298,0x529b,0x529b,0x529f,0x52a0,0x52a3,0x52a4,0x52a7,0x52a7,0x52a9,0x52ae,0x52b9,0x52b9,0x52be,0x52be,0x52c1,0x52c1,0x52c3,0x52c3,0x52c5,0x52c5,0x52c7,0x52c7,0x52c9,0x52c9,0x52cc,0x52cd,0x52d2,0x52d2,0x52d5,0x52d6,0x52d8,0x52d9,0x52db,0x52db,0x52dd,0x52e4,0x52e6,0x52e6,0x52ed,0x52ed,0x52f2,0x52f3,0x52f5,0x52f5,0x52f8,0x52fb,0x52fe,0x5303,0x5305,0x5305,0x5308,0x5308,0x530a,0x530a,0x530c,0x530d,0x530f,0x5310,0x5315,0x5317,0x5319,0x531a,0x5320,0x5321,0x5323,0x5323,0x5327,0x5327,0x532a,0x532a,0x532f,0x532f,0x5331,0x5331,0x5336,0x5336,0x5338,0x533b,0x533d,0x5341,0x5343,0x5345,0x5347,0x534a,0x534d,0x534d,0x5351,0x5354,0x5357,0x5357,0x535a,0x535a,0x535c,0x535c,0x535e,0x535e,0x5360,0x5361,0x5364,0x5364,0x5366,0x5366,0x5368,0x5369,0x536c,0x536c,0x536e,0x5375,0x5377,0x537b,0x537d,0x537f,0x5382,0x5382,0x5384,0x5384,0x538e,0x538e,0x5393,0x5393,0x5396,0x5396,0x5398,0x5398,0x539a,0x539a,0x539d,0x539d,0x539f,0x53a0,0x53a5,0x53a6,0x53aa,0x53aa,0x53ad,0x53ae,0x53b2,0x53b3,0x53b6,0x53b6,0x53b9,0x53b9,0x53bb,0x53bb,0x53c2,0x53c3,0x53c5,0x53c5,0x53c8,0x53cd,0x53d4,0x53d4,0x53d6,0x53d7,0x53d9,0x53d9,0x53db,0x53db,0x53df,0x53df,0x53e1,0x53e6,0x53e8,0x53f8,0x5401,0x5401,0x5403,0x5404,0x5408,0x5411,0x541b,0x541b,0x541d,0x541d,0x541f,0x5420,0x5426,0x5426,0x5429,0x5429,0x542b,0x542c,0x542e,0x542e,0x5431,0x5431,0x5433,0x5433,0x5436,0x5436,0x5438,0x5439,0x543b,0x543e,0x5440,0x5440,0x5442,0x5442,0x5446,0x5446,0x5448,0x5448,0x544a,0x544a,0x544e,0x544e,0x5451,0x5451,0x545d,0x545d,0x545f,0x545f,0x5462,0x5462,0x5464,0x5464,0x5466,0x5466,0x5468,0x5468,0x546a,0x546b,0x5470,0x5471,0x5473,0x5473,0x5475,0x5476,0x547b,0x547d,0x547f,0x5480,0x5484,0x5484,0x5486,0x5487,0x548b,0x5490,0x5496,0x5496,0x54a0,0x54a0,0x54a2,0x54a2,0x54a4,0x54a5,0x54a8,0x54a8,0x54ab,0x54ac,0x54af,0x54af,0x54b2,0x54b3,0x54b8,0x54b8,0x54bb,0x54bd,0x54bf,0x54c4,0x54c6,0x54c9,0x54e1,0x54e1,0x54e5,0x54e6,0x54e8,0x54e9,0x54ed,0x54ee,0x54f1,0x54f2,0x54fa,0x54fa,0x54fd,0x54fd,0x54ff,0x54ff,0x5504,0x5504,0x5506,0x5507,0x5509,0x5509,0x550e,0x5510,0x5514,0x5514,0x551c,0x551c,0x552b,0x552b,0x552e,0x552f,0x5531,0x5531,0x5533,0x5533,0x5535,0x5535,0x5539,0x5539,0x553c,0x553c,0x553e,0x553e,0x5540,0x5540,0x5542,0x5542,0x5544,0x5544,0x5546,0x5546,0x554a,0x554a,0x554f,0x554f,0x5553,0x5553,0x5556,0x5557,0x555c,0x555c,0x555e,0x555e,0x5563,0x5563,0x557b,0x5581,0x5583,0x5584,0x5586,0x5587,0x5589,0x558b,0x5591,0x5591,0x5593,0x5594,0x5598,0x559a,0x559c,0x559f,0x55a3,0x55a4,0x55a7,0x55ac,0x55ae,0x55ae,0x55b0,0x55b0,0x55c3,0x55c3,0x55c5,0x55c5,0x55c7,0x55c7,0x55c9,0x55c9,0x55d1,0x55d1,0x55d4,0x55d4,0x55da,0x55dc,0x55df,0x55e0,0x55e2,0x55e4,0x55f7,0x55f7,0x55fd,0x55ff,0x5604,0x5604,0x5606,0x5606,0x5608,0x5609,0x560c,0x5610,0x5612,0x5612,0x5614,0x5614,0x5616,0x5617,0x5629,0x5629,0x562c,0x562c,0x562f,0x562f,0x5632,0x5632,0x5634,0x5634,0x5636,0x5639,0x563b,0x563b,0x563f,0x563f,0x5641,0x5642,0x5649,0x5649,0x564b,0x564b,0x564d,0x564f,0x5653,0x5653,0x5664,0x5665,0x5668,0x566d,0x566f,0x566f,0x5672,0x5672,0x5674,0x5674,0x5676,0x5676,0x5678,0x5678,0x567a,0x567a,0x5680,0x5680,0x5684,0x5684,0x5686,0x5687,0x568f,0x568f,0x5699,0x569a,0x56a5,0x56a5,0x56a7,0x56a7,0x56ac,0x56ac,0x56ae,0x56ae,0x56b3,0x56b4,0x56b6,0x56b6,0x56bc,0x56bc,0x56c0,0x56c3,0x56c8,0x56ca,0x56cd,0x56cd,0x56d1,0x56d1,0x56d7,0x56d7,0x56da,0x56db,0x56de,0x56e0,0x56e3,0x56e3,0x56e6,0x56e7,0x56eb,0x56eb,0x56ed,0x56ee,0x56f0,0x56f0,0x56f3,0x56f3,0x56f7,0x56f7,0x56f9,0x56fa,0x56fd,0x56fd,0x56ff,0x56ff,0x5701,0x5704,0x5707,0x570b,0x570d,0x570d,0x5712,0x5713,0x5716,0x5716,0x5718,0x5718,0x571c,0x571c,0x571f,0x571f,0x5725,0x5725,0x5728,0x572a,0x572c,0x572e,0x5730,0x5730,0x573b,0x573b,0x573e,0x573e,0x5740,0x5742,0x5747,0x5747,0x574a,0x574a,0x574c,0x5751,0x5761,0x5761,0x5764,0x5764,0x5766,0x576a,0x576e,0x5771,0x5773,0x5773,0x5775,0x5775,0x5777,0x5778,0x577b,0x577c,0x5782,0x5782,0x5788,0x5788,0x578b,0x578c,0x5793,0x5793,0x5795,0x5795,0x579e,0x579e,0x57a0,0x57a0,0x57a2,0x57a4,0x57b8,0x57b8,0x57bd,0x57bd,0x57c3,0x57c3,0x57c6,0x57c9,0x57cb,0x57cb,0x57ce,0x57cf,0x57d1,0x57d2,0x57dc,0x57dc,0x57df,0x57e0,0x57e4,0x57e4,0x57e9,0x57e9,0x57ed,0x57ee,0x57f0,0x57f0,0x57f3,0x57f4,0x57f6,0x57f7,0x57f9,0x57fd,0x5800,0x5800,0x5802,0x5806,0x5808,0x580b,0x5817,0x5817,0x5819,0x5819,0x581d,0x581e,0x5820,0x5821,0x5823,0x5824,0x5826,0x5827,0x582a,0x582a,0x582d,0x582d,0x582f,0x5831,0x5834,0x5835,0x583a,0x583a,0x5840,0x5840,0x5849,0x584d,0x584f,0x5852,0x5854,0x5854,0x5857,0x585a,0x585e,0x585e,0x5861,0x5862,0x5864,0x5864,0x5869,0x5869,0x5875,0x5875,0x5879,0x5879,0x587c,0x587e,0x5880,0x5881,0x5883,0x5883,0x5885,0x5885,0x5889,0x588a,0x588c,0x588d,0x5890,0x5890,0x5893,0x5893,0x589c,0x589f,0x58a1,0x58a1,0x58a3,0x58a3,0x58a8,0x58a9,0x58ab,0x58ab,0x58ae,0x58ae,0x58b0,0x58b1,0x58b3,0x58b3,0x58ba,0x58bb,0x58be,0x58be,0x58c1,0x58c1,0x58c3,0x58c3,0x58c5,0x58c5,0x58c7,0x58c7,0x58ce,0x58ce,0x58d1,0x58d1,0x58d3,0x58d5,0x58d8,0x58da,0x58dc,0x58df,0x58e1,0x58e1,0x58e4,0x58e4,0x58eb,0x58ec,0x58ee,0x58f0,0x58f2,0x58f2,0x58f9,0x58fb,0x58fd,0x58fd,0x5902,0x5902,0x5906,0x5906,0x5908,0x5908,0x590a,0x590a,0x590f,0x5910,0x5914,0x5916,0x5919,0x591c,0x5922,0x5922,0x5924,0x5925,0x5927,0x5927,0x5929,0x592f,0x5931,0x5932,0x5937,0x5938,0x593d,0x593e,0x5944,0x5944,0x5947,0x5949,0x594c,0x594c,0x594e,0x5951,0x5953,0x5955,0x5957,0x5958,0x595a,0x595a,0x595c,0x595c,0x5960,0x5960,0x5962,0x5962,0x5967,0x5967,0x5969,0x596e,0x5972,0x5974,0x5976,0x5976,0x5978,0x5978,0x597d,0x597d,0x5982,0x5984,0x598a,0x598a,0x598c,0x598d,0x5991,0x5993,0x5996,0x5997,0x5999,0x5999,0x599d,0x599d,0x59a3,0x59a5,0x59a7,0x59a8,0x59ac,0x59ac,0x59af,0x59af,0x59b2,0x59b2,0x59b5,0x59b6,0x59b8,0x59b9,0x59bb,0x59bb,0x59be,0x59bf,0x59c1,0x59c1,0x59c3,0x59c3,0x59c6,0x59c6,0x59c8,0x59cb,0x59cd,0x59cd,0x59d0,0x59d4,0x59d9,0x59da,0x59dc,0x59de,0x59e2,0x59e6,0x59e8,0x59e8,0x59ea,0x59ec,0x59ee,0x59ee,0x59f0,0x59f0,0x59f2,0x59f2,0x59f7,0x59fc,0x59ff,0x59ff,0x5a01,0x5a01,0x5a03,0x5a03,0x5a09,0x5a0a,0x5a0d,0x5a0d,0x5a11,0x5a11,0x5a13,0x5a13,0x5a18,0x5a19,0x5a1b,0x5a1c,0x5a1f,0x5a20,0x5a23,0x5a23,0x5a25,0x5a25,0x5a27,0x5a27,0x5a29,0x5a29,0x5a2b,0x5a2b,0x5a2d,0x5a2d,0x5a35,0x5a36,0x5a3c,0x5a3c,0x5a3f,0x5a41,0x5a46,0x5a47,0x5a49,0x5a49,0x5a4b,0x5a4c,0x5a50,0x5a51,0x5a5a,0x5a5a,0x5a60,0x5a60,0x5a62,0x5a63,0x5a66,0x5a67,0x5a69,0x5a6a,0x5a6d,0x5a6d,0x5a72,0x5a72,0x5a77,0x5a77,0x5a7f,0x5a7f,0x5a84,0x5a84,0x5a8d,0x5a8d,0x5a90,0x5a90,0x5a92,0x5a93,0x5a95,0x5a95,0x5a9a,0x5a9b,0x5a9e,0x5a9f,0x5aa2,0x5aa2,0x5aa4,0x5aa4,0x5aa7,0x5aa7,0x5aaa,0x5aaa,0x5ab3,0x5ab3,0x5ab5,0x5ab5,0x5aba,0x5abf,0x5ac1,0x5ac2,0x5ac4,0x5ac4,0x5ac8,0x5ac9,0x5acb,0x5acc,0x5ad5,0x5ad7,0x5ad9,0x5adb,0x5add,0x5add,0x5ae0,0x5ae6,0x5ae9,0x5ae9,0x5aeb,0x5aeb,0x5aed,0x5aef,0x5af6,0x5af6,0x5afa,0x5afb,0x5afd,0x5afd,0x5b00,0x5b00,0x5b05,0x5b05,0x5b08,0x5b09,0x5b0b,0x5b0c,0x5b16,0x5b16,0x5b19,0x5b19,0x5b1b,0x5b1b,0x5b25,0x5b25,0x5b28,0x5b28,0x5b2a,0x5b2a,0x5b2d,0x5b2d,0x5b30,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b3e,0x5b40,0x5b43,0x5b43,0x5b45,0x5b45,0x5b4c,0x5b4c,0x5b50,0x5b51,0x5b54,0x5b58,0x5b5a,0x5b5d,0x5b5f,0x5b5f,0x5b61,0x5b61,0x5b63,0x5b66,0x5b69,0x5b69,0x5b6b,0x5b6b,0x5b70,0x5b71,0x5b75,0x5b76,0x5b78,0x5b78,0x5b7a,0x5b7a,0x5b7c,0x5b7c,0x5b7f,0x5b82,0x5b85,0x5b85,0x5b87,0x5b8c,0x5b8f,0x5b8f,0x5b93,0x5b93,0x5b95,0x5b9d,0x5b9f,0x5b9f,0x5ba2,0x5ba6,0x5bac,0x5bac,0x5bae,0x5bae,0x5bb0,0x5bb0,0x5bb3,0x5bb6,0x5bb8,0x5bb9,0x5bbf,0x5bc0,0x5bc2,0x5bc7,0x5bcc,0x5bcc,0x5bd0,0x5bd0,0x5bd2,0x5bd4,0x5bd6,0x5bd8,0x5bdb,0x5bdb,0x5bde,0x5bdf,0x5be1,0x5be2,0x5be4,0x5be9,0x5beb,0x5bf0,0x5bf5,0x5bf6,0x5bf8,0x5bfa,0x5bff,0x5bff,0x5c01,0x5c01,0x5c04,0x5c0f,0x5c11,0x5c11,0x5c14,0x5c14,0x5c16,0x5c16,0x5c19,0x5c19,0x5c1f,0x5c20,0x5c22,0x5c24,0x5c28,0x5c28,0x5c2b,0x5c2b,0x5c31,0x5c31,0x5c38,0x5c41,0x5c45,0x5c48,0x5c4b,0x5c4b,0x5c4d,0x5c4e,0x5c50,0x5c51,0x5c55,0x5c55,0x5c5b,0x5c5b,0x5c60,0x5c60,0x5c62,0x5c62,0x5c64,0x5c65,0x5c68,0x5c68,0x5c6c,0x5c6c,0x5c6f,0x5c6f,0x5c71,0x5c71,0x5c73,0x5c73,0x5c79,0x5c7a,0x5c88,0x5c88,0x5c8a,0x5c8a,0x5c8c,0x5c8c,0x5c8f,0x5c92,0x5c94,0x5c94,0x5c9d,0x5c9d,0x5ca1,0x5ca1,0x5ca3,0x5ca3,0x5ca5,0x5cad,0x5cb1,0x5cb1,0x5cb3,0x5cb3,0x5cb5,0x5cb5,0x5cb7,0x5cb8,0x5cba,0x5cba,0x5cbe,0x5cbe,0x5cc0,0x5cc0,0x5ccb,0x5ccb,0x5cd2,0x5cd2,0x5cd9,0x5cd9,0x5ce0,0x5ce0,0x5ce8,0x5ce9,0x5ced,0x5ced,0x5cef,0x5cf1,0x5cf4,0x5cf4,0x5cf6,0x5cf6,0x5cfb,0x5cfb,0x5cfd,0x5cfd,0x5d06,0x5d07,0x5d0d,0x5d0e,0x5d10,0x5d11,0x5d14,0x5d19,0x5d1b,0x5d1b,0x5d1f,0x5d1f,0x5d22,0x5d22,0x5d24,0x5d24,0x5d26,0x5d27,0x5d29,0x5d29,0x5d34,0x5d34,0x5d3d,0x5d3d,0x5d41,0x5d42,0x5d44,0x5d44,0x5d4b,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d50,0x5d53,0x5d54,0x5d69,0x5d69,0x5d6c,0x5d6c,0x5d6f,0x5d6f,0x5d71,0x5d71,0x5d81,0x5d82,0x5d84,0x5d84,0x5d86,0x5d87,0x5d8b,0x5d8b,0x5d92,0x5d92,0x5d94,0x5d95,0x5d99,0x5d99,0x5d9d,0x5d9d,0x5da0,0x5da0,0x5da2,0x5da2,0x5da7,0x5da7,0x5daa,0x5dab,0x5dae,0x5dae,0x5db0,0x5db0,0x5db7,0x5db8,0x5dba,0x5dba,0x5dbc,0x5dbe,0x5dc9,0x5dc9,0x5dcb,0x5dcb,0x5dcd,0x5dcd,0x5dd1,0x5dd3,0x5dd6,0x5dd6,0x5dda,0x5ddb,0x5ddd,0x5dde,0x5de0,0x5de2,0x5de5,0x5de8,0x5deb,0x5deb,0x5dee,0x5dee,0x5df1,0x5df5,0x5df7,0x5df9,0x5dfb,0x5dfb,0x5dfd,0x5dfe,0x5e02,0x5e03,0x5e06,0x5e06,0x5e09,0x5e09,0x5e0c,0x5e0c,0x5e11,0x5e11,0x5e15,0x5e16,0x5e19,0x5e1b,0x5e1d,0x5e1d,0x5e20,0x5e20,0x5e25,0x5e25,0x5e28,0x5e28,0x5e2b,0x5e2b,0x5e2d,0x5e2d,0x5e33,0x5e33,0x5e36,0x5e38,0x5e3d,0x5e3d,0x5e3f,0x5e40,0x5e43,0x5e45,0x5e47,0x5e47,0x5e4c,0x5e4c,0x5e4e,0x5e4e,0x5e54,0x5e55,0x5e58,0x5e58,0x5e5e,0x5e5f,0x5e61,0x5e63,0x5e68,0x5e68,0x5e6a,0x5e6c,0x5e70,0x5e74,0x5e76,0x5e80,0x5e83,0x5e84,0x5e87,0x5e87,0x5e8a,0x5e8b,0x5e8f,0x5e8f,0x5e95,0x5e97,0x5e9a,0x5e9a,0x5e9c,0x5e9c,0x5ea0,0x5ea0,0x5ea5,0x5ea8,0x5eab,0x5eab,0x5ead,0x5ead,0x5eb3,0x5eb3,0x5eb5,0x5eb8,0x5ebd,0x5ebe,0x5ec1,0x5ec2,0x5ec8,0x5ecb,0x5ecf,0x5ed1,0x5ed3,0x5ed3,0x5ed5,0x5ed6,0x5ed9,0x5edb,0x5edd,0x5ee3,0x5ee5,0x5ee5,0x5ee7,0x5ee9,0x5eec,0x5eec,0x5ef1,0x5ef1,0x5ef3,0x5ef4,0x5ef6,0x5ef7,0x5efa,0x5efb,0x5efe,0x5eff,0x5f01,0x5f01,0x5f03,0x5f04,0x5f07,0x5f08,0x5f0a,0x5f0b,0x5f0f,0x5f0f,0x5f11,0x5f15,0x5f17,0x5f18,0x5f1b,0x5f1b,0x5f1f,0x5f1f,0x5f22,0x5f22,0x5f25,0x5f27,0x5f29,0x5f29,0x5f2d,0x5f2d,0x5f31,0x5f31,0x5f34,0x5f35,0x5f37,0x5f37,0x5f3a,0x5f3a,0x5f3c,0x5f3c,0x5f3e,0x5f3e,0x5f40,0x5f40,0x5f46,0x5f46,0x5f48,0x5f48,0x5f4a,0x5f4a,0x5f4c,0x5f4c,0x5f4e,0x5f4e,0x5f50,0x5f51,0x5f53,0x5f54,0x5f56,0x5f59,0x5f5b,0x5f5b,0x5f5d,0x5f5d,0x5f61,0x5f62,0x5f64,0x5f67,0x5f69,0x5f6d,0x5f70,0x5f71,0x5f73,0x5f73,0x5f77,0x5f77,0x5f79,0x5f79,0x5f7c,0x5f7c,0x5f7f,0x5f82,0x5f85,0x5f85,0x5f87,0x5f8c,0x5f90,0x5f92,0x5f97,0x5f99,0x5f9c,0x5f9c,0x5f9e,0x5f9e,0x5fa0,0x5fa1,0x5fa3,0x5fa3,0x5fa7,0x5faa,0x5fac,0x5faf,0x5fb3,0x5fb3,0x5fb5,0x5fb5,0x5fb7,0x5fb7,0x5fb9,0x5fb9,0x5fbc,0x5fbd,0x5fc3,0x5fc5,0x5fc8,0x5fc9,0x5fcc,0x5fce,0x5fd0,0x5fd0,0x5fd2,0x5fd3,0x5fd5,0x5fd9,0x5fdc,0x5fe1,0x5fe4,0x5fe4,0x5fe8,0x5fe8,0x5feb,0x5feb,0x5fed,0x5fef,0x5ff1,0x5ff1,0x5ff5,0x5ff5,0x5ff8,0x5ff8,0x5ffb,0x5ffd,0x5fff,0x5fff,0x600a,0x600a,0x600d,0x600d,0x600f,0x600f,0x6012,0x6012,0x6014,0x6017,0x6019,0x6019,0x601b,0x601d,0x6020,0x6021,0x6025,0x602a,0x602f,0x6030,0x6033,0x6033,0x6041,0x6043,0x6046,0x6048,0x604a,0x604b,0x604d,0x604d,0x6050,0x6050,0x6052,0x6052,0x6055,0x6055,0x6059,0x605a,0x605d,0x605d,0x605f,0x6060,0x6062,0x6065,0x6068,0x606d,0x606f,0x6070,0x6075,0x6075,0x6081,0x6081,0x6083,0x6086,0x6089,0x608d,0x608f,0x608f,0x6092,0x6092,0x6094,0x6097,0x609a,0x609b,0x609f,0x60a0,0x60a2,0x60a4,0x60a7,0x60a7,0x60aa,0x60aa,0x60b0,0x60b6,0x60b8,0x60b8,0x60bb,0x60be,0x60c4,0x60c7,0x60c9,0x60c9,0x60cb,0x60cb,0x60cf,0x60cf,0x60d1,0x60d1,0x60d3,0x60d3,0x60d5,0x60d5,0x60d7,0x60e2,0x60f0,0x60f4,0x60f6,0x60fc,0x6100,0x6101,0x6103,0x6103,0x6106,0x6106,0x6108,0x6109,0x610d,0x610f,0x6114,0x6115,0x611a,0x611c,0x611e,0x611f,0x6122,0x6122,0x6127,0x6128,0x612b,0x612d,0x6130,0x6130,0x6134,0x6134,0x6137,0x6137,0x613c,0x613c,0x613e,0x613f,0x6142,0x6142,0x6144,0x6144,0x6146,0x6148,0x614a,0x614d,0x614f,0x614f,0x6152,0x6155,0x6158,0x615a,0x615c,0x615d,0x615f,0x6164,0x6167,0x6168,0x616a,0x616b,0x616e,0x616e,0x6170,0x6171,0x6173,0x6177,0x617a,0x617a,0x617c,0x617e,0x6181,0x6183,0x618a,0x618a,0x618d,0x618e,0x6190,0x6194,0x6196,0x6196,0x6198,0x619a,0x61a4,0x61a4,0x61a7,0x61a9,0x61ab,0x61ac,0x61ae,0x61af,0x61b2,0x61b2,0x61b6,0x61b6,0x61b8,0x61b8,0x61ba,0x61be,0x61c3,0x61c3,0x61c6,0x61cc,0x61cf,0x61cf,0x61d5,0x61d5,0x61d7,0x61d7,0x61de,0x61df,0x61e3,0x61e3,0x61e6,0x61e6,0x61f2,0x61f2,0x61f6,0x61f8,0x61fa,0x61fa,0x61fc,0x6200,0x6207,0x6208,0x620a,0x620a,0x620c,0x620e,0x6210,0x6212,0x6214,0x6216,0x6218,0x6218,0x621a,0x621a,0x621e,0x621f,0x6221,0x6222,0x6226,0x6227,0x6229,0x622a,0x622d,0x622e,0x6230,0x6236,0x6239,0x6239,0x623e,0x6241,0x6243,0x6243,0x6247,0x624e,0x6251,0x6253,0x6257,0x6258,0x625b,0x625c,0x625e,0x625e,0x6263,0x6263,0x6268,0x6268,0x626e,0x626e,0x6271,0x6271,0x6273,0x6273,0x6276,0x6276,0x6279,0x627a,0x627c,0x627c,0x627e,0x6280,0x6283,0x6284,0x6286,0x6286,0x6289,0x628a,0x628f,0x628f,0x6291,0x6292,0x6294,0x6298,0x629b,0x629b,0x62a6,0x62a6,0x62a8,0x62a8,0x62ab,0x62ac,0x62ae,0x62ae,0x62b1,0x62b2,0x62b5,0x62b5,0x62b9,0x62b9,0x62bc,0x62bd,0x62c2,0x62c2,0x62c4,0x62cd,0x62cf,0x62d9,0x62db,0x62dc,0x62e1,0x62e1,0x62ec,0x62ef,0x62f1,0x62f1,0x62f3,0x62f3,0x62f5,0x62f7,0x62fd,0x62ff,0x6301,0x6302,0x6307,0x6307,0x6309,0x6309,0x630c,0x630c,0x6310,0x6312,0x6328,0x6328,0x632a,0x632b,0x632f,0x632f,0x6339,0x633b,0x633d,0x633e,0x6342,0x6344,0x6346,0x6346,0x6349,0x6349,0x634c,0x6350,0x6353,0x6353,0x6355,0x6355,0x6357,0x6357,0x635a,0x635a,0x6367,0x6369,0x636b,0x636b,0x636e,0x636e,0x6371,0x6372,0x6376,0x6377,0x637a,0x637b,0x637f,0x6380,0x6383,0x6384,0x6387,0x638a,0x638c,0x638c,0x638e,0x638f,0x6392,0x6392,0x6396,0x6396,0x6398,0x6398,0x639b,0x639c,0x639f,0x63a2,0x63a5,0x63a5,0x63a7,0x63aa,0x63ac,0x63ac,0x63be,0x63be,0x63c0,0x63c0,0x63c3,0x63c4,0x63c6,0x63c6,0x63c9,0x63c9,0x63cf,0x63d0,0x63d2,0x63d2,0x63d6,0x63d6,0x63da,0x63db,0x63df,0x63e1,0x63e3,0x63e3,0x63e9,0x63e9,0x63eb,0x63eb,0x63ed,0x63ee,0x63f2,0x63f2,0x63f4,0x63f7,0x6406,0x6406,0x6409,0x6409,0x640d,0x640d,0x640f,0x640f,0x6412,0x6412,0x6414,0x6414,0x6416,0x6418,0x641c,0x641c,0x6420,0x6420,0x6422,0x6422,0x6424,0x6425,0x6428,0x6428,0x642a,0x642d,0x642f,0x6430,0x6434,0x6434,0x6436,0x6436,0x643a,0x643a,0x643e,0x643e,0x6458,0x6458,0x645b,0x645b,0x645e,0x645e,0x6460,0x6460,0x6467,0x6467,0x6469,0x6469,0x646d,0x646d,0x646f,0x646f,0x6473,0x6473,0x6478,0x647b,0x647d,0x647d,0x6485,0x6485,0x6488,0x6488,0x6490,0x6493,0x6495,0x6495,0x6499,0x649b,0x649d,0x649f,0x64a4,0x64a5,0x64a9,0x64a9,0x64ab,0x64ab,0x64ad,0x64ae,0x64b0,0x64b0,0x64b2,0x64b2,0x64bb,0x64bc,0x64be,0x64bf,0x64c1,0x64c1,0x64c4,0x64c5,0x64c7,0x64c7,0x64c9,0x64ca,0x64cd,0x64ce,0x64d0,0x64d0,0x64d2,0x64d2,0x64d4,0x64d5,0x64d7,0x64d8,0x64da,0x64da,0x64e0,0x64e3,0x64e5,0x64e7,0x64ec,0x64ed,0x64ef,0x64ef,0x64f1,0x64f2,0x64f4,0x64f4,0x64fa,0x64fa,0x64fe,0x64fe,0x6500,0x6500,0x6502,0x6502,0x6504,0x6504,0x6507,0x6507,0x650a,0x650a,0x650f,0x650f,0x6514,0x6514,0x6518,0x6519,0x651d,0x651d,0x6522,0x6524,0x652a,0x652c,0x652f,0x652f,0x6532,0x6532,0x6534,0x6539,0x653b,0x653b,0x653d,0x653f,0x6543,0x6543,0x6545,0x6545,0x6548,0x6549,0x654d,0x654f,0x6551,0x6552,0x6554,0x6559,0x655d,0x655e,0x6562,0x6563,0x6566,0x6566,0x656c,0x656d,0x6572,0x6572,0x6574,0x6575,0x6577,0x6578,0x657e,0x657e,0x6581,0x6583,0x6585,0x6585,0x6587,0x6587,0x6589,0x6589,0x658c,0x658c,0x6590,0x6591,0x6597,0x6597,0x6599,0x6599,0x659b,0x659d,0x659f,0x659f,0x65a1,0x65a1,0x65a4,0x65a5,0x65a7,0x65a7,0x65ab,0x65ad,0x65af,0x65b2,0x65b7,0x65b7,0x65b9,0x65b9,0x65bc,0x65bd,0x65bf,0x65bf,0x65c1,0x65c6,0x65ca,0x65cc,0x65cf,0x65cf,0x65d2,0x65d2,0x65d7,0x65d7,0x65e0,0x65e1,0x65e3,0x65e3,0x65e5,0x65e6,0x65e8,0x65e9,0x65ec,0x65ed,0x65f1,0x65f2,0x65f4,0x65f4,0x65fa,0x65fd,0x65ff,0x6600,0x6602,0x6603,0x6606,0x6607,0x6609,0x660a,0x660c,0x6611,0x6613,0x6615,0x661b,0x661c,0x661e,0x6621,0x6623,0x6625,0x6627,0x6628,0x662b,0x662b,0x662d,0x662d,0x662f,0x6631,0x6634,0x6637,0x663a,0x663b,0x6641,0x6644,0x6648,0x6649,0x664b,0x664c,0x664e,0x6651,0x6659,0x665b,0x665d,0x6662,0x6664,0x6669,0x666b,0x6670,0x6673,0x6674,0x6676,0x667b,0x667d,0x667d,0x667f,0x667f,0x6684,0x6684,0x6687,0x6689,0x668b,0x668c,0x668e,0x668e,0x6690,0x6691,0x6696,0x6698,0x669a,0x669a,0x669d,0x669e,0x66a0,0x66a0,0x66a2,0x66a3,0x66ab,0x66ac,0x66ae,0x66ae,0x66b1,0x66b5,0x66b8,0x66bb,0x66be,0x66c1,0x66c4,0x66c9,0x66d3,0x66d4,0x66d6,0x66d6,0x66d8,0x66de,0x66e0,0x66e0,0x66e3,0x66e3,0x66e6,0x66e6,0x66e8,0x66ea,0x66ec,0x66ec,0x66ee,0x66f0,0x66f2,0x66f4,0x66f7,0x66fa,0x66fc,0x66fc,0x66fe,0x6700,0x6703,0x6705,0x6708,0x670d,0x6710,0x6710,0x6714,0x6715,0x6717,0x6717,0x671b,0x671b,0x671d,0x6720,0x6722,0x6723,0x6726,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6734,0x6736,0x6736,0x673a,0x673a,0x673d,0x673e,0x6745,0x6746,0x6749,0x6749,0x674b,0x674c,0x674e,0x6751,0x6753,0x6753,0x6756,0x6756,0x675c,0x6760,0x6765,0x6765,0x676a,0x676a,0x676c,0x676d,0x676f,0x6773,0x6775,0x6775,0x6777,0x6777,0x677b,0x677c,0x677e,0x677f,0x6783,0x6783,0x6787,0x6787,0x6789,0x6789,0x678b,0x678c,0x678f,0x6790,0x6792,0x6793,0x6795,0x6795,0x6797,0x679a,0x679c,0x679d,0x67af,0x67b0,0x67b2,0x67b3,0x67b6,0x67b8,0x67be,0x67be,0x67c1,0x67c1,0x67c4,0x67c5,0x67ca,0x67ca,0x67cf,0x67d4,0x67d6,0x67da,0x67dd,0x67df,0x67e2,0x67e2,0x67e9,0x67e9,0x67ec,0x67ec,0x67ef,0x67f1,0x67f3,0x67f6,0x67f9,0x67f9,0x67fb,0x67fb,0x67fe,0x67ff,0x6803,0x6804,0x6810,0x6810,0x6812,0x6813,0x6816,0x6817,0x681d,0x681e,0x6821,0x6822,0x682a,0x682a,0x682e,0x682f,0x6831,0x6832,0x6834,0x6834,0x6838,0x6839,0x683b,0x683d,0x6840,0x6844,0x6846,0x6846,0x6848,0x6849,0x684e,0x684e,0x6850,0x6851,0x6853,0x6854,0x686d,0x686d,0x686f,0x686f,0x6874,0x6874,0x6876,0x6877,0x687e,0x687f,0x6881,0x6881,0x6883,0x6883,0x6885,0x6886,0x688f,0x688f,0x6893,0x6894,0x6897,0x6897,0x689b,0x689b,0x689d,0x689d,0x689f,0x68a3,0x68a7,0x68a8,0x68ad,0x68ad,0x68af,0x68b1,0x68b3,0x68b3,0x68b5,0x68b6,0x68c4,0x68c5,0x68c9,0x68cd,0x68d0,0x68d0,0x68d2,0x68d2,0x68d5,0x68d8,0x68da,0x68da,0x68df,0x68e0,0x68e3,0x68e3,0x68e7,0x68e8,0x68ec,0x68ec,0x68ee,0x68ee,0x68f2,0x68f2,0x68f9,0x68fd,0x6900,0x6901,0x6904,0x6906,0x690b,0x690b,0x690d,0x690f,0x6911,0x6912,0x6919,0x6919,0x691c,0x691c,0x6927,0x6927,0x6930,0x6930,0x6934,0x6934,0x6936,0x6936,0x6939,0x6939,0x693d,0x693d,0x693f,0x693f,0x6942,0x6942,0x694a,0x694a,0x694f,0x694f,0x6953,0x6955,0x6957,0x6957,0x6959,0x695a,0x695d,0x695e,0x6960,0x6963,0x6965,0x6965,0x6968,0x6968,0x696a,0x696f,0x6973,0x6973,0x6975,0x6975,0x6977,0x6979,0x697b,0x697b,0x697d,0x697d,0x698e,0x698e,0x6991,0x6991,0x6994,0x6995,0x6998,0x6998,0x699b,0x699c,0x699f,0x699f,0x69a4,0x69a7,0x69ad,0x69ae,0x69b0,0x69b2,0x69b4,0x69b4,0x69b7,0x69b7,0x69ba,0x69bc,0x69be,0x69c1,0x69c3,0x69c3,0x69c7,0x69c7,0x69ca,0x69d0,0x69d3,0x69d3,0x69d6,0x69d6,0x69e2,0x69e2,0x69e5,0x69ea,0x69ed,0x69ed,0x69f2,0x69f2,0x69f9,0x69f9,0x69fb,0x69fb,0x69fd,0x69fd,0x69ff,0x6a00,0x6a02,0x6a02,0x6a05,0x6a05,0x6a0a,0x6a0b,0x6a11,0x6a14,0x6a17,0x6a17,0x6a19,0x6a19,0x6a1b,0x6a1b,0x6a1e,0x6a1f,0x6a21,0x6a21,0x6a23,0x6a23,0x6a29,0x6a29,0x6a2b,0x6a2b,0x6a35,0x6a35,0x6a38,0x6a3b,0x6a3d,0x6a3d,0x6a43,0x6a45,0x6a47,0x6a4d,0x6a50,0x6a50,0x6a52,0x6a53,0x6a58,0x6a5a,0x6a5f,0x6a5f,0x6a61,0x6a62,0x6a64,0x6a64,0x6a66,0x6a66,0x6a6b,0x6a6b,0x6a72,0x6a72,0x6a75,0x6a75,0x6a7f,0x6a80,0x6a83,0x6a84,0x6a89,0x6a89,0x6a8d,0x6a8e,0x6a90,0x6a90,0x6a94,0x6a94,0x6a97,0x6a97,0x6a9c,0x6a9d,0x6a9f,0x6aa0,0x6aa2,0x6aa3,0x6aae,0x6aae,0x6ab3,0x6ab3,0x6ab6,0x6ab6,0x6abb,0x6abc,0x6abf,0x6abf,0x6ac2,0x6ac3,0x6ad3,0x6ad3,0x6ada,0x6adf,0x6ae8,0x6ae8,0x6aea,0x6aea,0x6aec,0x6aec,0x6af6,0x6af6,0x6afb,0x6afc,0x6b02,0x6b04,0x6b0a,0x6b0a,0x6b0c,0x6b0c,0x6b11,0x6b12,0x6b16,0x6b16,0x6b1e,0x6b1e,0x6b20,0x6b21,0x6b23,0x6b23,0x6b2c,0x6b2c,0x6b32,0x6b32,0x6b37,0x6b3b,0x6b3d,0x6b3f,0x6b43,0x6b43,0x6b46,0x6b47,0x6b49,0x6b4a,0x6b4c,0x6b4c,0x6b4e,0x6b4e,0x6b50,0x6b50,0x6b54,0x6b54,0x6b59,0x6b5b,0x6b5f,0x6b67,0x6b69,0x6b6a,0x6b6f,0x6b6f,0x6b72,0x6b72,0x6b77,0x6b7b,0x6b7f,0x6b80,0x6b82,0x6b84,0x6b86,0x6b86,0x6b89,0x6b8a,0x6b8d,0x6b8d,0x6b91,0x6b91,0x6b96,0x6b96,0x6b98,0x6b98,0x6b9e,0x6b9e,0x6ba2,0x6ba2,0x6ba4,0x6ba4,0x6bab,0x6bab,0x6bad,0x6baf,0x6bb2,0x6bb3,0x6bb5,0x6bb5,0x6bb7,0x6bb7,0x6bba,0x6bba,0x6bbc,0x6bbd,0x6bbf,0x6bc1,0x6bc4,0x6bc6,0x6bcb,0x6bcb,0x6bcd,0x6bcd,0x6bcf,0x6bcf,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdb,0x6beb,0x6bec,0x6bef,0x6bef,0x6bf3,0x6bf3,0x6bf8,0x6bf8,0x6bff,0x6bff,0x6c05,0x6c05,0x6c08,0x6c08,0x6c0f,0x6c11,0x6c13,0x6c14,0x6c17,0x6c17,0x6c1b,0x6c1b,0x6c23,0x6c24,0x6c33,0x6c38,0x6c3e,0x6c43,0x6c4b,0x6c4b,0x6c4e,0x6c50,0x6c52,0x6c55,0x6c57,0x6c57,0x6c59,0x6c60,0x6c66,0x6c66,0x6c68,0x6c6a,0x6c6d,0x6c6d,0x6c70,0x6c70,0x6c72,0x6c72,0x6c74,0x6c74,0x6c76,0x6c76,0x6c7a,0x6c7a,0x6c7d,0x6c7e,0x6c81,0x6c89,0x6c8c,0x6c8d,0x6c90,0x6c90,0x6c92,0x6c96,0x6c98,0x6c9b,0x6ca2,0x6ca2,0x6cab,0x6cac,0x6cae,0x6cae,0x6cb0,0x6cb1,0x6cb3,0x6cb3,0x6cb6,0x6cb6,0x6cb8,0x6cb9,0x6cbb,0x6cbf,0x6cc1,0x6cc2,0x6cc4,0x6cc6,0x6cc9,0x6cca,0x6ccc,0x6ccc,0x6cd0,0x6cd1,0x6cd3,0x6cd5,0x6cd7,0x6cd7,0x6cd9,0x6cdd,0x6ce0,0x6ce3,0x6ce5,0x6ce5,0x6ce8,0x6ce8,0x6ceb,0x6ceb,0x6cee,0x6cf1,0x6cf3,0x6cf3,0x6cff,0x6cff,0x6d04,0x6d04,0x6d07,0x6d07,0x6d0a,0x6d0c,0x6d11,0x6d12,0x6d14,0x6d14,0x6d17,0x6d17,0x6d19,0x6d19,0x6d1b,0x6d1b,0x6d1e,0x6d1f,0x6d23,0x6d23,0x6d25,0x6d25,0x6d27,0x6d2c,0x6d2e,0x6d2e,0x6d32,0x6d32,0x6d35,0x6d36,0x6d38,0x6d3e,0x6d41,0x6d41,0x6d59,0x6d5a,0x6d5c,0x6d5c,0x6d61,0x6d61,0x6d63,0x6d67,0x6d69,0x6d6a,0x6d6c,0x6d6c,0x6d6e,0x6d6f,0x6d72,0x6d72,0x6d74,0x6d74,0x6d77,0x6d79,0x6d7f,0x6d7f,0x6d82,0x6d82,0x6d85,0x6d85,0x6d87,0x6d89,0x6d8c,0x6d8f,0x6d91,0x6d91,0x6d93,0x6d97,0x6daa,0x6dac,0x6daf,0x6daf,0x6db2,0x6db2,0x6db4,0x6db5,0x6db7,0x6db8,0x6dbc,0x6dbc,0x6dbf,0x6dc0,0x6dc3,0x6dc8,0x6dcb,0x6dcc,0x6dcf,0x6dd2,0x6dd6,0x6dd6,0x6dd8,0x6dda,0x6ddd,0x6dde,0x6de0,0x6de6,0x6de8,0x6de8,0x6dea,0x6dec,0x6dee,0x6dee,0x6df1,0x6df1,0x6df3,0x6df3,0x6df5,0x6dfc,0x6e05,0x6e05,0x6e08,0x6e08,0x6e0a,0x6e0a,0x6e17,0x6e17,0x6e19,0x6e1b,0x6e1d,0x6e1d,0x6e1f,0x6e26,0x6e28,0x6e28,0x6e2b,0x6e2d,0x6e2f,0x6e2f,0x6e32,0x6e32,0x6e34,0x6e34,0x6e36,0x6e38,0x6e3a,0x6e3a,0x6e3c,0x6e3e,0x6e40,0x6e40,0x6e43,0x6e45,0x6e4a,0x6e4a,0x6e4d,0x6e4e,0x6e51,0x6e51,0x6e53,0x6e56,0x6e58,0x6e58,0x6e5b,0x6e5c,0x6e5e,0x6e5f,0x6e63,0x6e63,0x6e67,0x6e67,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e72,0x6e73,0x6e75,0x6e75,0x6e7a,0x6e7a,0x6e8f,0x6e90,0x6e95,0x6e96,0x6e98,0x6e98,0x6e9c,0x6e9d,0x6e9f,0x6e9f,0x6ea2,0x6ea2,0x6ea5,0x6ea5,0x6ea7,0x6ea8,0x6eaa,0x6eab,0x6eaf,0x6eaf,0x6eb1,0x6eb2,0x6eb5,0x6eb7,0x6eba,0x6eba,0x6ebd,0x6ebd,0x6ec2,0x6ec5,0x6ec8,0x6ec9,0x6ecb,0x6ecc,0x6ece,0x6ece,0x6ed1,0x6ed1,0x6ed3,0x6ed5,0x6ed9,0x6ed9,0x6eec,0x6eed,0x6eef,0x6eef,0x6ef2,0x6ef2,0x6ef4,0x6ef5,0x6ef7,0x6ef8,0x6efc,0x6efc,0x6efe,0x6eff,0x6f01,0x6f02,0x6f04,0x6f04,0x6f06,0x6f06,0x6f09,0x6f09,0x6f0c,0x6f0c,0x6f0f,0x6f0f,0x6f11,0x6f11,0x6f13,0x6f15,0x6f19,0x6f1a,0x6f20,0x6f20,0x6f22,0x6f24,0x6f26,0x6f28,0x6f2a,0x6f2d,0x6f30,0x6f33,0x6f38,0x6f38,0x6f3c,0x6f3c,0x6f3e,0x6f3f,0x6f41,0x6f41,0x6f4f,0x6f4f,0x6f51,0x6f52,0x6f54,0x6f54,0x6f57,0x6f5f,0x6f61,0x6f64,0x6f66,0x6f66,0x6f6d,0x6f71,0x6f74,0x6f74,0x6f78,0x6f78,0x6f7a,0x6f7a,0x6f7c,0x6f7e,0x6f81,0x6f82,0x6f84,0x6f84,0x6f86,0x6f89,0x6f8b,0x6f8e,0x6f90,0x6f90,0x6f92,0x6f92,0x6f94,0x6f98,0x6f9f,0x6f9f,0x6fa1,0x6fa1,0x6fa3,0x6fa5,0x6fa7,0x6fa8,0x6faa,0x6faa,0x6fae,0x6faf,0x6fb1,0x6fb1,0x6fb3,0x6fb3,0x6fb6,0x6fb6,0x6fb9,0x6fb9,0x6fbe,0x6fbe,0x6fc0,0x6fc3,0x6fc6,0x6fc7,0x6fc9,0x6fca,0x6fd4,0x6fd5,0x6fd8,0x6fd8,0x6fda,0x6fdb,0x6fde,0x6fe1,0x6fe4,0x6fe6,0x6fe9,0x6fe9,0x6feb,0x6fec,0x6fee,0x6fef,0x6ff1,0x6ff1,0x6ff3,0x6ff4,0x6ff6,0x6ff6,0x6ffa,0x6ffa,0x6ffe,0x6ffe,0x7001,0x7001,0x7005,0x7007,0x7009,0x7009,0x700b,0x700b,0x700f,0x700f,0x7011,0x7013,0x7015,0x7015,0x7018,0x7018,0x701a,0x701f,0x7023,0x7023,0x7026,0x7028,0x702f,0x7030,0x7032,0x7032,0x7037,0x7038,0x703c,0x703c,0x703e,0x703e,0x7044,0x7044,0x7046,0x7046,0x704c,0x704c,0x704e,0x704e,0x7050,0x7051,0x7053,0x7053,0x7058,0x7058,0x705d,0x705e,0x7063,0x7063,0x7066,0x7066,0x7069,0x7069,0x706b,0x706c,0x706f,0x7070,0x7078,0x7078,0x707c,0x707e,0x7081,0x7081,0x7085,0x7086,0x708a,0x708a,0x708e,0x708e,0x7092,0x7092,0x7095,0x7095,0x7098,0x709b,0x70a1,0x70a1,0x70a4,0x70a4,0x70a6,0x70a6,0x70ab,0x70b0,0x70b3,0x70b3,0x70b7,0x70ba,0x70c8,0x70c8,0x70ca,0x70cb,0x70cf,0x70cf,0x70d3,0x70d4,0x70d8,0x70d9,0x70dc,0x70dd,0x70df,0x70df,0x70ef,0x70ef,0x70f1,0x70f1,0x70f9,0x70fa,0x70fd,0x70fd,0x7103,0x7104,0x7106,0x7106,0x7109,0x7109,0x710c,0x710c,0x7119,0x711a,0x711c,0x711c,0x711e,0x711e,0x7120,0x7121,0x7126,0x7126,0x712d,0x7131,0x7136,0x7136,0x7143,0x7143,0x7146,0x7147,0x7149,0x714a,0x714c,0x714c,0x714e,0x714e,0x7150,0x7150,0x7152,0x7153,0x7155,0x7157,0x7159,0x7159,0x715c,0x715e,0x7162,0x7162,0x7164,0x7169,0x716c,0x716c,0x716e,0x716e,0x717d,0x717d,0x7180,0x7180,0x7184,0x7185,0x7187,0x718a,0x718f,0x718f,0x7192,0x7192,0x7194,0x7194,0x7199,0x7199,0x719b,0x719b,0x719f,0x71a2,0x71a4,0x71a4,0x71a8,0x71a9,0x71ac,0x71ac,0x71af,0x71af,0x71b1,0x71b2,0x71b9,0x71ba,0x71be,0x71be,0x71c1,0x71c1,0x71c3,0x71c3,0x71c8,0x71c9,0x71cb,0x71cb,0x71ce,0x71d0,0x71d2,0x71d2,0x71d4,0x71d6,0x71d9,0x71d9,0x71db,0x71db,0x71df,0x71e0,0x71e5,0x71e7,0x71ec,0x71ee,0x71f9,0x71f9,0x71fb,0x7201,0x7206,0x7207,0x720b,0x720d,0x7210,0x7210,0x7214,0x7214,0x7217,0x7217,0x721a,0x721b,0x721f,0x721f,0x7225,0x7225,0x7228,0x7228,0x722a,0x722a,0x722c,0x722d,0x7230,0x7230,0x7232,0x7232,0x7235,0x7236,0x7238,0x723b,0x723d,0x7240,0x7242,0x7242,0x7246,0x7248,0x724b,0x724c,0x7252,0x7254,0x7256,0x7256,0x7258,0x725b,0x725d,0x725d,0x725f,0x725f,0x7261,0x7263,0x7267,0x7267,0x7269,0x7269,0x726f,0x726f,0x7272,0x7272,0x7274,0x7274,0x7278,0x7279,0x727d,0x727d,0x7280,0x7282,0x7287,0x7287,0x728d,0x728d,0x7292,0x7292,0x7296,0x7296,0x72a2,0x72a2,0x72a7,0x72a7,0x72ac,0x72ad,0x72af,0x72af,0x72b3,0x72b5,0x72c0,0x72c0,0x72c2,0x72c2,0x72c4,0x72c4,0x72c9,0x72c9,0x72ce,0x72ce,0x72d0,0x72d0,0x72d2,0x72d2,0x72d7,0x72d7,0x72d9,0x72d9,0x72e1,0x72e2,0x72e5,0x72e5,0x72e8,0x72e9,0x72ec,0x72ec,0x72f4,0x72f4,0x72f7,0x72fd,0x7309,0x730a,0x7313,0x7313,0x7316,0x7319,0x731b,0x731d,0x7322,0x7322,0x7325,0x7325,0x7327,0x732b,0x7331,0x7331,0x7334,0x7334,0x7336,0x7337,0x733e,0x733f,0x7343,0x7345,0x734e,0x734e,0x7350,0x7350,0x7352,0x7352,0x7357,0x7358,0x735c,0x735c,0x7360,0x7360,0x7368,0x736c,0x736f,0x7370,0x7372,0x7372,0x7375,0x7375,0x7377,0x7378,0x737a,0x737c,0x7381,0x7381,0x7384,0x7384,0x7386,0x7389,0x738b,0x738b,0x738e,0x738e,0x7392,0x7392,0x7394,0x7398,0x739e,0x73a0,0x73a6,0x73a7,0x73a9,0x73ab,0x73ad,0x73ad,0x73b2,0x73b4,0x73b7,0x73b7,0x73b9,0x73b9,0x73bb,0x73bd,0x73bf,0x73c0,0x73c2,0x73c2,0x73c6,0x73c6,0x73c8,0x73ca,0x73cc,0x73cd,0x73cf,0x73cf,0x73d2,0x73d2,0x73d6,0x73d9,0x73dd,0x73de,0x73e0,0x73e0,0x73e2,0x73e6,0x73e9,0x73eb,0x73ed,0x73ee,0x73f5,0x73f5,0x73f7,0x73f9,0x73fd,0x73fe,0x7401,0x7401,0x7403,0x7407,0x7409,0x7409,0x7413,0x7413,0x7417,0x7418,0x741b,0x741b,0x741d,0x741d,0x741f,0x7422,0x7424,0x7426,0x7428,0x7428,0x742a,0x742c,0x742e,0x7436,0x7438,0x7438,0x743a,0x743a,0x743f,0x7446,0x7448,0x7449,0x744b,0x744c,0x744e,0x744e,0x7455,0x7455,0x7457,0x7457,0x7459,0x7460,0x7462,0x7465,0x7468,0x746a,0x746d,0x7473,0x747d,0x747e,0x7480,0x7480,0x7482,0x7487,0x7489,0x748c,0x7490,0x7490,0x7498,0x7498,0x749c,0x749f,0x74a1,0x74a1,0x74a3,0x74a3,0x74a5,0x74a5,0x74a7,0x74a8,0x74aa,0x74ab,0x74b0,0x74b2,0x74b5,0x74b6,0x74b8,0x74b9,0x74bc,0x74bd,0x74bf,0x74c0,0x74c6,0x74c6,0x74ca,0x74ca,0x74cd,0x74cd,0x74cf,0x74d0,0x74d3,0x74d4,0x74d8,0x74d8,0x74da,0x74dc,0x74e0,0x74e0,0x74e2,0x74e3,0x74e6,0x74e6,0x74e9,0x74e9,0x74ee,0x74ee,0x74f2,0x74f3,0x74f7,0x74f7,0x7501,0x7501,0x7503,0x7504,0x750c,0x750e,0x7511,0x7511,0x7513,0x7513,0x7515,0x7515,0x7518,0x7518,0x751a,0x751c,0x751e,0x751f,0x7522,0x7526,0x7528,0x7528,0x752b,0x752c,0x7530,0x7533,0x7537,0x7538,0x753a,0x753b,0x753f,0x753f,0x7543,0x7543,0x7547,0x7547,0x754a,0x754c,0x754e,0x754f,0x7551,0x7551,0x7553,0x7554,0x7559,0x755d,0x7560,0x7560,0x7562,0x7562,0x7564,0x7567,0x756a,0x756b,0x756f,0x7570,0x7575,0x7576,0x7578,0x7578,0x757a,0x757a,0x757f,0x757f,0x7586,0x7588,0x758a,0x758b,0x758e,0x758f,0x7591,0x7592,0x7594,0x7594,0x7599,0x759a,0x759d,0x759d,0x75a3,0x75a3,0x75a5,0x75a5,0x75a9,0x75a9,0x75ab,0x75ab,0x75b1,0x75b5,0x75b8,0x75b9,0x75bc,0x75be,0x75c0,0x75c0,0x75c2,0x75c3,0x75c5,0x75c5,0x75c7,0x75c7,0x75ca,0x75ca,0x75cd,0x75ce,0x75d2,0x75d5,0x75d8,0x75d9,0x75db,0x75db,0x75de,0x75de,0x75e2,0x75e4,0x75e7,0x75e7,0x75f0,0x75f0,0x75f2,0x75f4,0x75f9,0x75fa,0x75fc,0x75fc,0x75ff,0x7601,0x7607,0x7609,0x760b,0x760b,0x760d,0x760d,0x7610,0x7610,0x7615,0x7615,0x7619,0x7619,0x761f,0x7622,0x7624,0x7624,0x7626,0x7627,0x762f,0x7631,0x7633,0x7634,0x763b,0x763b,0x7642,0x7643,0x7646,0x7649,0x764c,0x764c,0x764e,0x764e,0x7652,0x7652,0x7655,0x7656,0x7658,0x7658,0x765c,0x765c,0x7661,0x7662,0x7664,0x7665,0x7667,0x7669,0x766c,0x7672,0x7676,0x7676,0x7678,0x7678,0x767a,0x767e,0x7680,0x7681,0x7683,0x7684,0x7686,0x7687,0x768b,0x768b,0x768e,0x768e,0x7690,0x7690,0x7692,0x7693,0x7696,0x7697,0x769a,0x769c,0x769e,0x769e,0x76a4,0x76a4,0x76ac,0x76ac,0x76ae,0x76ae,0x76b4,0x76b4,0x76b6,0x76b6,0x76b8,0x76b8,0x76ba,0x76ba,0x76bf,0x76bf,0x76c2,0x76c3,0x76c6,0x76c6,0x76c8,0x76c8,0x76ca,0x76ca,0x76cc,0x76ce,0x76d2,0x76d4,0x76d6,0x76d6,0x76d9,0x76d9,0x76db,0x76dc,0x76de,0x76df,0x76e1,0x76e1,0x76e3,0x76e5,0x76e7,0x76e7,0x76ea,0x76ea,0x76ec,0x76ec,0x76ee,0x76ee,0x76f1,0x76f2,0x76f4,0x76f4,0x76f8,0x76f9,0x76fb,0x76fc,0x76fe,0x7702,0x7704,0x7704,0x7707,0x770c,0x7710,0x7710,0x771a,0x771b,0x771e,0x7720,0x7725,0x7726,0x7728,0x7729,0x7734,0x7734,0x7737,0x773c,0x773e,0x773e,0x7740,0x7740,0x7743,0x7743,0x7746,0x7747,0x774d,0x774d,0x7752,0x7752,0x775a,0x775b,0x775f,0x7763,0x7765,0x7766,0x7768,0x7768,0x776b,0x776c,0x7777,0x7777,0x7779,0x7779,0x777d,0x777f,0x778b,0x778b,0x778d,0x778e,0x7791,0x7791,0x7796,0x7796,0x7799,0x7799,0x779e,0x779e,0x77a0,0x77a0,0x77a2,0x77a2,0x77a5,0x77a5,0x77aa,0x77aa,0x77ac,0x77ae,0x77b0,0x77b0,0x77b3,0x77b3,0x77b9,0x77b9,0x77bb,0x77bd,0x77bf,0x77bf,0x77c7,0x77c7,0x77c9,0x77c9,0x77cd,0x77cd,0x77d7,0x77d7,0x77d9,0x77dc,0x77de,0x77de,0x77e1,0x77e3,0x77e5,0x77e5,0x77e7,0x77e7,0x77e9,0x77e9,0x77ed,0x77f0,0x77f3,0x77f3,0x77f8,0x77f8,0x77fa,0x77fd,0x7802,0x7802,0x7807,0x7807,0x780c,0x780c,0x780f,0x780f,0x7811,0x7812,0x7814,0x7814,0x7822,0x7822,0x7825,0x7827,0x782c,0x782d,0x7830,0x7830,0x7832,0x7832,0x7834,0x7834,0x7843,0x7843,0x7845,0x7845,0x784f,0x784f,0x785c,0x785d,0x7860,0x7860,0x7867,0x7868,0x786a,0x786c,0x786e,0x786f,0x787c,0x787c,0x7881,0x7881,0x7884,0x7884,0x7887,0x7887,0x788c,0x788f,0x7891,0x7891,0x7893,0x7893,0x7897,0x7897,0x789f,0x789f,0x78a3,0x78a4,0x78a7,0x78a9,0x78ac,0x78ad,0x78ba,0x78bc,0x78be,0x78be,0x78c1,0x78c1,0x78c5,0x78c5,0x78c8,0x78c8,0x78ca,0x78cb,0x78ce,0x78d1,0x78d4,0x78d5,0x78da,0x78da,0x78e0,0x78e0,0x78e7,0x78e8,0x78ea,0x78ea,0x78ec,0x78ec,0x78ef,0x78ef,0x78f4,0x78f5,0x78f7,0x78f7,0x78fa,0x78fd,0x7901,0x7901,0x790c,0x790c,0x790e,0x790f,0x7911,0x7912,0x7916,0x7916,0x7919,0x7919,0x7927,0x7927,0x792a,0x792d,0x7931,0x7931,0x793a,0x793c,0x793e,0x793e,0x7940,0x7941,0x7944,0x794a,0x7950,0x7950,0x7953,0x7958,0x795a,0x7960,0x7962,0x7962,0x7965,0x7965,0x7967,0x7968,0x796d,0x796d,0x7979,0x797a,0x797c,0x797c,0x797f,0x7981,0x798a,0x798b,0x798d,0x798f,0x7991,0x7991,0x7994,0x7994,0x799b,0x799b,0x799d,0x799d,0x79a6,0x79a8,0x79aa,0x79ab,0x79ae,0x79ae,0x79b0,0x79b1,0x79b3,0x79b4,0x79b8,0x79c1,0x79c4,0x79c4,0x79c6,0x79c6,0x79c9,0x79cb,0x79d1,0x79d2,0x79d5,0x79d5,0x79d8,0x79d8,0x79de,0x79df,0x79e2,0x79e4,0x79e6,0x79e7,0x79e9,0x79ec,0x79f5,0x79f5,0x79f8,0x79f8,0x79fb,0x79fb,0x7a00,0x7a02,0x7a05,0x7a05,0x7a08,0x7a08,0x7a0a,0x7a0d,0x7a14,0x7a14,0x7a17,0x7a1a,0x7a1c,0x7a1c,0x7a1e,0x7a20,0x7a22,0x7a22,0x7a27,0x7a27,0x7a2e,0x7a2e,0x7a30,0x7a31,0x7a33,0x7a33,0x7a36,0x7a37,0x7a39,0x7a39,0x7a3b,0x7a3d,0x7a3f,0x7a40,0x7a42,0x7a42,0x7a45,0x7a46,0x7a49,0x7a49,0x7a4c,0x7a4e,0x7a57,0x7a57,0x7a60,0x7a62,0x7a66,0x7a66,0x7a69,0x7a69,0x7a6b,0x7a6b,0x7a70,0x7a70,0x7a74,0x7a76,0x7a79,0x7a7a,0x7a7d,0x7a86,0x7a88,0x7a88,0x7a8a,0x7a8a,0x7a92,0x7a93,0x7a95,0x7a99,0x7a9b,0x7a9b,0x7a9f,0x7aa0,0x7aa3,0x7aa3,0x7aa9,0x7aaa,0x7aac,0x7aac,0x7aae,0x7aaf,0x7ab3,0x7ab3,0x7ab6,0x7ab6,0x7ab9,0x7abb,0x7abe,0x7abf,0x7ac4,0x7ac5,0x7ac7,0x7ac8,0x7aca,0x7acb,0x7ad7,0x7ad7,0x7ad9,0x7ad9,0x7adc,0x7add,0x7adf,0x7ae0,0x7ae2,0x7ae3,0x7ae5,0x7ae6,0x7aea,0x7aea,0x7aed,0x7aed,0x7aef,0x7aef,0x7af4,0x7af4,0x7af6,0x7af6,0x7af8,0x7afa,0x7afd,0x7afd,0x7aff,0x7aff,0x7b06,0x7b06,0x7b08,0x7b08,0x7b0a,0x7b0a,0x7b0c,0x7b0c,0x7b0e,0x7b0f,0x7b11,0x7b12,0x7b18,0x7b19,0x7b1b,0x7b1b,0x7b1e,0x7b1e,0x7b20,0x7b20,0x7b25,0x7b28,0x7b2c,0x7b2d,0x7b2f,0x7b2f,0x7b33,0x7b33,0x7b35,0x7b35,0x7b39,0x7b39,0x7b45,0x7b46,0x7b48,0x7b49,0x7b4b,0x7b4d,0x7b4f,0x7b54,0x7b56,0x7b56,0x7b5f,0x7b60,0x7b65,0x7b67,0x7b69,0x7b69,0x7b6c,0x7b6c,0x7b6e,0x7b6e,0x7b71,0x7b71,0x7b73,0x7b73,0x7b75,0x7b75,0x7b7d,0x7b7d,0x7b87,0x7b87,0x7b8b,0x7b8b,0x7b8d,0x7b8f,0x7b92,0x7b92,0x7b94,0x7b95,0x7b97,0x7b97,0x7b99,0x7b9a,0x7b9c,0x7b9d,0x7ba0,0x7ba1,0x7bad,0x7bad,0x7bb1,0x7bb1,0x7bb4,0x7bb4,0x7bb8,0x7bb8,0x7bbe,0x7bbe,0x7bc0,0x7bc1,0x7bc4,0x7bc4,0x7bc6,0x7bc7,0x7bc9,0x7bcc,0x7bd2,0x7bd2,0x7bd4,0x7bd4,0x7bd9,0x7bd9,0x7bdb,0x7bdb,0x7bdd,0x7bdd,0x7be0,0x7be1,0x7be4,0x7be4,0x7be6,0x7be6,0x7be9,0x7bea,0x7bf3,0x7bf3,0x7bf7,0x7bf7,0x7bfe,0x7bfe,0x7c00,0x7c00,0x7c07,0x7c07,0x7c09,0x7c09,0x7c0b,0x7c0b,0x7c0f,0x7c0f,0x7c12,0x7c12,0x7c1e,0x7c21,0x7c27,0x7c27,0x7c2a,0x7c2b,0x7c37,0x7c38,0x7c3d,0x7c3f,0x7c43,0x7c43,0x7c4c,0x7c4d,0x7c50,0x7c50,0x7c52,0x7c52,0x7c54,0x7c54,0x7c5b,0x7c5c,0x7c5f,0x7c60,0x7c64,0x7c65,0x7c67,0x7c67,0x7c69,0x7c69,0x7c6c,0x7c6c,0x7c72,0x7c73,0x7c7e,0x7c7e,0x7c81,0x7c81,0x7c83,0x7c83,0x7c89,0x7c89,0x7c8d,0x7c8d,0x7c92,0x7c92,0x7c95,0x7c95,0x7c97,0x7c98,0x7c9f,0x7c9f,0x7ca2,0x7ca2,0x7ca4,0x7ca8,0x7cae,0x7cae,0x7cb1,0x7cb3,0x7cb9,0x7cb9,0x7cbc,0x7cbe,0x7cc5,0x7cc6,0x7cca,0x7cca,0x7cd5,0x7cd7,0x7cd9,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce5,0x7ce5,0x7ce7,0x7ce7,0x7cef,0x7cef,0x7cf1,0x7cf2,0x7cf4,0x7cf6,0x7cf8,0x7cfb,0x7cfe,0x7cfe,0x7d00,0x7d00,0x7d02,0x7d08,0x7d0a,0x7d0b,0x7d0d,0x7d0d,0x7d10,0x7d10,0x7d13,0x7d15,0x7d17,0x7d1c,0x7d20,0x7d22,0x7d2b,0x7d2c,0x7d2e,0x7d33,0x7d35,0x7d35,0x7d38,0x7d3a,0x7d41,0x7d46,0x7d49,0x7d49,0x7d4c,0x7d4d,0x7d50,0x7d51,0x7d55,0x7d56,0x7d59,0x7d59,0x7d5b,0x7d5c,0x7d5e,0x7d5e,0x7d61,0x7d63,0x7d66,0x7d66,0x7d68,0x7d6a,0x7d6e,0x7d6e,0x7d70,0x7d73,0x7d75,0x7d76,0x7d79,0x7d7a,0x7d7f,0x7d7f,0x7d83,0x7d83,0x7d86,0x7d86,0x7d8e,0x7d8f,0x7d93,0x7d93,0x7d98,0x7d98,0x7d9a,0x7d9a,0x7d9c,0x7d9c,0x7da0,0x7da0,0x7da2,0x7da3,0x7da5,0x7da7,0x7da9,0x7da9,0x7dab,0x7dae,0x7db0,0x7db2,0x7db4,0x7db5,0x7db8,0x7db8,0x7dba,0x7dbb,0x7dbd,0x7dbf,0x7dc4,0x7dc4,0x7dc7,0x7dc7,0x7dca,0x7dcd,0x7dcf,0x7dcf,0x7dd6,0x7dd8,0x7dda,0x7dda,0x7ddc,0x7dde,0x7de0,0x7de1,0x7de3,0x7de3,0x7de6,0x7de6,0x7de8,0x7de9,0x7dec,0x7dec,0x7def,0x7def,0x7df4,0x7df4,0x7df6,0x7df6,0x7df9,0x7df9,0x7dfb,0x7dfb,0x7e03,0x7e03,0x7e08,0x7e0b,0x7e10,0x7e11,0x7e15,0x7e15,0x7e17,0x7e18,0x7e1b,0x7e1b,0x7e1d,0x7e23,0x7e2b,0x7e2b,0x7e2e,0x7e2f,0x7e31,0x7e33,0x7e35,0x7e35,0x7e37,0x7e37,0x7e39,0x7e39,0x7e3b,0x7e3b,0x7e3d,0x7e3e,0x7e41,0x7e41,0x7e43,0x7e48,0x7e50,0x7e50,0x7e52,0x7e52,0x7e54,0x7e57,0x7e59,0x7e5a,0x7e5e,0x7e5e,0x7e61,0x7e62,0x7e69,0x7e6b,0x7e6d,0x7e6d,0x7e6f,0x7e70,0x7e76,0x7e76,0x7e79,0x7e79,0x7e7c,0x7e7e,0x7e81,0x7e82,0x7e87,0x7e88,0x7e8a,0x7e8a,0x7e8c,0x7e8d,0x7e8f,0x7e8f,0x7e93,0x7e94,0x7e96,0x7e96,0x7e98,0x7e98,0x7e9b,0x7e9c,0x7e9f,0x7e9f,0x7f36,0x7f38,0x7f3a,0x7f3a,0x7f3e,0x7f3f,0x7f43,0x7f45,0x7f47,0x7f47,0x7f4b,0x7f4e,0x7f50,0x7f55,0x7f58,0x7f58,0x7f5d,0x7f5d,0x7f5f,0x7f61,0x7f63,0x7f63,0x7f66,0x7f66,0x7f68,0x7f68,0x7f6a,0x7f6b,0x7f6e,0x7f6e,0x7f70,0x7f70,0x7f72,0x7f72,0x7f75,0x7f75,0x7f77,0x7f79,0x7f7c,0x7f7e,0x7f82,0x7f82,0x7f85,0x7f88,0x7f8a,0x7f8a,0x7f8c,0x7f8c,0x7f8e,0x7f8e,0x7f94,0x7f94,0x7f96,0x7f98,0x7f9a,0x7f9a,0x7f9d,0x7f9e,0x7fa1,0x7fa1,0x7fa4,0x7fa4,0x7fa8,0x7fa9,0x7fab,0x7fab,0x7faf,0x7faf,0x7fb2,0x7fb2,0x7fb6,0x7fb6,0x7fb8,0x7fb9,0x7fbd,0x7fbd,0x7fbf,0x7fbf,0x7fc1,0x7fc1,0x7fc5,0x7fc5,0x7fca,0x7fca,0x7fcc,0x7fcc,0x7fce,0x7fce,0x7fd2,0x7fd2,0x7fd4,0x7fd6,0x7fdb,0x7fdb,0x7fdf,0x7fe1,0x7fe3,0x7fe4,0x7fe6,0x7fe6,0x7fe9,0x7fe9,0x7feb,0x7fec,0x7fee,0x7fee,0x7ff0,0x7ff0,0x7ff3,0x7ff3,0x7ff9,0x7ffc,0x7ffe,0x7ffe,0x8000,0x8009,0x800c,0x800c,0x8010,0x8012,0x8014,0x8019,0x801e,0x801e,0x8021,0x8021,0x8026,0x8026,0x8028,0x8028,0x802c,0x802d,0x8030,0x8030,0x8033,0x8033,0x8036,0x8036,0x803d,0x803d,0x803f,0x803f,0x8043,0x8043,0x8046,0x8046,0x8048,0x8048,0x804a,0x804a,0x8052,0x8052,0x8055,0x8056,0x8058,0x8058,0x805a,0x805a,0x805e,0x805e,0x8061,0x8061,0x806f,0x8073,0x8075,0x8077,0x807d,0x8080,0x8084,0x8087,0x8089,0x8089,0x808b,0x808c,0x8093,0x8093,0x8096,0x8096,0x8098,0x8098,0x809a,0x809b,0x809d,0x809d,0x80a1,0x80a2,0x80a5,0x80a6,0x80a9,0x80ab,0x80ad,0x80ad,0x80af,0x80af,0x80b1,0x80b2,0x80b4,0x80b5,0x80ba,0x80ba,0x80c3,0x80c4,0x80c6,0x80c6,0x80ca,0x80ca,0x80cc,0x80cc,0x80ce,0x80ce,0x80d5,0x80d6,0x80d9,0x80dc,0x80de,0x80de,0x80e0,0x80e1,0x80e4,0x80e5,0x80ef,0x80ef,0x80f1,0x80f1,0x80f4,0x80f4,0x80f7,0x80f8,0x80fd,0x80fe,0x8102,0x8102,0x8105,0x810a,0x8116,0x8118,0x811a,0x811b,0x8123,0x8124,0x8127,0x8127,0x8129,0x8129,0x812b,0x812b,0x812f,0x8130,0x8139,0x813a,0x813e,0x813e,0x8141,0x8141,0x8146,0x8146,0x814a,0x814b,0x814e,0x814e,0x8150,0x8155,0x8160,0x8160,0x8164,0x8166,0x816b,0x816b,0x816d,0x816d,0x8170,0x8171,0x8174,0x8174,0x8176,0x817a,0x817f,0x8180,0x8182,0x8184,0x8186,0x8186,0x8188,0x8188,0x818a,0x818b,0x818f,0x818f,0x819a,0x819a,0x819c,0x819e,0x81a0,0x81a0,0x81a3,0x81a3,0x81a8,0x81a9,0x81b0,0x81b0,0x81b3,0x81b5,0x81b8,0x81ba,0x81bd,0x81c0,0x81c2,0x81c2,0x81c6,0x81c6,0x81ca,0x81ca,0x81cd,0x81cd,0x81cf,0x81cf,0x81d1,0x81d1,0x81d8,0x81da,0x81dd,0x81dd,0x81df,0x81e0,0x81e3,0x81e3,0x81e5,0x81e5,0x81e7,0x81e8,0x81ea,0x81ea,0x81ec,0x81ed,0x81f3,0x81f4,0x81f6,0x81f6,0x81fa,0x81fc,0x81fe,0x81fe,0x8201,0x8203,0x8205,0x8205,0x8207,0x8208,0x820a,0x820a,0x820c,0x820d,0x8210,0x8210,0x8212,0x8212,0x8216,0x8216,0x8218,0x8218,0x821b,0x821c,0x821e,0x821f,0x8221,0x8221,0x822a,0x822c,0x8233,0x8233,0x8235,0x8239,0x823d,0x823d,0x8240,0x8240,0x8245,0x8245,0x8247,0x8247,0x8251,0x8251,0x8258,0x825a,0x825f,0x825f,0x8264,0x8264,0x8266,0x8266,0x8268,0x8268,0x826a,0x826b,0x826e,0x826f,0x8271,0x8272,0x8274,0x8274,0x8276,0x8279,0x827d,0x827e,0x8283,0x8283,0x828a,0x828b,0x828d,0x828e,0x8290,0x8290,0x8292,0x8292,0x8294,0x8294,0x8298,0x829a,0x829d,0x829d,0x829f,0x829f,0x82a1,0x82a3,0x82a5,0x82b1,0x82b3,0x82b3,0x82b7,0x82b9,0x82bb,0x82bf,0x82c5,0x82c5,0x82d1,0x82d5,0x82d7,0x82d7,0x82db,0x82dc,0x82de,0x82e1,0x82e3,0x82e3,0x82e5,0x82e7,0x82e9,0x82e9,0x82eb,0x82eb,0x82f1,0x82f1,0x82f3,0x82f4,0x82f9,0x82fb,0x82fd,0x8305,0x8308,0x8309,0x8317,0x8317,0x831b,0x831d,0x8323,0x8325,0x8328,0x8328,0x832a,0x832b,0x832f,0x832f,0x8331,0x8336,0x8338,0x8339,0x833c,0x833c,0x8340,0x8340,0x8343,0x8343,0x8347,0x8347,0x8349,0x834a,0x834f,0x8352,0x8363,0x8363,0x8373,0x8373,0x8377,0x8377,0x837a,0x837b,0x8382,0x8382,0x8385,0x8385,0x8389,0x838a,0x838e,0x838e,0x8392,0x8393,0x8396,0x8396,0x8398,0x8398,0x839a,0x839b,0x839d,0x83a0,0x83a2,0x83a2,0x83a8,0x83ab,0x83bd,0x83c2,0x83c5,0x83c5,0x83c9,0x83ca,0x83cc,0x83cc,0x83d1,0x83d1,0x83d3,0x83d4,0x83d6,0x83d6,0x83d8,0x83d8,0x83dc,0x83dc,0x83df,0x83e1,0x83e9,0x83e9,0x83eb,0x83eb,0x83ef,0x83f2,0x83f4,0x83f4,0x83f6,0x83f6,0x83f9,0x83f9,0x83fb,0x83fb,0x83fd,0x83fd,0x8403,0x8404,0x8406,0x8407,0x840a,0x840e,0x8429,0x8429,0x842c,0x842c,0x8431,0x8431,0x8435,0x8435,0x8438,0x8439,0x843c,0x843d,0x8446,0x8446,0x8449,0x844a,0x8451,0x8451,0x8457,0x8457,0x845a,0x845b,0x8461,0x8461,0x8463,0x8463,0x8466,0x8466,0x8469,0x846d,0x846f,0x8471,0x8473,0x8473,0x8475,0x8475,0x8477,0x8477,0x847a,0x847a,0x8482,0x8482,0x8490,0x8491,0x8494,0x8494,0x8499,0x8499,0x849c,0x849c,0x849f,0x849f,0x84a1,0x84a1,0x84a8,0x84a8,0x84ad,0x84ad,0x84af,0x84af,0x84b2,0x84b2,0x84b4,0x84b4,0x84b8,0x84bd,0x84bf,0x84c2,0x84c4,0x84c4,0x84c6,0x84c6,0x84c9,0x84cb,0x84cd,0x84cd,0x84cf,0x84d1,0x84d3,0x84d3,0x84d6,0x84d6,0x84da,0x84da,0x84ec,0x84ef,0x84f1,0x84f1,0x84f4,0x84f4,0x84fa,0x84fa,0x84fc,0x84fd,0x8500,0x8500,0x8506,0x8506,0x850e,0x850e,0x8511,0x8511,0x8513,0x8515,0x8517,0x8518,0x851a,0x851a,0x851e,0x851f,0x8521,0x8521,0x8523,0x8523,0x8525,0x8526,0x852a,0x852a,0x852c,0x852d,0x852f,0x8530,0x853d,0x853d,0x853f,0x853f,0x8541,0x8541,0x8543,0x8543,0x8546,0x8546,0x8549,0x854b,0x854e,0x854e,0x8553,0x8553,0x8555,0x8559,0x855e,0x855e,0x8561,0x8561,0x8563,0x8564,0x8568,0x856b,0x856d,0x856d,0x8578,0x8578,0x857a,0x857a,0x857e,0x857e,0x8580,0x8580,0x8584,0x8584,0x8586,0x8587,0x8589,0x858a,0x858c,0x858c,0x858f,0x858f,0x8591,0x8591,0x8594,0x8594,0x8597,0x8597,0x8599,0x8599,0x859b,0x859b,0x859d,0x859d,0x85a4,0x85a6,0x85a8,0x85ab,0x85af,0x85b0,0x85ba,0x85ba,0x85c1,0x85c1,0x85c7,0x85c7,0x85c9,0x85c9,0x85cd,0x85d0,0x85d5,0x85d5,0x85dc,0x85dd,0x85e4,0x85e5,0x85e9,0x85ea,0x85f7,0x85f7,0x85f9,0x85fb,0x85fd,0x85fd,0x85ff,0x8600,0x8602,0x8602,0x8604,0x8604,0x8606,0x8607,0x860a,0x860b,0x8616,0x8618,0x861a,0x861a,0x861f,0x861f,0x8622,0x8622,0x8627,0x8627,0x8629,0x862a,0x862d,0x862d,0x862f,0x862f,0x863c,0x863c,0x863f,0x863f,0x8641,0x8641,0x864d,0x864e,0x8650,0x8650,0x8653,0x8655,0x865b,0x865c,0x865e,0x865f,0x8667,0x8667,0x866b,0x866c,0x866f,0x866f,0x8671,0x8671,0x8678,0x867b,0x868a,0x868d,0x8693,0x8693,0x8695,0x8695,0x86a3,0x86a4,0x86a8,0x86aa,0x86af,0x86b1,0x86b4,0x86b4,0x86c0,0x86c0,0x86c5,0x86c7,0x86c9,0x86c9,0x86cb,0x86cb,0x86d4,0x86d4,0x86d9,0x86d9,0x86db,0x86db,0x86de,0x86df,0x86e3,0x86e4,0x86e9,0x86e9,0x86ec,0x86ed,0x86f8,0x86f9,0x86fb,0x86fb,0x86fe,0x86fe,0x8700,0x8700,0x8702,0x8703,0x8706,0x8706,0x8708,0x870b,0x8711,0x8711,0x8718,0x8718,0x871a,0x871a,0x871c,0x871d,0x8721,0x8721,0x8725,0x8725,0x8728,0x8729,0x8734,0x8735,0x8737,0x8737,0x873a,0x873b,0x873f,0x8740,0x874c,0x874c,0x874e,0x874e,0x8755,0x8755,0x8757,0x8757,0x8759,0x8759,0x875f,0x8760,0x8764,0x8766,0x8768,0x8768,0x876e,0x876e,0x8774,0x8774,0x8776,0x8776,0x8778,0x8778,0x8782,0x8783,0x878c,0x878d,0x8798,0x8798,0x879e,0x879f,0x87a2,0x87a3,0x87ad,0x87ad,0x87b3,0x87b4,0x87ba,0x87bb,0x87bd,0x87bd,0x87c0,0x87c0,0x87c4,0x87c4,0x87c7,0x87c7,0x87ca,0x87cb,0x87d2,0x87d2,0x87da,0x87db,0x87e0,0x87e0,0x87e3,0x87e3,0x87ec,0x87ec,0x87ef,0x87ef,0x87f2,0x87f2,0x87f7,0x87f7,0x87f9,0x87f9,0x87fb,0x87fb,0x87fe,0x87fe,0x8805,0x8805,0x880d,0x880d,0x8811,0x8811,0x8815,0x8815,0x881f,0x881f,0x8821,0x8823,0x8831,0x8832,0x8836,0x8836,0x8839,0x8839,0x883b,0x883b,0x8840,0x8840,0x8844,0x8844,0x8846,0x8846,0x884a,0x884a,0x884c,0x884e,0x8852,0x8853,0x8857,0x8857,0x8859,0x8859,0x885b,0x885b,0x885d,0x885e,0x8861,0x8864,0x8868,0x8868,0x886b,0x886b,0x886e,0x886e,0x8870,0x8870,0x8872,0x8872,0x8877,0x8877,0x887d,0x887f,0x8881,0x8882,0x8888,0x8888,0x888b,0x888b,0x888d,0x888d,0x8892,0x8892,0x8896,0x8897,0x889b,0x889b,0x889d,0x889e,0x88a2,0x88a2,0x88aa,0x88ab,0x88b4,0x88b4,0x88c0,0x88c2,0x88c5,0x88c5,0x88ca,0x88ca,0x88cd,0x88cd,0x88cf,0x88cf,0x88d2,0x88d2,0x88d4,0x88d5,0x88d8,0x88d9,0x88dc,0x88dd,0x88df,0x88df,0x88e1,0x88e1,0x88e8,0x88e8,0x88ef,0x88ef,0x88f1,0x88f1,0x88f3,0x88f5,0x88f8,0x88f9,0x88fd,0x88fe,0x8904,0x8904,0x8907,0x8907,0x890a,0x890a,0x890c,0x890c,0x8910,0x8913,0x8915,0x8915,0x8918,0x891a,0x8925,0x8925,0x8927,0x8927,0x892a,0x892b,0x892f,0x8930,0x8936,0x8936,0x8938,0x8938,0x893a,0x893b,0x8941,0x8941,0x8944,0x8944,0x894d,0x894d,0x8952,0x8952,0x8956,0x8956,0x8958,0x8958,0x895c,0x895c,0x895e,0x8960,0x8964,0x8964,0x896a,0x896a,0x896d,0x896d,0x896f,0x896f,0x8972,0x8972,0x8974,0x8974,0x897e,0x8981,0x8983,0x8983,0x8986,0x8989,0x898b,0x898b,0x898f,0x898f,0x8993,0x8993,0x8996,0x8998,0x899a,0x899a,0x89a0,0x89a1,0x89a8,0x89aa,0x89ac,0x89ac,0x89af,0x89af,0x89b2,0x89b3,0x89b6,0x89b7,0x89ba,0x89ba,0x89bd,0x89bd,0x89bf,0x89c1,0x89d2,0x89d2,0x89d4,0x89d4,0x89d6,0x89d7,0x89da,0x89da,0x89dc,0x89dd,0x89e3,0x89e3,0x89e5,0x89e7,0x89f0,0x89f1,0x89f3,0x89f4,0x89f6,0x89f6,0x89f8,0x89f8,0x8a00,0x8a00,0x8a02,0x8a03,0x8a07,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a0e,0x8a10,0x8a18,0x8a1b,0x8a1b,0x8a1d,0x8a1d,0x8a1f,0x8a1f,0x8a22,0x8a23,0x8a25,0x8a25,0x8a2a,0x8a2a,0x8a2d,0x8a2d,0x8a31,0x8a31,0x8a33,0x8a34,0x8a36,0x8a36,0x8a3a,0x8a3c,0x8a3e,0x8a3e,0x8a41,0x8a41,0x8a46,0x8a46,0x8a4b,0x8a4b,0x8a50,0x8a51,0x8a54,0x8a58,0x8a5b,0x8a5b,0x8a5e,0x8a5e,0x8a60,0x8a63,0x8a66,0x8a66,0x8a69,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a73,0x8a75,0x8a75,0x8a79,0x8a79,0x8a7c,0x8a7c,0x8a7f,0x8a7f,0x8a82,0x8a82,0x8a84,0x8a87,0x8a8c,0x8a8d,0x8a91,0x8a91,0x8a93,0x8a93,0x8a95,0x8a95,0x8a98,0x8a98,0x8a9a,0x8a9a,0x8a9e,0x8a9e,0x8aa0,0x8aa8,0x8aaa,0x8aaa,0x8ab0,0x8ab0,0x8ab2,0x8ab2,0x8ab9,0x8ab9,0x8abc,0x8abc,0x8abe,0x8abf,0x8ac2,0x8ac2,0x8ac4,0x8ac4,0x8ac7,0x8ac7,0x8ac9,0x8ac9,0x8acb,0x8acb,0x8acd,0x8acd,0x8acf,0x8acf,0x8ad2,0x8ad2,0x8ad6,0x8ad7,0x8adb,0x8ae1,0x8ae4,0x8ae4,0x8ae6,0x8ae7,0x8aea,0x8aeb,0x8aed,0x8aee,0x8af0,0x8af4,0x8af6,0x8af8,0x8afa,0x8afa,0x8afc,0x8afc,0x8afe,0x8afe,0x8b00,0x8b02,0x8b04,0x8b04,0x8b07,0x8b07,0x8b0c,0x8b0c,0x8b0e,0x8b0e,0x8b10,0x8b11,0x8b14,0x8b14,0x8b16,0x8b17,0x8b19,0x8b1d,0x8b20,0x8b20,0x8b23,0x8b23,0x8b26,0x8b26,0x8b28,0x8b28,0x8b2b,0x8b2c,0x8b33,0x8b33,0x8b37,0x8b37,0x8b39,0x8b39,0x8b3c,0x8b3c,0x8b3e,0x8b3e,0x8b41,0x8b41,0x8b43,0x8b43,0x8b46,0x8b46,0x8b49,0x8b49,0x8b4c,0x8b4c,0x8b4e,0x8b4f,0x8b53,0x8b54,0x8b56,0x8b56,0x8b58,0x8b5a,0x8b5c,0x8b5c,0x8b5e,0x8b5f,0x8b66,0x8b66,0x8b6b,0x8b6c,0x8b6f,0x8b71,0x8b74,0x8b74,0x8b77,0x8b77,0x8b7d,0x8b7d,0x8b7f,0x8b80,0x8b83,0x8b83,0x8b89,0x8b8a,0x8b8c,0x8b8c,0x8b8e,0x8b8e,0x8b90,0x8b90,0x8b92,0x8b93,0x8b96,0x8b96,0x8b9a,0x8b9a,0x8b9c,0x8b9c,0x8b9e,0x8b9e,0x8ba0,0x8ba0,0x8c37,0x8c37,0x8c3f,0x8c3f,0x8c41,0x8c41,0x8c46,0x8c4a,0x8c4c,0x8c4c,0x8c4e,0x8c4e,0x8c50,0x8c50,0x8c55,0x8c56,0x8c5a,0x8c5a,0x8c61,0x8c62,0x8c68,0x8c68,0x8c6a,0x8c6c,0x8c73,0x8c73,0x8c78,0x8c7a,0x8c82,0x8c83,0x8c8a,0x8c8a,0x8c8c,0x8c8d,0x8c93,0x8c94,0x8c98,0x8c98,0x8c9d,0x8ca2,0x8ca7,0x8cac,0x8caf,0x8cb0,0x8cb2,0x8cb4,0x8cb6,0x8cbd,0x8cbf,0x8cc4,0x8cc6,0x8cc8,0x8cca,0x8cca,0x8cd1,0x8cd1,0x8cd3,0x8cd3,0x8cd9,0x8cdc,0x8cde,0x8cde,0x8ce0,0x8ce6,0x8cea,0x8cea,0x8cec,0x8ced,0x8cf0,0x8cf1,0x8cf3,0x8cf4,0x8cfb,0x8cfd,0x8d04,0x8d05,0x8d07,0x8d08,0x8d0a,0x8d0b,0x8d0d,0x8d0d,0x8d0f,0x8d10,0x8d13,0x8d14,0x8d16,0x8d16,0x8d1b,0x8d1b,0x8d1d,0x8d1d,0x8d64,0x8d64,0x8d66,0x8d67,0x8d6b,0x8d6b,0x8d6d,0x8d6e,0x8d70,0x8d70,0x8d73,0x8d74,0x8d76,0x8d77,0x8d81,0x8d81,0x8d85,0x8d85,0x8d8a,0x8d8a,0x8d8e,0x8d8e,0x8d90,0x8d90,0x8d99,0x8d99,0x8da0,0x8da0,0x8da3,0x8da3,0x8da8,0x8da8,0x8dab,0x8dab,0x8db2,0x8db3,0x8dba,0x8dba,0x8dbe,0x8dbe,0x8dc2,0x8dc2,0x8dc6,0x8dc6,0x8dcb,0x8dcc,0x8dce,0x8dcf,0x8dd5,0x8dd7,0x8ddb,0x8ddb,0x8ddd,0x8ddd,0x8ddf,0x8ddf,0x8de1,0x8de1,0x8de3,0x8de3,0x8de8,0x8de8,0x8dea,0x8ded,0x8def,0x8def,0x8df1,0x8df1,0x8df3,0x8df3,0x8dfc,0x8dfc,0x8e06,0x8e06,0x8e08,0x8e0a,0x8e0f,0x8e10,0x8e14,0x8e14,0x8e1d,0x8e1f,0x8e2a,0x8e2a,0x8e30,0x8e30,0x8e34,0x8e36,0x8e3a,0x8e3a,0x8e3d,0x8e3d,0x8e40,0x8e40,0x8e42,0x8e42,0x8e44,0x8e44,0x8e47,0x8e4a,0x8e4c,0x8e4c,0x8e4f,0x8e4f,0x8e55,0x8e55,0x8e59,0x8e59,0x8e5c,0x8e5c,0x8e5f,0x8e60,0x8e63,0x8e64,0x8e72,0x8e72,0x8e74,0x8e74,0x8e76,0x8e76,0x8e7b,0x8e7b,0x8e81,0x8e81,0x8e85,0x8e85,0x8e87,0x8e87,0x8e89,0x8e8b,0x8e8d,0x8e8d,0x8e90,0x8e91,0x8e93,0x8e94,0x8e99,0x8e99,0x8e9e,0x8e9e,0x8ea1,0x8ea1,0x8ea9,0x8eac,0x8eb1,0x8eb1,0x8eb3,0x8eb3,0x8ebe,0x8ebe,0x8ec0,0x8ec0,0x8ec6,0x8ec6,0x8eca,0x8ecd,0x8ed2,0x8ed2,0x8ede,0x8edf,0x8ee2,0x8ee2,0x8ee8,0x8ee8,0x8eeb,0x8eeb,0x8ef8,0x8efc,0x8efe,0x8efe,0x8f03,0x8f03,0x8f05,0x8f05,0x8f07,0x8f09,0x8f12,0x8f15,0x8f1b,0x8f1f,0x8f26,0x8f2a,0x8f2d,0x8f2d,0x8f2f,0x8f30,0x8f33,0x8f33,0x8f38,0x8f39,0x8f3b,0x8f3b,0x8f3e,0x8f40,0x8f42,0x8f42,0x8f44,0x8f46,0x8f49,0x8f49,0x8f4d,0x8f4e,0x8f52,0x8f52,0x8f54,0x8f54,0x8f57,0x8f58,0x8f5d,0x8f5f,0x8f61,0x8f64,0x8f66,0x8f66,0x8f9b,0x8f9c,0x8f9f,0x8f9f,0x8fa2,0x8fa3,0x8fa6,0x8fa6,0x8fa8,0x8fa8,0x8fad,0x8fb2,0x8fb5,0x8fb6,0x8fbb,0x8fbb,0x8fbf,0x8fc0,0x8fc2,0x8fc5,0x8fcd,0x8fce,0x8fd0,0x8fd1,0x8fd3,0x8fd5,0x8fe2,0x8fe2,0x8fe4,0x8fe6,0x8fe8,0x8fe8,0x8fea,0x8fed,0x8ff0,0x8ff0,0x8ff2,0x8ff2,0x8ff4,0x8ff4,0x8ff7,0x8ffa,0x8ffc,0x8ffd,0x8fff,0x9003,0x9005,0x9006,0x9008,0x9008,0x900b,0x9011,0x9014,0x9017,0x9019,0x901a,0x901d,0x9023,0x902e,0x902e,0x9031,0x9032,0x9034,0x9036,0x9038,0x9038,0x903c,0x903c,0x903e,0x903e,0x9041,0x9042,0x9047,0x9047,0x9049,0x904b,0x904d,0x9055,0x9058,0x9059,0x905b,0x905e,0x9060,0x9061,0x9063,0x9063,0x9068,0x9069,0x906c,0x906f,0x9072,0x9072,0x9075,0x9078,0x907a,0x907a,0x907c,0x9085,0x9087,0x9088,0x908a,0x908a,0x908c,0x908d,0x908f,0x9091,0x9095,0x9095,0x9097,0x9099,0x90a0,0x90a0,0x90a2,0x90a3,0x90a6,0x90a6,0x90a8,0x90a8,0x90aa,0x90aa,0x90af,0x90b1,0x90b3,0x90b3,0x90b5,0x90b5,0x90b8,0x90b8,0x90bd,0x90be,0x90c1,0x90c1,0x90c3,0x90c5,0x90ca,0x90ca,0x90ce,0x90ce,0x90dc,0x90de,0x90e1,0x90e2,0x90e8,0x90e8,0x90ea,0x90eb,0x90ed,0x90ed,0x90ef,0x90ef,0x90f3,0x90f5,0x90fd,0x90fd,0x9102,0x9102,0x9112,0x9112,0x9115,0x9117,0x9119,0x9119,0x911e,0x911e,0x9122,0x9123,0x9127,0x9127,0x912d,0x912d,0x9130,0x9132,0x9134,0x9134,0x913d,0x913d,0x9148,0x914e,0x9152,0x9152,0x9156,0x9157,0x9162,0x9165,0x9169,0x916a,0x916c,0x916c,0x9172,0x9172,0x9174,0x9179,0x9183,0x9183,0x9187,0x9187,0x9189,0x9189,0x918b,0x918b,0x918d,0x918d,0x9190,0x9190,0x9192,0x9192,0x919c,0x919c,0x919e,0x919e,0x91a2,0x91a2,0x91aa,0x91ac,0x91ae,0x91af,0x91b1,0x91b2,0x91b4,0x91b5,0x91bc,0x91bc,0x91c0,0x91c1,0x91c3,0x91c3,0x91c5,0x91c7,0x91c9,0x91c9,0x91cb,0x91d1,0x91d7,0x91d8,0x91dc,0x91dd,0x91e3,0x91e7,0x91e9,0x91ea,0x91ed,0x91ed,0x91f5,0x91f5,0x91ff,0x91ff,0x9207,0x9207,0x920d,0x920d,0x9210,0x9212,0x9214,0x9215,0x9217,0x9217,0x921c,0x921c,0x921e,0x921f,0x9226,0x9226,0x9231,0x9231,0x9234,0x9235,0x9237,0x9238,0x923a,0x923a,0x923f,0x9241,0x9244,0x9245,0x9249,0x9249,0x924b,0x924b,0x924d,0x9252,0x9257,0x9257,0x925b,0x925b,0x925e,0x925e,0x9262,0x9262,0x9264,0x9266,0x9277,0x9278,0x927c,0x927c,0x927e,0x927e,0x9280,0x9280,0x9283,0x9283,0x9285,0x9285,0x928b,0x928b,0x9291,0x9291,0x9293,0x9293,0x9295,0x9296,0x9298,0x929c,0x92b3,0x92b4,0x92b6,0x92b7,0x92b9,0x92b9,0x92c6,0x92c6,0x92cc,0x92cc,0x92cf,0x92cf,0x92d1,0x92d2,0x92d5,0x92d5,0x92d7,0x92d7,0x92df,0x92df,0x92e4,0x92e5,0x92ea,0x92ea,0x92f2,0x92f2,0x92f8,0x92fa,0x92fc,0x92fe,0x9300,0x9300,0x9304,0x9304,0x9306,0x9306,0x930f,0x9310,0x9315,0x9315,0x9318,0x931a,0x931e,0x9324,0x9326,0x9328,0x932a,0x932c,0x932e,0x932f,0x9348,0x934b,0x934d,0x934d,0x9351,0x9351,0x9354,0x9354,0x9357,0x9357,0x935b,0x935d,0x9364,0x9365,0x936b,0x936c,0x936e,0x936e,0x9370,0x9370,0x9372,0x9372,0x9375,0x9375,0x937c,0x937c,0x937e,0x937e,0x938a,0x938a,0x938c,0x938c,0x9394,0x9394,0x9396,0x9397,0x939a,0x939b,0x939f,0x93a1,0x93a3,0x93a4,0x93a7,0x93a7,0x93ac,0x93ad,0x93b0,0x93b0,0x93bb,0x93bb,0x93c3,0x93c3,0x93c7,0x93c8,0x93ca,0x93cc,0x93d1,0x93d1,0x93d6,0x93d8,0x93dc,0x93df,0x93e1,0x93e2,0x93e4,0x93e4,0x93e6,0x93e6,0x93e8,0x93e8,0x93f6,0x93f6,0x93f8,0x93f9,0x93fb,0x93fb,0x9403,0x9404,0x940f,0x9410,0x9413,0x9414,0x9418,0x9419,0x9425,0x9425,0x942a,0x942b,0x9435,0x9436,0x9438,0x9438,0x943a,0x943a,0x9442,0x9442,0x9444,0x9444,0x944a,0x944a,0x944c,0x944c,0x9451,0x9452,0x9455,0x9455,0x945b,0x945b,0x945e,0x945e,0x9460,0x9460,0x9462,0x9463,0x946a,0x946b,0x9470,0x9472,0x9475,0x9475,0x9477,0x9477,0x947c,0x947f,0x9485,0x9485,0x9577,0x9578,0x957f,0x9580,0x9583,0x9583,0x9588,0x958b,0x958e,0x958f,0x9591,0x9594,0x9598,0x9598,0x959c,0x959c,0x959f,0x95a0,0x95a2,0x95a5,0x95a8,0x95a9,0x95ab,0x95ad,0x95b1,0x95b1,0x95b6,0x95b6,0x95b9,0x95b9,0x95bb,0x95be,0x95c3,0x95c3,0x95c7,0x95c8,0x95ca,0x95cd,0x95d3,0x95d6,0x95da,0x95da,0x95dc,0x95dc,0x95de,0x95de,0x95e0,0x95e2,0x95e5,0x95e5,0x95e8,0x95e8,0x961c,0x961d,0x9621,0x9621,0x9624,0x9624,0x9627,0x962a,0x962d,0x962f,0x9632,0x9632,0x963b,0x963b,0x963f,0x9640,0x9642,0x9642,0x9644,0x9644,0x964b,0x964d,0x9650,0x9650,0x9654,0x9654,0x9656,0x9656,0x9658,0x9658,0x965b,0x965f,0x9661,0x9664,0x966a,0x966a,0x966c,0x966c,0x9670,0x9670,0x9672,0x9679,0x967c,0x967d,0x9684,0x9686,0x968a,0x968b,0x968d,0x968f,0x9691,0x9691,0x9694,0x9695,0x9697,0x9698,0x969b,0x969c,0x96a3,0x96a4,0x96a7,0x96aa,0x96b0,0x96b1,0x96b3,0x96b4,0x96b6,0x96b9,0x96bb,0x96bc,0x96c0,0x96c1,0x96c4,0x96c7,0x96c9,0x96c9,0x96cb,0x96ce,0x96d5,0x96d6,0x96d9,0x96de,0x96e2,0x96e3,0x96e8,0x96ea,0x96ef,0x96f0,0x96f2,0x96f2,0x96f6,0x96f7,0x96f9,0x96fb,0x9700,0x9700,0x9704,0x9709,0x970c,0x970f,0x9711,0x9711,0x9713,0x9714,0x9716,0x9716,0x9719,0x9719,0x971c,0x971c,0x971e,0x971e,0x9723,0x9723,0x9726,0x9727,0x972a,0x972a,0x9730,0x9730,0x9732,0x9732,0x9738,0x9739,0x973d,0x973d,0x9742,0x9742,0x9744,0x9744,0x9746,0x9746,0x9748,0x9749,0x974c,0x974c,0x9751,0x9752,0x9755,0x9756,0x9758,0x975e,0x9760,0x9762,0x9766,0x9766,0x9768,0x9769,0x976d,0x976d,0x9773,0x9775,0x9777,0x9777,0x977a,0x977a,0x977c,0x977c,0x9780,0x9781,0x9784,0x9785,0x978b,0x978b,0x978d,0x978d,0x978f,0x978f,0x9798,0x9798,0x97a0,0x97a0,0x97a3,0x97a3,0x97a6,0x97a6,0x97a8,0x97a8,0x97ab,0x97ad,0x97b1,0x97b1,0x97b4,0x97b4,0x97b8,0x97b9,0x97c1,0x97c1,0x97c3,0x97c3,0x97c6,0x97c6,0x97cb,0x97cd,0x97d0,0x97d0,0x97d3,0x97d3,0x97d9,0x97d9,0x97dc,0x97de,0x97e0,0x97e1,0x97e6,0x97e6,0x97ed,0x97ee,0x97f1,0x97f3,0x97f5,0x97f6,0x97fa,0x97fb,0x97fe,0x9803,0x9805,0x9806,0x9808,0x9808,0x980a,0x980a,0x980c,0x9813,0x9816,0x9818,0x981e,0x981e,0x9821,0x9821,0x9823,0x9824,0x9826,0x9826,0x982b,0x982b,0x982d,0x982e,0x9830,0x9830,0x9832,0x9832,0x9837,0x9839,0x983b,0x983c,0x983f,0x983f,0x9842,0x9842,0x9846,0x9848,0x984b,0x984e,0x9852,0x9855,0x9858,0x985a,0x985c,0x985c,0x985e,0x985e,0x9865,0x9867,0x986b,0x986b,0x986f,0x9871,0x9873,0x9875,0x98a8,0x98a8,0x98ad,0x98ad,0x98af,0x98af,0x98b1,0x98b2,0x98b6,0x98b6,0x98ba,0x98ba,0x98bc,0x98bc,0x98bf,0x98bf,0x98c2,0x98c2,0x98c4,0x98c4,0x98c6,0x98c7,0x98c9,0x98c9,0x98cb,0x98cb,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e2,0x98e6,0x98e7,0x98ea,0x98eb,0x98ed,0x98ef,0x98f1,0x98f1,0x98f4,0x98f4,0x98fb,0x98fe,0x9903,0x9903,0x9909,0x990a,0x990c,0x990c,0x9910,0x9910,0x9912,0x9915,0x9918,0x9918,0x991a,0x991a,0x991e,0x991e,0x9920,0x9920,0x9926,0x9928,0x992a,0x992a,0x992c,0x992c,0x992e,0x992e,0x9930,0x9931,0x9933,0x9933,0x9939,0x9939,0x993c,0x993d,0x9942,0x9942,0x9945,0x9945,0x9948,0x9949,0x994b,0x994d,0x9950,0x9952,0x9954,0x9955,0x9957,0x9957,0x995c,0x995c,0x995e,0x995e,0x9963,0x9963,0x9996,0x9999,0x999c,0x999d,0x999f,0x999f,0x99a1,0x99a1,0x99a3,0x99a3,0x99a5,0x99a5,0x99a7,0x99a8,0x99aa,0x99aa,0x99ac,0x99ae,0x99b0,0x99b1,0x99b3,0x99b4,0x99b6,0x99b6,0x99b9,0x99b9,0x99c1,0x99c1,0x99c4,0x99c5,0x99c8,0x99c9,0x99cf,0x99d2,0x99d5,0x99d5,0x99d8,0x99d9,0x99db,0x99df,0x99e2,0x99e2,0x99e8,0x99e8,0x99ea,0x99ea,0x99ed,0x99ee,0x99f1,0x99f1,0x99f8,0x99f8,0x99fa,0x99fb,0x99fd,0x99fd,0x99ff,0x99ff,0x9a01,0x9a05,0x9a08,0x9a08,0x9a0b,0x9a0b,0x9a0d,0x9a0f,0x9a11,0x9a11,0x9a16,0x9a16,0x9a18,0x9a19,0x9a1b,0x9a1b,0x9a2b,0x9a2b,0x9a2d,0x9a2d,0x9a30,0x9a30,0x9a35,0x9a38,0x9a3e,0x9a3e,0x9a40,0x9a45,0x9a4a,0x9a4a,0x9a4c,0x9a4f,0x9a52,0x9a52,0x9a55,0x9a55,0x9a57,0x9a58,0x9a5a,0x9a5b,0x9a5f,0x9a5f,0x9a62,0x9a62,0x9a64,0x9a65,0x9a69,0x9a6a,0x9a6c,0x9a6c,0x9aa8,0x9aa8,0x9aaa,0x9aaa,0x9ab0,0x9ab0,0x9ab8,0x9ab9,0x9abc,0x9abc,0x9abf,0x9ac0,0x9ac6,0x9ac6,0x9acf,0x9acf,0x9ad1,0x9ad1,0x9ad3,0x9ad4,0x9ad6,0x9ad8,0x9adf,0x9adf,0x9ae1,0x9ae1,0x9ae3,0x9ae3,0x9ae5,0x9ae6,0x9aeb,0x9aeb,0x9aed,0x9aee,0x9af0,0x9af0,0x9af2,0x9af2,0x9af4,0x9af4,0x9af9,0x9afb,0x9afd,0x9afd,0x9b02,0x9b02,0x9b05,0x9b06,0x9b0a,0x9b0b,0x9b0d,0x9b0d,0x9b10,0x9b10,0x9b12,0x9b12,0x9b16,0x9b16,0x9b18,0x9b1a,0x9b1f,0x9b1f,0x9b22,0x9b23,0x9b25,0x9b25,0x9b27,0x9b2a,0x9b2e,0x9b2f,0x9b31,0x9b32,0x9b3a,0x9b3a,0x9b3c,0x9b3c,0x9b41,0x9b45,0x9b48,0x9b48,0x9b4b,0x9b4b,0x9b4d,0x9b4f,0x9b51,0x9b51,0x9b54,0x9b54,0x9b58,0x9b58,0x9b5a,0x9b5a,0x9b66,0x9b66,0x9b6f,0x9b6f,0x9b74,0x9b74,0x9b80,0x9b80,0x9b83,0x9b83,0x9b8e,0x9b8e,0x9b90,0x9b93,0x9b97,0x9b97,0x9b9f,0x9b9f,0x9ba7,0x9ba8,0x9baa,0x9bab,0x9bad,0x9bae,0x9bb9,0x9bb9,0x9bc1,0x9bc1,0x9bc6,0x9bc6,0x9bc9,0x9bca,0x9bd4,0x9bd4,0x9bd6,0x9bd6,0x9bdb,0x9bdb,0x9be2,0x9be2,0x9be4,0x9be4,0x9be8,0x9be8,0x9bf7,0x9bf7,0x9c08,0x9c08,0x9c0a,0x9c0a,0x9c0c,0x9c0d,0x9c10,0x9c10,0x9c12,0x9c13,0x9c15,0x9c15,0x9c24,0x9c25,0x9c2d,0x9c2f,0x9c31,0x9c32,0x9c35,0x9c35,0x9c39,0x9c3b,0x9c3e,0x9c3e,0x9c47,0x9c47,0x9c49,0x9c49,0x9c4f,0x9c4f,0x9c52,0x9c53,0x9c57,0x9c57,0x9c60,0x9c60,0x9c63,0x9c63,0x9c67,0x9c67,0x9c78,0x9c78,0x9c7b,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9ce9,0x9cf3,0x9cf4,0x9cf6,0x9cf6,0x9d03,0x9d03,0x9d06,0x9d09,0x9d0c,0x9d0c,0x9d12,0x9d12,0x9d15,0x9d15,0x9d18,0x9d19,0x9d1b,0x9d1b,0x9d1e,0x9d1f,0x9d23,0x9d23,0x9d25,0x9d26,0x9d28,0x9d28,0x9d2f,0x9d30,0x9d36,0x9d36,0x9d3b,0x9d3b,0x9d41,0x9d42,0x9d44,0x9d44,0x9d51,0x9d51,0x9d53,0x9d54,0x9d5d,0x9d5e,0x9d60,0x9d61,0x9d66,0x9d66,0x9d69,0x9d69,0x9d6c,0x9d6c,0x9d6f,0x9d70,0x9d72,0x9d72,0x9d77,0x9d77,0x9d7b,0x9d7b,0x9d7e,0x9d7e,0x9d84,0x9d84,0x9d89,0x9d8a,0x9d96,0x9d96,0x9d9a,0x9d9a,0x9da1,0x9da1,0x9da4,0x9da4,0x9da9,0x9da9,0x9dac,0x9dac,0x9daf,0x9daf,0x9db4,0x9db5,0x9db8,0x9db9,0x9dbb,0x9dbb,0x9dbf,0x9dbf,0x9dc1,0x9dc2,0x9dc4,0x9dc4,0x9dc7,0x9dc7,0x9dd3,0x9dd3,0x9dd6,0x9dd7,0x9dd9,0x9dd9,0x9de6,0x9de6,0x9de9,0x9deb,0x9df0,0x9df3,0x9df8,0x9dfa,0x9dfd,0x9dfd,0x9dff,0x9dff,0x9e07,0x9e07,0x9e0f,0x9e0f,0x9e15,0x9e15,0x9e1a,0x9e1f,0x9e75,0x9e75,0x9e77,0x9e77,0x9e79,0x9e7b,0x9e7d,0x9e7d,0x9e7f,0x9e80,0x9e82,0x9e82,0x9e84,0x9e84,0x9e8b,0x9e8c,0x9e8f,0x9e8f,0x9e91,0x9e93,0x9e97,0x9e98,0x9e9d,0x9e9f,0x9ea4,0x9ea6,0x9ea9,0x9eaa,0x9eaf,0x9eaf,0x9eb4,0x9eb5,0x9ebb,0x9ebb,0x9ebd,0x9ebf,0x9ec3,0x9ec5,0x9ecc,0x9ed1,0x9ed4,0x9ed4,0x9ed6,0x9ed6,0x9ed8,0x9ed8,0x9eda,0x9ede,0x9ee0,0x9ee0,0x9ee5,0x9ee5,0x9ee8,0x9ee8,0x9eee,0x9eef,0x9ef2,0x9ef2,0x9ef4,0x9ef7,0x9ef9,0x9f00,0x9f02,0x9f02,0x9f04,0x9f04,0x9f07,0x9f0a,0x9f0e,0x9f0e,0x9f10,0x9f10,0x9f13,0x9f14,0x9f17,0x9f17,0x9f19,0x9f19,0x9f20,0x9f20,0x9f22,0x9f22,0x9f2b,0x9f2c,0x9f2f,0x9f2f,0x9f34,0x9f34,0x9f38,0x9f39,0x9f3b,0x9f3b,0x9f3e,0x9f3e,0x9f4a,0x9f4b,0x9f4e,0x9f4e,0x9f50,0x9f50,0x9f52,0x9f52,0x9f54,0x9f55,0x9f57,0x9f57,0x9f5f,0x9f61,0x9f66,0x9f67,0x9f69,0x9f6c,0x9f72,0x9f72,0x9f76,0x9f77,0x9f7f,0x9f7f,0x9f8d,0x9f8e,0x9f90,0x9f92,0x9f94,0x9f95,0x9f99,0x9f99,0x9f9c,0x9f9d,0x9f9f,0x9fa0,0x9fa2,0x9fa2,0x9fa5,0x9fa5,0xa960,0xa97c,0xac00,0xd7a3,0xd7b0,0xd7c6,0xd7cb,0xd7fb,0xf900,0xf95e,0xf960,0xf9a9,0xf9ab,0xfa0b,0xfa12,0xfa12,0xfa15,0xfa17,0xfa19,0xfa1e,0xfa22,0xfa22,0xfa26,0xfa26,0xfa2a,0xfa2c,0xfa2e,0xfa31,0xfa33,0xfa3d,0xfa3f,0xfa3f,0xfa41,0xfa41,0xfa43,0xfa55,0xfa57,0xfa57,0xfa59,0xfa68,0xfa6a,0xfa6a,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x200d7,0x200d7,0x2012c,0x2012c,0x205ca,0x205ca,0x20628,0x20628,0x20984,0x20984,0x21155,0x21155,0x2128d,0x2128d,0x21594,0x21594,0x21727,0x21727,0x21f5c,0x21f5c,0x224b0,0x224b0,0x224ed,0x224ed,0x2294f,0x2294f,0x22c6f,0x22c6f,0x22ee0,0x22ee0,0x230fd,0x230fd,0x23343,0x23343,0x2363b,0x2363b,0x23ad9,0x23ad9,0x242f1,0x242f1,0x2439d,0x2439d,0x248e9,0x248e9,0x248f0,0x248f0,0x24a01,0x24a01,0x24a12,0x24a12,0x25055,0x25055,0x2533e,0x2533e,0x253b5,0x253b5,0x253fe,0x253fe,0x25832,0x25832,0x2583a,0x2583a,0x25874,0x25874,0x25978,0x25978,0x25ad7,0x25ad7,0x25b97,0x25b97,0x25e44,0x25e44,0x26057,0x26057,0x265a4,0x265a4,0x267d8,0x267d8,0x26951,0x26951,0x27144,0x27144,0x275ff,0x275ff,0x27625,0x27625,0x278b2,0x278b2,0x27a51,0x27a51,0x27b02,0x27b02,0x27cef,0x27cef,0x27e7d,0x27e7d,0x27f1b,0x27f1b,0x27fb7,0x27fb7,0x283f6,0x283f6,0x284dc,0x284dc,0x28d8a,0x28d8a,0x28da1,0x28da1,0x28e0f,0x28e0f,0x291d5,0x291d5,0x291e3,0x291e3,0x294de,0x294de,0x29509,0x29509,0x2967f,0x2967f,0x29810,0x29810,0x2983b,0x2983b,0x2a2ad,0x2a2ad,0x2a4d0,0x2a4d0,0x2a664,0x2a664,0x2c115,0x2c115,0x2c7d3,0x2c7d3,0x2d544,0x2d544,0x2e569,0x2e569,0x2f815,0x2f815,0x2f818,0x2f818,0x2f81a,0x2f81a,0x2f82c,0x2f82c,0x2f833,0x2f833,0x2f852,0x2f852,0x2f862,0x2f862,0x2f877,0x2f877,0x2f884,0x2f884,0x2f8b2,0x2f8b2,0x2f8ed,0x2f8ed,0x2f8fc,0x2f8fc,0x2f920,0x2f920,0x2f96c,0x2f96c,0x2f9d0,0x2f9d0,0x2f9df,0x2f9df,0x30729,0x30729,0x30ede,0x30ede,]), + NotoFont.fromFlatRanges('Noto Sans Kaithi', 'http://fonts.gstatic.com/s/notosanskaithi/v15/buEtppS9f8_vkXadMBJJu0tWjLwjQi0KdoZIKlo.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x966,0x96f,0x200b,0x200d,0x2010,0x2010,0x25cc,0x25cc,0xa830,0xa839,0x11080,0x110c1,0x110cd,0x110cd,]), + NotoFont.fromFlatRanges('Noto Sans Kannada', 'http://fonts.gstatic.com/s/notosanskannada/v21/8vIs7xs32H97qzQKnzfeXycxXZyUmySvZWItmf1fe6TVmgop9ndpS-BqHEyGrDvNzSIMLsPKrkY.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xc80,0xc8c,0xc8e,0xc90,0xc92,0xca8,0xcaa,0xcb3,0xcb5,0xcb9,0xcbc,0xcc4,0xcc6,0xcc8,0xcca,0xccd,0xcd5,0xcd6,0xcde,0xcde,0xce0,0xce3,0xce6,0xcef,0xcf1,0xcf2,0x1cd0,0x1cd0,0x1cd2,0x1cd2,0x1cda,0x1cda,0x1cf2,0x1cf2,0x1cf4,0x1cf5,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa835,]), + NotoFont.fromFlatRanges('Noto Sans Kayah Li', 'http://fonts.gstatic.com/s/notosanskayahli/v18/B50nF61OpWTRcGrhOVJJwOMXdca6Yecki3E06x2jVTX3WCc3CZH4EXLuKVM.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x200c,0x200d,0x2010,0x2010,0x25cc,0x25cc,0xa900,0xa92f,]), + NotoFont.fromFlatRanges('Noto Sans Kharoshthi', 'http://fonts.gstatic.com/s/notosanskharoshthi/v15/Fh4qPiLjKS30-P4-pGMMXCCfvkc5Vd7KE5z4rFyx5mR1.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x200b,0x200d,0x2010,0x2010,0x25cc,0x25cc,0x10a00,0x10a03,0x10a05,0x10a06,0x10a0c,0x10a13,0x10a15,0x10a17,0x10a19,0x10a35,0x10a38,0x10a3a,0x10a3f,0x10a48,0x10a50,0x10a58,]), + NotoFont.fromFlatRanges('Noto Sans Khmer', 'http://fonts.gstatic.com/s/notosanskhmer/v18/ijw3s5roRME5LLRxjsRb-gssOenAyendxrgV2c-Zw-9vbVUti_Z_dWgtWYuNAJz4kAbrddiA.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1780,0x17dd,0x17e0,0x17e9,0x17f0,0x17f9,0x19e0,0x19ff,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Khojki', 'http://fonts.gstatic.com/s/notosanskhojki/v15/-nFnOHM29Oofr2wohFbTuPPKVWpmK_d709jy92k.ttf', [0x20,0x20,0xa0,0xa0,0xae6,0xaef,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11200,0x11211,0x11213,0x1123e,]), + NotoFont.fromFlatRanges('Noto Sans Khudawadi', 'http://fonts.gstatic.com/s/notosanskhudawadi/v15/fdNi9t6ZsWBZ2k5ltHN73zZ5hc8HANlHIjRnVVXz9MY.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x965,0x200c,0x200d,0x2013,0x2014,0x25cc,0x25cc,0xa830,0xa839,0x112b0,0x112ea,0x112f0,0x112f9,]), + NotoFont.fromFlatRanges('Noto Sans Lao', 'http://fonts.gstatic.com/s/notosanslao/v24/bx6lNx2Ol_ixgdYWLm9BwxM3NW6BOkuf763Clj73CiQ_J1Djx9pidOt4ccbdf5MK3riB2w.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0xe81,0xe82,0xe84,0xe84,0xe87,0xe88,0xe8a,0xe8a,0xe8d,0xe8d,0xe94,0xe97,0xe99,0xe9f,0xea1,0xea3,0xea5,0xea5,0xea7,0xea7,0xeaa,0xeab,0xead,0xeb9,0xebb,0xebd,0xec0,0xec4,0xec6,0xec6,0xec8,0xecd,0xed0,0xed9,0xedc,0xedf,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ad,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Lepcha', 'http://fonts.gstatic.com/s/notosanslepcha/v15/0QI7MWlB_JWgA166SKhu05TekNS32AJstqBXgd4.ttf', [0x20,0x20,0xa0,0xa0,0x1c00,0x1c37,0x1c3b,0x1c49,0x1c4d,0x1c4f,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Limbu', 'http://fonts.gstatic.com/s/notosanslimbu/v15/3JnlSDv90Gmq2mrzckOBBRRoNJVj0MF3OHRDnA.ttf', [0x20,0x20,0xa0,0xa0,0x965,0x965,0x1900,0x191e,0x1920,0x192b,0x1930,0x193b,0x1940,0x1940,0x1944,0x194f,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Linear A', 'http://fonts.gstatic.com/s/notosanslineara/v16/oPWS_l16kP4jCuhpgEGmwJOiA18FZj22zmHQAGQicw.ttf', [0x20,0x20,0xa0,0xa0,0x10600,0x10736,0x10740,0x10755,0x10760,0x10767,]), + NotoFont.fromFlatRanges('Noto Sans Linear B', 'http://fonts.gstatic.com/s/notosanslinearb/v15/HhyJU4wt9vSgfHoORYOiXOckKNB737IV3BkFTq4EPw.ttf', [0x20,0x20,0xa0,0xa0,0x10000,0x1000b,0x1000d,0x10026,0x10028,0x1003a,0x1003c,0x1003d,0x1003f,0x1004d,0x10050,0x1005d,0x10080,0x100fa,0x10100,0x10102,0x10107,0x10133,0x10137,0x1013f,]), + NotoFont.fromFlatRanges('Noto Sans Lisu', 'http://fonts.gstatic.com/s/notosanslisu/v21/uk-3EGO3o6EruUbnwovcYhz6kh57_nqbcTdjJnHP2Vwt29IlxkVdig.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2cd,0x2cd,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0x300a,0x300b,0xa4d0,0xa4ff,0x11fb0,0x11fb0,]), + NotoFont.fromFlatRanges('Noto Sans Lycian', 'http://fonts.gstatic.com/s/notosanslycian/v15/QldVNSNMqAsHtsJ7UmqxBQA9r8wA5_naCJwn00E.ttf', [0x20,0x20,0xa0,0xa0,0x10280,0x1029c,]), + NotoFont.fromFlatRanges('Noto Sans Lydian', 'http://fonts.gstatic.com/s/notosanslydian/v15/c4m71mVzGN7s8FmIukZJ1v4ZlcPReUPXMoIjEQI.ttf', [0x20,0x20,0xa0,0xa0,0x10920,0x10939,0x1093f,0x1093f,]), + NotoFont.fromFlatRanges('Noto Sans Mahajani', 'http://fonts.gstatic.com/s/notosansmahajani/v15/-F6sfiVqLzI2JPCgQBnw60Agp0JrvD5Fh8ARHNh4zg.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x96f,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11150,0x11176,]), + NotoFont.fromFlatRanges('Noto Sans Malayalam', 'http://fonts.gstatic.com/s/notosansmalayalam/v21/sJoi3K5XjsSdcnzn071rL37lpAOsUThnDZIfPdbeSNzVakglNM-Qw8EaeB8Nss-_RuD9BFzEr6HxEA.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x323,0x323,0x326,0x328,0x951,0x952,0x964,0x965,0xd00,0xd0c,0xd0e,0xd10,0xd12,0xd44,0xd46,0xd48,0xd4a,0xd4f,0xd54,0xd63,0xd66,0xd7f,0x1cda,0x1cda,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa832,]), + NotoFont.fromFlatRanges('Noto Sans Mandaic', 'http://fonts.gstatic.com/s/notosansmandaic/v15/cIfnMbdWt1w_HgCcilqhKQBo_OsMI5_A_gMk0izH.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x840,0x85b,0x85e,0x85e,0x200c,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Manichaean', 'http://fonts.gstatic.com/s/notosansmanichaean/v15/taiVGntiC4--qtsfi4Jp9-_GkPZZCcrfekqCNTtFCtdX.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x200c,0x200d,0x25cc,0x25cc,0xfe00,0xfe00,0x10ac0,0x10ae6,0x10aeb,0x10af6,]), + NotoFont.fromFlatRanges('Noto Sans Marchen', 'http://fonts.gstatic.com/s/notosansmarchen/v15/aFTO7OZ_Y282EP-WyG6QTOX_C8WZMHhPk652ZaHk.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x11c70,0x11c8f,0x11c92,0x11ca7,0x11ca9,0x11cb6,]), + NotoFont.fromFlatRanges('Noto Sans Masaram Gondi', 'http://fonts.gstatic.com/s/notosansmasaramgondi/v15/6xK_dThFKcWIu4bpRBjRYRV7KZCbUq6n_1kPnuGe7RI9WSWX.ttf', [0x20,0x22,0x25,0x25,0x27,0x2f,0x3a,0x3f,0xa0,0xa0,0xd7,0xd7,0xf7,0xf7,0x964,0x965,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x2212,0x2212,0x25cc,0x25cc,0x11d00,0x11d06,0x11d08,0x11d09,0x11d0b,0x11d36,0x11d3a,0x11d3a,0x11d3c,0x11d3d,0x11d3f,0x11d47,0x11d50,0x11d59,]), + NotoFont.fromFlatRanges('Noto Sans Math', 'http://fonts.gstatic.com/s/notosansmath/v15/7Aump_cpkSecTWaHRlH2hyV5UHkG-V048PW0.ttf', [0x20,0x7e,0xa0,0xa0,0xa7,0xa7,0xac,0xac,0xb1,0xb1,0xd7,0xd7,0xf7,0xf7,0x302,0x303,0x305,0x305,0x307,0x308,0x330,0x330,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x3d1,0x3d1,0x3d5,0x3d6,0x3f0,0x3f1,0x3f4,0x3f5,0x2032,0x2037,0x2057,0x2057,0x20d0,0x20dc,0x20e1,0x20e1,0x20e5,0x20ef,0x2102,0x2102,0x210a,0x210e,0x2110,0x2112,0x2115,0x2115,0x2119,0x211d,0x2124,0x2124,0x2128,0x2128,0x212c,0x212d,0x212f,0x2131,0x2133,0x2138,0x213c,0x2140,0x2145,0x2149,0x2190,0x21ae,0x21b0,0x21e5,0x21f1,0x21f2,0x21f4,0x22ff,0x2308,0x230b,0x2310,0x2310,0x2319,0x2319,0x231c,0x2321,0x2336,0x237a,0x237c,0x237c,0x2395,0x2395,0x239b,0x23b6,0x23d0,0x23d0,0x23dc,0x23e1,0x2474,0x2475,0x25af,0x25af,0x25b3,0x25b3,0x25b7,0x25b7,0x25bd,0x25bd,0x25c1,0x25c1,0x25ca,0x25ca,0x25cc,0x25cc,0x25fb,0x25fb,0x266d,0x266f,0x27c0,0x27ff,0x2900,0x2aff,0x2b0e,0x2b11,0x2b30,0x2b4c,0x2bfe,0x2bfe,0xff5b,0xff5b,0xff5d,0xff5d,0x1d400,0x1d454,0x1d456,0x1d49c,0x1d49e,0x1d49f,0x1d4a2,0x1d4a2,0x1d4a5,0x1d4a6,0x1d4a9,0x1d4ac,0x1d4ae,0x1d4b9,0x1d4bb,0x1d4bb,0x1d4bd,0x1d4c3,0x1d4c5,0x1d505,0x1d507,0x1d50a,0x1d50d,0x1d514,0x1d516,0x1d51c,0x1d51e,0x1d539,0x1d53b,0x1d53e,0x1d540,0x1d544,0x1d546,0x1d546,0x1d54a,0x1d550,0x1d552,0x1d6a5,0x1d6a8,0x1d7cb,0x1d7ce,0x1d7ff,0x1ee00,0x1ee03,0x1ee05,0x1ee1f,0x1ee21,0x1ee22,0x1ee24,0x1ee24,0x1ee27,0x1ee27,0x1ee29,0x1ee32,0x1ee34,0x1ee37,0x1ee39,0x1ee39,0x1ee3b,0x1ee3b,0x1ee42,0x1ee42,0x1ee47,0x1ee47,0x1ee49,0x1ee49,0x1ee4b,0x1ee4b,0x1ee4d,0x1ee4f,0x1ee51,0x1ee52,0x1ee54,0x1ee54,0x1ee57,0x1ee57,0x1ee59,0x1ee59,0x1ee5b,0x1ee5b,0x1ee5d,0x1ee5d,0x1ee5f,0x1ee5f,0x1ee61,0x1ee62,0x1ee64,0x1ee64,0x1ee67,0x1ee6a,0x1ee6c,0x1ee72,0x1ee74,0x1ee77,0x1ee79,0x1ee7c,0x1ee7e,0x1ee7e,0x1ee80,0x1ee89,0x1ee8b,0x1ee9b,0x1eea1,0x1eea3,0x1eea5,0x1eea9,0x1eeab,0x1eebb,0x1eef0,0x1eef1,]), + NotoFont.fromFlatRanges('Noto Sans Mayan Numerals', 'http://fonts.gstatic.com/s/notosansmayannumerals/v15/PlIuFk25O6RzLfvNNVSivR09_KqYMwvvDKYjfIiE68oo6eepYQ.ttf', [0x20,0x20,0xa0,0xa0,0x1d2e0,0x1d2f3,]), + NotoFont.fromFlatRanges('Noto Sans Medefaidrin', 'http://fonts.gstatic.com/s/notosansmedefaidrin/v19/WwkzxOq6Dk-wranENynkfeVsNbRZtbOIdLb1exeM4ZeuabBfmErWlT318e5A3rw.ttf', [0x20,0x20,0xa0,0xa0,0x16e40,0x16e9a,]), + NotoFont.fromFlatRanges('Noto Sans Meetei Mayek', 'http://fonts.gstatic.com/s/notosansmeeteimayek/v10/HTxAL3QyKieByqY9eZPFweO0be7M21uSphSdhqILnmrRfJ8t_1TJ_vTW5PgeFYVa.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xaae0,0xaaf6,0xabc0,0xabed,0xabf0,0xabf9,]), + NotoFont.fromFlatRanges('Noto Sans Meroitic', 'http://fonts.gstatic.com/s/notosansmeroitic/v16/IFS5HfRJndhE3P4b5jnZ3ITPvC6i00UDgDhTiKY9KQ.ttf', [0x20,0x20,0x3a,0x3a,0xa0,0xa0,0x2026,0x2026,0x205d,0x205d,0x10980,0x109b7,0x109bc,0x109cf,0x109d2,0x109ff,]), + NotoFont.fromFlatRanges('Noto Sans Miao', 'http://fonts.gstatic.com/s/notosansmiao/v15/Dxxz8jmXMW75w3OmoDXVV4zyZUjgUYVslLhx.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x16f00,0x16f4a,0x16f4f,0x16f87,0x16f8f,0x16f9f,]), + NotoFont.fromFlatRanges('Noto Sans Modi', 'http://fonts.gstatic.com/s/notosansmodi/v15/pe03MIySN5pO62Z5YkFyT7jeav5qWVAgVol-.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11600,0x11644,0x11650,0x11659,]), + NotoFont.fromFlatRanges('Noto Sans Mongolian', 'http://fonts.gstatic.com/s/notosansmongolian/v15/VdGCAYADGIwE0EopZx8xQfHlgEAMsrToxLsg6-av1x0.ttf', [0x20,0x22,0x28,0x29,0x2d,0x2d,0x3f,0x3f,0xa0,0xa0,0x1800,0x180e,0x1810,0x1819,0x1820,0x1878,0x1880,0x18aa,0x200c,0x200d,0x2013,0x2014,0x201c,0x201d,0x202f,0x202f,0x2048,0x2049,0x2460,0x2473,0x25cc,0x25cc,0x3001,0x3002,0x300a,0x300f,0xfe3d,0xfe3e,0xfe41,0xfe44,0x11660,0x1166c,]), + NotoFont.fromFlatRanges('Noto Sans Mro', 'http://fonts.gstatic.com/s/notosansmro/v15/qWcsB6--pZv9TqnUQMhe9b39WDzRtjkho4M.ttf', [0x20,0x20,0xa0,0xa0,0x16a40,0x16a5e,0x16a60,0x16a69,0x16a6e,0x16a6f,]), + NotoFont.fromFlatRanges('Noto Sans Multani', 'http://fonts.gstatic.com/s/notosansmultani/v15/9Bty3ClF38_RfOpe1gCaZ8p30BOFO1A0pfCs5Kos.ttf', [0x20,0x20,0xa0,0xa0,0xa66,0xa6f,0x11280,0x11286,0x11288,0x11288,0x1128a,0x1128d,0x1128f,0x1129d,0x1129f,0x112a9,]), + NotoFont.fromFlatRanges('Noto Sans Myanmar', 'http://fonts.gstatic.com/s/notosansmyanmar/v19/AlZq_y1ZtY3ymOryg38hOCSdOnFq0En23OU4o1AC.ttf', [0x20,0x20,0x3f,0x3f,0xa0,0xa0,0x1000,0x109f,0x200b,0x200d,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x25cc,0x25cc,0xa92e,0xa92e,0xa9e0,0xa9fe,0xaa60,0xaa7f,0xfe00,0xfe00,]), + NotoFont.fromFlatRanges('Noto Sans N Ko', 'http://fonts.gstatic.com/s/notosansnko/v17/6NUP8FqDKBaKKjnr6P8v-sxPpvVBVNmme3gf.ttf', [0x20,0x20,0xa0,0xa0,0x60c,0x60c,0x61b,0x61b,0x61f,0x61f,0x66a,0x66a,0x7c0,0x7fa,0x7fd,0x7ff,0x200c,0x200f,0x25cc,0x25cc,0x2e1c,0x2e1d,0xfd3e,0xfd3f,]), + NotoFont.fromFlatRanges('Noto Sans Nabataean', 'http://fonts.gstatic.com/s/notosansnabataean/v15/IFS4HfVJndhE3P4b5jnZ34DfsjO330dNoBJ9hK8kMK4.ttf', [0x20,0x20,0xa0,0xa0,0x10880,0x1089e,0x108a7,0x108af,]), + NotoFont.fromFlatRanges('Noto Sans New Tai Lue', 'http://fonts.gstatic.com/s/notosansnewtailue/v15/H4c5BW-Pl9DZ0Xe_nHUapt7PovLXAhAnY7wwY55O4AS32A.ttf', [0x20,0x20,0xa0,0xa0,0x1980,0x19ab,0x19b0,0x19c9,0x19d0,0x19da,0x19de,0x19df,0x200c,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Newa', 'http://fonts.gstatic.com/s/notosansnewa/v15/7r3fqXp6utEsO9pI4f8ok8sWg8n_qN4R5lNU.ttf', [0x20,0x20,0xa0,0xa0,0xb7,0xb7,0x1dfb,0x1dfb,0x200c,0x200d,0x25cc,0x25cc,0x11400,0x1145b,0x1145d,0x11461,]), + NotoFont.fromFlatRanges('Noto Sans Nushu', 'http://fonts.gstatic.com/s/notosansnushu/v18/rnCw-xRQ3B7652emAbAe_Ai1IYaFWFAMArZKqQ.ttf', [0x20,0x20,0xa0,0xa0,0x16fe1,0x16fe1,0x1b170,0x1b2fb,]), + NotoFont.fromFlatRanges('Noto Sans Ogham', 'http://fonts.gstatic.com/s/notosansogham/v15/kmKlZqk1GBDGN0mY6k5lmEmww4hrt5laQxcoCA.ttf', [0x20,0x20,0xa0,0xa0,0x1680,0x169c,]), + NotoFont.fromFlatRanges('Noto Sans Ol Chiki', 'http://fonts.gstatic.com/s/notosansolchiki/v17/N0b92TJNOPt-eHmFZCdQbrL32r-4CvhzDzRwlxOQYuVALWk267I6gVrz5gQ.ttf', [0x20,0x20,0xa0,0xa0,0x1c50,0x1c7f,0x20b9,0x20b9,]), + NotoFont.fromFlatRanges('Noto Sans Old Hungarian', 'http://fonts.gstatic.com/s/notosansoldhungarian/v15/E213_cD6hP3GwCJPEUssHEM0KqLaHJXg2PiIgRfjbg5nCYXt.ttf', [0x20,0x20,0xa0,0xa0,0x200d,0x200d,0x10c80,0x10cb2,0x10cc0,0x10cf2,0x10cfa,0x10cff,]), + NotoFont.fromFlatRanges('Noto Sans Old Italic', 'http://fonts.gstatic.com/s/notosansolditalic/v15/TuGOUUFzXI5FBtUq5a8bh68BJxxEVam7tWlRdRhtCC4d.ttf', [0x20,0x20,0xa0,0xa0,0x10300,0x10323,0x1032d,0x1032f,]), + NotoFont.fromFlatRanges('Noto Sans Old North Arabian', 'http://fonts.gstatic.com/s/notosansoldnortharabian/v15/esDF30BdNv-KYGGJpKGk2tNiMt7Jar6olZDyNdr81zBQmUo_xw4ABw.ttf', [0x20,0x20,0xa0,0xa0,0x10a80,0x10a9f,]), + NotoFont.fromFlatRanges('Noto Sans Old Permic', 'http://fonts.gstatic.com/s/notosansoldpermic/v16/snf1s1q1-dF8pli1TesqcbUY4Mr-ElrwKLdXgv_dKYB5.ttf', [0x20,0x20,0xa0,0xa0,0x300,0x300,0x306,0x308,0x313,0x313,0x483,0x483,0x20db,0x20db,0x25cc,0x25cc,0x10350,0x1037a,]), + NotoFont.fromFlatRanges('Noto Sans Old Persian', 'http://fonts.gstatic.com/s/notosansoldpersian/v15/wEOjEAbNnc5caQTFG18FHrZr9Bp6-8CmIJ_tqOlQfx9CjA.ttf', [0x20,0x20,0xa0,0xa0,0x103a0,0x103c3,0x103c8,0x103d5,]), + NotoFont.fromFlatRanges('Noto Sans Old Sogdian', 'http://fonts.gstatic.com/s/notosansoldsogdian/v15/3JnjSCH90Gmq2mrzckOBBhFhdrMst48aURt7neIqM-9uyg.ttf', [0x20,0x20,0xa0,0xa0,0x10f00,0x10f27,]), + NotoFont.fromFlatRanges('Noto Sans Old South Arabian', 'http://fonts.gstatic.com/s/notosansoldsoutharabian/v15/3qT5oiOhnSyU8TNFIdhZTice3hB_HWKsEnF--0XCHiKx1OtDT9HwTA.ttf', [0x20,0x20,0xa0,0xa0,0x10a60,0x10a7f,]), + NotoFont.fromFlatRanges('Noto Sans Old Turkic', 'http://fonts.gstatic.com/s/notosansoldturkic/v15/yMJNMJVya43H0SUF_WmcGEQVqoEMKDKbsE2RjEw-Vyws.ttf', [0x20,0x20,0xa0,0xa0,0x10c00,0x10c48,]), + NotoFont.fromFlatRanges('Noto Sans Oriya', 'http://fonts.gstatic.com/s/notosansoriya/v16/AYCTpXfzfccDCstK_hrjDyADv5en5K3DZq1hIg.ttf', [0x20,0x23,0x25,0x25,0x27,0x2c,0x2e,0x3f,0x5b,0x5f,0x7b,0x7e,0xa0,0xa0,0xad,0xad,0xd7,0xd7,0xf7,0xf7,0x964,0x965,0xb01,0xb03,0xb05,0xb0c,0xb0f,0xb10,0xb13,0xb28,0xb2a,0xb30,0xb32,0xb33,0xb35,0xb39,0xb3c,0xb44,0xb47,0xb48,0xb4b,0xb4d,0xb56,0xb57,0xb5c,0xb5d,0xb5f,0xb63,0xb66,0xb77,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x20b9,0x20b9,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Osage', 'http://fonts.gstatic.com/s/notosansosage/v15/oPWX_kB6kP4jCuhpgEGmw4mtAVtXRlaSxkrMCQ.ttf', [0x20,0x20,0xa0,0xa0,0x301,0x301,0x304,0x304,0x30b,0x30b,0x358,0x358,0x25cc,0x25cc,0x104b0,0x104d3,0x104d8,0x104fb,]), + NotoFont.fromFlatRanges('Noto Sans Osmanya', 'http://fonts.gstatic.com/s/notosansosmanya/v15/8vIS7xs32H97qzQKnzfeWzUyUpOJmz6kR47NCV5Z.ttf', [0x20,0x20,0xa0,0xa0,0x10480,0x1049d,0x104a0,0x104a9,]), + NotoFont.fromFlatRanges('Noto Sans Pahawh Hmong', 'http://fonts.gstatic.com/s/notosanspahawhhmong/v15/bWtp7e_KfBziStx7lIzKKaMUOBEA3UPQDW7krzc_c48aMpM.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x16b00,0x16b45,0x16b50,0x16b59,0x16b5b,0x16b61,0x16b63,0x16b77,0x16b7d,0x16b8f,]), + NotoFont.fromFlatRanges('Noto Sans Palmyrene', 'http://fonts.gstatic.com/s/notosanspalmyrene/v15/ZgNPjOdKPa7CHqq0h37c_ASCWvH93SFCPnK5ZpdNtcA.ttf', [0x20,0x20,0xa0,0xa0,0x10860,0x1087f,]), + NotoFont.fromFlatRanges('Noto Sans Pau Cin Hau', 'http://fonts.gstatic.com/s/notosanspaucinhau/v16/x3d-cl3IZKmUqiMg_9wBLLtzl22EayN7ehIdjEWqKMxsKw.ttf', [0x20,0x20,0xa0,0xa0,0x11ac0,0x11af8,]), + NotoFont.fromFlatRanges('Noto Sans Phags Pa', 'http://fonts.gstatic.com/s/notosansphagspa/v15/pxiZyoo6v8ZYyWh5WuPeJzMkd4SrGChkqkSsrvNXiA.ttf', [0x20,0x20,0xa0,0xa0,0x1801,0x1803,0x1805,0x1805,0x200b,0x200f,0x2025,0x2026,0x25cc,0x25cc,0x3001,0x3002,0x3007,0x3011,0x3014,0x301b,0xa840,0xa877,0xfe00,0xfe00,]), + NotoFont.fromFlatRanges('Noto Sans Phoenician', 'http://fonts.gstatic.com/s/notosansphoenician/v15/jizFRF9Ksm4Bt9PvcTaEkIHiTVtxmFtS5X7Jot-p5561.ttf', [0x20,0x20,0xa0,0xa0,0x10900,0x1091b,0x1091f,0x1091f,]), + NotoFont.fromFlatRanges('Noto Sans Psalter Pahlavi', 'http://fonts.gstatic.com/s/notosanspsalterpahlavi/v15/rP2Vp3K65FkAtHfwd-eISGznYihzggmsicPfud3w1G3KsUQBct4.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x200c,0x200d,0x25cc,0x25cc,0x10b80,0x10b91,0x10b99,0x10b9c,0x10ba9,0x10baf,]), + NotoFont.fromFlatRanges('Noto Sans Rejang', 'http://fonts.gstatic.com/s/notosansrejang/v15/Ktk2AKuMeZjqPnXgyqrib7DIogqwN4O3WYZB_sU.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa930,0xa953,0xa95f,0xa95f,]), + NotoFont.fromFlatRanges('Noto Sans Runic', 'http://fonts.gstatic.com/s/notosansrunic/v15/H4c_BXWPl9DZ0Xe_nHUaus7W68WWaxpvHtgIYg.ttf', [0x20,0x20,0xa0,0xa0,0x16a0,0x16f8,]), + NotoFont.fromFlatRanges('Noto Sans SC', 'http://fonts.gstatic.com/s/notosanssc/v26/k3kXo84MPvpLmixcA63oeALhL4iJ-Q7m8w.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x4db5,0x4e00,0x9fef,0xf900,0xf903,0xf905,0xf906,0xf90b,0xf90c,0xf915,0xf915,0xf917,0xf91a,0xf921,0xf921,0xf92c,0xf92d,0xf92f,0xf92f,0xf931,0xf935,0xf937,0xf93a,0xf943,0xf943,0xf947,0xf94a,0xf94e,0xf94e,0xf952,0xf953,0xf95e,0xf95e,0xf962,0xf967,0xf96e,0xf96e,0xf972,0xf972,0xf974,0xf974,0xf976,0xf976,0xf979,0xf97b,0xf97e,0xf980,0xf984,0xf985,0xf98a,0xf98c,0xf98e,0xf98e,0xf993,0xf993,0xf995,0xf995,0xf998,0xf998,0xf9ae,0xf9ae,0xf9b3,0xf9b3,0xf9b7,0xf9b7,0xf9bb,0xf9bb,0xf9bd,0xf9be,0xf9c0,0xf9c0,0xf9c5,0xf9c6,0xf9d0,0xf9d0,0xf9d8,0xf9d9,0xf9dc,0xf9e0,0xf9e2,0xf9e4,0xf9e7,0xf9e7,0xf9e9,0xf9e9,0xf9f1,0xf9f1,0xf9f4,0xf9f5,0xf9fa,0xf9fa,0xf9fd,0xf9fd,0xf9ff,0xf9ff,0xfa02,0xfa02,0xfa05,0xfa08,0xfa0a,0xfa0a,0xfa0c,0xfa0f,0xfa11,0xfa11,0xfa13,0xfa14,0xfa18,0xfa18,0xfa1f,0xfa21,0xfa23,0xfa24,0xfa27,0xfa29,0xfa2f,0xfa2f,0xfa33,0xfa35,0xfa37,0xfa38,0xfa3a,0xfa3a,0xfa47,0xfa47,0xfa49,0xfa49,0xfa4b,0xfa4b,0xfa5d,0xfa5e,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x20087,0x20087,0x20089,0x20089,0x200cc,0x200cc,0x20164,0x20164,0x20628,0x20628,0x20676,0x20676,0x20cd0,0x20cd0,0x2139a,0x2139a,0x21413,0x21413,0x215d7,0x215d7,0x2298f,0x2298f,0x235cb,0x235cb,0x23c97,0x23c98,0x23e23,0x23e23,0x241fe,0x241fe,0x2420e,0x2420e,0x248e9,0x248e9,0x249db,0x249db,0x24a01,0x24a01,0x24a7d,0x24a7d,0x24ac9,0x24ac9,0x25532,0x25532,0x25562,0x25562,0x255a8,0x255a8,0x25ad7,0x25ad7,0x25ed7,0x25ed7,0x26221,0x26221,0x2648d,0x2648d,0x26676,0x26676,0x2677c,0x2677c,0x26951,0x26951,0x26b5c,0x26b5c,0x26c21,0x26c21,0x278b2,0x278b2,0x27eaf,0x27eaf,0x27fb7,0x27fb7,0x27ff9,0x27ff9,0x28408,0x28408,0x28678,0x28678,0x28695,0x28695,0x287e0,0x287e0,0x28b49,0x28b49,0x28c47,0x28c47,0x28c4f,0x28c4f,0x28c51,0x28c51,0x28c54,0x28c54,0x28e0f,0x28e0f,0x28e99,0x28e99,0x2967f,0x2967f,0x29810,0x29810,0x29f7e,0x29f7e,0x29f83,0x29f83,0x29f8c,0x29f8c,0x2a7dd,0x2a7dd,0x2a8fb,0x2a8fb,0x2a917,0x2a917,0x2aa30,0x2aa30,0x2aa36,0x2aa36,0x2aa58,0x2aa58,0x2afa2,0x2afa2,0x2b127,0x2b128,0x2b137,0x2b138,0x2b1ed,0x2b1ed,0x2b300,0x2b300,0x2b363,0x2b363,0x2b36f,0x2b36f,0x2b372,0x2b372,0x2b37d,0x2b37d,0x2b404,0x2b404,0x2b410,0x2b410,0x2b413,0x2b413,0x2b461,0x2b461,0x2b4e7,0x2b4e7,0x2b4ef,0x2b4ef,0x2b4f6,0x2b4f6,0x2b4f9,0x2b4f9,0x2b50d,0x2b50e,0x2b536,0x2b536,0x2b5ae,0x2b5af,0x2b5b3,0x2b5b3,0x2b5e7,0x2b5e7,0x2b5f4,0x2b5f4,0x2b61c,0x2b61d,0x2b626,0x2b628,0x2b62a,0x2b62a,0x2b62c,0x2b62c,0x2b695,0x2b696,0x2b6ad,0x2b6ad,0x2b6ed,0x2b6ed,0x2b7a9,0x2b7a9,0x2b7c5,0x2b7c5,0x2b7e6,0x2b7e6,0x2b7f9,0x2b7f9,0x2b7fc,0x2b7fc,0x2b806,0x2b806,0x2b80a,0x2b80a,0x2b81c,0x2b81c,0x2b8b8,0x2b8b8,0x2bac7,0x2bac7,0x2bb5f,0x2bb5f,0x2bb62,0x2bb62,0x2bb7c,0x2bb7c,0x2bb83,0x2bb83,0x2bc1b,0x2bc1b,0x2bd77,0x2bd77,0x2bd87,0x2bd87,0x2bdf7,0x2bdf7,0x2be29,0x2be29,0x2c029,0x2c02a,0x2c0a9,0x2c0a9,0x2c0ca,0x2c0ca,0x2c1d5,0x2c1d5,0x2c1d9,0x2c1d9,0x2c1f9,0x2c1f9,0x2c27c,0x2c27c,0x2c288,0x2c288,0x2c2a4,0x2c2a4,0x2c317,0x2c317,0x2c35b,0x2c35b,0x2c361,0x2c361,0x2c364,0x2c364,0x2c488,0x2c488,0x2c494,0x2c494,0x2c497,0x2c497,0x2c542,0x2c542,0x2c613,0x2c613,0x2c618,0x2c618,0x2c621,0x2c621,0x2c629,0x2c629,0x2c62b,0x2c62d,0x2c62f,0x2c62f,0x2c642,0x2c642,0x2c64a,0x2c64b,0x2c72c,0x2c72c,0x2c72f,0x2c72f,0x2c79f,0x2c79f,0x2c7c1,0x2c7c1,0x2c7fd,0x2c7fd,0x2c8d9,0x2c8d9,0x2c8de,0x2c8de,0x2c8e1,0x2c8e1,0x2c8f3,0x2c8f3,0x2c907,0x2c907,0x2c90a,0x2c90a,0x2c91d,0x2c91d,0x2ca02,0x2ca02,0x2ca0e,0x2ca0e,0x2ca7d,0x2ca7d,0x2caa9,0x2caa9,0x2cb29,0x2cb29,0x2cb2d,0x2cb2e,0x2cb31,0x2cb31,0x2cb38,0x2cb39,0x2cb3b,0x2cb3b,0x2cb3f,0x2cb3f,0x2cb41,0x2cb41,0x2cb4a,0x2cb4a,0x2cb4e,0x2cb4e,0x2cb5a,0x2cb5b,0x2cb64,0x2cb64,0x2cb69,0x2cb69,0x2cb6c,0x2cb6c,0x2cb6f,0x2cb6f,0x2cb73,0x2cb73,0x2cb76,0x2cb76,0x2cb78,0x2cb78,0x2cb7c,0x2cb7c,0x2cbb1,0x2cbb1,0x2cbbf,0x2cbc0,0x2cbce,0x2cbce,0x2cc56,0x2cc56,0x2cc5f,0x2cc5f,0x2ccf5,0x2ccf6,0x2ccfd,0x2ccfd,0x2ccff,0x2ccff,0x2cd02,0x2cd03,0x2cd0a,0x2cd0a,0x2cd8b,0x2cd8b,0x2cd8d,0x2cd8d,0x2cd8f,0x2cd90,0x2cd9f,0x2cda0,0x2cda8,0x2cda8,0x2cdad,0x2cdae,0x2cdd5,0x2cdd5,0x2ce18,0x2ce18,0x2ce1a,0x2ce1a,0x2ce23,0x2ce23,0x2ce26,0x2ce26,0x2ce2a,0x2ce2a,0x2ce7c,0x2ce7c,0x2ce88,0x2ce88,0x2ce93,0x2ce93,0x2d544,0x2d544,0x2f884,0x2f884,0x2f8b6,0x2f8b6,0x30edd,0x30ede,0x3106c,0x3106c,]), + NotoFont.fromFlatRanges('Noto Sans Saurashtra', 'http://fonts.gstatic.com/s/notosanssaurashtra/v15/ea8GacQ0Wfz_XKWXe6OtoA8w8zvmYwTef9ndjhPTSIx9.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa880,0xa8c5,0xa8ce,0xa8d9,]), + NotoFont.fromFlatRanges('Noto Sans Sharada', 'http://fonts.gstatic.com/s/notosanssharada/v15/gok0H7rwAEdtF9N8-mdTGALG6p0kwoXLPOwr4H8a.ttf', [0x20,0x20,0xa0,0xa0,0x951,0x951,0x1cd7,0x1cd7,0x1cd9,0x1cd9,0x1cdc,0x1cdd,0x1ce0,0x1ce0,0x200c,0x200d,0x25cc,0x25cc,0x11180,0x111df,]), + NotoFont.fromFlatRanges('Noto Sans Shavian', 'http://fonts.gstatic.com/s/notosansshavian/v15/CHy5V_HZE0jxJBQlqAeCKjJvQBNF4EFQSplv2Cwg.ttf', [0x20,0x20,0xa0,0xa0,0x10450,0x1047f,]), + NotoFont.fromFlatRanges('Noto Sans Siddham', 'http://fonts.gstatic.com/s/notosanssiddham/v15/OZpZg-FwqiNLe9PELUikxTWDoCCeGqndk3Ic92ZH.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x11580,0x115b5,0x115b8,0x115dd,]), + NotoFont.fromFlatRanges('Noto Sans Sinhala', 'http://fonts.gstatic.com/s/notosanssinhala/v25/yMJ2MJBya43H0SUF_WmcBEEf4rQVO2P524V5N_MxQzQtb-tf5dJbC30Fu9zUwg2a5lgLpJwbQRM.ttf', [0x20,0x23,0x25,0x25,0x27,0x3f,0x5b,0x5f,0x7b,0x7e,0xa0,0xa0,0xad,0xad,0xd7,0xd7,0xf7,0xf7,0x964,0x965,0xd81,0xd83,0xd85,0xd96,0xd9a,0xdb1,0xdb3,0xdbb,0xdbd,0xdbd,0xdc0,0xdc6,0xdca,0xdca,0xdcf,0xdd4,0xdd6,0xdd6,0xdd8,0xddf,0xde6,0xdef,0xdf2,0xdf4,0x200b,0x200d,0x2013,0x2014,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x2212,0x2212,0x25cc,0x25cc,0x111e1,0x111f4,]), + NotoFont.fromFlatRanges('Noto Sans Sogdian', 'http://fonts.gstatic.com/s/notosanssogdian/v15/taiQGn5iC4--qtsfi4Jp6eHPnfxQBo--Pm6KHidM.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x200c,0x200c,0x25cc,0x25cc,0x10f30,0x10f59,]), + NotoFont.fromFlatRanges('Noto Sans Sora Sompeng', 'http://fonts.gstatic.com/s/notosanssorasompeng/v17/PlIRFkO5O6RzLfvNNVSioxM2_OTrEhPyDLolKvCsHzCxWuGkYHR818DpZXJQd4Mu.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x2010,0x2010,0x110d0,0x110e8,0x110f0,0x110f9,]), + NotoFont.fromFlatRanges('Noto Sans Soyombo', 'http://fonts.gstatic.com/s/notosanssoyombo/v15/RWmSoL-Y6-8q5LTtXs6MF6q7xsxgY0FrIFOcK25W.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x11a50,0x11aa2,]), + NotoFont.fromFlatRanges('Noto Sans Sundanese', 'http://fonts.gstatic.com/s/notosanssundanese/v17/FwZw7_84xUkosG2xJo2gm7nFwSLQkdymq2mkz3Gz1_b6ctxpNNHCizv7fQES.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x1b80,0x1bbf,0x1cc0,0x1cc7,0x200b,0x200d,0x2010,0x2010,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Syloti Nagri', 'http://fonts.gstatic.com/s/notosanssylotinagri/v15/uU9eCAQZ75uhfF9UoWDRiY3q7Sf_VFV3m4dGFVfxN87gsj0.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x965,0x9e6,0x9ef,0x200b,0x200d,0x2010,0x2011,0x2055,0x2055,0x25cc,0x25cc,0xa800,0xa82c,]), + NotoFont.fromFlatRanges('Noto Sans Syriac', 'http://fonts.gstatic.com/s/notosanssyriac/v15/Ktk2AKuMeZjqPnXgyqribqzQqgW0N4O3WYZB_sU.ttf', [0x20,0x21,0x28,0x2b,0x2d,0x2f,0x3a,0x3a,0x3d,0x3d,0x5b,0x5d,0xa0,0xa0,0xab,0xab,0xb0,0xb0,0xbb,0xbb,0x303,0x304,0x307,0x308,0x30a,0x30a,0x320,0x320,0x323,0x325,0x32d,0x32e,0x330,0x331,0x60c,0x60c,0x61b,0x61b,0x61f,0x61f,0x621,0x621,0x640,0x640,0x64b,0x655,0x660,0x66c,0x670,0x670,0x700,0x70d,0x70f,0x74a,0x74d,0x74f,0x200c,0x200f,0x2026,0x2026,0x2044,0x2044,0x2212,0x2212,0x25cc,0x25cc,0x2670,0x2671,]), + NotoFont.fromFlatRanges('Noto Sans TC', 'http://fonts.gstatic.com/s/notosanstc/v26/-nF7OG829Oofr2wohFbTp9iFOSsLA_ZJ1g.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x3435,0x3435,0x3440,0x3440,0x344a,0x344a,0x344c,0x344c,0x3464,0x3464,0x3473,0x3473,0x347a,0x347a,0x347d,0x347e,0x3493,0x3493,0x3496,0x3496,0x34a5,0x34a5,0x34af,0x34af,0x34bc,0x34bc,0x34c1,0x34c1,0x34c8,0x34c8,0x34df,0x34df,0x34e4,0x34e4,0x34e6,0x34e6,0x34fb,0x34fb,0x3506,0x3506,0x353e,0x353e,0x3551,0x3551,0x3553,0x3553,0x3559,0x3559,0x3561,0x3561,0x356d,0x356d,0x3570,0x3570,0x3572,0x3572,0x3577,0x3578,0x3584,0x3584,0x3597,0x3598,0x35a1,0x35a1,0x35a5,0x35a5,0x35ad,0x35ad,0x35bf,0x35bf,0x35c1,0x35c1,0x35c5,0x35c5,0x35c7,0x35c7,0x35ca,0x35ca,0x35ce,0x35ce,0x35d2,0x35d2,0x35d6,0x35d6,0x35db,0x35db,0x35dd,0x35dd,0x35f1,0x35f3,0x35fb,0x35fb,0x35fe,0x35fe,0x3609,0x3609,0x3618,0x3618,0x361a,0x361a,0x3623,0x3623,0x3625,0x3625,0x362d,0x362d,0x3635,0x3635,0x3639,0x3639,0x363e,0x363e,0x3647,0x3649,0x364e,0x364e,0x365f,0x365f,0x3661,0x3661,0x367a,0x367a,0x3681,0x3681,0x369a,0x369a,0x36a5,0x36a5,0x36aa,0x36aa,0x36ac,0x36ac,0x36b0,0x36b1,0x36b5,0x36b5,0x36b9,0x36b9,0x36bc,0x36bc,0x36c1,0x36c1,0x36c3,0x36c5,0x36c7,0x36c8,0x36d3,0x36d4,0x36d6,0x36d6,0x36dd,0x36dd,0x36e1,0x36e2,0x36e5,0x36e6,0x36f5,0x36f5,0x3701,0x3701,0x3703,0x3703,0x3708,0x3708,0x370a,0x370a,0x370d,0x370d,0x371c,0x371c,0x3722,0x3723,0x3725,0x3725,0x372c,0x372d,0x3730,0x3730,0x3732,0x3733,0x373a,0x373a,0x3740,0x3740,0x3743,0x3743,0x3762,0x3762,0x376f,0x376f,0x3797,0x3797,0x37a0,0x37a0,0x37b9,0x37b9,0x37be,0x37be,0x37d6,0x37d6,0x37f2,0x37f2,0x37f8,0x37f8,0x37fb,0x37fb,0x380f,0x380f,0x3819,0x3819,0x3820,0x3820,0x382d,0x382d,0x3836,0x3836,0x3838,0x3838,0x3863,0x3863,0x3875,0x3875,0x38a0,0x38a0,0x38c3,0x38c3,0x38cc,0x38cc,0x38d1,0x38d1,0x38d4,0x38d4,0x38fa,0x38fa,0x3908,0x3908,0x3914,0x3914,0x3927,0x3927,0x3932,0x3932,0x393f,0x393f,0x394d,0x394d,0x3963,0x3963,0x3978,0x3978,0x3980,0x3980,0x3989,0x398a,0x3992,0x3992,0x3999,0x3999,0x399b,0x399b,0x39a1,0x39a1,0x39a4,0x39a4,0x39b8,0x39b8,0x39dc,0x39dc,0x39e2,0x39e2,0x39e5,0x39e5,0x39ec,0x39ec,0x39f8,0x39f8,0x39fb,0x39fb,0x39fe,0x39fe,0x3a01,0x3a01,0x3a03,0x3a03,0x3a06,0x3a06,0x3a17,0x3a18,0x3a29,0x3a2a,0x3a34,0x3a34,0x3a4b,0x3a4b,0x3a52,0x3a52,0x3a57,0x3a57,0x3a5c,0x3a5c,0x3a5e,0x3a5e,0x3a66,0x3a67,0x3a97,0x3a97,0x3aab,0x3aab,0x3abd,0x3abd,0x3ada,0x3ada,0x3ade,0x3ade,0x3ae0,0x3ae0,0x3af0,0x3af0,0x3af2,0x3af2,0x3af5,0x3af5,0x3afb,0x3afb,0x3b0e,0x3b0e,0x3b19,0x3b19,0x3b22,0x3b22,0x3b2b,0x3b2b,0x3b39,0x3b39,0x3b42,0x3b42,0x3b58,0x3b58,0x3b60,0x3b60,0x3b71,0x3b72,0x3b7b,0x3b7c,0x3b80,0x3b80,0x3b95,0x3b96,0x3b99,0x3b99,0x3ba1,0x3ba1,0x3bbc,0x3bbc,0x3bbe,0x3bbe,0x3bc2,0x3bc2,0x3bc4,0x3bc4,0x3bd7,0x3bd7,0x3bdd,0x3bdd,0x3bec,0x3bec,0x3bf2,0x3bf4,0x3c0d,0x3c0d,0x3c11,0x3c11,0x3c15,0x3c15,0x3c18,0x3c18,0x3c54,0x3c54,0x3c8b,0x3c8b,0x3ccb,0x3ccb,0x3ccd,0x3ccd,0x3cd1,0x3cd1,0x3cd6,0x3cd6,0x3cdc,0x3cdc,0x3ceb,0x3ceb,0x3cef,0x3cef,0x3d12,0x3d13,0x3d1d,0x3d1d,0x3d32,0x3d32,0x3d3b,0x3d3b,0x3d46,0x3d46,0x3d4c,0x3d4c,0x3d4e,0x3d4e,0x3d51,0x3d51,0x3d5f,0x3d5f,0x3d62,0x3d62,0x3d69,0x3d6a,0x3d6f,0x3d6f,0x3d75,0x3d75,0x3d7d,0x3d7d,0x3d85,0x3d85,0x3d88,0x3d88,0x3d8a,0x3d8a,0x3d8f,0x3d8f,0x3d91,0x3d91,0x3da5,0x3da5,0x3dad,0x3dad,0x3db4,0x3db4,0x3dbf,0x3dbf,0x3dc6,0x3dc7,0x3dc9,0x3dc9,0x3dcc,0x3dcd,0x3dd3,0x3dd3,0x3ddb,0x3ddb,0x3de7,0x3de8,0x3deb,0x3deb,0x3df3,0x3df4,0x3df7,0x3df7,0x3dfc,0x3dfd,0x3e06,0x3e06,0x3e40,0x3e40,0x3e43,0x3e43,0x3e48,0x3e48,0x3e55,0x3e55,0x3e74,0x3e74,0x3ea8,0x3eaa,0x3ead,0x3ead,0x3eb1,0x3eb1,0x3eb8,0x3eb8,0x3ebf,0x3ebf,0x3ec2,0x3ec2,0x3ec7,0x3ec7,0x3eca,0x3eca,0x3ecc,0x3ecc,0x3ed0,0x3ed1,0x3ed6,0x3ed7,0x3eda,0x3edb,0x3ede,0x3ede,0x3ee1,0x3ee2,0x3ee7,0x3ee7,0x3ee9,0x3ee9,0x3eeb,0x3eec,0x3ef0,0x3ef0,0x3ef3,0x3ef4,0x3efa,0x3efa,0x3efc,0x3efc,0x3eff,0x3f00,0x3f04,0x3f04,0x3f06,0x3f07,0x3f0e,0x3f0e,0x3f53,0x3f53,0x3f58,0x3f59,0x3f63,0x3f63,0x3f7c,0x3f7c,0x3f93,0x3f93,0x3fc0,0x3fc0,0x3fc8,0x3fc8,0x3fd7,0x3fd7,0x3fdc,0x3fdc,0x3fe5,0x3fe5,0x3fed,0x3fed,0x3ff9,0x3ffa,0x4004,0x4004,0x4009,0x4009,0x401d,0x401d,0x4039,0x4039,0x4045,0x4045,0x4053,0x4053,0x4057,0x4057,0x4062,0x4062,0x4065,0x4065,0x406a,0x406a,0x406f,0x406f,0x4071,0x4071,0x40a8,0x40a8,0x40b4,0x40b4,0x40bb,0x40bb,0x40bf,0x40bf,0x40c8,0x40c8,0x40d8,0x40d8,0x40df,0x40df,0x40f8,0x40f8,0x40fa,0x40fa,0x4102,0x4104,0x4109,0x4109,0x410e,0x410e,0x4131,0x4132,0x4167,0x4167,0x416c,0x416c,0x416e,0x416e,0x417c,0x417c,0x417f,0x417f,0x4181,0x4181,0x4190,0x4190,0x41b2,0x41b2,0x41c4,0x41c4,0x41ca,0x41ca,0x41cf,0x41cf,0x41db,0x41db,0x41ed,0x41ed,0x41ef,0x41ef,0x41f9,0x41f9,0x4211,0x4211,0x4223,0x4223,0x4240,0x4240,0x4260,0x4260,0x426a,0x426a,0x4276,0x4276,0x427a,0x427a,0x428c,0x428c,0x4294,0x4294,0x42a2,0x42a2,0x42b5,0x42b5,0x42b9,0x42b9,0x42bc,0x42bc,0x42f4,0x42f4,0x42fb,0x42fc,0x430a,0x430a,0x432b,0x432b,0x436e,0x436e,0x4397,0x4397,0x439a,0x439a,0x43ba,0x43ba,0x43c1,0x43c1,0x43d9,0x43d9,0x43df,0x43df,0x43ed,0x43ed,0x43f0,0x43f0,0x43f2,0x43f2,0x4401,0x4402,0x4413,0x4413,0x4425,0x4425,0x442d,0x442d,0x447a,0x447a,0x448f,0x448f,0x4491,0x4491,0x449f,0x44a0,0x44a2,0x44a2,0x44b0,0x44b0,0x44b7,0x44b7,0x44bd,0x44bd,0x44c0,0x44c0,0x44c3,0x44c3,0x44c5,0x44c5,0x44ce,0x44ce,0x44dd,0x44df,0x44e1,0x44e1,0x44e4,0x44e4,0x44e9,0x44ec,0x44f4,0x44f4,0x4503,0x4504,0x4509,0x4509,0x450b,0x450b,0x4516,0x4516,0x451b,0x451b,0x451d,0x451d,0x4527,0x4527,0x452e,0x452e,0x4533,0x4533,0x4536,0x4536,0x453b,0x453b,0x453d,0x453d,0x453f,0x453f,0x4543,0x4543,0x4551,0x4552,0x4555,0x4555,0x4558,0x4558,0x455c,0x455c,0x4561,0x4562,0x456a,0x456a,0x456d,0x456d,0x4577,0x4578,0x4585,0x4585,0x45a6,0x45a6,0x45b3,0x45b3,0x45da,0x45da,0x45e9,0x45ea,0x4603,0x4603,0x4606,0x4606,0x460f,0x460f,0x4615,0x4615,0x4617,0x4617,0x465b,0x465b,0x467a,0x467a,0x4680,0x4680,0x46a1,0x46a1,0x46ae,0x46ae,0x46bb,0x46bb,0x46cf,0x46d0,0x46f5,0x46f5,0x46f7,0x46f7,0x4713,0x4713,0x4718,0x4718,0x4736,0x4736,0x4744,0x4744,0x474e,0x474f,0x477c,0x477c,0x4798,0x4798,0x47a6,0x47a6,0x47d5,0x47d5,0x47ed,0x47ed,0x47f4,0x47f4,0x4800,0x4800,0x480b,0x480b,0x4837,0x4837,0x485d,0x485d,0x4871,0x4871,0x489b,0x489b,0x48ad,0x48ae,0x48d0,0x48d0,0x48dd,0x48dd,0x48ed,0x48ed,0x48f3,0x48f3,0x48fa,0x48fa,0x4906,0x4906,0x4911,0x4911,0x491e,0x491e,0x4925,0x4925,0x492a,0x492a,0x492d,0x492d,0x492f,0x4930,0x4935,0x4935,0x493c,0x493c,0x493e,0x493e,0x4945,0x4945,0x4951,0x4951,0x4953,0x4953,0x4965,0x4965,0x496a,0x496a,0x4972,0x4972,0x4989,0x4989,0x49a1,0x49a1,0x49a7,0x49a7,0x49df,0x49df,0x49e5,0x49e5,0x49e7,0x49e7,0x4a0f,0x4a0f,0x4a1d,0x4a1d,0x4a24,0x4a24,0x4a35,0x4a35,0x4a96,0x4a96,0x4aa4,0x4aa4,0x4ab4,0x4ab4,0x4ab8,0x4ab8,0x4ad1,0x4ad1,0x4ae4,0x4ae4,0x4aff,0x4aff,0x4b10,0x4b10,0x4b19,0x4b19,0x4b20,0x4b20,0x4b2c,0x4b2c,0x4b37,0x4b37,0x4b6f,0x4b70,0x4b72,0x4b72,0x4b7b,0x4b7b,0x4b7e,0x4b7e,0x4b8e,0x4b8e,0x4b90,0x4b90,0x4b93,0x4b93,0x4b96,0x4b97,0x4b9d,0x4b9d,0x4bbd,0x4bbe,0x4bc0,0x4bc0,0x4c04,0x4c04,0x4c07,0x4c07,0x4c0e,0x4c0e,0x4c32,0x4c32,0x4c3b,0x4c3b,0x4c3e,0x4c3e,0x4c40,0x4c40,0x4c47,0x4c47,0x4c57,0x4c57,0x4c5b,0x4c5b,0x4c6d,0x4c6d,0x4c77,0x4c77,0x4c7b,0x4c7b,0x4c7d,0x4c7d,0x4c81,0x4c81,0x4c85,0x4c85,0x4ca4,0x4ca4,0x4cae,0x4cae,0x4cb0,0x4cb0,0x4cb7,0x4cb7,0x4ccd,0x4ccd,0x4ce1,0x4ce2,0x4ced,0x4ced,0x4d07,0x4d07,0x4d09,0x4d09,0x4d10,0x4d10,0x4d34,0x4d34,0x4d76,0x4d77,0x4d89,0x4d89,0x4d91,0x4d91,0x4d9c,0x4d9c,0x4e00,0x4e01,0x4e03,0x4e04,0x4e07,0x4e11,0x4e14,0x4e16,0x4e18,0x4e1a,0x4e1c,0x4e1c,0x4e1e,0x4e1f,0x4e21,0x4e22,0x4e24,0x4e24,0x4e26,0x4e26,0x4e28,0x4e28,0x4e2a,0x4e33,0x4e36,0x4e39,0x4e3b,0x4e3d,0x4e3f,0x4e3f,0x4e42,0x4e43,0x4e45,0x4e45,0x4e47,0x4e49,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e52,0x4e53,0x4e56,0x4e56,0x4e58,0x4e5f,0x4e69,0x4e6a,0x4e73,0x4e73,0x4e78,0x4e78,0x4e7e,0x4e89,0x4e8b,0x4e8e,0x4e91,0x4e95,0x4e98,0x4e9b,0x4e9e,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eae,0x4eb3,0x4eb3,0x4eb6,0x4eb7,0x4eb9,0x4ebc,0x4ebf,0x4ec4,0x4ec6,0x4ecb,0x4ecd,0x4ece,0x4ed4,0x4eda,0x4edc,0x4edf,0x4ee1,0x4ee1,0x4ee3,0x4ee5,0x4ee8,0x4eeb,0x4eee,0x4eee,0x4ef0,0x4ef8,0x4efb,0x4efb,0x4efd,0x4efd,0x4eff,0x4f05,0x4f08,0x4f0b,0x4f0d,0x4f15,0x4f17,0x4f1a,0x4f1d,0x4f1d,0x4f22,0x4f22,0x4f28,0x4f29,0x4f2c,0x4f2d,0x4f2f,0x4f30,0x4f32,0x4f34,0x4f36,0x4f3f,0x4f41,0x4f43,0x4f45,0x4f49,0x4f4b,0x4f64,0x4f67,0x4f67,0x4f69,0x4f6c,0x4f6e,0x4f70,0x4f72,0x4f8b,0x4f8d,0x4f8d,0x4f8f,0x4f92,0x4f94,0x4f98,0x4f9a,0x4f9e,0x4fa2,0x4fa2,0x4fa8,0x4fa8,0x4fab,0x4fab,0x4fae,0x4fb0,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbd,0x4fbd,0x4fbf,0x4fc5,0x4fc7,0x4fd1,0x4fd3,0x4fd4,0x4fd6,0x4fe1,0x4fe4,0x4fe5,0x4fec,0x4fec,0x4fee,0x4ffa,0x4ffd,0x4ffe,0x5000,0x5000,0x5003,0x5003,0x5005,0x5009,0x500b,0x500f,0x5011,0x501c,0x501e,0x5023,0x5025,0x5031,0x5033,0x5035,0x5037,0x5037,0x503b,0x503c,0x5040,0x5041,0x5043,0x5043,0x5045,0x504f,0x5051,0x5051,0x5053,0x5053,0x5055,0x5058,0x505a,0x5066,0x5068,0x5070,0x5072,0x5077,0x507a,0x507a,0x507d,0x507d,0x5080,0x5083,0x5085,0x5085,0x5087,0x5088,0x508b,0x508e,0x5090,0x5092,0x5094,0x5096,0x5098,0x509e,0x50a2,0x50a3,0x50a6,0x50a6,0x50ac,0x50b8,0x50ba,0x50bf,0x50c1,0x50c2,0x50c4,0x50cb,0x50cd,0x50d1,0x50d3,0x50d7,0x50d9,0x50db,0x50dd,0x50dd,0x50df,0x50e1,0x50e3,0x50ea,0x50ec,0x50f1,0x50f3,0x50f6,0x50f8,0x50f9,0x50fb,0x510e,0x5110,0x5115,0x5117,0x5118,0x511a,0x511a,0x511c,0x511c,0x511f,0x5122,0x5124,0x5126,0x5129,0x512b,0x512d,0x512e,0x5130,0x5135,0x5137,0x513d,0x513f,0x5141,0x5143,0x5149,0x514b,0x514d,0x5151,0x5152,0x5154,0x5157,0x5159,0x5163,0x5165,0x5165,0x5167,0x516e,0x5171,0x5171,0x5174,0x5179,0x517c,0x517c,0x5180,0x5180,0x5182,0x5182,0x5186,0x518a,0x518d,0x518d,0x518f,0x518f,0x5191,0x5198,0x519a,0x519a,0x519c,0x519c,0x519e,0x519e,0x51a0,0x51a0,0x51a2,0x51a2,0x51a4,0x51a5,0x51a7,0x51a8,0x51aa,0x51ac,0x51ae,0x51ae,0x51b0,0x51b9,0x51bc,0x51be,0x51c3,0x51d4,0x51d7,0x51d8,0x51db,0x51e2,0x51e4,0x51e4,0x51ed,0x51ed,0x51f0,0x51f1,0x51f3,0x51f6,0x51f8,0x51fa,0x51fc,0x51fe,0x5200,0x5203,0x5205,0x520c,0x520e,0x520e,0x5210,0x5213,0x5216,0x5217,0x521c,0x5221,0x5224,0x522a,0x522e,0x522e,0x5230,0x5238,0x523a,0x523c,0x5241,0x5241,0x5243,0x5244,0x5246,0x5247,0x5249,0x524f,0x5252,0x5252,0x5254,0x5257,0x5259,0x5262,0x5268,0x526f,0x5272,0x5275,0x5277,0x527d,0x527f,0x5284,0x5287,0x528d,0x528f,0x5291,0x5293,0x5294,0x5296,0x529b,0x529f,0x52a1,0x52a3,0x52a4,0x52a6,0x52a6,0x52a8,0x52ae,0x52b5,0x52b5,0x52b9,0x52b9,0x52bb,0x52bc,0x52be,0x52be,0x52c0,0x52c3,0x52c5,0x52c5,0x52c7,0x52c7,0x52c9,0x52c9,0x52cc,0x52cd,0x52d0,0x52d3,0x52d5,0x52d9,0x52db,0x52db,0x52dd,0x52e4,0x52e6,0x52e6,0x52e9,0x52e9,0x52eb,0x52eb,0x52ef,0x52f1,0x52f3,0x52f5,0x52f7,0x52fc,0x52fe,0x52ff,0x5301,0x5301,0x5305,0x5306,0x5308,0x530b,0x530d,0x5312,0x5315,0x5317,0x5319,0x531a,0x531c,0x531d,0x531f,0x5324,0x5327,0x5327,0x532a,0x532a,0x532c,0x532d,0x532f,0x5334,0x5337,0x5339,0x533b,0x5345,0x5347,0x534a,0x534c,0x534e,0x5351,0x5354,0x5357,0x5357,0x535a,0x535a,0x535c,0x5361,0x5363,0x5364,0x5366,0x5367,0x5369,0x5369,0x536c,0x5375,0x5377,0x5379,0x537b,0x537f,0x5382,0x5382,0x5384,0x5384,0x538a,0x538a,0x538e,0x538f,0x5392,0x5394,0x5396,0x539a,0x539c,0x53a0,0x53a2,0x53a2,0x53a4,0x53ae,0x53b0,0x53b0,0x53b2,0x53b2,0x53b4,0x53b4,0x53b6,0x53b6,0x53b9,0x53b9,0x53bb,0x53bb,0x53c1,0x53c3,0x53c5,0x53c5,0x53c8,0x53cd,0x53d0,0x53d2,0x53d4,0x53d4,0x53d6,0x53db,0x53df,0x53e6,0x53e8,0x53f3,0x53f5,0x53f8,0x53fb,0x53fc,0x53fe,0x53fe,0x5401,0x5401,0x5403,0x5404,0x5406,0x5414,0x5416,0x5416,0x5418,0x5421,0x5423,0x5439,0x543b,0x5443,0x5445,0x5448,0x544a,0x544f,0x5454,0x5454,0x5460,0x546d,0x546f,0x5478,0x547a,0x5482,0x5484,0x5488,0x548b,0x5498,0x549a,0x549a,0x549c,0x549c,0x549e,0x549e,0x54a0,0x54b4,0x54b6,0x54c9,0x54cb,0x54d0,0x54d6,0x54d6,0x54da,0x54da,0x54de,0x54de,0x54e0,0x54eb,0x54ed,0x54ef,0x54f1,0x54f3,0x54f7,0x54f8,0x54fa,0x54fd,0x54ff,0x54ff,0x5501,0x5514,0x5517,0x5518,0x551a,0x551a,0x551e,0x551e,0x5523,0x5523,0x5525,0x5528,0x552a,0x5539,0x553b,0x553c,0x553e,0x5541,0x5543,0x554b,0x554d,0x5553,0x5555,0x5557,0x555c,0x555f,0x5561,0x5566,0x5569,0x556b,0x5571,0x5573,0x5575,0x5577,0x5579,0x5579,0x557b,0x5584,0x5586,0x5595,0x5598,0x559a,0x559c,0x559d,0x559f,0x559f,0x55a1,0x55ae,0x55b0,0x55b5,0x55b9,0x55bc,0x55bf,0x55df,0x55e1,0x55ea,0x55ec,0x55ec,0x55ee,0x55f2,0x55f5,0x55f7,0x55f9,0x5602,0x5604,0x5606,0x5608,0x5609,0x560c,0x5617,0x561b,0x5623,0x5625,0x5625,0x5627,0x5627,0x5629,0x562a,0x562c,0x5630,0x5632,0x563b,0x563d,0x5643,0x5645,0x5646,0x5648,0x564a,0x564c,0x5650,0x5652,0x5654,0x5657,0x565a,0x565d,0x565e,0x5660,0x5666,0x5668,0x5674,0x5676,0x567c,0x567e,0x5687,0x5689,0x5690,0x5692,0x5693,0x5695,0x5695,0x5697,0x569a,0x569c,0x569f,0x56a1,0x56a1,0x56a4,0x56a8,0x56aa,0x56af,0x56b1,0x56b7,0x56b9,0x56b9,0x56bc,0x56c3,0x56c5,0x56c6,0x56c8,0x56cd,0x56d1,0x56d1,0x56d3,0x56d4,0x56d6,0x56d7,0x56da,0x56db,0x56dd,0x56e2,0x56e4,0x56e5,0x56e7,0x56e7,0x56ea,0x56eb,0x56ed,0x56f1,0x56f7,0x56f7,0x56f9,0x56fb,0x56fd,0x56fd,0x56ff,0x5704,0x5707,0x570d,0x5712,0x5716,0x5718,0x5718,0x571a,0x5720,0x5722,0x5723,0x5728,0x572a,0x572c,0x5730,0x5732,0x5734,0x573b,0x573b,0x573d,0x5743,0x5745,0x5747,0x5749,0x5752,0x5754,0x5754,0x5757,0x5757,0x575b,0x575b,0x575f,0x575f,0x5761,0x5762,0x5764,0x5764,0x5766,0x576b,0x576d,0x576d,0x576f,0x5777,0x577a,0x5780,0x5782,0x5783,0x5788,0x5788,0x578a,0x578d,0x578f,0x5790,0x5793,0x5795,0x5797,0x57a5,0x57a7,0x57a7,0x57aa,0x57aa,0x57ae,0x57ae,0x57b3,0x57b6,0x57b8,0x57bf,0x57c1,0x57c4,0x57c6,0x57c8,0x57cb,0x57cc,0x57ce,0x57d0,0x57d2,0x57d2,0x57d4,0x57d5,0x57d7,0x57d7,0x57dc,0x57e7,0x57e9,0x57e9,0x57ec,0x57fe,0x5800,0x580e,0x5810,0x5810,0x5812,0x5812,0x5814,0x5814,0x5818,0x5819,0x581b,0x581e,0x5820,0x582a,0x582c,0x583b,0x583d,0x583d,0x583f,0x5840,0x5844,0x5844,0x5847,0x584f,0x5851,0x5855,0x5857,0x585f,0x5862,0x5865,0x5868,0x5869,0x586b,0x586d,0x586f,0x586f,0x5871,0x5876,0x5879,0x5883,0x5885,0x588b,0x588e,0x5894,0x5896,0x5896,0x5898,0x589a,0x589c,0x58a1,0x58a3,0x58a3,0x58a5,0x58ac,0x58ae,0x58b1,0x58b3,0x58b3,0x58b5,0x58b6,0x58ba,0x58bf,0x58c1,0x58c2,0x58c5,0x58c9,0x58cb,0x58cb,0x58ce,0x58d6,0x58d8,0x58e0,0x58e2,0x58e4,0x58e7,0x58e9,0x58eb,0x58ec,0x58ef,0x58f0,0x58f2,0x58f4,0x58f9,0x58ff,0x5902,0x5907,0x590a,0x590a,0x590c,0x590f,0x5911,0x5912,0x5914,0x5917,0x5919,0x591a,0x591c,0x591d,0x591f,0x5920,0x5922,0x5922,0x5924,0x5925,0x5927,0x5927,0x5929,0x592f,0x5931,0x5932,0x5934,0x5934,0x5937,0x5938,0x593c,0x593c,0x593e,0x593e,0x5940,0x5940,0x5944,0x5945,0x5947,0x594a,0x594e,0x5951,0x5953,0x5955,0x5957,0x5958,0x595a,0x595a,0x595c,0x595c,0x5960,0x5962,0x5965,0x5965,0x5967,0x5967,0x5969,0x596e,0x5970,0x5979,0x597b,0x5985,0x5989,0x598a,0x598d,0x5990,0x5992,0x5994,0x5996,0x599a,0x599d,0x59a8,0x59ac,0x59ac,0x59ae,0x59c1,0x59c3,0x59d4,0x59d6,0x59d6,0x59d8,0x59de,0x59e0,0x59e1,0x59e3,0x59e6,0x59e8,0x5a03,0x5a09,0x5a0d,0x5a0f,0x5a0f,0x5a11,0x5a13,0x5a15,0x5a1c,0x5a1e,0x5a21,0x5a23,0x5a25,0x5a27,0x5a27,0x5a29,0x5a2e,0x5a33,0x5a33,0x5a35,0x5a39,0x5a3c,0x5a3e,0x5a40,0x5a4a,0x5a4c,0x5a4d,0x5a50,0x5a6e,0x5a70,0x5a71,0x5a77,0x5a7f,0x5a81,0x5a84,0x5a86,0x5a86,0x5a88,0x5a88,0x5a8a,0x5a8c,0x5a8e,0x5a97,0x5a99,0x5aa2,0x5aa4,0x5aa7,0x5aa9,0x5aac,0x5aae,0x5ac4,0x5ac6,0x5acf,0x5ad1,0x5ad1,0x5ad3,0x5ad3,0x5ad5,0x5ae6,0x5ae8,0x5aee,0x5af0,0x5af0,0x5af2,0x5afb,0x5afd,0x5aff,0x5b01,0x5b03,0x5b05,0x5b05,0x5b07,0x5b09,0x5b0b,0x5b0d,0x5b0f,0x5b11,0x5b13,0x5b17,0x5b19,0x5b1b,0x5b1d,0x5b21,0x5b23,0x5b28,0x5b2a,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b38,0x5b38,0x5b3c,0x5b41,0x5b43,0x5b48,0x5b4a,0x5b51,0x5b53,0x5b58,0x5b5a,0x5b5d,0x5b5f,0x5b5f,0x5b62,0x5b66,0x5b68,0x5b69,0x5b6b,0x5b6e,0x5b70,0x5b78,0x5b7a,0x5b7d,0x5b7f,0x5b85,0x5b87,0x5b89,0x5b8b,0x5b8c,0x5b8e,0x5b90,0x5b92,0x5b93,0x5b95,0x5b9f,0x5ba2,0x5ba8,0x5baa,0x5baa,0x5bac,0x5bae,0x5bb0,0x5bb0,0x5bb3,0x5bb9,0x5bbf,0x5bc7,0x5bca,0x5bce,0x5bd0,0x5bd9,0x5bdb,0x5bdb,0x5bde,0x5bec,0x5bee,0x5bf3,0x5bf5,0x5bf6,0x5bf8,0x5bf8,0x5bfa,0x5bfa,0x5bff,0x5bff,0x5c01,0x5c01,0x5c03,0x5c05,0x5c07,0x5c16,0x5c1a,0x5c1a,0x5c1c,0x5c1c,0x5c1e,0x5c20,0x5c22,0x5c25,0x5c28,0x5c28,0x5c2a,0x5c2a,0x5c2c,0x5c2c,0x5c30,0x5c31,0x5c33,0x5c33,0x5c37,0x5c3c,0x5c3e,0x5c41,0x5c44,0x5c51,0x5c53,0x5c56,0x5c58,0x5c59,0x5c5c,0x5c5e,0x5c60,0x5c60,0x5c62,0x5c65,0x5c67,0x5c6a,0x5c6c,0x5c6f,0x5c71,0x5c71,0x5c73,0x5c74,0x5c78,0x5c7c,0x5c7e,0x5c7e,0x5c85,0x5c86,0x5c88,0x5c8d,0x5c8f,0x5c95,0x5c99,0x5c9a,0x5c9c,0x5cb1,0x5cb3,0x5cb3,0x5cb5,0x5cb8,0x5cba,0x5cba,0x5cc1,0x5cc2,0x5cc6,0x5ccc,0x5cce,0x5cdb,0x5cde,0x5cdf,0x5ce5,0x5ce5,0x5ce8,0x5cea,0x5cec,0x5cf1,0x5cf4,0x5cf9,0x5cfb,0x5cfd,0x5cff,0x5d01,0x5d06,0x5d07,0x5d0b,0x5d12,0x5d14,0x5d1b,0x5d1d,0x5d20,0x5d22,0x5d29,0x5d2c,0x5d2c,0x5d2e,0x5d3a,0x5d3c,0x5d43,0x5d45,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d52,0x5d55,0x5d57,0x5d59,0x5d59,0x5d5b,0x5d5b,0x5d5e,0x5d5e,0x5d62,0x5d63,0x5d65,0x5d65,0x5d67,0x5d69,0x5d6b,0x5d6c,0x5d6f,0x5d72,0x5d74,0x5d74,0x5d77,0x5d82,0x5d84,0x5d8b,0x5d8d,0x5d8e,0x5d92,0x5d95,0x5d97,0x5d97,0x5d99,0x5d9a,0x5d9c,0x5da2,0x5da4,0x5da4,0x5da7,0x5db2,0x5db4,0x5dba,0x5dbc,0x5dbd,0x5dc0,0x5dc3,0x5dc6,0x5dc7,0x5dc9,0x5dc9,0x5dcb,0x5dcb,0x5dcd,0x5dcd,0x5dcf,0x5dcf,0x5dd1,0x5dd2,0x5dd4,0x5dd8,0x5ddb,0x5ddb,0x5ddd,0x5de2,0x5de5,0x5de8,0x5deb,0x5deb,0x5dee,0x5dee,0x5df0,0x5df5,0x5df7,0x5df7,0x5df9,0x5df9,0x5dfd,0x5dff,0x5e02,0x5e04,0x5e06,0x5e06,0x5e09,0x5e0c,0x5e0e,0x5e0e,0x5e11,0x5e12,0x5e14,0x5e1b,0x5e1d,0x5e1d,0x5e1f,0x5e25,0x5e28,0x5e29,0x5e2b,0x5e2b,0x5e2d,0x5e2e,0x5e33,0x5e34,0x5e36,0x5e38,0x5e3d,0x5e3e,0x5e40,0x5e45,0x5e48,0x5e48,0x5e4a,0x5e4f,0x5e53,0x5e55,0x5e57,0x5e59,0x5e5b,0x5e63,0x5e66,0x5e70,0x5e72,0x5e76,0x5e78,0x5e80,0x5e82,0x5e84,0x5e86,0x5e8d,0x5e8f,0x5e8f,0x5e92,0x5e92,0x5e95,0x5e97,0x5e99,0x5e9c,0x5ea0,0x5ea0,0x5ea2,0x5ea8,0x5eaa,0x5eae,0x5eb0,0x5eb9,0x5ebd,0x5ebe,0x5ec1,0x5ec2,0x5ec4,0x5ece,0x5ed0,0x5ee3,0x5ee5,0x5ee9,0x5eec,0x5eec,0x5eee,0x5eef,0x5ef1,0x5ef4,0x5ef6,0x5efc,0x5efe,0x5eff,0x5f01,0x5f02,0x5f04,0x5f05,0x5f07,0x5f08,0x5f0a,0x5f0f,0x5f12,0x5f15,0x5f17,0x5f18,0x5f1a,0x5f1b,0x5f1d,0x5f1d,0x5f1f,0x5f1f,0x5f22,0x5f29,0x5f2d,0x5f2e,0x5f30,0x5f31,0x5f33,0x5f33,0x5f35,0x5f38,0x5f3a,0x5f3c,0x5f40,0x5f40,0x5f43,0x5f46,0x5f48,0x5f51,0x5f54,0x5f54,0x5f56,0x5f59,0x5f5c,0x5f5e,0x5f61,0x5f65,0x5f67,0x5f67,0x5f69,0x5f6d,0x5f6f,0x5f74,0x5f76,0x5f79,0x5f7b,0x5f83,0x5f85,0x5f8c,0x5f90,0x5f92,0x5f96,0x5f99,0x5f9b,0x5f9c,0x5f9e,0x5fa1,0x5fa4,0x5faf,0x5fb1,0x5fb2,0x5fb5,0x5fb7,0x5fb9,0x5fc5,0x5fc9,0x5fc9,0x5fcc,0x5fcd,0x5fcf,0x5fd2,0x5fd4,0x5fd9,0x5fdb,0x5fdb,0x5fdd,0x5fe1,0x5fe3,0x5fe5,0x5fe8,0x5fe8,0x5fea,0x5feb,0x5fed,0x5fef,0x5ff1,0x5ff1,0x5ff3,0x5ff5,0x5ff7,0x5ff8,0x5ffa,0x5ffb,0x5ffd,0x5ffd,0x5fff,0x6000,0x6009,0x6017,0x6019,0x601e,0x6020,0x602f,0x6031,0x6035,0x6037,0x6037,0x6039,0x6039,0x603b,0x603b,0x6040,0x6047,0x6049,0x604d,0x6050,0x6050,0x6052,0x6055,0x6058,0x605b,0x605d,0x605f,0x6062,0x6070,0x6072,0x6072,0x6075,0x6075,0x6077,0x6077,0x607e,0x6081,0x6083,0x608a,0x608c,0x608e,0x6090,0x6090,0x6092,0x6092,0x6094,0x6097,0x609a,0x60a0,0x60a2,0x60a4,0x60a6,0x60a8,0x60b0,0x60c1,0x60c3,0x60cf,0x60d1,0x60d1,0x60d3,0x60d5,0x60d7,0x60e4,0x60e6,0x60e9,0x60f0,0x6101,0x6103,0x6110,0x6112,0x6116,0x6118,0x611d,0x611f,0x6120,0x6122,0x6123,0x6127,0x6129,0x612b,0x612c,0x612e,0x6130,0x6132,0x6132,0x6134,0x6134,0x6136,0x6137,0x613b,0x613b,0x613d,0x6142,0x6144,0x6150,0x6152,0x6156,0x6158,0x6168,0x616a,0x616c,0x616e,0x6177,0x6179,0x617a,0x617c,0x617e,0x6180,0x6183,0x6187,0x6187,0x6189,0x618e,0x6190,0x6196,0x6198,0x619d,0x619f,0x619f,0x61a1,0x61a2,0x61a4,0x61a4,0x61a7,0x61ba,0x61bc,0x61bc,0x61be,0x61c3,0x61c5,0x61cd,0x61cf,0x61d0,0x61d3,0x61d3,0x61d6,0x61d6,0x61d8,0x61d8,0x61da,0x61da,0x61de,0x61e0,0x61e2,0x61eb,0x61ed,0x61ee,0x61f0,0x61f2,0x61f5,0x6201,0x6203,0x6204,0x6207,0x620a,0x620c,0x620e,0x6210,0x6212,0x6214,0x6216,0x6219,0x621b,0x621f,0x6225,0x6227,0x6227,0x6229,0x622e,0x6230,0x6230,0x6232,0x6234,0x6236,0x6237,0x6239,0x623a,0x623d,0x6243,0x6246,0x624e,0x6250,0x6254,0x6258,0x625c,0x625e,0x625e,0x6260,0x6266,0x6268,0x6268,0x626d,0x6274,0x6276,0x6277,0x6279,0x628a,0x628c,0x628c,0x628e,0x6298,0x629d,0x629d,0x62a4,0x62a4,0x62a6,0x62a6,0x62a8,0x62b1,0x62b3,0x62b6,0x62b8,0x62b9,0x62bb,0x62bf,0x62c1,0x62dc,0x62df,0x62df,0x62e5,0x62e5,0x62eb,0x6303,0x6307,0x6309,0x630b,0x6311,0x6313,0x6316,0x6318,0x6318,0x6328,0x632f,0x6331,0x633e,0x6340,0x6351,0x6354,0x635a,0x635d,0x635d,0x6364,0x6365,0x6367,0x6369,0x636b,0x6372,0x6375,0x637d,0x637f,0x6385,0x6387,0x6392,0x6394,0x6394,0x6396,0x6399,0x639b,0x63a5,0x63a7,0x63b1,0x63b9,0x63b9,0x63bd,0x63be,0x63c0,0x63d3,0x63d5,0x63eb,0x63ed,0x63f6,0x63f8,0x63f9,0x63fb,0x63fc,0x63fe,0x63fe,0x6406,0x6407,0x6409,0x6410,0x6412,0x6418,0x641a,0x641c,0x641e,0x6428,0x642a,0x6430,0x6432,0x643b,0x643d,0x6441,0x6443,0x6443,0x644b,0x644b,0x644d,0x644e,0x6450,0x6454,0x6458,0x6461,0x6465,0x6469,0x646b,0x647d,0x647f,0x647f,0x6482,0x6482,0x6485,0x6485,0x6487,0x648d,0x648f,0x6493,0x6495,0x649a,0x649c,0x64a0,0x64a2,0x64a6,0x64a9,0x64a9,0x64ab,0x64b4,0x64b6,0x64b6,0x64bb,0x64c5,0x64c7,0x64c7,0x64c9,0x64cb,0x64cd,0x64d0,0x64d2,0x64d4,0x64d6,0x64db,0x64dd,0x64dd,0x64e0,0x64ed,0x64ef,0x64f4,0x64f7,0x64f8,0x64fa,0x6501,0x6503,0x6504,0x6506,0x6507,0x6509,0x650a,0x650c,0x6511,0x6513,0x6519,0x651b,0x6526,0x6529,0x6530,0x6532,0x6539,0x653b,0x653b,0x653d,0x653f,0x6541,0x6541,0x6543,0x6543,0x6545,0x6546,0x6548,0x654a,0x654d,0x654d,0x654f,0x654f,0x6551,0x6551,0x6553,0x655a,0x655c,0x655f,0x6562,0x6568,0x656a,0x656d,0x656f,0x656f,0x6572,0x657c,0x657f,0x6589,0x658b,0x658c,0x6590,0x6592,0x6594,0x6597,0x6599,0x6599,0x659b,0x65a2,0x65a4,0x65a5,0x65a7,0x65a8,0x65aa,0x65ac,0x65ae,0x65b0,0x65b2,0x65b3,0x65b5,0x65b9,0x65bb,0x65bf,0x65c1,0x65c6,0x65cb,0x65d4,0x65d6,0x65d7,0x65da,0x65db,0x65dd,0x65e3,0x65e5,0x65e6,0x65e8,0x65e9,0x65ec,0x65f5,0x65fa,0x65fd,0x65ff,0x6600,0x6602,0x6615,0x6618,0x6618,0x661c,0x6628,0x662b,0x662b,0x662d,0x6636,0x6639,0x663a,0x6641,0x6645,0x6647,0x664d,0x664f,0x664f,0x6651,0x6653,0x6657,0x6657,0x6659,0x6668,0x666a,0x666c,0x666e,0x6674,0x6676,0x667e,0x6680,0x6680,0x6684,0x668e,0x6690,0x6692,0x6694,0x669a,0x669d,0x669d,0x669f,0x66a2,0x66a4,0x66a4,0x66a8,0x66ab,0x66ad,0x66bb,0x66bd,0x66c0,0x66c4,0x66c4,0x66c6,0x66cf,0x66d2,0x66d2,0x66d6,0x66d6,0x66d8,0x66de,0x66e0,0x66e0,0x66e3,0x66e4,0x66e6,0x66e9,0x66eb,0x66ee,0x66f0,0x66f4,0x66f6,0x66f9,0x66fc,0x66fc,0x66fe,0x6705,0x6708,0x6710,0x6712,0x6719,0x671b,0x671b,0x671d,0x6723,0x6725,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6736,0x6738,0x673f,0x6744,0x6749,0x674b,0x6751,0x6753,0x6753,0x6755,0x6757,0x6759,0x675a,0x675c,0x6762,0x6767,0x6767,0x676a,0x677f,0x6781,0x6787,0x6789,0x6789,0x678b,0x6795,0x6797,0x679a,0x679c,0x679d,0x679f,0x67a0,0x67a4,0x67a4,0x67ac,0x67ac,0x67ae,0x67bb,0x67bf,0x67c6,0x67c8,0x67d4,0x67d6,0x67df,0x67e2,0x67e7,0x67e9,0x67fa,0x67fc,0x67fc,0x67fe,0x6804,0x680d,0x680d,0x6810,0x6810,0x6812,0x6814,0x6816,0x6818,0x681a,0x6822,0x6825,0x6826,0x6828,0x682b,0x682d,0x682f,0x6831,0x683e,0x6840,0x6851,0x6853,0x6856,0x685d,0x685d,0x6865,0x6865,0x686b,0x686b,0x686d,0x686f,0x6871,0x6872,0x6874,0x6879,0x687b,0x688c,0x688f,0x6894,0x6896,0x6898,0x689b,0x689d,0x689f,0x68a4,0x68a6,0x68b6,0x68b9,0x68b9,0x68bd,0x68bd,0x68c1,0x68c1,0x68c3,0x68ce,0x68d0,0x68d8,0x68da,0x68da,0x68dc,0x68e1,0x68e3,0x68e4,0x68e6,0x68ec,0x68ee,0x68fd,0x6900,0x6915,0x6917,0x691b,0x6925,0x6925,0x692a,0x692a,0x692c,0x692c,0x692f,0x6930,0x6932,0x6939,0x693b,0x6946,0x6948,0x694c,0x694e,0x694f,0x6951,0x697b,0x6980,0x6980,0x6982,0x6983,0x6985,0x6986,0x698a,0x698a,0x698d,0x698e,0x6990,0x6991,0x6993,0x699c,0x699e,0x69b7,0x69b9,0x69b9,0x69bb,0x69c4,0x69c6,0x69c6,0x69c9,0x69d1,0x69d3,0x69d6,0x69d9,0x69d9,0x69e1,0x69e2,0x69e4,0x69e9,0x69eb,0x69ee,0x69f1,0x69f4,0x69f6,0x6a0d,0x6a0f,0x6a0f,0x6a11,0x6a11,0x6a13,0x6a21,0x6a23,0x6a23,0x6a25,0x6a29,0x6a2b,0x6a2d,0x6a32,0x6a35,0x6a38,0x6a41,0x6a43,0x6a49,0x6a4b,0x6a5b,0x6a5d,0x6a6b,0x6a6d,0x6a6d,0x6a6f,0x6a6f,0x6a71,0x6a71,0x6a74,0x6a74,0x6a76,0x6a76,0x6a7a,0x6a7a,0x6a7e,0x6a85,0x6a87,0x6a87,0x6a89,0x6a8a,0x6a8c,0x6a97,0x6a99,0x6aa8,0x6aab,0x6aaf,0x6ab1,0x6abb,0x6abd,0x6abe,0x6ac2,0x6ac3,0x6ac5,0x6acd,0x6acf,0x6ad1,0x6ad3,0x6ad4,0x6ad8,0x6ae1,0x6ae5,0x6ae5,0x6ae7,0x6ae8,0x6aea,0x6aec,0x6aee,0x6af1,0x6af3,0x6af3,0x6af6,0x6af6,0x6af8,0x6afc,0x6b00,0x6b00,0x6b02,0x6b05,0x6b08,0x6b0b,0x6b0f,0x6b13,0x6b16,0x6b1a,0x6b1d,0x6b1e,0x6b20,0x6b21,0x6b23,0x6b23,0x6b25,0x6b25,0x6b28,0x6b28,0x6b2c,0x6b2d,0x6b2f,0x6b2f,0x6b31,0x6b3f,0x6b41,0x6b43,0x6b45,0x6b4e,0x6b50,0x6b52,0x6b54,0x6b57,0x6b59,0x6b59,0x6b5b,0x6b5c,0x6b5e,0x6b67,0x6b6a,0x6b6a,0x6b6d,0x6b6d,0x6b6f,0x6b6f,0x6b72,0x6b72,0x6b74,0x6b74,0x6b76,0x6b7b,0x6b7e,0x6b84,0x6b86,0x6b86,0x6b88,0x6b8a,0x6b8c,0x6b8f,0x6b91,0x6b91,0x6b94,0x6b99,0x6b9b,0x6b9b,0x6b9e,0x6ba0,0x6ba2,0x6ba7,0x6baa,0x6bab,0x6bad,0x6bb0,0x6bb2,0x6bb3,0x6bb5,0x6bb7,0x6bba,0x6bba,0x6bbc,0x6bbd,0x6bbf,0x6bc1,0x6bc3,0x6bcd,0x6bcf,0x6bd0,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdc,0x6bde,0x6bde,0x6be0,0x6be4,0x6be6,0x6be8,0x6bea,0x6bec,0x6bef,0x6bf0,0x6bf2,0x6bf3,0x6bf7,0x6c06,0x6c08,0x6c09,0x6c0b,0x6c0d,0x6c0f,0x6c11,0x6c13,0x6c16,0x6c18,0x6c1d,0x6c1f,0x6c21,0x6c23,0x6c28,0x6c2a,0x6c2c,0x6c2e,0x6c3b,0x6c3d,0x6c43,0x6c46,0x6c46,0x6c49,0x6c50,0x6c52,0x6c52,0x6c54,0x6c55,0x6c57,0x6c61,0x6c65,0x6c6b,0x6c6d,0x6c76,0x6c78,0x6c7b,0x6c7d,0x6c90,0x6c92,0x6c96,0x6c98,0x6c9d,0x6c9f,0x6c9f,0x6ca2,0x6ca2,0x6caa,0x6cb4,0x6cb6,0x6cc7,0x6cc9,0x6cd7,0x6cd9,0x6ce3,0x6ce5,0x6ce5,0x6ce7,0x6cf3,0x6cf5,0x6cf5,0x6cf9,0x6cf9,0x6cff,0x6d12,0x6d16,0x6d1b,0x6d1d,0x6d20,0x6d22,0x6d22,0x6d24,0x6d42,0x6d4e,0x6d4e,0x6d57,0x6d5c,0x6d5e,0x6d6a,0x6d6c,0x6d72,0x6d74,0x6d98,0x6d9a,0x6d9a,0x6da4,0x6da5,0x6daa,0x6dac,0x6dae,0x6daf,0x6db1,0x6db5,0x6db7,0x6dc0,0x6dc2,0x6dc2,0x6dc4,0x6dcd,0x6dcf,0x6de6,0x6de8,0x6df7,0x6df9,0x6dfe,0x6e00,0x6e00,0x6e02,0x6e05,0x6e0a,0x6e0a,0x6e0f,0x6e0f,0x6e15,0x6e15,0x6e18,0x6e1d,0x6e1f,0x6e36,0x6e38,0x6e41,0x6e43,0x6e47,0x6e49,0x6e4b,0x6e4d,0x6e69,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e71,0x6e74,0x6e76,0x6e79,0x6e7c,0x6e7c,0x6e86,0x6e86,0x6e88,0x6e89,0x6e8b,0x6e8b,0x6e8d,0x6e90,0x6e92,0x6e94,0x6e96,0x6ea7,0x6eaa,0x6eab,0x6eae,0x6ed6,0x6ed8,0x6edd,0x6ee2,0x6ee2,0x6ee8,0x6ee9,0x6eeb,0x6eef,0x6ef1,0x6ef2,0x6ef4,0x6f0f,0x6f12,0x6f1a,0x6f1c,0x6f1c,0x6f1e,0x6f27,0x6f29,0x6f41,0x6f43,0x6f44,0x6f4e,0x6f58,0x6f5a,0x6f64,0x6f66,0x6f67,0x6f69,0x6f70,0x6f72,0x6f74,0x6f76,0x6f82,0x6f84,0x6f8e,0x6f90,0x6f90,0x6f92,0x6f97,0x6f9d,0x6fb6,0x6fb8,0x6fc4,0x6fc6,0x6fcf,0x6fd3,0x6fd5,0x6fd8,0x6fe4,0x6fe6,0x6fe9,0x6feb,0x6ff2,0x6ff4,0x6ff4,0x6ff6,0x6ff8,0x6ffa,0x6ffc,0x6ffe,0x7001,0x7003,0x7007,0x7009,0x700f,0x7011,0x7011,0x7014,0x7024,0x7026,0x702c,0x702f,0x7035,0x7037,0x703c,0x703e,0x7046,0x7048,0x704d,0x7050,0x7052,0x7054,0x7058,0x705a,0x706c,0x706e,0x7071,0x7074,0x707a,0x707c,0x707f,0x7081,0x7086,0x7089,0x708b,0x708e,0x708f,0x7091,0x7096,0x7098,0x709a,0x709f,0x70a1,0x70a3,0x70a7,0x70a9,0x70a9,0x70ab,0x70b1,0x70b3,0x70b5,0x70b7,0x70be,0x70c0,0x70c0,0x70c4,0x70c8,0x70ca,0x70da,0x70dc,0x70e2,0x70e4,0x70e4,0x70ef,0x70f1,0x70f3,0x7100,0x7102,0x7102,0x7104,0x7106,0x7109,0x710e,0x7110,0x7110,0x7113,0x7113,0x7117,0x7117,0x7119,0x7123,0x7125,0x7126,0x7128,0x7129,0x712b,0x712c,0x712e,0x7136,0x713a,0x713b,0x713e,0x713e,0x7140,0x7147,0x7149,0x7154,0x7156,0x715a,0x715c,0x716c,0x716e,0x716e,0x7170,0x7178,0x717a,0x717e,0x7180,0x7182,0x7184,0x718a,0x718c,0x718c,0x718e,0x7192,0x7194,0x7194,0x7196,0x71a5,0x71a7,0x71aa,0x71ac,0x71ad,0x71af,0x71b5,0x71b7,0x71ba,0x71bc,0x71cb,0x71ce,0x71d2,0x71d4,0x71d6,0x71d8,0x71dd,0x71df,0x71e2,0x71e4,0x71e8,0x71eb,0x71ee,0x71f0,0x71f2,0x71f4,0x71f6,0x71f8,0x71f9,0x71fb,0x7203,0x7205,0x7207,0x7209,0x720a,0x720c,0x7210,0x7213,0x7217,0x7219,0x721b,0x721d,0x721f,0x7222,0x722e,0x7230,0x7230,0x7235,0x7236,0x7238,0x723b,0x723d,0x7242,0x7244,0x7244,0x7246,0x724c,0x724f,0x7250,0x7252,0x7253,0x7255,0x7263,0x7266,0x7267,0x7269,0x726a,0x726c,0x726c,0x726e,0x7270,0x7272,0x7274,0x7276,0x7279,0x727b,0x7282,0x7284,0x7289,0x728b,0x7298,0x729a,0x729b,0x729d,0x729f,0x72a1,0x72aa,0x72ac,0x72b0,0x72b2,0x72b2,0x72b4,0x72b5,0x72ba,0x72ba,0x72bd,0x72bd,0x72bf,0x72c6,0x72c9,0x72ce,0x72d0,0x72d2,0x72d4,0x72d4,0x72d6,0x72da,0x72dc,0x72dc,0x72df,0x72e4,0x72e6,0x72e6,0x72e8,0x72eb,0x72f3,0x72f4,0x72f6,0x7302,0x7304,0x7304,0x7307,0x7308,0x730a,0x730c,0x730f,0x7313,0x7316,0x7319,0x731b,0x731e,0x7322,0x7323,0x7325,0x732e,0x7330,0x733c,0x733e,0x7345,0x7348,0x734a,0x734c,0x7352,0x7357,0x735b,0x735d,0x7362,0x7365,0x736c,0x736e,0x7378,0x737a,0x738c,0x738e,0x738f,0x7392,0x7398,0x739c,0x73a2,0x73a4,0x73ad,0x73b2,0x73bc,0x73be,0x73c0,0x73c2,0x73d0,0x73d2,0x73de,0x73e0,0x73eb,0x73ed,0x73ef,0x73f3,0x740d,0x7411,0x7412,0x7414,0x7417,0x7419,0x7426,0x7428,0x743a,0x743c,0x743c,0x743f,0x7457,0x7459,0x7465,0x7467,0x7476,0x7479,0x747a,0x747c,0x7483,0x7485,0x748d,0x7490,0x7490,0x7492,0x7492,0x7494,0x7495,0x7497,0x74a1,0x74a3,0x74ab,0x74ad,0x74ad,0x74af,0x74b2,0x74b4,0x74bb,0x74bd,0x74c3,0x74c5,0x74c6,0x74c8,0x74c8,0x74ca,0x74cc,0x74cf,0x74d0,0x74d3,0x74e9,0x74ec,0x74ec,0x74ee,0x74ee,0x74f0,0x74f2,0x74f4,0x74f8,0x74fb,0x74fb,0x74fd,0x7500,0x7502,0x7505,0x7507,0x7508,0x750b,0x751a,0x751c,0x751f,0x7521,0x7522,0x7525,0x7526,0x7528,0x7535,0x7537,0x753b,0x753d,0x7540,0x7542,0x7542,0x7546,0x7548,0x754a,0x754f,0x7551,0x7551,0x7553,0x7555,0x7559,0x755d,0x755f,0x7560,0x7562,0x7567,0x756a,0x7570,0x7572,0x7572,0x7576,0x757a,0x757d,0x7580,0x7583,0x7584,0x7586,0x7587,0x758a,0x7592,0x7594,0x7595,0x7598,0x759a,0x759d,0x759e,0x75a2,0x75a5,0x75a7,0x75a7,0x75aa,0x75ab,0x75b0,0x75b6,0x75b8,0x75c5,0x75c7,0x75c8,0x75ca,0x75d2,0x75d4,0x75d5,0x75d7,0x75e4,0x75e6,0x75e7,0x75ed,0x75ed,0x75ef,0x7603,0x7607,0x760d,0x760f,0x7611,0x7613,0x7616,0x7619,0x7629,0x762c,0x762d,0x762f,0x7635,0x7638,0x7638,0x763a,0x763d,0x7640,0x7640,0x7642,0x7643,0x7646,0x7649,0x764c,0x7654,0x7656,0x765a,0x765c,0x765c,0x765f,0x7662,0x7664,0x7667,0x7669,0x766a,0x766c,0x7676,0x7678,0x767f,0x7681,0x7682,0x7684,0x7684,0x7686,0x768b,0x768e,0x7690,0x7692,0x7693,0x7695,0x7696,0x7699,0x769e,0x76a1,0x76a1,0x76a4,0x76a6,0x76aa,0x76ab,0x76ad,0x76b0,0x76b4,0x76b5,0x76b7,0x76b8,0x76ba,0x76bb,0x76bd,0x76bf,0x76c2,0x76c6,0x76c8,0x76ca,0x76cc,0x76ce,0x76d2,0x76d4,0x76d6,0x76d6,0x76d9,0x76df,0x76e1,0x76e1,0x76e3,0x76e7,0x76e9,0x76ea,0x76ec,0x76f5,0x76f7,0x76fc,0x76fe,0x76fe,0x7701,0x7701,0x7703,0x7705,0x7707,0x770c,0x770e,0x7713,0x7715,0x7715,0x7719,0x771b,0x771d,0x7720,0x7722,0x7729,0x772b,0x772b,0x772d,0x772d,0x772f,0x772f,0x7731,0x773e,0x7740,0x7740,0x7743,0x7747,0x774a,0x774f,0x7752,0x7752,0x7754,0x7756,0x7758,0x775c,0x775e,0x7763,0x7765,0x776f,0x7772,0x7772,0x7777,0x7785,0x7787,0x7789,0x778b,0x778f,0x7791,0x7791,0x7793,0x7793,0x7795,0x7795,0x7797,0x77a3,0x77a5,0x77a5,0x77a7,0x77a8,0x77aa,0x77ad,0x77af,0x77b7,0x77b9,0x77bf,0x77c2,0x77c5,0x77c7,0x77c7,0x77c9,0x77d0,0x77d3,0x77d5,0x77d7,0x77de,0x77e0,0x77e0,0x77e2,0x77e3,0x77e5,0x77e9,0x77ec,0x77f4,0x77f7,0x77fe,0x7802,0x7803,0x7805,0x7806,0x7808,0x7809,0x780c,0x7814,0x7818,0x7818,0x781c,0x7823,0x7825,0x7835,0x7837,0x7839,0x783c,0x783d,0x7842,0x7845,0x7847,0x784e,0x7850,0x7854,0x785c,0x785e,0x7860,0x7860,0x7862,0x7862,0x7864,0x7866,0x7868,0x7871,0x7879,0x787c,0x787e,0x7881,0x7883,0x7889,0x788c,0x788f,0x7891,0x7891,0x7893,0x789a,0x789e,0x78a5,0x78a7,0x78ad,0x78af,0x78b4,0x78b6,0x78b6,0x78b8,0x78bc,0x78be,0x78be,0x78c1,0x78c1,0x78c3,0x78c5,0x78c7,0x78d5,0x78d7,0x78d8,0x78da,0x78db,0x78dd,0x78e5,0x78e7,0x78ea,0x78ec,0x78f5,0x78f7,0x78f7,0x78f9,0x78ff,0x7901,0x7902,0x7904,0x7906,0x7909,0x7909,0x790c,0x790c,0x790e,0x790e,0x7910,0x7914,0x7917,0x7917,0x7919,0x7919,0x791b,0x791e,0x7921,0x7921,0x7923,0x792f,0x7931,0x7936,0x7938,0x7942,0x7944,0x794c,0x794f,0x7965,0x7967,0x796b,0x796d,0x796d,0x7970,0x7974,0x7979,0x797a,0x797c,0x7983,0x7986,0x7988,0x798a,0x798b,0x798d,0x799d,0x799f,0x79a2,0x79a4,0x79ae,0x79b0,0x79b4,0x79b6,0x79bb,0x79bd,0x79c1,0x79c4,0x79c6,0x79c8,0x79d2,0x79d4,0x79d6,0x79d8,0x79d8,0x79dc,0x79e0,0x79e2,0x79e4,0x79e6,0x79e7,0x79e9,0x79ee,0x79f1,0x79f1,0x79f4,0x79f4,0x79f6,0x79f8,0x79fa,0x79fb,0x7a00,0x7a00,0x7a02,0x7a06,0x7a08,0x7a08,0x7a0a,0x7a0e,0x7a10,0x7a15,0x7a17,0x7a1c,0x7a1e,0x7a20,0x7a22,0x7a22,0x7a26,0x7a26,0x7a28,0x7a28,0x7a2a,0x7a32,0x7a37,0x7a37,0x7a39,0x7a40,0x7a43,0x7a4e,0x7a54,0x7a54,0x7a56,0x7a58,0x7a5a,0x7a5c,0x7a5f,0x7a62,0x7a65,0x7a65,0x7a67,0x7a69,0x7a6b,0x7a6e,0x7a70,0x7a72,0x7a74,0x7a76,0x7a78,0x7a7b,0x7a7d,0x7a81,0x7a83,0x7a8c,0x7a8f,0x7a99,0x7a9e,0x7aa0,0x7aa2,0x7aa3,0x7aa8,0x7aac,0x7aae,0x7ab8,0x7aba,0x7abc,0x7abe,0x7ac5,0x7ac7,0x7acb,0x7acf,0x7acf,0x7ad1,0x7ad1,0x7ad3,0x7ad3,0x7ad8,0x7add,0x7adf,0x7ae0,0x7ae2,0x7ae7,0x7ae9,0x7aeb,0x7aed,0x7aef,0x7af6,0x7af7,0x7af9,0x7b01,0x7b04,0x7b06,0x7b08,0x7b0c,0x7b0e,0x7b14,0x7b18,0x7b1b,0x7b1d,0x7b20,0x7b22,0x7b35,0x7b38,0x7b39,0x7b3b,0x7b3b,0x7b40,0x7b40,0x7b42,0x7b52,0x7b54,0x7b56,0x7b58,0x7b58,0x7b60,0x7b67,0x7b69,0x7b69,0x7b6c,0x7b78,0x7b7b,0x7b7b,0x7b82,0x7b82,0x7b84,0x7b85,0x7b87,0x7b88,0x7b8a,0x7b92,0x7b94,0x7b9d,0x7ba0,0x7ba4,0x7bac,0x7baf,0x7bb1,0x7bb2,0x7bb4,0x7bb5,0x7bb7,0x7bb9,0x7bbe,0x7bbe,0x7bc0,0x7bc1,0x7bc4,0x7bc7,0x7bc9,0x7bcc,0x7bce,0x7bd0,0x7bd4,0x7bd5,0x7bd8,0x7bec,0x7bf0,0x7bf4,0x7bf7,0x7c03,0x7c05,0x7c07,0x7c09,0x7c12,0x7c15,0x7c15,0x7c19,0x7c19,0x7c1b,0x7c23,0x7c25,0x7c2d,0x7c30,0x7c30,0x7c33,0x7c33,0x7c35,0x7c35,0x7c37,0x7c39,0x7c3b,0x7c40,0x7c42,0x7c45,0x7c47,0x7c4a,0x7c4c,0x7c4d,0x7c50,0x7c51,0x7c53,0x7c54,0x7c56,0x7c57,0x7c59,0x7c5d,0x7c5f,0x7c60,0x7c63,0x7c67,0x7c69,0x7c70,0x7c72,0x7c75,0x7c78,0x7c81,0x7c83,0x7c86,0x7c88,0x7c8a,0x7c8c,0x7c8e,0x7c91,0x7c92,0x7c94,0x7c98,0x7c9c,0x7c9c,0x7c9e,0x7c9f,0x7ca1,0x7ca3,0x7ca5,0x7ca8,0x7cac,0x7cac,0x7cae,0x7caf,0x7cb1,0x7cb5,0x7cb8,0x7cbf,0x7cc2,0x7cc3,0x7cc5,0x7cc5,0x7cc7,0x7cce,0x7cd0,0x7cd7,0x7cd9,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce6,0x7ce8,0x7cea,0x7cea,0x7cec,0x7cf9,0x7cfb,0x7cfe,0x7d00,0x7d22,0x7d25,0x7d25,0x7d28,0x7d29,0x7d2b,0x7d2c,0x7d2e,0x7d33,0x7d35,0x7d36,0x7d38,0x7d47,0x7d4a,0x7d4a,0x7d4d,0x7d56,0x7d58,0x7d58,0x7d5a,0x7d5f,0x7d61,0x7d63,0x7d66,0x7d6b,0x7d6d,0x7d73,0x7d79,0x7d7d,0x7d7f,0x7d81,0x7d83,0x7d86,0x7d88,0x7d89,0x7d8b,0x7d8f,0x7d91,0x7d97,0x7d9c,0x7da4,0x7da6,0x7db5,0x7db7,0x7dc2,0x7dc4,0x7dc7,0x7dc9,0x7dd0,0x7dd2,0x7dd4,0x7dd7,0x7de1,0x7de3,0x7dea,0x7dec,0x7dec,0x7dee,0x7df7,0x7df9,0x7dfe,0x7e03,0x7e03,0x7e07,0x7e17,0x7e1a,0x7e25,0x7e27,0x7e27,0x7e29,0x7e2b,0x7e2d,0x7e49,0x7e4c,0x7e4c,0x7e50,0x7e5c,0x7e5e,0x7e63,0x7e65,0x7e65,0x7e67,0x7e70,0x7e72,0x7e82,0x7e86,0x7e88,0x7e8a,0x7e8f,0x7e91,0x7e9c,0x7e9f,0x7e9f,0x7ea4,0x7ea4,0x7eac,0x7eac,0x7eba,0x7eba,0x7ec7,0x7ec7,0x7ecf,0x7ecf,0x7edf,0x7edf,0x7f06,0x7f06,0x7f36,0x7f3a,0x7f3d,0x7f41,0x7f43,0x7f45,0x7f47,0x7f55,0x7f58,0x7f58,0x7f5b,0x7f61,0x7f63,0x7f63,0x7f65,0x7f6e,0x7f70,0x7f73,0x7f75,0x7f7f,0x7f83,0x7f83,0x7f85,0x7f8f,0x7f91,0x7f97,0x7f9a,0x7f9e,0x7fa0,0x7fa9,0x7fac,0x7fc3,0x7fc5,0x7fc5,0x7fc7,0x7fc7,0x7fc9,0x7fd2,0x7fd4,0x7fd5,0x7fd7,0x7fd7,0x7fdb,0x7fe3,0x7fe5,0x7ff5,0x7ff7,0x8008,0x800b,0x8012,0x8014,0x8019,0x801b,0x8021,0x8024,0x8026,0x8028,0x802a,0x802c,0x802c,0x802e,0x8031,0x8033,0x8037,0x8039,0x8039,0x803b,0x803f,0x8043,0x8043,0x8046,0x8048,0x804a,0x804a,0x804f,0x8052,0x8054,0x8054,0x8056,0x8056,0x8058,0x8058,0x805a,0x805e,0x8061,0x8064,0x8066,0x8067,0x806c,0x806c,0x806f,0x8073,0x8075,0x8079,0x807d,0x8080,0x8082,0x8082,0x8084,0x8087,0x8089,0x808c,0x808f,0x8090,0x8092,0x8093,0x8095,0x8096,0x8098,0x809d,0x809f,0x809f,0x80a1,0x80a3,0x80a5,0x80a5,0x80a7,0x80a7,0x80a9,0x80ab,0x80ad,0x80af,0x80b1,0x80b2,0x80b4,0x80b8,0x80ba,0x80ba,0x80bc,0x80bd,0x80c2,0x80ca,0x80cc,0x80d1,0x80d4,0x80de,0x80e0,0x80e1,0x80e3,0x80e6,0x80e9,0x80e9,0x80ec,0x80ed,0x80ef,0x80f6,0x80f8,0x80fe,0x8100,0x8103,0x8105,0x810a,0x810c,0x810c,0x810e,0x810e,0x8112,0x8112,0x8114,0x811b,0x811d,0x811f,0x8121,0x8125,0x8127,0x8127,0x8129,0x812d,0x812f,0x8132,0x8134,0x8134,0x8137,0x8137,0x8139,0x813a,0x813d,0x813e,0x8142,0x8144,0x8146,0x8148,0x814a,0x8156,0x8159,0x815c,0x815e,0x815e,0x8160,0x8162,0x8164,0x8167,0x8169,0x8169,0x816b,0x8174,0x8176,0x817a,0x817c,0x817d,0x817f,0x8180,0x8182,0x8184,0x8186,0x818d,0x818f,0x818f,0x8193,0x8193,0x8195,0x8195,0x8197,0x81a0,0x81a2,0x81a3,0x81a5,0x81ac,0x81ae,0x81ae,0x81b0,0x81b7,0x81b9,0x81ca,0x81cc,0x81cd,0x81cf,0x81d2,0x81d5,0x81d5,0x81d7,0x81db,0x81dd,0x81ea,0x81ec,0x81ef,0x81f2,0x81f4,0x81f6,0x81fc,0x81fe,0x8202,0x8204,0x8205,0x8207,0x820d,0x8210,0x8212,0x8214,0x8216,0x8218,0x8218,0x821a,0x8222,0x8225,0x8226,0x8228,0x822d,0x822f,0x822f,0x8232,0x823a,0x823c,0x8240,0x8242,0x8242,0x8244,0x8245,0x8247,0x8247,0x8249,0x8249,0x824b,0x824b,0x824e,0x825c,0x825e,0x825f,0x8261,0x8266,0x8268,0x8269,0x826b,0x826f,0x8271,0x8272,0x8274,0x8280,0x8283,0x8285,0x8287,0x8287,0x828a,0x828b,0x828d,0x8294,0x8298,0x829b,0x829d,0x82b1,0x82b3,0x82c0,0x82c2,0x82c4,0x82ca,0x82ca,0x82cf,0x82d9,0x82db,0x82dc,0x82de,0x82e8,0x82ea,0x8309,0x830b,0x830d,0x8316,0x831e,0x8320,0x8320,0x8322,0x8322,0x8324,0x832d,0x832f,0x832f,0x8331,0x833d,0x833f,0x8345,0x8347,0x8354,0x8356,0x8357,0x8362,0x8363,0x8366,0x8366,0x836f,0x836f,0x8373,0x8378,0x837a,0x837f,0x8381,0x8381,0x8383,0x8383,0x8385,0x839e,0x83a0,0x83a0,0x83a2,0x83ac,0x83ae,0x83b0,0x83b9,0x83b9,0x83bd,0x83cf,0x83d1,0x83d1,0x83d3,0x83d9,0x83db,0x83e5,0x83e7,0x83f6,0x83f8,0x83ff,0x8401,0x8401,0x8403,0x8407,0x8409,0x8414,0x8416,0x8416,0x8418,0x8418,0x841b,0x841c,0x8420,0x8421,0x8423,0x8424,0x8426,0x8426,0x8429,0x8429,0x842b,0x8440,0x8442,0x844e,0x8450,0x8469,0x846b,0x847a,0x847d,0x8480,0x8482,0x8482,0x8484,0x8484,0x8486,0x8486,0x8488,0x8488,0x848d,0x8494,0x8496,0x84a4,0x84a7,0x84b2,0x84b4,0x84b4,0x84b6,0x84b6,0x84b8,0x84c2,0x84c4,0x84c7,0x84c9,0x84d4,0x84d6,0x84d7,0x84da,0x84db,0x84de,0x84de,0x84e1,0x84e2,0x84e4,0x84e5,0x84e7,0x84ec,0x84ee,0x84f4,0x84f6,0x8500,0x8502,0x851a,0x851c,0x8521,0x8523,0x8531,0x8533,0x8534,0x8538,0x8538,0x853b,0x853b,0x853d,0x853e,0x8540,0x854e,0x8551,0x855b,0x855d,0x8571,0x8573,0x8573,0x8575,0x857c,0x857e,0x857e,0x8580,0x8591,0x8593,0x85a4,0x85a6,0x85aa,0x85af,0x85b1,0x85b3,0x85ba,0x85bd,0x85c9,0x85cb,0x85cb,0x85cd,0x85d2,0x85d5,0x85da,0x85dc,0x85e6,0x85e8,0x85f2,0x85f4,0x85f4,0x85f6,0x8602,0x8604,0x8607,0x8609,0x860d,0x860f,0x8611,0x8613,0x8614,0x8616,0x861c,0x861e,0x862a,0x862c,0x862f,0x8631,0x8636,0x8638,0x863c,0x863e,0x8640,0x8642,0x8643,0x8645,0x8648,0x864b,0x864e,0x8650,0x8650,0x8652,0x8656,0x8659,0x8659,0x865b,0x865c,0x865e,0x865f,0x8661,0x8665,0x8667,0x8674,0x8677,0x8677,0x8679,0x867c,0x867e,0x867e,0x8685,0x8687,0x868a,0x868e,0x8690,0x869a,0x869c,0x869e,0x86a0,0x86a5,0x86a7,0x86aa,0x86ad,0x86ad,0x86af,0x86c9,0x86cb,0x86cc,0x86d0,0x86d1,0x86d3,0x86d4,0x86d6,0x86df,0x86e2,0x86e4,0x86e6,0x86e6,0x86e8,0x86ed,0x86ef,0x86ef,0x86f5,0x86fb,0x86fe,0x86fe,0x8700,0x870e,0x8711,0x8713,0x8715,0x8715,0x8718,0x871c,0x871e,0x871e,0x8720,0x872a,0x872c,0x872e,0x8730,0x8735,0x8737,0x8738,0x873a,0x873c,0x873e,0x8743,0x8746,0x8746,0x874c,0x8771,0x8773,0x877b,0x877d,0x877d,0x8781,0x8789,0x878b,0x878d,0x878f,0x8794,0x8796,0x8798,0x879a,0x879f,0x87a2,0x87a5,0x87a9,0x87c6,0x87c8,0x87cc,0x87ce,0x87ce,0x87d1,0x87d4,0x87d6,0x87e8,0x87ea,0x87ef,0x87f2,0x87f7,0x87f9,0x87fc,0x87fe,0x8806,0x8808,0x880d,0x880f,0x8811,0x8813,0x8819,0x881b,0x881d,0x881f,0x8833,0x8835,0x8839,0x883b,0x8846,0x8848,0x8848,0x884a,0x884f,0x8852,0x8853,0x8855,0x8857,0x8859,0x885b,0x885d,0x885e,0x8860,0x8865,0x8867,0x886b,0x886d,0x8872,0x8874,0x8877,0x8879,0x8879,0x887c,0x8884,0x8887,0x8889,0x888b,0x8893,0x8895,0x88a2,0x88a4,0x88a4,0x88a7,0x88a8,0x88aa,0x88ac,0x88ae,0x88ae,0x88b1,0x88b2,0x88b4,0x88ba,0x88bc,0x88c2,0x88c5,0x88c5,0x88c7,0x88c7,0x88c9,0x88d0,0x88d2,0x88d2,0x88d4,0x88df,0x88e1,0x88e1,0x88e6,0x88e8,0x88eb,0x88ec,0x88ee,0x8902,0x8905,0x8907,0x8909,0x890c,0x890e,0x890e,0x8910,0x891a,0x891e,0x891f,0x8921,0x8927,0x8929,0x8933,0x8935,0x8938,0x893b,0x893e,0x8941,0x8944,0x8946,0x8947,0x8949,0x8949,0x894b,0x894d,0x894f,0x8954,0x8956,0x8966,0x8969,0x896f,0x8971,0x8974,0x8976,0x8977,0x8979,0x897c,0x897e,0x8983,0x8985,0x898b,0x898f,0x898f,0x8991,0x8991,0x8993,0x8998,0x899b,0x899f,0x89a1,0x89a7,0x89a9,0x89aa,0x89ac,0x89af,0x89b2,0x89b2,0x89b6,0x89b7,0x89b9,0x89ba,0x89bc,0x89c1,0x89c6,0x89c6,0x89d2,0x89d6,0x89d9,0x89dd,0x89df,0x89e9,0x89eb,0x89ed,0x89f0,0x89f4,0x89f6,0x89f8,0x89fa,0x89fc,0x89fe,0x8a00,0x8a02,0x8a04,0x8a07,0x8a08,0x8a0a,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a13,0x8a15,0x8a18,0x8a1b,0x8a1f,0x8a22,0x8a23,0x8a25,0x8a25,0x8a27,0x8a27,0x8a29,0x8a2d,0x8a30,0x8a31,0x8a34,0x8a34,0x8a36,0x8a36,0x8a38,0x8a41,0x8a44,0x8a46,0x8a48,0x8a4a,0x8a4c,0x8a52,0x8a54,0x8a59,0x8a5b,0x8a5b,0x8a5e,0x8a5e,0x8a60,0x8a63,0x8a66,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a77,0x8a79,0x8a7c,0x8a7e,0x8a7f,0x8a81,0x8a87,0x8a8b,0x8a8d,0x8a8f,0x8a96,0x8a98,0x8a9a,0x8a9c,0x8a9c,0x8a9e,0x8a9e,0x8aa0,0x8aa1,0x8aa3,0x8aac,0x8aaf,0x8ab0,0x8ab2,0x8ab2,0x8ab4,0x8ab4,0x8ab6,0x8ab6,0x8ab8,0x8ac0,0x8ac2,0x8ac9,0x8acb,0x8acd,0x8acf,0x8acf,0x8ad1,0x8ae2,0x8ae4,0x8ae4,0x8ae6,0x8ae8,0x8aea,0x8aeb,0x8aed,0x8afc,0x8afe,0x8b02,0x8b04,0x8b08,0x8b0a,0x8b20,0x8b22,0x8b28,0x8b2a,0x8b31,0x8b33,0x8b33,0x8b35,0x8b37,0x8b39,0x8b43,0x8b45,0x8b5a,0x8b5c,0x8b60,0x8b62,0x8b63,0x8b65,0x8b6d,0x8b6f,0x8b70,0x8b74,0x8b74,0x8b77,0x8b7b,0x8b7d,0x8b86,0x8b88,0x8b88,0x8b8a,0x8b8c,0x8b8e,0x8b90,0x8b92,0x8b96,0x8b98,0x8b9c,0x8b9e,0x8ba0,0x8bbe,0x8bbe,0x8be2,0x8be2,0x8c37,0x8c37,0x8c39,0x8c39,0x8c3b,0x8c3f,0x8c41,0x8c43,0x8c45,0x8c51,0x8c54,0x8c57,0x8c5a,0x8c5a,0x8c5c,0x8c5d,0x8c5f,0x8c5f,0x8c61,0x8c62,0x8c64,0x8c66,0x8c68,0x8c6d,0x8c6f,0x8c73,0x8c75,0x8c7b,0x8c7d,0x8c7d,0x8c80,0x8c82,0x8c84,0x8c86,0x8c89,0x8c8a,0x8c8c,0x8c8d,0x8c8f,0x8c95,0x8c97,0x8ca5,0x8ca7,0x8cad,0x8caf,0x8cb0,0x8cb2,0x8cc5,0x8cc7,0x8cc8,0x8cca,0x8cca,0x8ccc,0x8ccd,0x8ccf,0x8ccf,0x8cd1,0x8cd7,0x8cd9,0x8cee,0x8cf0,0x8cf5,0x8cf7,0x8cfe,0x8d00,0x8d00,0x8d02,0x8d0d,0x8d0f,0x8d19,0x8d1b,0x8d1d,0x8d64,0x8d64,0x8d66,0x8d69,0x8d6b,0x8d70,0x8d72,0x8d74,0x8d76,0x8d7b,0x8d7d,0x8d7d,0x8d80,0x8d82,0x8d84,0x8d85,0x8d89,0x8d8a,0x8d8c,0x8d96,0x8d99,0x8d99,0x8d9b,0x8d9c,0x8d9f,0x8da1,0x8da3,0x8da3,0x8da5,0x8daf,0x8db2,0x8db7,0x8db9,0x8dba,0x8dbc,0x8dbc,0x8dbe,0x8dc3,0x8dc5,0x8dc8,0x8dcb,0x8dd1,0x8dd3,0x8ddd,0x8ddf,0x8de4,0x8de6,0x8dec,0x8dee,0x8df4,0x8dfa,0x8dfa,0x8dfc,0x8e07,0x8e09,0x8e0a,0x8e0d,0x8e2b,0x8e2d,0x8e2e,0x8e30,0x8e31,0x8e33,0x8e36,0x8e38,0x8e3a,0x8e3c,0x8e42,0x8e44,0x8e50,0x8e53,0x8e57,0x8e59,0x8e6a,0x8e6c,0x8e6d,0x8e6f,0x8e6f,0x8e71,0x8e78,0x8e7a,0x8e7c,0x8e7e,0x8e7e,0x8e80,0x8e82,0x8e84,0x8e8e,0x8e90,0x8e98,0x8e9a,0x8e9a,0x8e9d,0x8ea1,0x8ea3,0x8ead,0x8eb0,0x8eb0,0x8eb2,0x8eb2,0x8eb6,0x8eb6,0x8eb9,0x8eba,0x8ebc,0x8ebd,0x8ec0,0x8ec0,0x8ec2,0x8ec3,0x8ec9,0x8ecf,0x8ed1,0x8ed4,0x8ed7,0x8ed8,0x8eda,0x8ee2,0x8ee4,0x8ee9,0x8eeb,0x8eef,0x8ef1,0x8ef2,0x8ef4,0x8efc,0x8efe,0x8f03,0x8f05,0x8f0b,0x8f0d,0x8f0e,0x8f10,0x8f20,0x8f23,0x8f26,0x8f29,0x8f2a,0x8f2c,0x8f30,0x8f32,0x8f39,0x8f3b,0x8f3c,0x8f3e,0x8f4b,0x8f4d,0x8f64,0x8f66,0x8f67,0x8f6e,0x8f6e,0x8f93,0x8f93,0x8f9b,0x8f9c,0x8f9f,0x8fa0,0x8fa3,0x8fa3,0x8fa5,0x8fa8,0x8fad,0x8fbc,0x8fbe,0x8fbf,0x8fc1,0x8fc2,0x8fc4,0x8fc6,0x8fc9,0x8fd7,0x8fda,0x8fda,0x8fe0,0x8fe6,0x8fe8,0x8fe8,0x8fea,0x8feb,0x8fed,0x8fee,0x8ff0,0x8ff0,0x8ff4,0x9006,0x9008,0x9008,0x900b,0x900d,0x900f,0x9012,0x9014,0x9017,0x9019,0x9024,0x902d,0x902f,0x9031,0x9038,0x903c,0x903f,0x9041,0x9042,0x9044,0x9044,0x9046,0x9047,0x9049,0x9056,0x9058,0x9059,0x905b,0x905e,0x9060,0x9064,0x9067,0x9069,0x906b,0x9070,0x9072,0x9088,0x908a,0x908b,0x908d,0x908d,0x908f,0x9091,0x9094,0x9095,0x9097,0x9099,0x909b,0x909b,0x909e,0x90a3,0x90a5,0x90a8,0x90aa,0x90aa,0x90ae,0x90b6,0x90b8,0x90b8,0x90bb,0x90bb,0x90bd,0x90bf,0x90c1,0x90c1,0x90c3,0x90c5,0x90c7,0x90c8,0x90ca,0x90cb,0x90ce,0x90ce,0x90d4,0x90dd,0x90df,0x90e5,0x90e8,0x90ed,0x90ef,0x90f5,0x90f9,0x9109,0x910b,0x910b,0x910d,0x9112,0x9114,0x9114,0x9116,0x9124,0x9126,0x9136,0x9138,0x913b,0x913e,0x9141,0x9143,0x9153,0x9155,0x915a,0x915c,0x915c,0x915e,0x9165,0x9167,0x916a,0x916c,0x916c,0x916e,0x9170,0x9172,0x917a,0x917c,0x917c,0x9180,0x9187,0x9189,0x9193,0x9196,0x9196,0x9199,0x91a3,0x91a5,0x91a5,0x91a7,0x91b7,0x91b9,0x91be,0x91c0,0x91c7,0x91c9,0x91c9,0x91cb,0x91d1,0x91d3,0x91da,0x91dc,0x91dd,0x91df,0x91df,0x91e2,0x91ee,0x91f1,0x91f1,0x91f3,0x91fa,0x91fd,0x920a,0x920c,0x921a,0x921c,0x921c,0x921e,0x921e,0x9221,0x9221,0x9223,0x9228,0x922a,0x922b,0x922d,0x922e,0x9230,0x923a,0x923c,0x9241,0x9244,0x9246,0x9248,0x9258,0x925a,0x925b,0x925d,0x9267,0x926b,0x9270,0x9272,0x9272,0x9276,0x928f,0x9291,0x9291,0x9293,0x929d,0x92a0,0x92ac,0x92ae,0x92ae,0x92b1,0x92b7,0x92b9,0x92bc,0x92be,0x92d5,0x92d7,0x92d9,0x92db,0x92db,0x92dd,0x92e1,0x92e3,0x92f4,0x92f6,0x9304,0x9306,0x9309,0x930b,0x9310,0x9312,0x9316,0x9318,0x931b,0x931d,0x9331,0x9333,0x9336,0x9338,0x9339,0x933c,0x933c,0x9340,0x9352,0x9354,0x935c,0x935e,0x936e,0x9370,0x9371,0x9373,0x937e,0x9380,0x938a,0x938c,0x9392,0x9394,0x93aa,0x93ac,0x93b5,0x93b7,0x93b8,0x93bb,0x93bb,0x93bd,0x93bd,0x93bf,0x93c0,0x93c2,0x93c4,0x93c6,0x93c8,0x93ca,0x93e4,0x93e6,0x93e8,0x93ec,0x93ec,0x93ee,0x93ee,0x93f0,0x93f1,0x93f3,0x9401,0x9403,0x9404,0x9406,0x9419,0x941b,0x941b,0x941d,0x941d,0x9420,0x9420,0x9424,0x9433,0x9435,0x9440,0x9442,0x944d,0x944f,0x9452,0x9454,0x9455,0x9457,0x9458,0x945b,0x945b,0x945d,0x945e,0x9460,0x9460,0x9462,0x9465,0x9467,0x9479,0x947b,0x9483,0x9485,0x9485,0x949f,0x949f,0x94a2,0x94a2,0x94c1,0x94c1,0x94c3,0x94c3,0x94dc,0x94dc,0x94f6,0x94f6,0x952d,0x952d,0x9547,0x9547,0x9577,0x9578,0x957a,0x957d,0x957f,0x9580,0x9582,0x9583,0x9585,0x9586,0x9588,0x9589,0x958b,0x9594,0x9596,0x9599,0x959b,0x959c,0x959e,0x95ae,0x95b0,0x95b2,0x95b5,0x95b7,0x95b9,0x95c0,0x95c3,0x95c3,0x95c5,0x95cd,0x95d0,0x95d6,0x95da,0x95dc,0x95de,0x95e5,0x95e8,0x95e8,0x95f4,0x95f4,0x961c,0x961e,0x9620,0x9624,0x9628,0x9628,0x962a,0x962a,0x962c,0x9633,0x9638,0x963d,0x963f,0x9645,0x964a,0x9651,0x9653,0x9654,0x9656,0x9656,0x9658,0x9658,0x965b,0x965f,0x9661,0x9664,0x9669,0x966d,0x966f,0x9678,0x967b,0x967e,0x9680,0x9681,0x9683,0x968b,0x968d,0x968f,0x9691,0x9699,0x969b,0x969c,0x969e,0x969e,0x96a1,0x96a5,0x96a7,0x96aa,0x96ac,0x96ac,0x96ae,0x96ae,0x96b0,0x96b1,0x96b3,0x96b4,0x96b6,0x96b6,0x96b8,0x96b9,0x96bb,0x96bd,0x96bf,0x96ce,0x96d2,0x96df,0x96e1,0x96e3,0x96e5,0x96e5,0x96e8,0x96ea,0x96ef,0x96f2,0x96f4,0x96fb,0x96fd,0x96fd,0x96ff,0x9700,0x9702,0x9709,0x970b,0x970b,0x970d,0x9713,0x9716,0x9716,0x9718,0x9719,0x971b,0x972c,0x972e,0x9732,0x9734,0x9736,0x9738,0x973a,0x973d,0x9744,0x9746,0x974b,0x9751,0x9752,0x9755,0x9758,0x975a,0x9762,0x9766,0x9766,0x9768,0x976a,0x976c,0x976e,0x9770,0x9774,0x9776,0x9778,0x977a,0x9785,0x9787,0x978b,0x978d,0x978f,0x9794,0x9794,0x9797,0x97a6,0x97a8,0x97a8,0x97aa,0x97ae,0x97b1,0x97b4,0x97b6,0x97bb,0x97bd,0x97c9,0x97cb,0x97d0,0x97d2,0x97d9,0x97dc,0x97e1,0x97e3,0x97e3,0x97e5,0x97e6,0x97ed,0x97ee,0x97f0,0x97f3,0x97f5,0x97f6,0x97f8,0x97fb,0x97fd,0x9808,0x980a,0x980a,0x980c,0x9818,0x981b,0x9821,0x9823,0x9824,0x9826,0x9829,0x982b,0x982b,0x982d,0x9830,0x9832,0x9835,0x9837,0x9839,0x983b,0x983b,0x9841,0x9841,0x9843,0x9853,0x9856,0x9859,0x985b,0x9860,0x9862,0x986c,0x986f,0x9875,0x98a8,0x98a9,0x98ac,0x98af,0x98b1,0x98b4,0x98b6,0x98c4,0x98c6,0x98cc,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e3,0x98e5,0x98e7,0x98e9,0x98ed,0x98ef,0x98ef,0x98f1,0x98f2,0x98f4,0x98f6,0x98f9,0x98fa,0x98fc,0x98fe,0x9900,0x9900,0x9902,0x9903,0x9905,0x9905,0x9907,0x990a,0x990c,0x990c,0x990e,0x990e,0x9910,0x991c,0x991e,0x991f,0x9921,0x9921,0x9924,0x9925,0x9927,0x9933,0x9935,0x9935,0x9937,0x9943,0x9945,0x9945,0x9947,0x994e,0x9950,0x9959,0x995b,0x995f,0x9961,0x9963,0x9996,0x9999,0x999b,0x999e,0x99a1,0x99a1,0x99a3,0x99a8,0x99aa,0x99b5,0x99b8,0x99bd,0x99c1,0x99c5,0x99c7,0x99c7,0x99c9,0x99c9,0x99cb,0x99dd,0x99df,0x99e7,0x99e9,0x99ea,0x99ec,0x99ee,0x99f0,0x99f1,0x99f4,0x99ff,0x9a01,0x9a07,0x9a09,0x9a11,0x9a14,0x9a16,0x9a19,0x9a27,0x9a29,0x9a32,0x9a34,0x9a46,0x9a48,0x9a4a,0x9a4c,0x9a50,0x9a52,0x9a5c,0x9a5e,0x9a60,0x9a62,0x9a6c,0x9a8f,0x9a8f,0x9aa8,0x9aa8,0x9aab,0x9aab,0x9aad,0x9aad,0x9aaf,0x9ab4,0x9ab6,0x9ac2,0x9ac6,0x9ac7,0x9aca,0x9aca,0x9acd,0x9acd,0x9acf,0x9ad8,0x9adc,0x9adc,0x9adf,0x9ae3,0x9ae6,0x9ae7,0x9aeb,0x9aef,0x9af1,0x9af4,0x9af6,0x9af7,0x9af9,0x9aff,0x9b01,0x9b06,0x9b08,0x9b12,0x9b14,0x9b1a,0x9b1e,0x9b20,0x9b22,0x9b25,0x9b27,0x9b2b,0x9b2d,0x9b2f,0x9b31,0x9b35,0x9b37,0x9b37,0x9b39,0x9b3c,0x9b3e,0x9b46,0x9b48,0x9b48,0x9b4a,0x9b52,0x9b54,0x9b56,0x9b58,0x9b5b,0x9b5f,0x9b61,0x9b64,0x9b64,0x9b66,0x9b69,0x9b6c,0x9b6c,0x9b6f,0x9b71,0x9b74,0x9b77,0x9b7a,0x9b83,0x9b85,0x9b88,0x9b8b,0x9b8b,0x9b8d,0x9b93,0x9b95,0x9b95,0x9b97,0x9b97,0x9b9a,0x9b9b,0x9b9d,0x9ba2,0x9ba4,0x9ba6,0x9ba8,0x9ba8,0x9baa,0x9bab,0x9bad,0x9bb0,0x9bb5,0x9bb6,0x9bb8,0x9bb9,0x9bbd,0x9bbd,0x9bbf,0x9bc1,0x9bc3,0x9bc4,0x9bc6,0x9bca,0x9bcf,0x9bcf,0x9bd3,0x9bd7,0x9bd9,0x9bde,0x9be0,0x9be2,0x9be4,0x9bed,0x9bf0,0x9bf1,0x9bf4,0x9bf4,0x9bf7,0x9bf8,0x9bfd,0x9bfd,0x9bff,0x9bff,0x9c02,0x9c02,0x9c05,0x9c0e,0x9c10,0x9c10,0x9c12,0x9c15,0x9c17,0x9c17,0x9c1b,0x9c1d,0x9c1f,0x9c21,0x9c23,0x9c26,0x9c28,0x9c29,0x9c2b,0x9c2d,0x9c2f,0x9c2f,0x9c31,0x9c37,0x9c39,0x9c41,0x9c44,0x9c50,0x9c52,0x9c59,0x9c5d,0x9c60,0x9c62,0x9c63,0x9c66,0x9c68,0x9c6d,0x9c6e,0x9c71,0x9c75,0x9c77,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9cea,0x9ced,0x9ced,0x9cf1,0x9cf7,0x9cf9,0x9cfd,0x9cff,0x9d00,0x9d02,0x9d09,0x9d0c,0x9d0c,0x9d10,0x9d10,0x9d12,0x9d12,0x9d14,0x9d19,0x9d1b,0x9d1b,0x9d1d,0x9d23,0x9d25,0x9d26,0x9d28,0x9d29,0x9d2d,0x9d31,0x9d33,0x9d34,0x9d36,0x9d39,0x9d3b,0x9d3b,0x9d3d,0x9d45,0x9d49,0x9d4c,0x9d4e,0x9d54,0x9d56,0x9d61,0x9d67,0x9d75,0x9d77,0x9d79,0x9d7b,0x9d8c,0x9d90,0x9d90,0x9d92,0x9d94,0x9d96,0x9dad,0x9daf,0x9daf,0x9db1,0x9dc5,0x9dc7,0x9ddf,0x9de1,0x9de6,0x9de8,0x9de9,0x9deb,0x9df0,0x9df2,0x9e07,0x9e09,0x9e15,0x9e17,0x9e1f,0x9e75,0x9e75,0x9e79,0x9e7d,0x9e7f,0x9e8e,0x9e90,0x9ea2,0x9ea4,0x9eb1,0x9eb4,0x9eb7,0x9ebb,0x9ec4,0x9ec6,0x9ec8,0x9ecc,0x9ed1,0x9ed3,0x9ed6,0x9ed8,0x9ed8,0x9eda,0x9ee0,0x9ee2,0x9ee2,0x9ee4,0x9ee8,0x9eeb,0x9eeb,0x9eed,0x9f02,0x9f06,0x9f0a,0x9f0e,0x9f10,0x9f12,0x9f13,0x9f15,0x9f1c,0x9f1e,0x9f1e,0x9f20,0x9f20,0x9f22,0x9f39,0x9f3b,0x9f3b,0x9f3d,0x9f3e,0x9f40,0x9f50,0x9f52,0x9f67,0x9f69,0x9f6c,0x9f6e,0x9f72,0x9f74,0x9f7b,0x9f7e,0x9f7f,0x9f8d,0x9f8e,0x9f90,0x9f92,0x9f94,0x9f99,0x9f9c,0x9f9c,0x9f9f,0x9fa0,0x9fa2,0x9fa2,0x9fa4,0x9fb3,0x9fc7,0x9fcb,0x9fd0,0x9fd0,0xf900,0xf903,0xf905,0xf907,0xf90b,0xf90b,0xf90d,0xf90d,0xf915,0xf915,0xf917,0xf917,0xf91a,0xf91a,0xf922,0xf922,0xf92d,0xf92d,0xf931,0xf931,0xf937,0xf937,0xf939,0xf93a,0xf943,0xf943,0xf947,0xf948,0xf94a,0xf94a,0xf952,0xf952,0xf95e,0xf95e,0xf962,0xf962,0xf965,0xf965,0xf967,0xf967,0xf972,0xf972,0xf976,0xf976,0xf978,0xf979,0xf97e,0xf97e,0xf980,0xf980,0xf986,0xf986,0xf98a,0xf98a,0xf98e,0xf98e,0xf995,0xf995,0xf99c,0xf99c,0xf99f,0xf99f,0xf9b5,0xf9b5,0xf9bb,0xf9bb,0xf9bd,0xf9bd,0xf9c5,0xf9c6,0xf9c8,0xf9c8,0xf9d8,0xf9d8,0xf9dc,0xf9de,0xf9e0,0xf9e0,0xf9e4,0xf9e4,0xf9e7,0xf9e7,0xf9e9,0xf9e9,0xf9f4,0xf9f5,0xf9fa,0xf9fa,0xf9fd,0xf9fd,0xf9ff,0xf9ff,0xfa02,0xfa02,0xfa05,0xfa08,0xfa0a,0xfa0a,0xfa0c,0xfa0d,0xfa33,0xfa35,0xfa3a,0xfa3a,0xfa49,0xfa49,0xfa4b,0xfa4b,0xfa5d,0xfa5e,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x20021,0x20021,0x2003e,0x2003e,0x20046,0x20046,0x2004e,0x2004e,0x20068,0x20068,0x20086,0x20087,0x2008a,0x2008a,0x20094,0x20094,0x200ca,0x200cd,0x200d1,0x200d1,0x200ee,0x200ee,0x2010c,0x2010c,0x2010e,0x2010e,0x20118,0x20118,0x201a4,0x201a4,0x201a9,0x201a9,0x201ab,0x201ab,0x201c1,0x201c1,0x201d4,0x201d4,0x201f2,0x201f2,0x20204,0x20204,0x2020c,0x2020c,0x20214,0x20214,0x20239,0x20239,0x2025b,0x2025b,0x20274,0x20275,0x20299,0x20299,0x2029e,0x2029e,0x202a0,0x202a0,0x202b7,0x202b7,0x202bf,0x202c0,0x202e5,0x202e5,0x2030a,0x2030a,0x20325,0x20325,0x20341,0x20341,0x20345,0x20347,0x2037e,0x20380,0x203a0,0x203a0,0x203a7,0x203a7,0x203b5,0x203b5,0x203c9,0x203c9,0x203cb,0x203cb,0x203f5,0x203f5,0x203fc,0x203fc,0x20413,0x20414,0x2041f,0x2041f,0x20465,0x20465,0x20487,0x20487,0x2048e,0x2048e,0x20491,0x20492,0x204a3,0x204a3,0x204d7,0x204d7,0x204fc,0x204fc,0x204fe,0x204fe,0x20547,0x20547,0x2058e,0x2058e,0x205a5,0x205a5,0x205b3,0x205b3,0x205c3,0x205c3,0x205ca,0x205ca,0x205d0,0x205d0,0x205d5,0x205d5,0x205df,0x205e0,0x205eb,0x205eb,0x20611,0x20611,0x20615,0x20615,0x20619,0x2061a,0x20628,0x20628,0x20630,0x20630,0x20656,0x20656,0x20676,0x20676,0x2070e,0x2070e,0x20731,0x20731,0x20779,0x20779,0x2082c,0x2082c,0x20873,0x20873,0x208d5,0x208d5,0x20916,0x20916,0x20923,0x20923,0x20954,0x20954,0x20979,0x20979,0x209e7,0x209e7,0x20a11,0x20a11,0x20a50,0x20a50,0x20a6f,0x20a6f,0x20a8a,0x20a8a,0x20ab4,0x20ab4,0x20ac2,0x20ac2,0x20acd,0x20acd,0x20b0d,0x20b0d,0x20b8f,0x20b8f,0x20b9f,0x20b9f,0x20ba8,0x20ba9,0x20bbf,0x20bbf,0x20bc6,0x20bc6,0x20bcb,0x20bcb,0x20be2,0x20be2,0x20beb,0x20beb,0x20bfb,0x20bfb,0x20bff,0x20bff,0x20c0b,0x20c0b,0x20c0d,0x20c0d,0x20c20,0x20c20,0x20c34,0x20c34,0x20c3a,0x20c3b,0x20c41,0x20c43,0x20c53,0x20c53,0x20c65,0x20c65,0x20c77,0x20c78,0x20c7c,0x20c7c,0x20c8d,0x20c8d,0x20c96,0x20c96,0x20c9c,0x20c9c,0x20cb5,0x20cb5,0x20cb8,0x20cb8,0x20ccf,0x20ccf,0x20cd3,0x20cd6,0x20cdd,0x20cdd,0x20ced,0x20ced,0x20cff,0x20cff,0x20d15,0x20d15,0x20d28,0x20d28,0x20d31,0x20d32,0x20d46,0x20d49,0x20d4c,0x20d4e,0x20d6f,0x20d6f,0x20d71,0x20d71,0x20d74,0x20d74,0x20d7c,0x20d7c,0x20d7e,0x20d7f,0x20d96,0x20d96,0x20d9c,0x20d9c,0x20da7,0x20da7,0x20db2,0x20db2,0x20dc8,0x20dc8,0x20e04,0x20e04,0x20e09,0x20e0a,0x20e0d,0x20e11,0x20e16,0x20e16,0x20e1d,0x20e1d,0x20e4c,0x20e4c,0x20e6d,0x20e6d,0x20e73,0x20e73,0x20e75,0x20e7b,0x20e8c,0x20e8c,0x20e96,0x20e96,0x20e98,0x20e98,0x20e9d,0x20e9d,0x20ea2,0x20ea2,0x20eaa,0x20eac,0x20eb6,0x20eb6,0x20ed7,0x20ed8,0x20edd,0x20edd,0x20ef8,0x20efb,0x20f1d,0x20f1d,0x20f26,0x20f26,0x20f2d,0x20f2e,0x20f30,0x20f31,0x20f3b,0x20f3b,0x20f4c,0x20f4c,0x20f64,0x20f64,0x20f8d,0x20f8d,0x20f90,0x20f90,0x20fad,0x20fad,0x20fb4,0x20fb6,0x20fbc,0x20fbc,0x20fdf,0x20fdf,0x20fea,0x20fed,0x21014,0x21014,0x2101d,0x2101e,0x2104f,0x2104f,0x2105c,0x2105c,0x2106f,0x2106f,0x21075,0x21078,0x2107b,0x2107b,0x21088,0x21088,0x21096,0x21096,0x2109d,0x2109d,0x210b4,0x210b4,0x210bf,0x210c1,0x210c7,0x210c9,0x210cf,0x210cf,0x210d3,0x210d3,0x210e4,0x210e4,0x210f4,0x210f6,0x2112f,0x2112f,0x2113b,0x2113b,0x2113d,0x2113d,0x21145,0x21145,0x21148,0x21148,0x2114f,0x2114f,0x21180,0x21180,0x21187,0x21187,0x211d9,0x211d9,0x2123c,0x2123c,0x2124f,0x2124f,0x2127c,0x2127c,0x212a8,0x212a9,0x212b0,0x212b0,0x212e3,0x212e3,0x212fe,0x212fe,0x21302,0x21305,0x21336,0x21336,0x2133a,0x2133a,0x21375,0x21376,0x2138e,0x2138e,0x21398,0x21398,0x2139c,0x2139c,0x213c5,0x213c6,0x213ed,0x213ed,0x213fe,0x213fe,0x21413,0x21413,0x21416,0x21416,0x21424,0x21424,0x2143f,0x2143f,0x21452,0x21452,0x21454,0x21455,0x2148a,0x2148a,0x21497,0x21497,0x214b6,0x214b6,0x214e8,0x214e8,0x214fd,0x214fd,0x21577,0x21577,0x21582,0x21582,0x21596,0x21596,0x2160a,0x2160a,0x21613,0x21613,0x21619,0x21619,0x2163e,0x2163e,0x21661,0x21661,0x21692,0x21692,0x216b8,0x216b8,0x216ba,0x216ba,0x216c0,0x216c2,0x216d3,0x216d3,0x216d5,0x216d5,0x216df,0x216df,0x216e6,0x216e8,0x216fa,0x216fc,0x216fe,0x216fe,0x2170d,0x2170d,0x21710,0x21710,0x21726,0x21726,0x2173a,0x2173c,0x21757,0x21757,0x2176c,0x21771,0x21773,0x21774,0x217ab,0x217ab,0x217b0,0x217b5,0x217c3,0x217c3,0x217c7,0x217c7,0x217d9,0x217dc,0x217df,0x217df,0x217ef,0x217ef,0x217f5,0x217f6,0x217f8,0x217fc,0x21820,0x21820,0x21828,0x2182a,0x2182d,0x2182d,0x21839,0x2183b,0x21840,0x21840,0x21845,0x21845,0x21852,0x21852,0x2185e,0x2185e,0x21861,0x21864,0x21877,0x21877,0x2187b,0x2187b,0x21883,0x21885,0x2189e,0x218a2,0x218be,0x218bf,0x218d1,0x218d1,0x218d6,0x218d9,0x218fa,0x218fa,0x21903,0x21905,0x21910,0x21912,0x21915,0x21915,0x2191c,0x2191c,0x21922,0x21922,0x21927,0x21927,0x2193b,0x2193b,0x21944,0x21944,0x21958,0x21958,0x2196a,0x2196a,0x2197c,0x2197c,0x21980,0x21980,0x21983,0x21983,0x21988,0x21988,0x21996,0x21996,0x219db,0x219db,0x219f3,0x219f3,0x21a2d,0x21a2d,0x21a34,0x21a34,0x21a45,0x21a45,0x21a4b,0x21a4b,0x21a63,0x21a63,0x21b44,0x21b44,0x21bc1,0x21bc2,0x21c2a,0x21c2a,0x21c70,0x21c70,0x21ca2,0x21ca2,0x21ca5,0x21ca5,0x21cac,0x21cac,0x21d46,0x21d46,0x21d53,0x21d53,0x21d5e,0x21d5e,0x21d90,0x21d90,0x21db6,0x21db6,0x21dba,0x21dba,0x21dca,0x21dca,0x21dd1,0x21dd1,0x21deb,0x21deb,0x21df9,0x21df9,0x21e1c,0x21e1c,0x21e23,0x21e23,0x21e37,0x21e37,0x21e3d,0x21e3d,0x21e89,0x21e89,0x21ea4,0x21ea4,0x21ea8,0x21ea8,0x21ec8,0x21ec8,0x21ed5,0x21ed5,0x21f0f,0x21f0f,0x21f15,0x21f15,0x21f6a,0x21f6a,0x21f9e,0x21f9e,0x21fa1,0x21fa1,0x21fe8,0x21fe8,0x22045,0x22045,0x22049,0x22049,0x2207e,0x2207e,0x2209a,0x2209a,0x220c7,0x220c7,0x220fc,0x220fc,0x2212a,0x2212a,0x2215b,0x2215b,0x22173,0x22173,0x2217a,0x2217a,0x221a1,0x221a1,0x221c1,0x221c1,0x221c3,0x221c3,0x22208,0x22208,0x2227c,0x2227c,0x22321,0x22321,0x22325,0x22325,0x223bd,0x223bd,0x223d0,0x223d0,0x223d7,0x223d7,0x223fa,0x223fa,0x22465,0x22465,0x22471,0x22471,0x2248b,0x2248b,0x22491,0x22491,0x224b0,0x224b0,0x224bc,0x224bc,0x224c1,0x224c1,0x224c9,0x224c9,0x224cc,0x224cc,0x224ed,0x224ed,0x22513,0x22513,0x2251b,0x2251b,0x22530,0x22530,0x22554,0x22554,0x2258d,0x2258d,0x225af,0x225af,0x225be,0x225be,0x2261b,0x2261c,0x2262b,0x2262b,0x22668,0x22668,0x2267a,0x2267a,0x22696,0x22696,0x22698,0x22698,0x226f4,0x226f6,0x22712,0x22712,0x22714,0x22714,0x2271b,0x2271b,0x2271f,0x2271f,0x2272a,0x2272a,0x22775,0x22775,0x22781,0x22781,0x22796,0x22796,0x227b4,0x227b5,0x227cd,0x227cd,0x22803,0x22803,0x2285f,0x22860,0x22871,0x22871,0x228ad,0x228ad,0x228c1,0x228c1,0x228f7,0x228f7,0x22926,0x22926,0x22939,0x22939,0x2294f,0x2294f,0x22967,0x22967,0x2296b,0x2296b,0x22980,0x22980,0x22993,0x22993,0x22a66,0x22a66,0x22acf,0x22acf,0x22ad5,0x22ad5,0x22ae6,0x22ae6,0x22ae8,0x22ae8,0x22b0e,0x22b0e,0x22b22,0x22b22,0x22b3f,0x22b3f,0x22b43,0x22b43,0x22b6a,0x22b6a,0x22bca,0x22bca,0x22bce,0x22bce,0x22c26,0x22c27,0x22c38,0x22c38,0x22c4c,0x22c4c,0x22c51,0x22c51,0x22c55,0x22c55,0x22c62,0x22c62,0x22c88,0x22c88,0x22c9b,0x22c9b,0x22ca1,0x22ca1,0x22ca9,0x22ca9,0x22cb2,0x22cb2,0x22cb7,0x22cb7,0x22cc2,0x22cc2,0x22cc6,0x22cc6,0x22cc9,0x22cc9,0x22d07,0x22d08,0x22d12,0x22d12,0x22d44,0x22d44,0x22d4c,0x22d4c,0x22d67,0x22d67,0x22d8d,0x22d8d,0x22d95,0x22d95,0x22da0,0x22da0,0x22da3,0x22da4,0x22db7,0x22db7,0x22dee,0x22dee,0x22e0d,0x22e0d,0x22e36,0x22e36,0x22e42,0x22e42,0x22e78,0x22e78,0x22e8b,0x22e8b,0x22eb3,0x22eb3,0x22eef,0x22eef,0x22f74,0x22f74,0x22fcc,0x22fcc,0x22fe3,0x22fe3,0x23033,0x23033,0x23044,0x23044,0x2304b,0x2304b,0x23066,0x23066,0x2307d,0x2307e,0x2308e,0x2308e,0x230b7,0x230b7,0x230bc,0x230bc,0x230da,0x230da,0x23103,0x23103,0x2313d,0x2313d,0x2317d,0x2317d,0x23182,0x23182,0x231a4,0x231a5,0x231b3,0x231b3,0x231c8,0x231c9,0x231ea,0x231ea,0x231f7,0x231f9,0x2320f,0x2320f,0x23225,0x23225,0x2322f,0x2322f,0x23231,0x23234,0x23256,0x23256,0x2325e,0x2325e,0x23262,0x23262,0x23281,0x23281,0x23289,0x2328a,0x232ab,0x232ad,0x232d2,0x232d2,0x232e0,0x232e1,0x23300,0x23300,0x2330a,0x2330a,0x2331f,0x2331f,0x233b4,0x233b4,0x233cc,0x233cc,0x233de,0x233de,0x233e6,0x233e6,0x233f4,0x233f5,0x233f9,0x233fa,0x233fe,0x233fe,0x23400,0x23400,0x2343f,0x2343f,0x23450,0x23450,0x2346f,0x2346f,0x23472,0x23472,0x234e5,0x234e5,0x23519,0x23519,0x23530,0x23530,0x23551,0x23551,0x2355a,0x2355a,0x23567,0x23567,0x23595,0x23595,0x23599,0x23599,0x2359c,0x2359c,0x235bb,0x235bb,0x235cd,0x235cf,0x235f3,0x235f3,0x23600,0x23600,0x23617,0x23617,0x2361a,0x2361a,0x2363c,0x2363c,0x23640,0x23640,0x23659,0x23659,0x2365f,0x2365f,0x23677,0x23677,0x2368e,0x2368e,0x2369e,0x2369e,0x236a6,0x236a6,0x236ad,0x236ad,0x236ba,0x236ba,0x236df,0x236df,0x236ee,0x236ee,0x23703,0x23703,0x23716,0x23716,0x23720,0x23720,0x2372d,0x2372d,0x2372f,0x2372f,0x2373f,0x2373f,0x23766,0x23766,0x23781,0x23781,0x237a2,0x237a2,0x237bc,0x237bc,0x237c2,0x237c2,0x237d5,0x237d7,0x2383a,0x2383a,0x239c2,0x239c2,0x23aa7,0x23aa7,0x23adb,0x23adb,0x23aee,0x23aee,0x23afa,0x23afa,0x23b1a,0x23b1a,0x23b5a,0x23b5a,0x23c63,0x23c63,0x23c99,0x23c9b,0x23cb5,0x23cb5,0x23cb7,0x23cb7,0x23cc7,0x23cc9,0x23cfc,0x23cff,0x23d40,0x23d40,0x23d5b,0x23d5b,0x23d7e,0x23d7e,0x23d8f,0x23d8f,0x23db6,0x23dbd,0x23de3,0x23de3,0x23df8,0x23df8,0x23e06,0x23e06,0x23e11,0x23e11,0x23e2c,0x23e31,0x23e39,0x23e39,0x23e88,0x23e8b,0x23eb9,0x23eb9,0x23ebf,0x23ebf,0x23ed7,0x23ed7,0x23ef7,0x23efc,0x23f35,0x23f35,0x23f41,0x23f41,0x23f4a,0x23f4a,0x23f61,0x23f61,0x23f7f,0x23f82,0x23f8f,0x23f8f,0x23fb4,0x23fb4,0x23fb7,0x23fb7,0x23fc0,0x23fc0,0x23fc5,0x23fc5,0x23feb,0x23ff0,0x24011,0x24011,0x24039,0x2403d,0x24057,0x24057,0x24085,0x24085,0x2408b,0x2408d,0x24091,0x24091,0x240c9,0x240c9,0x240e1,0x240e1,0x240ec,0x240ec,0x24104,0x24104,0x2410f,0x2410f,0x24119,0x24119,0x2413f,0x24140,0x24144,0x24144,0x2414e,0x2414e,0x24155,0x24157,0x2415c,0x2415c,0x2415f,0x2415f,0x24161,0x24161,0x24177,0x24177,0x2417a,0x2417a,0x241a3,0x241a5,0x241ac,0x241ac,0x241b5,0x241b5,0x241cd,0x241cd,0x241e2,0x241e2,0x241fc,0x241fc,0x2421b,0x2421b,0x2424b,0x2424b,0x24256,0x24256,0x24259,0x24259,0x24276,0x24278,0x24284,0x24284,0x24293,0x24293,0x24295,0x24295,0x242a5,0x242a5,0x242bf,0x242bf,0x242c1,0x242c1,0x242c9,0x242ca,0x242ee,0x242ee,0x242fa,0x242fa,0x2430d,0x2430d,0x2431a,0x2431a,0x24334,0x24334,0x24348,0x24348,0x24362,0x24365,0x2438c,0x2438c,0x24396,0x24396,0x2439c,0x2439c,0x243bd,0x243bd,0x243c1,0x243c1,0x243e9,0x243ea,0x243f2,0x243f2,0x243f8,0x243f8,0x24404,0x24404,0x24435,0x24436,0x2445a,0x2445b,0x24473,0x24473,0x24487,0x24488,0x244b9,0x244b9,0x244bc,0x244bc,0x244ce,0x244ce,0x244d3,0x244d3,0x244d6,0x244d6,0x24505,0x24505,0x24521,0x24521,0x24578,0x24578,0x245c8,0x245c8,0x24618,0x24618,0x2462a,0x2462a,0x24665,0x24665,0x24674,0x24674,0x24697,0x24697,0x246d4,0x246d4,0x24706,0x24706,0x24725,0x24725,0x2472f,0x2472f,0x2478f,0x2478f,0x247e0,0x247e0,0x24812,0x24812,0x24823,0x24823,0x24882,0x24882,0x248e9,0x248e9,0x248f0,0x248f3,0x248fb,0x248fb,0x248ff,0x24901,0x2490c,0x2490c,0x24916,0x24917,0x24919,0x24919,0x2492f,0x2492f,0x24933,0x24934,0x2493e,0x24943,0x24962,0x24963,0x24974,0x24976,0x2497b,0x2497b,0x2497f,0x2497f,0x24982,0x24982,0x24988,0x2498f,0x24994,0x24994,0x249a4,0x249a4,0x249a7,0x249a7,0x249a9,0x249a9,0x249ab,0x249ad,0x249b7,0x249bb,0x249c5,0x249c5,0x249d0,0x249d0,0x249da,0x249da,0x249de,0x249df,0x249e3,0x249e3,0x249e5,0x249e5,0x249ec,0x249ed,0x249f6,0x249f9,0x249fb,0x249fb,0x24a0e,0x24a0e,0x24a12,0x24a13,0x24a15,0x24a15,0x24a21,0x24a2a,0x24a3e,0x24a3e,0x24a42,0x24a42,0x24a45,0x24a45,0x24a4a,0x24a4a,0x24a4e,0x24a51,0x24a5d,0x24a5d,0x24a65,0x24a67,0x24a71,0x24a71,0x24a77,0x24a7a,0x24a8c,0x24a8c,0x24a93,0x24a96,0x24aa4,0x24aa7,0x24ab1,0x24ab3,0x24aba,0x24abc,0x24ac0,0x24ac0,0x24ac7,0x24ac7,0x24aca,0x24aca,0x24ad1,0x24ad1,0x24adf,0x24adf,0x24ae2,0x24ae2,0x24ae9,0x24ae9,0x24b0f,0x24b0f,0x24b6e,0x24b6e,0x24bf5,0x24bf5,0x24c09,0x24c09,0x24c9e,0x24c9f,0x24cc9,0x24cc9,0x24cd9,0x24cd9,0x24d06,0x24d06,0x24d13,0x24d13,0x24db8,0x24db8,0x24dea,0x24deb,0x24e3b,0x24e3b,0x24e50,0x24e50,0x24ea5,0x24ea5,0x24ea7,0x24ea7,0x24f0e,0x24f0e,0x24f5c,0x24f5c,0x24f82,0x24f82,0x24f86,0x24f86,0x24f97,0x24f97,0x24f9a,0x24f9a,0x24fa9,0x24fa9,0x24fb8,0x24fb8,0x24fc2,0x24fc2,0x2502c,0x2502c,0x25052,0x25052,0x2509d,0x2509d,0x2512b,0x2512b,0x25148,0x25148,0x2517d,0x2517e,0x251cd,0x251cd,0x251e3,0x251e3,0x251e6,0x251e7,0x25220,0x25221,0x25250,0x25250,0x25299,0x25299,0x252c7,0x252c7,0x252d8,0x252d8,0x2530e,0x2530e,0x25311,0x25311,0x25313,0x25313,0x25419,0x25419,0x25425,0x25425,0x2542f,0x25430,0x25446,0x25446,0x2546c,0x2546c,0x2546e,0x2546e,0x2549a,0x2549a,0x25531,0x25531,0x25535,0x25535,0x2553f,0x2553f,0x2555b,0x2555e,0x25562,0x25562,0x25565,0x25566,0x25581,0x25581,0x25584,0x25584,0x2558f,0x2558f,0x255b9,0x255b9,0x255d5,0x255d5,0x255db,0x255db,0x255e0,0x255e0,0x25605,0x25605,0x25635,0x25635,0x25651,0x25651,0x25683,0x25683,0x25695,0x25695,0x256e3,0x256e3,0x256f6,0x256f6,0x25706,0x25706,0x2571d,0x2571d,0x25725,0x25725,0x2573d,0x2573d,0x25772,0x25772,0x257c7,0x257c7,0x257df,0x257e1,0x25857,0x25857,0x2585d,0x2585d,0x25872,0x25872,0x258c8,0x258c8,0x258de,0x258de,0x258e1,0x258e1,0x25903,0x25903,0x25946,0x25946,0x25956,0x25956,0x259ac,0x259ac,0x259cc,0x259cc,0x25a54,0x25a54,0x25a95,0x25a95,0x25a9c,0x25a9c,0x25aae,0x25aaf,0x25ad7,0x25ad7,0x25ae9,0x25ae9,0x25b74,0x25b74,0x25b89,0x25b89,0x25bb3,0x25bb4,0x25bc6,0x25bc6,0x25be4,0x25be4,0x25be8,0x25be8,0x25c01,0x25c01,0x25c06,0x25c06,0x25c21,0x25c21,0x25c4a,0x25c4a,0x25c65,0x25c65,0x25c91,0x25c91,0x25ca4,0x25ca4,0x25cc0,0x25cc1,0x25cfe,0x25cfe,0x25d20,0x25d20,0x25d30,0x25d30,0x25d43,0x25d43,0x25d99,0x25d99,0x25db9,0x25db9,0x25e0e,0x25e0e,0x25e49,0x25e49,0x25e81,0x25e83,0x25ea6,0x25ea6,0x25ebc,0x25ebc,0x25ed7,0x25ed8,0x25f1a,0x25f1a,0x25f4b,0x25f4b,0x25fe1,0x25fe2,0x26021,0x26021,0x26029,0x26029,0x26048,0x26048,0x26064,0x26064,0x26083,0x26083,0x26097,0x26097,0x260a4,0x260a5,0x26102,0x26102,0x26121,0x26121,0x26159,0x2615c,0x261ad,0x261ae,0x261b2,0x261b2,0x261dd,0x261dd,0x26258,0x26258,0x26261,0x26261,0x2626a,0x2626b,0x262d0,0x262d0,0x26335,0x26335,0x2634b,0x2634c,0x26351,0x26351,0x263be,0x263be,0x263f5,0x263f5,0x263f8,0x263f8,0x26402,0x26402,0x26410,0x26412,0x2644a,0x2644a,0x26469,0x26469,0x26484,0x26484,0x26488,0x26489,0x2648d,0x2648d,0x26498,0x26498,0x26512,0x26512,0x26572,0x26572,0x265a0,0x265a0,0x265ad,0x265ad,0x265bf,0x265bf,0x26612,0x26612,0x26626,0x26626,0x266af,0x266af,0x266b1,0x266b1,0x266b5,0x266b5,0x266da,0x266da,0x266e8,0x266e8,0x266fc,0x266fc,0x26716,0x26716,0x26741,0x26741,0x26799,0x26799,0x267b3,0x267b4,0x267cc,0x267cc,0x2681c,0x2681c,0x26846,0x26846,0x2685e,0x2685e,0x2686e,0x2686e,0x26888,0x26888,0x2688a,0x2688a,0x26893,0x26893,0x268c7,0x268c7,0x2690e,0x2690e,0x26911,0x26911,0x26926,0x26926,0x26939,0x26939,0x26951,0x26951,0x269a8,0x269a8,0x269b5,0x269b5,0x269f2,0x269f2,0x269fa,0x269fa,0x26a2d,0x26a2e,0x26a34,0x26a34,0x26a42,0x26a42,0x26a51,0x26a52,0x26b05,0x26b05,0x26b0a,0x26b0a,0x26b13,0x26b13,0x26b15,0x26b15,0x26b23,0x26b23,0x26b28,0x26b28,0x26b50,0x26b53,0x26b5b,0x26b5b,0x26b75,0x26b75,0x26b82,0x26b82,0x26b96,0x26b97,0x26b9d,0x26b9d,0x26bb3,0x26bb3,0x26bc0,0x26bc0,0x26bf7,0x26bf7,0x26c21,0x26c21,0x26c40,0x26c41,0x26c46,0x26c46,0x26c7e,0x26c82,0x26ca4,0x26ca4,0x26cb7,0x26cb8,0x26cbd,0x26cbd,0x26cc0,0x26cc0,0x26cc3,0x26cc3,0x26cd1,0x26cd1,0x26d22,0x26d2a,0x26d51,0x26d51,0x26d74,0x26d74,0x26da0,0x26da7,0x26dae,0x26dae,0x26ddc,0x26ddc,0x26dea,0x26deb,0x26df0,0x26df0,0x26e00,0x26e00,0x26e05,0x26e05,0x26e07,0x26e07,0x26e12,0x26e12,0x26e42,0x26e45,0x26e6e,0x26e6e,0x26e72,0x26e72,0x26e77,0x26e77,0x26e84,0x26e84,0x26e88,0x26e88,0x26e8b,0x26e8b,0x26e99,0x26e99,0x26ed0,0x26ed7,0x26f26,0x26f26,0x26f73,0x26f74,0x26f9f,0x26f9f,0x26fa1,0x26fa1,0x26fbe,0x26fbe,0x26fde,0x26fdf,0x2700e,0x2700e,0x2704b,0x2704b,0x27052,0x27053,0x27088,0x27088,0x270ad,0x270af,0x270cd,0x270cd,0x270d2,0x270d2,0x270f0,0x270f0,0x270f8,0x270f8,0x27109,0x27109,0x2710c,0x2710d,0x27126,0x27127,0x27164,0x27165,0x27175,0x27175,0x271cd,0x271cd,0x2721b,0x2721b,0x27267,0x27267,0x27280,0x27280,0x27285,0x27285,0x2728b,0x2728b,0x272b2,0x272b2,0x272b6,0x272b6,0x272e6,0x272e6,0x27352,0x27352,0x2739a,0x2739a,0x273ff,0x273ff,0x27422,0x27422,0x27450,0x27450,0x27484,0x27484,0x27486,0x27486,0x27574,0x27574,0x275a3,0x275a3,0x275e0,0x275e0,0x275e4,0x275e4,0x275fd,0x275fe,0x27607,0x27607,0x2760c,0x2760c,0x27632,0x27632,0x27639,0x27639,0x27655,0x27657,0x27694,0x27694,0x2770f,0x2770f,0x27735,0x27736,0x27741,0x27741,0x2775e,0x2775e,0x27784,0x27785,0x277cc,0x277cc,0x27858,0x27858,0x27870,0x27870,0x2789d,0x2789d,0x278b2,0x278b2,0x278c8,0x278c8,0x27924,0x27924,0x27967,0x27967,0x2797a,0x2797a,0x279a0,0x279a0,0x279dd,0x279dd,0x279fd,0x279fd,0x27a0a,0x27a0a,0x27a0e,0x27a0e,0x27a3e,0x27a3e,0x27a53,0x27a53,0x27a59,0x27a59,0x27a79,0x27a79,0x27a84,0x27a84,0x27abd,0x27abe,0x27af4,0x27af4,0x27b06,0x27b06,0x27b0b,0x27b0b,0x27b18,0x27b18,0x27b38,0x27b3a,0x27b48,0x27b48,0x27b65,0x27b65,0x27bef,0x27bef,0x27bf4,0x27bf4,0x27c12,0x27c12,0x27c6c,0x27c6c,0x27cb1,0x27cb1,0x27cc5,0x27cc5,0x27d2f,0x27d2f,0x27d53,0x27d54,0x27d66,0x27d66,0x27d73,0x27d73,0x27d84,0x27d84,0x27d8f,0x27d8f,0x27d98,0x27d98,0x27dbd,0x27dbd,0x27ddc,0x27ddc,0x27e4d,0x27e4d,0x27e4f,0x27e4f,0x27f2e,0x27f2e,0x27fb7,0x27fb7,0x27ff9,0x27ff9,0x28002,0x28002,0x28009,0x28009,0x2801e,0x2801e,0x28023,0x28024,0x28048,0x28048,0x28083,0x28083,0x28090,0x28090,0x280bd,0x280be,0x280e8,0x280e9,0x280f4,0x280f4,0x2812e,0x2812e,0x2814f,0x2814f,0x2815d,0x2815d,0x2816f,0x2816f,0x28189,0x28189,0x281af,0x281af,0x281bc,0x281bc,0x28207,0x28207,0x28218,0x28218,0x2821a,0x2821a,0x28256,0x28256,0x2827c,0x2827c,0x2829b,0x2829b,0x282cd,0x282cd,0x282e2,0x282e2,0x28306,0x28306,0x28318,0x28318,0x2832f,0x2832f,0x2833a,0x2833a,0x28365,0x28365,0x2836d,0x2836d,0x2837d,0x2837d,0x2838a,0x2838a,0x28412,0x28412,0x28468,0x28468,0x2846c,0x2846c,0x28473,0x28473,0x28482,0x28482,0x28501,0x28501,0x2853c,0x2853d,0x2856c,0x2856c,0x285e8,0x285e8,0x285f4,0x285f4,0x28600,0x28600,0x2860b,0x2860b,0x28625,0x28625,0x2863b,0x2863b,0x286aa,0x286ab,0x286b2,0x286b2,0x286bc,0x286bc,0x286d8,0x286d8,0x286e6,0x286e6,0x2870f,0x2870f,0x28713,0x28713,0x28804,0x28804,0x2882b,0x2882b,0x2890d,0x2890d,0x28933,0x28933,0x28948,0x28949,0x28956,0x28956,0x28964,0x28964,0x28968,0x28968,0x2896c,0x2896d,0x2897e,0x2897e,0x28989,0x28989,0x289a8,0x289a8,0x289aa,0x289ab,0x289b8,0x289b8,0x289bc,0x289bc,0x289c0,0x289c0,0x289dc,0x289dc,0x289de,0x289de,0x289e1,0x289e1,0x289e3,0x289e4,0x289e7,0x289e8,0x289f9,0x289fc,0x28a0f,0x28a0f,0x28a16,0x28a16,0x28a25,0x28a25,0x28a29,0x28a29,0x28a32,0x28a32,0x28a36,0x28a36,0x28a44,0x28a4b,0x28a59,0x28a5a,0x28a81,0x28a83,0x28a9a,0x28a9c,0x28ac0,0x28ac0,0x28ac6,0x28ac6,0x28acb,0x28acc,0x28ace,0x28ace,0x28ade,0x28ae3,0x28ae5,0x28ae5,0x28aea,0x28aea,0x28afc,0x28afc,0x28b0c,0x28b0c,0x28b13,0x28b13,0x28b21,0x28b22,0x28b2b,0x28b2d,0x28b2f,0x28b2f,0x28b46,0x28b46,0x28b4c,0x28b4c,0x28b4e,0x28b4e,0x28b50,0x28b50,0x28b63,0x28b66,0x28b6c,0x28b6c,0x28b8f,0x28b8f,0x28b99,0x28b99,0x28b9c,0x28b9d,0x28bb9,0x28bb9,0x28bc2,0x28bc2,0x28bc5,0x28bc5,0x28bd4,0x28bd4,0x28bd7,0x28bd7,0x28bd9,0x28bda,0x28be7,0x28bec,0x28bf5,0x28bf5,0x28bff,0x28bff,0x28c03,0x28c03,0x28c09,0x28c09,0x28c1c,0x28c1d,0x28c23,0x28c23,0x28c26,0x28c26,0x28c2b,0x28c2b,0x28c30,0x28c30,0x28c39,0x28c39,0x28c3b,0x28c3b,0x28cca,0x28cca,0x28ccd,0x28ccd,0x28cd2,0x28cd2,0x28d34,0x28d34,0x28d99,0x28d99,0x28db9,0x28db9,0x28e0f,0x28e0f,0x28e36,0x28e36,0x28e39,0x28e39,0x28e65,0x28e66,0x28e97,0x28e97,0x28eac,0x28eac,0x28eb2,0x28eb3,0x28ed9,0x28ed9,0x28ee7,0x28ee7,0x28fc5,0x28fc5,0x29079,0x29079,0x29088,0x29088,0x2908b,0x2908b,0x29093,0x29093,0x290af,0x290b1,0x290c0,0x290c0,0x290e4,0x290e5,0x290ec,0x290ed,0x2910d,0x2910d,0x29110,0x29110,0x2913c,0x2913c,0x2914d,0x2914d,0x2915b,0x2915b,0x2915e,0x2915e,0x29170,0x29170,0x2919c,0x2919c,0x291a8,0x291a8,0x291d5,0x291d5,0x291eb,0x291eb,0x2941d,0x2941d,0x29420,0x29420,0x29433,0x29433,0x2943f,0x2943f,0x29448,0x29448,0x294d0,0x294d0,0x294d9,0x294da,0x294e5,0x294e5,0x294e7,0x294e7,0x2959e,0x2959e,0x295b0,0x295b0,0x295b8,0x295b8,0x295d7,0x295d7,0x295e9,0x295e9,0x295f4,0x295f4,0x2967f,0x2967f,0x29720,0x29720,0x29732,0x29732,0x297d4,0x297d4,0x29810,0x29810,0x29857,0x29857,0x298a4,0x298a4,0x298d1,0x298d1,0x298ea,0x298ea,0x298f1,0x298f1,0x298fa,0x298fa,0x29903,0x29903,0x29905,0x29905,0x2992f,0x2992f,0x29945,0x29945,0x29947,0x29949,0x2995d,0x2995d,0x2996a,0x2996a,0x2999d,0x2999d,0x299c3,0x299c3,0x299c9,0x299c9,0x29a28,0x29a28,0x29a4d,0x29a4d,0x29b05,0x29b05,0x29b0e,0x29b0e,0x29bd5,0x29bd5,0x29c73,0x29c73,0x29cad,0x29cad,0x29d3e,0x29d3e,0x29d5a,0x29d5a,0x29d7c,0x29d7c,0x29d98,0x29d98,0x29d9b,0x29d9b,0x29df6,0x29df6,0x29e06,0x29e06,0x29e2d,0x29e2d,0x29e68,0x29e68,0x29eac,0x29eac,0x29eb0,0x29eb0,0x29ec3,0x29ec3,0x29ef8,0x29ef8,0x29f23,0x29f23,0x29f30,0x29f30,0x29fb7,0x29fb7,0x29fde,0x29fde,0x2a014,0x2a014,0x2a087,0x2a087,0x2a0b9,0x2a0b9,0x2a0e1,0x2a0e1,0x2a0ed,0x2a0ed,0x2a0f3,0x2a0f3,0x2a0f8,0x2a0f8,0x2a0fe,0x2a0fe,0x2a107,0x2a107,0x2a123,0x2a123,0x2a133,0x2a134,0x2a150,0x2a150,0x2a192,0x2a193,0x2a1ab,0x2a1ab,0x2a1b4,0x2a1b5,0x2a1df,0x2a1df,0x2a1f5,0x2a1f5,0x2a220,0x2a220,0x2a233,0x2a233,0x2a293,0x2a293,0x2a29f,0x2a29f,0x2a2b2,0x2a2b2,0x2a2b4,0x2a2b4,0x2a2b6,0x2a2b6,0x2a2ba,0x2a2ba,0x2a2bd,0x2a2bd,0x2a2df,0x2a2df,0x2a2ff,0x2a2ff,0x2a351,0x2a351,0x2a3a9,0x2a3a9,0x2a3ed,0x2a3ed,0x2a434,0x2a434,0x2a45b,0x2a45b,0x2a5c6,0x2a5c6,0x2a5cb,0x2a5cb,0x2a601,0x2a601,0x2a632,0x2a632,0x2a64a,0x2a64a,0x2a65b,0x2a65b,0x2a6a9,0x2a6a9,0x2adff,0x2adff,0x2d544,0x2d544,0x2f825,0x2f825,0x2f83b,0x2f83b,0x2f840,0x2f840,0x2f878,0x2f878,0x2f894,0x2f894,0x2f8a6,0x2f8a6,0x2f8cd,0x2f8cd,0x2f8db,0x2f8db,0x2f994,0x2f994,0x2f9b2,0x2f9b2,0x2f9bc,0x2f9bc,0x2f9d4,0x2f9d4,0x30edd,0x30ede,0x3106c,0x3106c,]), + NotoFont.fromFlatRanges('Noto Sans Tagalog', 'http://fonts.gstatic.com/s/notosanstagalog/v15/J7aFnoNzCnFcV9ZI-sUYuvote1R0wwEAA8jHexnL.ttf', [0x20,0x20,0xa0,0xa0,0x1700,0x170c,0x170e,0x1714,0x1735,0x1736,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Tagbanwa', 'http://fonts.gstatic.com/s/notosanstagbanwa/v15/Y4GWYbB8VTEp4t3MKJSMmQdIKjRtt_nZRjQEaYpGoQ.ttf', [0x20,0x20,0xa0,0xa0,0x1735,0x1736,0x1760,0x176c,0x176e,0x1770,0x1772,0x1773,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Tai Le', 'http://fonts.gstatic.com/s/notosanstaile/v15/vEFK2-VODB8RrNDvZSUmVxEATwR58tK1W77HtMo.ttf', [0x20,0x20,0xa0,0xa0,0x300,0x301,0x307,0x308,0x30c,0x30c,0x1040,0x1049,0x1950,0x196d,0x1970,0x1974,0x200b,0x200d,0x25cc,0x25cc,0x3001,0x3002,0x3008,0x300b,]), + NotoFont.fromFlatRanges('Noto Sans Tai Tham', 'http://fonts.gstatic.com/s/notosanstaitham/v17/kJEbBv0U4hgtwxDUw2x9q7tbjLIfbPGHBoaVSAZ3MdLJBCUbPgquyaRGKMw.ttf', [0x20,0x20,0xa0,0xa0,0x1a20,0x1a5e,0x1a60,0x1a7c,0x1a7f,0x1a89,0x1a90,0x1a99,0x1aa0,0x1aad,0x200b,0x200d,0x2219,0x2219,]), + NotoFont.fromFlatRanges('Noto Sans Tai Viet', 'http://fonts.gstatic.com/s/notosanstaiviet/v15/8QIUdj3HhN_lv4jf9vsE-9GMOLsaSPZr644fWsRO9w.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa78b,0xa78c,0xaa80,0xaac2,0xaadb,0xaadf,]), + NotoFont.fromFlatRanges('Noto Sans Takri', 'http://fonts.gstatic.com/s/notosanstakri/v15/TuGJUVpzXI5FBtUq5a8bnKIOdTwQNO_W3khJXg.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x965,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11680,0x116b8,0x116c0,0x116c9,]), + NotoFont.fromFlatRanges('Noto Sans Tamil', 'http://fonts.gstatic.com/s/notosanstamil/v21/ieVc2YdFI3GCY6SyQy1KfStzYKZgzN1z4LKDbeZce-0429tBManUktuex7vGo70RqKDt_EvT.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xb82,0xb83,0xb85,0xb8a,0xb8e,0xb90,0xb92,0xb95,0xb99,0xb9a,0xb9c,0xb9c,0xb9e,0xb9f,0xba3,0xba4,0xba8,0xbaa,0xbae,0xbb9,0xbbe,0xbc2,0xbc6,0xbc8,0xbca,0xbcd,0xbd0,0xbd0,0xbd7,0xbd7,0xbe6,0xbfa,0x1cda,0x1cda,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x2074,0x2074,0x2082,0x2084,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa8f3,0xa8f3,0x11301,0x11301,0x11303,0x11303,0x1133b,0x1133c,]), + NotoFont.fromFlatRanges('Noto Sans Tamil Supplement', 'http://fonts.gstatic.com/s/notosanstamilsupplement/v19/DdTz78kEtnooLS5rXF1DaruiCd_bFp_Ph4sGcn7ax_vsAeMkeq1x.ttf', [0x11fc0,0x11ff1,0x11fff,0x11fff,]), + NotoFont.fromFlatRanges('Noto Sans Telugu', 'http://fonts.gstatic.com/s/notosanstelugu/v19/0FlxVOGZlE2Rrtr-HmgkMWJNjJ5_RyT8o8c7fHkeg-esVC5dzHkHIJQqrEntezbqQUbf-3v37w.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xc00,0xc0c,0xc0e,0xc10,0xc12,0xc28,0xc2a,0xc39,0xc3d,0xc44,0xc46,0xc48,0xc4a,0xc4d,0xc55,0xc56,0xc58,0xc5a,0xc60,0xc63,0xc66,0xc6f,0xc77,0xc7f,0x1cda,0x1cda,0x1cf2,0x1cf2,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Thaana', 'http://fonts.gstatic.com/s/notosansthaana/v16/C8c14dM-vnz-s-3jaEsxlxHkBH-WZOETXfoQrfQ9Y4XrbhLhnu4-tbNu.ttf', [0x20,0x21,0x28,0x29,0x2c,0x2c,0x2e,0x2e,0x3a,0x3b,0xa0,0xa0,0x60c,0x60c,0x61b,0x61b,0x61f,0x61f,0x660,0x66c,0x780,0x7b1,0x200b,0x200f,0x2018,0x2019,0x201c,0x201d,0x25cc,0x25cc,0xfdf2,0xfdf2,0xfdfd,0xfdfd,]), + NotoFont.fromFlatRanges('Noto Sans Thai', 'http://fonts.gstatic.com/s/notosansthai/v20/iJWnBXeUZi_OHPqn4wq6hQ2_hbJ1xyN9wd43SofNWcd1MKVQt_So_9CdU5RtpzF-QRvzzXg.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2d7,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x331,0x331,0xe01,0xe3a,0xe3f,0xe5b,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Tifinagh', 'http://fonts.gstatic.com/s/notosanstifinagh/v15/I_uzMoCduATTei9eI8dawkHIwvmhCvbn6rnEcXfs4Q.ttf', [0x20,0x20,0xa0,0xa0,0x2c7,0x2c7,0x301,0x302,0x304,0x304,0x306,0x307,0x309,0x309,0x323,0x323,0x331,0x331,0x200c,0x200d,0x202e,0x202e,0x25cc,0x25cc,0x2d30,0x2d67,0x2d6f,0x2d70,0x2d7f,0x2d7f,]), + NotoFont.fromFlatRanges('Noto Sans Tirhuta', 'http://fonts.gstatic.com/s/notosanstirhuta/v15/t5t6IQYRNJ6TWjahPR6X-M-apUyby7uGUBsTrn5P.ttf', [0x20,0x20,0xa0,0xa0,0x951,0x952,0x964,0x965,0x9f4,0x9f7,0x1cf2,0x1cf2,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11480,0x114c7,0x114d0,0x114d9,]), + NotoFont.fromFlatRanges('Noto Sans Ugaritic', 'http://fonts.gstatic.com/s/notosansugaritic/v15/3qTwoiqhnSyU8TNFIdhZVCwbjCpkAXXkMhoIkiazfg.ttf', [0x20,0x20,0xa0,0xa0,0x10380,0x1039d,0x1039f,0x1039f,]), + NotoFont.fromFlatRanges('Noto Sans Vai', 'http://fonts.gstatic.com/s/notosansvai/v15/NaPecZTSBuhTirw6IaFn_UrURMTsDIRSfr0.ttf', [0x20,0x20,0xa0,0xa0,0xa500,0xa62b,]), + NotoFont.fromFlatRanges('Noto Sans Wancho', 'http://fonts.gstatic.com/s/notosanswancho/v15/zrf-0GXXyfn6Fs0lH9P4cUubP0GBqAPopiRfKp8.ttf', [0x20,0x20,0x22,0x22,0x27,0x29,0x2c,0x2f,0x5b,0x5d,0x7b,0x7b,0x7d,0x7d,0xa0,0xa0,0x201c,0x201d,0x25cc,0x25cc,0x1e2c0,0x1e2f9,0x1e2ff,0x1e2ff,]), + NotoFont.fromFlatRanges('Noto Sans Warang Citi', 'http://fonts.gstatic.com/s/notosanswarangciti/v15/EYqtmb9SzL1YtsZSScyKDXIeOv3w-zgsNvKRpeVCCXzdgA.ttf', [0x20,0x20,0x27,0x27,0xa0,0xa0,0x200c,0x200d,0x118a0,0x118f2,0x118ff,0x118ff,]), + NotoFont.fromFlatRanges('Noto Sans Yi', 'http://fonts.gstatic.com/s/notosansyi/v15/sJoD3LFXjsSdcnzn071rO3apxVDJNVgSNg.ttf', [0x20,0x20,0xa0,0xa0,0x3001,0x3002,0x3008,0x3011,0x3014,0x301b,0x30fb,0x30fb,0xa000,0xa48c,0xa490,0xa4c6,0xff61,0xff65,]), + NotoFont.fromFlatRanges('Noto Sans Zanabazar Square', 'http://fonts.gstatic.com/s/notosanszanabazarsquare/v15/Cn-jJsuGWQxOjaGwMQ6fOicyxLBEMRfDtkzl4uagQtJxOCEgN0Gc.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x11a00,0x11a47,]), +]; diff --git a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart index 40a915f44876c..9550db92c02fd 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:convert'; import 'dart:typed_data'; import '../dom.dart'; @@ -11,9 +10,11 @@ import '../font_change_util.dart'; import '../platform_dispatcher.dart'; import '../util.dart'; import 'canvaskit_api.dart'; +import 'font_fallback_data.dart'; import 'fonts.dart'; import 'initialization.dart'; import 'interval_tree.dart'; +import 'noto_font.dart'; /// Global static font fallback data. class FontFallbackData { @@ -27,13 +28,9 @@ class FontFallbackData { /// Used for tests. static void debugReset() { _instance = FontFallbackData(); + notoDownloadQueue = FallbackFontDownloadQueue(); } - /// Whether or not "Noto Sans Symbols" and "Noto Color Emoji" fonts have been - /// downloaded. We download these as fallbacks when no other font covers the - /// given code units. - bool registeredSymbolsAndEmoji = false; - /// Code units that no known font has a glyph for. final Set codeUnitsWithNoKnownFont = {}; @@ -47,15 +44,9 @@ class FontFallbackData { final Map> ranges = >{}; - for (final NotoFont font in _notoFonts) { - // TODO(yjbanov): instead of mutating the font tree during reset, it's - // better to construct an immutable tree of resolved fonts - // pointing back to the original NotoFont objects. Then - // resetting the tree would be a matter of reconstructing - // the new resolved tree. - font.reset(); + for (final NotoFont font in fallbackFonts) { // ignore: prefer_foreach - for (final CodeunitRange range in font.approximateUnicodeRanges) { + for (final CodeunitRange range in font.computeUnicodeRanges()) { ranges.putIfAbsent(font, () => []).add(range); } } @@ -68,8 +59,6 @@ class FontFallbackData { final List globalFontFallbacks = ['Roboto']; - final Map fontFallbackCounts = {}; - /// A list of code units to check against the global fallback fonts. final Set _codeUnitsToCheckAgainstFallbackFonts = {}; @@ -165,6 +154,9 @@ class FontFallbackData { _scheduledCodeUnitCheck = false; // We don't know if the remaining code units are covered by our fallback // fonts. Check them and update the cache. + if (_codeUnitsToCheckAgainstFallbackFonts.isEmpty) { + return; + } final List codeUnits = _codeUnitsToCheckAgainstFallbackFonts.toList(); _codeUnitsToCheckAgainstFallbackFonts.clear(); final List codeUnitsSupported = @@ -225,23 +217,19 @@ class FontFallbackData { printWarning('Failed to parse fallback font $family as a font.'); return; } - fontFallbackCounts.putIfAbsent(family, () => 0); - final int fontFallbackTag = fontFallbackCounts[family]!; - fontFallbackCounts[family] = fontFallbackCounts[family]! + 1; - final String countedFamily = '$family $fontFallbackTag'; // Insert emoji font before all other fallback fonts so we use the emoji // whenever it's available. - registeredFallbackFonts.add(RegisteredFont(bytes, countedFamily, typeface)); + registeredFallbackFonts.add(RegisteredFont(bytes, family, typeface)); // Insert emoji font before all other fallback fonts so we use the emoji // whenever it's available. - if (family == 'Noto Color Emoji Compat') { + if (family == 'Noto Emoji') { if (globalFontFallbacks.first == 'Roboto') { - globalFontFallbacks.insert(1, countedFamily); + globalFontFallbacks.insert(1, family); } else { - globalFontFallbacks.insert(0, countedFamily); + globalFontFallbacks.insert(0, family); } } else { - globalFontFallbacks.add(countedFamily); + globalFontFallbacks.add(family); } } } @@ -262,209 +250,24 @@ Future findFontsForMissingCodeunits(List codeUnits) async { } } - for (final NotoFont font in fonts) { - await font.ensureResolved(); - } - // The call to `findMinimumFontsForCodeUnits` will remove all code units that // were matched by `fonts` from `unmatchedCodeUnits`. final Set unmatchedCodeUnits = Set.from(coveredCodeUnits); fonts = findMinimumFontsForCodeUnits(unmatchedCodeUnits, fonts); - final Set<_ResolvedNotoSubset> resolvedFonts = <_ResolvedNotoSubset>{}; - for (final int codeUnit in coveredCodeUnits) { - for (final NotoFont font in fonts) { - if (font.resolvedFont == null) { - // We failed to resolve the font earlier. - continue; - } - resolvedFonts.addAll(font.resolvedFont!.tree.intersections(codeUnit)); - } - } - resolvedFonts.forEach(notoDownloadQueue.add); + fonts.forEach(notoDownloadQueue.add); // We looked through the Noto font tree and didn't find any font families // covering some code units, or we did find a font family, but when we // downloaded the fonts we found that they actually didn't cover them. So // we try looking them up in the symbols and emojis fonts. if (missingCodeUnits.isNotEmpty || unmatchedCodeUnits.isNotEmpty) { - if (!data.registeredSymbolsAndEmoji) { - await _registerSymbolsAndEmoji(); - } else { - if (!notoDownloadQueue.isPending) { - printWarning( - 'Could not find a set of Noto fonts to display all missing ' - 'characters. Please add a font asset for the missing characters.' - ' See: https://flutter.dev/docs/cookbook/design/fonts'); - data.codeUnitsWithNoKnownFont.addAll(missingCodeUnits); - } - } - } -} - -/// Parse the CSS file for a font and make a list of resolved subsets. -/// -/// A CSS file from Google Fonts looks like this: -/// -/// /* [0] */ -/// @font-face { -/// font-family: 'Noto Sans KR'; -/// font-style: normal; -/// font-weight: 400; -/// src: url(https://fonts.gstatic.com/s/notosanskr/v13/PbykFmXiEBPT4ITbgNA5Cgm20xz64px_1hVWr0wuPNGmlQNMEfD4.0.woff2) format('woff2'); -/// unicode-range: U+f9ca-fa0b, U+ff03-ff05, U+ff07, U+ff0a-ff0b, U+ff0d-ff19, U+ff1b, U+ff1d, U+ff20-ff5b, U+ff5d, U+ffe0-ffe3, U+ffe5-ffe6; -/// } -/// /* [1] */ -/// @font-face { -/// font-family: 'Noto Sans KR'; -/// font-style: normal; -/// font-weight: 400; -/// src: url(https://fonts.gstatic.com/s/notosanskr/v13/PbykFmXiEBPT4ITbgNA5Cgm20xz64px_1hVWr0wuPNGmlQNMEfD4.1.woff2) format('woff2'); -/// unicode-range: U+f92f-f980, U+f982-f9c9; -/// } -/// /* [2] */ -/// @font-face { -/// font-family: 'Noto Sans KR'; -/// font-style: normal; -/// font-weight: 400; -/// src: url(https://fonts.gstatic.com/s/notosanskr/v13/PbykFmXiEBPT4ITbgNA5Cgm20xz64px_1hVWr0wuPNGmlQNMEfD4.2.woff2) format('woff2'); -/// unicode-range: U+d723-d728, U+d72a-d733, U+d735-d748, U+d74a-d74f, U+d752-d753, U+d755-d757, U+d75a-d75f, U+d762-d764, U+d766-d768, U+d76a-d76b, U+d76d-d76f, U+d771-d787, U+d789-d78b, U+d78d-d78f, U+d791-d797, U+d79a, U+d79c, U+d79e-d7a3, U+f900-f909, U+f90b-f92e; -/// } -_ResolvedNotoFont? _makeResolvedNotoFontFromCss(String css, String name) { - final List<_ResolvedNotoSubset> subsets = <_ResolvedNotoSubset>[]; - bool resolvingFontFace = false; - String? fontFaceUrl; - List? fontFaceUnicodeRanges; - for (final String line in LineSplitter.split(css)) { - // Search for the beginning of a @font-face. - if (!resolvingFontFace) { - if (line == '@font-face {') { - resolvingFontFace = true; - } else { - continue; - } - } else { - // We are resolving a @font-face, read out the url and ranges. - if (line.startsWith(' src:')) { - final int urlStart = line.indexOf('url('); - if (urlStart == -1) { - printWarning('Unable to resolve Noto font URL: $line'); - return null; - } - final int urlEnd = line.indexOf(')'); - fontFaceUrl = line.substring(urlStart + 4, urlEnd); - } else if (line.startsWith(' unicode-range:')) { - fontFaceUnicodeRanges = []; - final String rangeString = line.substring(17, line.length - 1); - final List rawRanges = rangeString.split(', '); - for (final String rawRange in rawRanges) { - final List startEnd = rawRange.split('-'); - if (startEnd.length == 1) { - final String singleRange = startEnd.single; - assert(singleRange.startsWith('U+')); - final int rangeValue = - int.parse(singleRange.substring(2), radix: 16); - fontFaceUnicodeRanges.add(CodeunitRange(rangeValue, rangeValue)); - } else { - assert(startEnd.length == 2); - final String startRange = startEnd[0]; - final String endRange = startEnd[1]; - assert(startRange.startsWith('U+')); - final int startValue = - int.parse(startRange.substring(2), radix: 16); - final int endValue = int.parse(endRange, radix: 16); - fontFaceUnicodeRanges.add(CodeunitRange(startValue, endValue)); - } - } - } else if (line == '}') { - if (fontFaceUrl == null || fontFaceUnicodeRanges == null) { - printWarning('Unable to parse Google Fonts CSS: $css'); - return null; - } - subsets - .add(_ResolvedNotoSubset(fontFaceUrl, name, fontFaceUnicodeRanges)); - resolvingFontFace = false; - } else { - continue; - } - } - } - - if (resolvingFontFace) { - printWarning('Unable to parse Google Fonts CSS: $css'); - return null; - } - - final Map<_ResolvedNotoSubset, List> rangesMap = - <_ResolvedNotoSubset, List>{}; - for (final _ResolvedNotoSubset subset in subsets) { - // ignore: prefer_foreach - for (final CodeunitRange range in subset.ranges) { - rangesMap.putIfAbsent(subset, () => []).add(range); - } - } - - if (rangesMap.isEmpty) { - printWarning('Parsed Google Fonts CSS was empty: $css'); - return null; - } - - final IntervalTree<_ResolvedNotoSubset> tree = - IntervalTree<_ResolvedNotoSubset>.createFromRanges(rangesMap); - - return _ResolvedNotoFont(name, subsets, tree); -} - -/// In the case where none of the known Noto Fonts cover a set of code units, -/// try the Symbols and Emoji fonts. We don't know the exact range of code units -/// that are covered by these fonts, so we download them and hope for the best. -Future _registerSymbolsAndEmoji() async { - final FontFallbackData data = FontFallbackData.instance; - if (data.registeredSymbolsAndEmoji) { - return; - } - data.registeredSymbolsAndEmoji = true; - const String emojiUrl = - 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'; - const String symbolsUrl = - 'https://fonts.googleapis.com/css2?family=Noto+Sans+Symbols'; - - final String emojiCss = - await notoDownloadQueue.downloader.downloadAsString(emojiUrl); - final String symbolsCss = - await notoDownloadQueue.downloader.downloadAsString(symbolsUrl); - - String? extractUrlFromCss(String css) { - for (final String line in LineSplitter.split(css)) { - if (line.startsWith(' src:')) { - final int urlStart = line.indexOf('url('); - if (urlStart == -1) { - printWarning('Unable to resolve Noto font URL: $line'); - return null; - } - final int urlEnd = line.indexOf(')'); - return line.substring(urlStart + 4, urlEnd); - } + if (!notoDownloadQueue.isPending) { + printWarning('Could not find a set of Noto fonts to display all missing ' + 'characters. Please add a font asset for the missing characters.' + ' See: https://flutter.dev/docs/cookbook/design/fonts'); + data.codeUnitsWithNoKnownFont.addAll(missingCodeUnits); } - printWarning('Unable to determine URL for Noto font'); - return null; - } - - final String? emojiFontUrl = extractUrlFromCss(emojiCss); - final String? symbolsFontUrl = extractUrlFromCss(symbolsCss); - - if (emojiFontUrl != null) { - notoDownloadQueue.add(_ResolvedNotoSubset( - emojiFontUrl, 'Noto Color Emoji Compat', const [])); - } else { - printWarning('Error parsing CSS for Noto Emoji font.'); - } - - if (symbolsFontUrl != null) { - notoDownloadQueue.add(_ResolvedNotoSubset( - symbolsFontUrl, 'Noto Sans Symbols', const [])); - } else { - printWarning('Error parsing CSS for Noto Symbols font.'); } } @@ -493,7 +296,7 @@ Set findMinimumFontsForCodeUnits( for (final NotoFont font in fonts) { int codeUnitsCovered = 0; for (final int codeUnit in codeUnits) { - if (font.resolvedFont?.tree.containsDeep(codeUnit) ?? false) { + if (font.contains(codeUnit)) { codeUnitsCovered++; } } @@ -535,321 +338,43 @@ Set findMinimumFontsForCodeUnits( if (bestFonts.contains(_notoSansJP)) { bestFont = _notoSansJP; } + } else if (language == 'ko') { + if (bestFonts.contains(_notoSansKR)) { + bestFont = _notoSansKR; + } + } else if (bestFonts.contains(_notoSansSC)) { + bestFont = _notoSansSC; + } + } else { + // To be predictable, if Simplified Chinese is one of the best fonts, + // choose that since it is the most common script. + if (bestFonts.contains(_notoSansSC)) { + bestFont = _notoSansSC; } } } codeUnits.removeWhere((int codeUnit) { - return bestFont.resolvedFont!.tree.containsDeep(codeUnit); + return bestFont.contains(codeUnit); }); - minimumFonts.addAll(bestFonts); + minimumFonts.add(bestFont); } return minimumFonts; } -class NotoFont { - NotoFont(this.name, this.approximateUnicodeRanges); - - final String name; - final List approximateUnicodeRanges; - - Completer? _decodingCompleter; - _ResolvedNotoFont? resolvedFont; - - String get googleFontsCssUrl => - 'https://fonts.googleapis.com/css2?family=${name.replaceAll(' ', '+')}'; - - Future ensureResolved() async { - if (resolvedFont == null) { - if (_decodingCompleter == null) { - _decodingCompleter = Completer(); - final String googleFontCss = await notoDownloadQueue.downloader - .downloadAsString(googleFontsCssUrl); - final _ResolvedNotoFont? googleFont = - _makeResolvedNotoFontFromCss(googleFontCss, name); - resolvedFont = googleFont; - _decodingCompleter!.complete(); - } else { - await _decodingCompleter!.future; - } - } - } - - void reset() { - resolvedFont = null; - _decodingCompleter = null; - } -} - -class CodeunitRange { - const CodeunitRange(this.start, this.end); - - final int start; - final int end; - - bool contains(int codeUnit) { - return start <= codeUnit && codeUnit <= end; - } - - @override - bool operator ==(dynamic other) { - if (other is! CodeunitRange) { - return false; - } - final CodeunitRange range = other; - return range.start == start && range.end == end; - } - - @override - int get hashCode => Object.hash(start, end); - - @override - String toString() => '[$start, $end]'; -} - -class _ResolvedNotoFont { - const _ResolvedNotoFont(this.name, this.subsets, this.tree); - - final String name; - final List<_ResolvedNotoSubset> subsets; - final IntervalTree<_ResolvedNotoSubset> tree; -} - -class _ResolvedNotoSubset { - _ResolvedNotoSubset(this.url, this.family, this.ranges); - - final String url; - final String family; - final List ranges; - - @override - String toString() => '_ResolvedNotoSubset($family, $url)'; -} - -NotoFont _notoSansSC = NotoFont('Noto Sans SC', [ - const CodeunitRange(12288, 12591), - const CodeunitRange(12800, 13311), - const CodeunitRange(19968, 40959), - const CodeunitRange(65072, 65135), - const CodeunitRange(65280, 65519), -]); - -NotoFont _notoSansTC = NotoFont('Noto Sans TC', [ - const CodeunitRange(12288, 12351), - const CodeunitRange(12549, 12585), - const CodeunitRange(19968, 40959), -]); - -NotoFont _notoSansHK = NotoFont('Noto Sans HK', [ - const CodeunitRange(12288, 12351), - const CodeunitRange(12549, 12585), - const CodeunitRange(19968, 40959), -]); - -NotoFont _notoSansJP = NotoFont('Noto Sans JP', [ - const CodeunitRange(12288, 12543), - const CodeunitRange(19968, 40959), - const CodeunitRange(65280, 65519), -]); - -List _cjkFonts = [ - _notoSansSC, - _notoSansTC, - _notoSansHK, - _notoSansJP, -]; - -List _notoFonts = [ - _notoSansSC, - _notoSansTC, - _notoSansHK, - _notoSansJP, - NotoFont('Noto Naskh Arabic UI', [ - const CodeunitRange(1536, 1791), - const CodeunitRange(8204, 8206), - const CodeunitRange(8208, 8209), - const CodeunitRange(8271, 8271), - const CodeunitRange(11841, 11841), - const CodeunitRange(64336, 65023), - const CodeunitRange(65132, 65276), - ]), - NotoFont('Noto Sans Armenian', [ - const CodeunitRange(1328, 1424), - const CodeunitRange(64275, 64279), - ]), - NotoFont('Noto Sans Bengali UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(2433, 2555), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Myanmar UI', [ - const CodeunitRange(4096, 4255), - const CodeunitRange(8204, 8205), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Egyptian Hieroglyphs', [ - const CodeunitRange(77824, 78894), - ]), - NotoFont('Noto Sans Ethiopic', [ - const CodeunitRange(4608, 5017), - const CodeunitRange(11648, 11742), - const CodeunitRange(43777, 43822), - ]), - NotoFont('Noto Sans Georgian', [ - const CodeunitRange(1417, 1417), - const CodeunitRange(4256, 4351), - const CodeunitRange(11520, 11567), - ]), - NotoFont('Noto Sans Gujarati UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(2688, 2815), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - const CodeunitRange(43056, 43065), - ]), - NotoFont('Noto Sans Gurmukhi UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(2561, 2677), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - const CodeunitRange(9772, 9772), - const CodeunitRange(43056, 43065), - ]), - NotoFont('Noto Sans Hebrew', [ - const CodeunitRange(1424, 1535), - const CodeunitRange(8362, 8362), - const CodeunitRange(9676, 9676), - const CodeunitRange(64285, 64335), - ]), - NotoFont('Noto Sans Devanagari UI', [ - const CodeunitRange(2304, 2431), - const CodeunitRange(7376, 7414), - const CodeunitRange(7416, 7417), - const CodeunitRange(8204, 8205), - const CodeunitRange(8360, 8360), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - const CodeunitRange(43056, 43065), - const CodeunitRange(43232, 43259), - ]), - NotoFont('Noto Sans Kannada UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(3202, 3314), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Khmer UI', [ - const CodeunitRange(6016, 6143), - const CodeunitRange(8204, 8204), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans KR', [ - const CodeunitRange(12593, 12686), - const CodeunitRange(12800, 12828), - const CodeunitRange(12896, 12923), - const CodeunitRange(44032, 55215), - ]), - NotoFont('Noto Sans Lao UI', [ - const CodeunitRange(3713, 3807), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Malayalam UI', [ - const CodeunitRange(775, 775), - const CodeunitRange(803, 803), - const CodeunitRange(2404, 2405), - const CodeunitRange(3330, 3455), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Sinhala', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(3458, 3572), - const CodeunitRange(8204, 8205), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Tamil UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(2946, 3066), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Telugu UI', [ - const CodeunitRange(2385, 2386), - const CodeunitRange(2404, 2405), - const CodeunitRange(3072, 3199), - const CodeunitRange(7386, 7386), - const CodeunitRange(8204, 8205), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Thai UI', [ - const CodeunitRange(3585, 3675), - const CodeunitRange(8204, 8205), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans', [ - const CodeunitRange(0, 255), - const CodeunitRange(305, 305), - const CodeunitRange(338, 339), - const CodeunitRange(699, 700), - const CodeunitRange(710, 710), - const CodeunitRange(730, 730), - const CodeunitRange(732, 732), - const CodeunitRange(8192, 8303), - const CodeunitRange(8308, 8308), - const CodeunitRange(8364, 8364), - const CodeunitRange(8482, 8482), - const CodeunitRange(8593, 8593), - const CodeunitRange(8595, 8595), - const CodeunitRange(8722, 8722), - const CodeunitRange(8725, 8725), - const CodeunitRange(65279, 65279), - const CodeunitRange(65533, 65533), - const CodeunitRange(1024, 1119), - const CodeunitRange(1168, 1169), - const CodeunitRange(1200, 1201), - const CodeunitRange(8470, 8470), - const CodeunitRange(1120, 1327), - const CodeunitRange(7296, 7304), - const CodeunitRange(8372, 8372), - const CodeunitRange(11744, 11775), - const CodeunitRange(42560, 42655), - const CodeunitRange(65070, 65071), - const CodeunitRange(880, 1023), - const CodeunitRange(7936, 8191), - const CodeunitRange(256, 591), - const CodeunitRange(601, 601), - const CodeunitRange(7680, 7935), - const CodeunitRange(8224, 8224), - const CodeunitRange(8352, 8363), - const CodeunitRange(8365, 8399), - const CodeunitRange(8467, 8467), - const CodeunitRange(11360, 11391), - const CodeunitRange(42784, 43007), - const CodeunitRange(258, 259), - const CodeunitRange(272, 273), - const CodeunitRange(296, 297), - const CodeunitRange(360, 361), - const CodeunitRange(416, 417), - const CodeunitRange(431, 432), - const CodeunitRange(7840, 7929), - const CodeunitRange(8363, 8363), - ]), -]; +NotoFont _notoSansSC = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans SC'); +NotoFont _notoSansTC = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans TC'); +NotoFont _notoSansHK = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans HK'); +NotoFont _notoSansJP = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans JP'); +NotoFont _notoSansKR = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans KR'); +List _cjkFonts = [_notoSansSC, _notoSansTC, _notoSansHK, _notoSansJP, _notoSansKR]; class FallbackFontDownloadQueue { NotoDownloader downloader = NotoDownloader(); - final Set<_ResolvedNotoSubset> downloadedSubsets = <_ResolvedNotoSubset>{}; - final Map pendingSubsets = - {}; + final Set downloadedFonts = {}; + final Map pendingFonts = {}; - bool get isPending => pendingSubsets.isNotEmpty || _fontsLoading != null; + bool get isPending => pendingFonts.isNotEmpty || _fontsLoading != null; Future? _fontsLoading; bool get debugIsLoadingFonts => _fontsLoading != null; @@ -861,9 +386,9 @@ class FallbackFontDownloadQueue { if (_fontsLoading != null) { await _fontsLoading; } - if (pendingSubsets.isNotEmpty) { + if (pendingFonts.isNotEmpty) { await Future.delayed(const Duration(milliseconds: 100)); - if (pendingSubsets.isEmpty) { + if (pendingFonts.isEmpty) { await Future.delayed(const Duration(milliseconds: 100)); } } @@ -873,13 +398,13 @@ class FallbackFontDownloadQueue { } } - void add(_ResolvedNotoSubset subset) { - if (downloadedSubsets.contains(subset) || - pendingSubsets.containsKey(subset.url)) { + void add(NotoFont font) { + if (downloadedFonts.contains(font) || + pendingFonts.containsKey(font.url)) { return; } - final bool firstInBatch = pendingSubsets.isEmpty; - pendingSubsets[subset.url] = subset; + final bool firstInBatch = pendingFonts.isEmpty; + pendingFonts[font.url] = font; if (firstInBatch) { Timer.run(startDownloads); } @@ -888,20 +413,20 @@ class FallbackFontDownloadQueue { Future startDownloads() async { final Map> downloads = >{}; final Map downloadedData = {}; - for (final _ResolvedNotoSubset subset in pendingSubsets.values) { - downloads[subset.url] = Future(() async { + for (final NotoFont font in pendingFonts.values) { + downloads[font.url] = Future(() async { ByteBuffer buffer; try { - buffer = await downloader.downloadAsBytes(subset.url, - debugDescription: subset.family); + buffer = await downloader.downloadAsBytes(font.url, + debugDescription: font.name); } catch (e) { - pendingSubsets.remove(subset.url); - printWarning('Failed to load font ${subset.family} at ${subset.url}'); + pendingFonts.remove(font.url); + printWarning('Failed to load font ${font.name} at ${font.url}'); printWarning(e.toString()); return; } - downloadedSubsets.add(subset); - downloadedData[subset.url] = buffer.asUint8List(); + downloadedFonts.add(font); + downloadedData[font.url] = buffer.asUint8List(); }); } @@ -913,10 +438,10 @@ class FallbackFontDownloadQueue { final List downloadOrder = (downloadedData.keys.toList()..sort()).reversed.toList(); for (final String url in downloadOrder) { - final _ResolvedNotoSubset subset = pendingSubsets.remove(url)!; + final NotoFont font = pendingFonts.remove(url)!; final Uint8List bytes = downloadedData[url]!; - FontFallbackData.instance.registerFallbackFont(subset.family, bytes); - if (pendingSubsets.isEmpty) { + FontFallbackData.instance.registerFallbackFont(font.name, bytes); + if (pendingFonts.isEmpty) { _fontsLoading = skiaFontCollection.ensureFontsLoaded(); try { await _fontsLoading; @@ -927,7 +452,7 @@ class FallbackFontDownloadQueue { } } - if (pendingSubsets.isNotEmpty) { + if (pendingFonts.isNotEmpty) { await startDownloads(); } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart index 29d16421bbb5b..7f10373c51527 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart @@ -4,7 +4,7 @@ import 'dart:math' as math; -import 'font_fallbacks.dart' show CodeunitRange; +import 'noto_font.dart' show CodeunitRange; /// A tree which stores a set of intervals that can be queried for intersection. class IntervalTree { diff --git a/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart b/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart new file mode 100644 index 0000000000000..83964c6f4222c --- /dev/null +++ b/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart @@ -0,0 +1,98 @@ +// 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. + +class NotoFont { + const NotoFont(this.name, this.url, this._rangeStarts, this._rangeEnds); + + factory NotoFont.fromFlatRanges(String name, String url, List flatRanges) { + final List starts = []; + final List ends = []; + for (int i = 0; i < flatRanges.length; i += 2) { + starts.add(flatRanges[i]); + ends.add(flatRanges[i+1]); + } + return NotoFont(name, url, starts, ends); + } + + final String name; + final String url; + // A sorted list of Unicode range start points. + final List _rangeStarts; + + // A sorted list of Unicode range end points. + final List _rangeEnds; + + List computeUnicodeRanges() { + final List result = []; + for (int i = 0; i < _rangeStarts.length; i++) { + result.add(CodeunitRange(_rangeStarts[i], _rangeEnds[i])); + } + return result; + } + + // Returns `true` if this font has a glyph for the given [codeunit]. + bool contains(int codeUnit) { + // Binary search through the starts and ends to see if there + // is a range that contains the codeunit. + int min = 0; + int max = _rangeStarts.length - 1; + // Search for the first rangeStart that is greater than codeunit. + while (min < max) { + final int mid = (min + max) ~/ 2; + if (_rangeStarts[mid] > codeUnit) { + if (mid == 0) { + final int rangeStart = _rangeStarts[mid]; + final int rangeEnd = _rangeEnds[mid]; + return rangeStart <= codeUnit && codeUnit <= rangeEnd; + } + final int rangeStart = _rangeStarts[mid - 1]; + if (rangeStart <= codeUnit) { + final int rangeEnd = _rangeEnds[mid - 1]; + return rangeStart <= codeUnit && codeUnit <= rangeEnd; + } else { + max = mid - 1; + } + } else if (_rangeStarts[mid] < codeUnit) { + // If this is the last index, check if the codeunit is contained within it. + if (mid == _rangeStarts.length) { + final int rangeStart = _rangeStarts[mid]; + final int rangeEnd = _rangeEnds[mid]; + return rangeStart <= codeUnit && codeUnit <= rangeEnd; + } + min = mid + 1; + } else { + // _rangeStarts[mid] == codeUnit + return true; + } + } + return false; + } +} + +class CodeunitRange { + const CodeunitRange(this.start, this.end); + + final int start; + final int end; + + + bool contains(int codeUnit) { + return start <= codeUnit && codeUnit <= end; + } + + @override + bool operator ==(dynamic other) { + if (other is! CodeunitRange) { + return false; + } + final CodeunitRange range = other; + return range.start == start && range.end == end; + } + + @override + int get hashCode => Object.hash(start, end); + + @override + String toString() => '[$start, $end]'; +} diff --git a/lib/web_ui/test/canvaskit/canvas_golden_test.dart b/lib/web_ui/test/canvaskit/canvas_golden_test.dart index 77a3a57eb7fc5..8e90dd50a2938 100644 --- a/lib/web_ui/test/canvaskit/canvas_golden_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_golden_test.dart @@ -33,6 +33,7 @@ void testMain() { setUp(() { expect(notoDownloadQueue.downloader.debugActiveDownloadCount, 0); expect(notoDownloadQueue.isPending, isFalse); + FontFallbackData.debugReset(); }); tearDown(() { @@ -565,7 +566,6 @@ void testMain() { // some of these symbols. To make sure the test produces predictable // results we reset the fallback data forcing the engine to reload // fallbacks, which for this test will only load Noto Symbols. - FontFallbackData.debugReset(); await testTextStyle( 'symbols', outerText: '← ↑ → ↓ ', @@ -821,7 +821,6 @@ void testMain() { Future testSampleText(String language, String text, {ui.TextDirection textDirection = ui.TextDirection.ltr, bool write = false}) async { - FontFallbackData.debugReset(); const double testWidth = 300; double paragraphHeight = 0; final CkPicture picture = await generatePictureWhenFontsStable(() { @@ -1330,7 +1329,7 @@ Future testTextStyle( write: write, ); expect(notoDownloadQueue.debugIsLoadingFonts, isFalse); - expect(notoDownloadQueue.pendingSubsets, isEmpty); + expect(notoDownloadQueue.pendingFonts, isEmpty); expect(notoDownloadQueue.downloader.debugActiveDownloadCount, 0); } diff --git a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart index ed1293b813e23..adfeef58d6f76 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -28,10 +28,20 @@ void testMain() { ui.PlatformMessageCallback? savedCallback; setUp(() { + FontFallbackData.debugReset(); notoDownloadQueue.downloader = TestDownloader(); TestDownloader.mockDownloads.clear(); + final String notoSansArabicUrl = fallbackFonts + .singleWhere((NotoFont font) => font.name == 'Noto Sans Arabic') + .url; + final String notoEmojiUrl = fallbackFonts + .singleWhere((NotoFont font) => font.name == 'Noto Emoji') + .url; + TestDownloader.mockDownloads[notoSansArabicUrl] = + '/assets/fonts/NotoNaskhArabic-Regular.ttf'; + TestDownloader.mockDownloads[notoEmojiUrl] = + '/assets/fonts/NotoColorEmoji.ttf'; savedCallback = ui.window.onPlatformMessage; - FontFallbackData.debugReset(); }); tearDown(() { @@ -42,20 +52,7 @@ void testMain() { expect(FontFallbackData.instance.globalFontFallbacks, contains('Roboto')); }); - test('will download Noto Naskh Arabic if Arabic text is added', () async { - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = - ''' -/* arabic */ -@font-face { - font-family: 'Noto Naskh Arabic UI'; - font-style: normal; - font-weight: 400; - src: url(/assets/fonts/NotoNaskhArabic-Regular.ttf) format('ttf'); - unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC; -} -'''; - + test('will download Noto Sans Arabic if Arabic text is added', () async { expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); // Creating this paragraph should cause us to start to download the @@ -70,7 +67,7 @@ void testMain() { await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, - contains('Noto Naskh Arabic UI 0')); + contains('Noto Sans Arabic')); final CkPictureRecorder recorder = CkPictureRecorder(); final CkCanvas canvas = recorder.beginRecording(kDefaultRegion); @@ -96,28 +93,6 @@ void testMain() { test('will put the Noto Emoji font before other fallback fonts in the list', () async { - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'] = - ''' -@font-face { - font-family: 'Noto Color Emoji'; - src: url(/assets/fonts/NotoColorEmoji.ttf) format('ttf'); -} -'''; - - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = - ''' -/* arabic */ -@font-face { - font-family: 'Noto Naskh Arabic UI'; - font-style: normal; - font-weight: 400; - src: url(/assets/fonts/NotoNaskhArabic-Regular.ttf) format('ttf'); - unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC; -} -'''; - expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); // Creating this paragraph should cause us to start to download the @@ -132,7 +107,7 @@ void testMain() { await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, - ['Roboto', 'Noto Naskh Arabic UI 0']); + ['Roboto', 'Noto Sans Arabic']); pb = CkParagraphBuilder( CkParagraphStyle(), @@ -149,22 +124,13 @@ void testMain() { expect(FontFallbackData.instance.globalFontFallbacks, [ 'Roboto', - 'Noto Color Emoji Compat 0', - 'Noto Naskh Arabic UI 0', + 'Noto Emoji', + 'Noto Sans Arabic', ]); }); test('will download Noto Emojis and Noto Symbols if no matching Noto Font', () async { - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'] = - ''' -@font-face { - font-family: 'Noto Color Emoji'; - src: url(/assets/fonts/NotoColorEmoji.ttf) format('ttf'); -} -'''; - expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); // Creating this paragraph should cause us to start to download the @@ -179,7 +145,7 @@ void testMain() { await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, - contains('Noto Color Emoji Compat 0')); + contains('Noto Emoji')); final CkPictureRecorder recorder = CkPictureRecorder(); final CkCanvas canvas = recorder.beginRecording(kDefaultRegion); @@ -203,30 +169,6 @@ void testMain() { // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); - test('will gracefully fail if we cannot parse the Google Fonts CSS', - () async { - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = - 'invalid CSS... this should cause our parser to fail'; - - expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); - - // Creating this paragraph should cause us to start to download the - // fallback font. - final CkParagraphBuilder pb = CkParagraphBuilder( - CkParagraphStyle(), - ); - pb.addText('مرحبا'); - - // Flush microtasks and test that we didn't start any downloads. - EnginePlatformDispatcher.instance.rasterizer! - .debugRunPostFrameCallbacks(); - await Future.delayed(Duration.zero); - - expect(notoDownloadQueue.isPending, isFalse); - expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); - }); - // Regression test for https://github.com/flutter/flutter/issues/75836 // When we had this bug our font fallback resolution logic would end up in an // infinite loop and this test would freeze and time out. @@ -241,16 +183,12 @@ void testMain() { CkParagraphBuilder(CkParagraphStyle()).addText('ヽಠ'); EnginePlatformDispatcher.instance.rasterizer! .debugRunPostFrameCallbacks(); - await notoDownloadQueue.downloader.debugWhenIdle(); + await notoDownloadQueue.debugWhenIdle(); expect( loggingDownloader.log, [ - 'https://fonts.googleapis.com/css2?family=Noto+Sans+SC', - 'https://fonts.googleapis.com/css2?family=Noto+Sans+JP', - 'https://fonts.googleapis.com/css2?family=Noto+Sans+Kannada+UI', 'Noto Sans SC', - 'Noto Sans JP', - 'Noto Sans Kannada UI', + 'Noto Sans Kannada', ], ); @@ -259,7 +197,7 @@ void testMain() { CkParagraphBuilder(CkParagraphStyle()).addText('ヽಠ'); EnginePlatformDispatcher.instance.rasterizer! .debugRunPostFrameCallbacks(); - await notoDownloadQueue.downloader.debugWhenIdle(); + await notoDownloadQueue.debugWhenIdle(); expect(loggingDownloader.log, isEmpty); }); @@ -276,7 +214,7 @@ void testMain() { FontFallbackData.instance.notoTree; for (final NotoFont font in notoTree.root.enumerateAllElements()) { testedFonts.add(font.name); - for (final CodeunitRange range in font.approximateUnicodeRanges) { + for (final CodeunitRange range in font.computeUnicodeRanges()) { for (int codeUnit = range.start; codeUnit < range.end; codeUnit += 1) { @@ -291,30 +229,146 @@ void testMain() { testedFonts, unorderedEquals({ 'Noto Sans', - 'Noto Sans Malayalam UI', + 'Noto Emoji', + 'Noto Sans Symbols', + 'Noto Sans Symbols 2', + 'Noto Sans Adlam', + 'Noto Sans Anatolian Hieroglyphs', + 'Noto Sans Arabic', 'Noto Sans Armenian', + 'Noto Sans Avestan', + 'Noto Sans Balinese', + 'Noto Sans Bamum', + 'Noto Sans Bassa Vah', + 'Noto Sans Batak', + 'Noto Sans Bengali', + 'Noto Sans Bhaiksuki', + 'Noto Sans Brahmi', + 'Noto Sans Buginese', + 'Noto Sans Buhid', + 'Noto Sans Canadian Aboriginal', + 'Noto Sans Carian', + 'Noto Sans Caucasian Albanian', + 'Noto Sans Chakma', + 'Noto Sans Cham', + 'Noto Sans Cherokee', + 'Noto Sans Coptic', + 'Noto Sans Cuneiform', + 'Noto Sans Cypriot', + 'Noto Sans Deseret', + 'Noto Sans Devanagari', + 'Noto Sans Duployan', + 'Noto Sans Egyptian Hieroglyphs', + 'Noto Sans Elbasan', + 'Noto Sans Elymaic', 'Noto Sans Georgian', + 'Noto Sans Glagolitic', + 'Noto Sans Gothic', + 'Noto Sans Grantha', + 'Noto Sans Gujarati', + 'Noto Sans Gunjala Gondi', + 'Noto Sans Gurmukhi', + 'Noto Sans HK', + 'Noto Sans Hanunoo', + 'Noto Sans Hatran', 'Noto Sans Hebrew', - 'Noto Naskh Arabic UI', - 'Noto Sans Devanagari UI', - 'Noto Sans Telugu UI', - 'Noto Sans Tamil UI', - 'Noto Sans Kannada UI', - 'Noto Sans Sinhala', - 'Noto Sans Gurmukhi UI', - 'Noto Sans Gujarati UI', - 'Noto Sans Bengali UI', - 'Noto Sans Thai UI', - 'Noto Sans Lao UI', - 'Noto Sans Myanmar UI', - 'Noto Sans Ethiopic', - 'Noto Sans Khmer UI', - 'Noto Sans SC', + 'Noto Sans Imperial Aramaic', + 'Noto Sans Indic Siyaq Numbers', + 'Noto Sans Inscriptional Pahlavi', + 'Noto Sans Inscriptional Parthian', 'Noto Sans JP', - 'Noto Sans TC', - 'Noto Sans HK', + 'Noto Sans Javanese', 'Noto Sans KR', - 'Noto Sans Egyptian Hieroglyphs', + 'Noto Sans Kaithi', + 'Noto Sans Kannada', + 'Noto Sans Kayah Li', + 'Noto Sans Kharoshthi', + 'Noto Sans Khmer', + 'Noto Sans Khojki', + 'Noto Sans Khudawadi', + 'Noto Sans Lao', + 'Noto Sans Lepcha', + 'Noto Sans Limbu', + 'Noto Sans Linear A', + 'Noto Sans Linear B', + 'Noto Sans Lisu', + 'Noto Sans Lycian', + 'Noto Sans Lydian', + 'Noto Sans Mahajani', + 'Noto Sans Malayalam', + 'Noto Sans Mandaic', + 'Noto Sans Manichaean', + 'Noto Sans Marchen', + 'Noto Sans Masaram Gondi', + 'Noto Sans Math', + 'Noto Sans Mayan Numerals', + 'Noto Sans Medefaidrin', + 'Noto Sans Meetei Mayek', + 'Noto Sans Meroitic', + 'Noto Sans Miao', + 'Noto Sans Modi', + 'Noto Sans Mongolian', + 'Noto Sans Mro', + 'Noto Sans Multani', + 'Noto Sans Myanmar', + 'Noto Sans N Ko', + 'Noto Sans Nabataean', + 'Noto Sans New Tai Lue', + 'Noto Sans Newa', + 'Noto Sans Nushu', + 'Noto Sans Ogham', + 'Noto Sans Ol Chiki', + 'Noto Sans Old Hungarian', + 'Noto Sans Old Italic', + 'Noto Sans Old North Arabian', + 'Noto Sans Old Permic', + 'Noto Sans Old Persian', + 'Noto Sans Old Sogdian', + 'Noto Sans Old South Arabian', + 'Noto Sans Old Turkic', + 'Noto Sans Oriya', + 'Noto Sans Osage', + 'Noto Sans Osmanya', + 'Noto Sans Pahawh Hmong', + 'Noto Sans Palmyrene', + 'Noto Sans Pau Cin Hau', + 'Noto Sans Phags Pa', + 'Noto Sans Phoenician', + 'Noto Sans Psalter Pahlavi', + 'Noto Sans Rejang', + 'Noto Sans Runic', + 'Noto Sans SC', + 'Noto Sans Saurashtra', + 'Noto Sans Sharada', + 'Noto Sans Shavian', + 'Noto Sans Siddham', + 'Noto Sans Sinhala', + 'Noto Sans Sogdian', + 'Noto Sans Sora Sompeng', + 'Noto Sans Soyombo', + 'Noto Sans Sundanese', + 'Noto Sans Syloti Nagri', + 'Noto Sans Syriac', + 'Noto Sans TC', + 'Noto Sans Tagalog', + 'Noto Sans Tagbanwa', + 'Noto Sans Tai Le', + 'Noto Sans Tai Tham', + 'Noto Sans Tai Viet', + 'Noto Sans Takri', + 'Noto Sans Tamil', + 'Noto Sans Tamil Supplement', + 'Noto Sans Telugu', + 'Noto Sans Thaana', + 'Noto Sans Thai', + 'Noto Sans Tifinagh', + 'Noto Sans Tirhuta', + 'Noto Sans Ugaritic', + 'Noto Sans Vai', + 'Noto Sans Wancho', + 'Noto Sans Warang Citi', + 'Noto Sans Yi', + 'Noto Sans Zanabazar Square', })); // Construct random paragraphs out of supported code units. @@ -358,16 +412,34 @@ void testMain() { } class TestDownloader extends NotoDownloader { + // Where to redirect downloads to. static final Map mockDownloads = {}; @override Future downloadAsString(String url, {String? debugDescription}) async { if (mockDownloads.containsKey(url)) { - return mockDownloads[url]!; + url = mockDownloads[url]!; + final Uri uri = Uri.parse(url); + expect(uri.isScheme('http'), isFalse); + expect(uri.isScheme('https'), isFalse); + return super.downloadAsString(url); } else { return ''; } } + + @override + Future downloadAsBytes(String url, {String? debugDescription}) { + if (mockDownloads.containsKey(url)) { + url = mockDownloads[url]!; + final Uri uri = Uri.parse(url); + expect(uri.isScheme('http'), isFalse); + expect(uri.isScheme('https'), isFalse); + return super.downloadAsBytes(url); + } else { + return Future.value(Uint8List(0).buffer); + } + } } class LoggingDownloader implements NotoDownloader { From 6b7d2f7eb69481d327196ab3939ad2ceabbfce39 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 22:13:25 -0400 Subject: [PATCH 414/558] Roll Dart SDK from d89d5a7170f1 to d6387a631d60 (1 revision) (#35524) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 34 +------------------------ 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/DEPS b/DEPS index d3c0d5c950aa1..58e308934ae7e 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'd89d5a7170f11e4a4df9dd181cba4490a444fcee', + 'dart_revision': 'd6387a631d6060fba37d2c0c5f6b10017b74a85c', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index ae0832e00ba42..b4647fb516544 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 1848a5ce55d69934a9554b0e9dc098e3 +Signature: 2f94bdf454754437e7d871aa49d74179 UNUSED LICENSES: @@ -10674,8 +10674,6 @@ FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPa FILE: ../../../third_party/dart/runtime/vm/compiler/ffi/unit_tests/union5bytesPackedx10/x64_win.expect FILE: ../../../third_party/dart/samples/ffi/sqlite/docs/lib/scenario-default.svg FILE: ../../../third_party/dart/samples/ffi/sqlite/docs/lib/scenario-full.svg -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/docs/lib/scenario-default.svg -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/docs/lib/scenario-full.svg FILE: ../../../third_party/dart/sdk/lib/_internal/allowed_experiments.json FILE: ../../../third_party/dart/sdk/lib/html/html_common/conversions_dart2js.dart FILE: ../../../third_party/dart/sdk/lib/html/html_common/html_common.dart @@ -10981,30 +10979,6 @@ FILE: ../../../third_party/dart/samples/ffi/sqlite/lib/src/bindings/types.dart FILE: ../../../third_party/dart/samples/ffi/sqlite/lib/src/collections/closable_iterator.dart FILE: ../../../third_party/dart/samples/ffi/sqlite/lib/src/database.dart FILE: ../../../third_party/dart/samples/ffi/sqlite/lib/src/ffi/dylib_utils.dart -FILE: ../../../third_party/dart/samples_2/ffi/coordinate.dart -FILE: ../../../third_party/dart/samples_2/ffi/dylib_utils.dart -FILE: ../../../third_party/dart/samples_2/ffi/resource_management/arena_isolate_shutdown_sample.dart -FILE: ../../../third_party/dart/samples_2/ffi/resource_management/arena_sample.dart -FILE: ../../../third_party/dart/samples_2/ffi/resource_management/arena_zoned_sample.dart -FILE: ../../../third_party/dart/samples_2/ffi/resource_management/resource_management_test.dart -FILE: ../../../third_party/dart/samples_2/ffi/resource_management/unmanaged_sample.dart -FILE: ../../../third_party/dart/samples_2/ffi/sample_ffi_bitfield.dart -FILE: ../../../third_party/dart/samples_2/ffi/sample_ffi_data.dart -FILE: ../../../third_party/dart/samples_2/ffi/sample_ffi_dynamic_library.dart -FILE: ../../../third_party/dart/samples_2/ffi/sample_ffi_functions.dart -FILE: ../../../third_party/dart/samples_2/ffi/sample_ffi_functions_callbacks.dart -FILE: ../../../third_party/dart/samples_2/ffi/sample_ffi_functions_structs.dart -FILE: ../../../third_party/dart/samples_2/ffi/sample_ffi_structs.dart -FILE: ../../../third_party/dart/samples_2/ffi/samples_test.dart -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/example/main.dart -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/lib/sqlite.dart -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/lib/src/bindings/bindings.dart -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/lib/src/bindings/constants.dart -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/lib/src/bindings/signatures.dart -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/lib/src/bindings/types.dart -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/lib/src/collections/closable_iterator.dart -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/lib/src/database.dart -FILE: ../../../third_party/dart/samples_2/ffi/sqlite/lib/src/ffi/dylib_utils.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_shared/lib/rti.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_shared/lib/synced/recipe_syntax.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart @@ -11128,7 +11102,6 @@ FILE: ../../../third_party/dart/runtime/vm/thread_interrupter_android_arm.S FILE: ../../../third_party/dart/runtime/vm/virtual_memory_compressed.cc FILE: ../../../third_party/dart/runtime/vm/virtual_memory_compressed.h FILE: ../../../third_party/dart/samples/ffi/resource_management/utf8_helpers.dart -FILE: ../../../third_party/dart/samples_2/ffi/resource_management/utf8_helpers.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_runtime/lib/dart2js_runtime_metrics.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_runtime/lib/late_helper.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/ffi_allocation_patch.dart @@ -11304,10 +11277,6 @@ FILE: ../../../third_party/dart/samples/ffi/async/async_test.dart FILE: ../../../third_party/dart/samples/ffi/async/sample_async_callback.dart FILE: ../../../third_party/dart/samples/ffi/async/sample_native_port_call.dart FILE: ../../../third_party/dart/samples/ffi/sample_ffi_functions_callbacks_closures.dart -FILE: ../../../third_party/dart/samples_2/ffi/async/async_test.dart -FILE: ../../../third_party/dart/samples_2/ffi/async/sample_async_callback.dart -FILE: ../../../third_party/dart/samples_2/ffi/async/sample_native_port_call.dart -FILE: ../../../third_party/dart/samples_2/ffi/sample_ffi_functions_callbacks_closures.dart FILE: ../../../third_party/dart/sdk/lib/_http/embedder_config.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_dev_runtime/patch/js_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_runtime/lib/js_patch.dart @@ -11777,7 +11746,6 @@ FILE: ../../../third_party/dart/runtime/vm/zone.cc FILE: ../../../third_party/dart/runtime/vm/zone.h FILE: ../../../third_party/dart/runtime/vm/zone_test.cc FILE: ../../../third_party/dart/samples/samples.status -FILE: ../../../third_party/dart/samples_2/samples_2.status FILE: ../../../third_party/dart/sdk/lib/_http/crypto.dart FILE: ../../../third_party/dart/sdk/lib/_http/http_date.dart FILE: ../../../third_party/dart/sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart From b9c9648067dbe30e1f676333c9c0be0fc3c12bbf Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 22:19:08 -0400 Subject: [PATCH 415/558] Roll Clang Linux from d9e02a30b16e to 60d276923902 (#35523) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 58e308934ae7e..e57a78670d5b0 100644 --- a/DEPS +++ b/DEPS @@ -628,7 +628,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/clang/linux-amd64', - 'version': 'git_revision:d9e02a30b16ea65a7da87913c40af03e22c9571f' + 'version': 'git_revision:60d276923902051192eba692e5312e605c9d9f65' } ], 'condition': 'host_os == "linux" and host_cpu == "x64"', From 9e1fe4da8eb7ec33eb53e7f05f503da44765748a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 22:31:01 -0400 Subject: [PATCH 416/558] Roll Clang Mac from d9e02a30b16e to 60d276923902 (#35522) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e57a78670d5b0..6b7a372bbd331 100644 --- a/DEPS +++ b/DEPS @@ -606,7 +606,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/clang/mac-amd64', - 'version': 'git_revision:d9e02a30b16ea65a7da87913c40af03e22c9571f' + 'version': 'git_revision:60d276923902051192eba692e5312e605c9d9f65' } ], 'condition': 'host_os == "mac"', From 353c8776f3a6a28d165895230a1a3f1c6bc63420 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 18 Aug 2022 22:37:35 -0400 Subject: [PATCH 417/558] Roll Skia from 79633dd54c6f to 13ef19f19e87 (1 revision) (#35525) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6b7a372bbd331..ca8cfb42ae0d5 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': '79633dd54c6fa17b311dbb94fd3390394edb0bac', + 'skia_revision': '13ef19f19e874b821adb525e0bc021308e01924a', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 59321ab83dabe..c08df710f1dff 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 0b72c565b4a6025f947e1b9dbb482ed2 +Signature: 43065d1f5f572149aac6a7074449a607 UNUSED LICENSES: From 9347c684ad2e046e8a03ba31b4d14348948c7944 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 01:27:24 -0400 Subject: [PATCH 418/558] Roll Skia from 13ef19f19e87 to c805263f1697 (1 revision) (#35526) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ca8cfb42ae0d5..3173082512507 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': '13ef19f19e874b821adb525e0bc021308e01924a', + 'skia_revision': 'c805263f16973c011d9d8bf89da77024fc549d42', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index c08df710f1dff..8c8d0e93b23be 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 43065d1f5f572149aac6a7074449a607 +Signature: 36eac77f6ac07a55ce85cc08fb7a14f3 UNUSED LICENSES: From 5cb60e9d10b14978c4df6b020511f0a78e2b38db Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 02:03:15 -0400 Subject: [PATCH 419/558] Roll Fuchsia Linux SDK from gqQZ7EN2TeYTzOqKI... to -NNSCH3WIpT1x-ZpP... (#35528) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 3173082512507..580ea6f9c1f6a 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'gqQZ7EN2TeYTzOqKIjxGXNNpoDcz68MXn-l9Vtg2fYoC' + 'version': '-NNSCH3WIpT1x-ZpP3cDjMDYEmdhGciRL4ixvBkopcEC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index c7b22d2885907..e71e92d463d46 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 1b38c5821e7b2fd78bd830c6346c2ef5 +Signature: 12ea8269e6915822944b0d05c09c0c62 UNUSED LICENSES: @@ -553,11 +553,14 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.gfx/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.input/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.input3/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.lifecycle/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.observation.geometry/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointer.augment/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointer/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointerinjector/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.policy/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.scenic/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.input/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.scene/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.types/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.views/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ultrasound/meta.json @@ -1305,11 +1308,14 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.gfx/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.input/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.input3/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.lifecycle/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.observation.geometry/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointer.augment/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointer/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointerinjector/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.policy/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.scenic/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.input/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.scene/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.types/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.views/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ultrasound/meta.json @@ -1954,11 +1960,14 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.gfx/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.input/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.input3/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.lifecycle/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.observation.geometry/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointer.augment/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointer/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointerinjector/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.policy/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.scenic/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.input/meta.json +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.scene/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.types/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.views/meta.json FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ultrasound/meta.json @@ -2330,6 +2339,7 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.settings/keyboard.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.thermal/client_state.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.composition/allocator.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.composition/flatland.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.observation.geometry/watcher.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.views/flatland_tokens.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.wlan.common/wlan_common.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.wlan.ieee80211/constants.fidl @@ -3624,10 +3634,16 @@ FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.composition/screenshot.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.gfx/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.input/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.input3/overview.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.observation.geometry/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointer/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.pointerinjector/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.policy/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.scenic/overview.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.input/overview.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.input/registry.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.input/touch.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.scene/controller.fidl +FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.test.scene/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.ui.views/overview.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.unknown/unknown.fidl FILE: ../../../fuchsia/sdk/linux/fidl/fuchsia.update.config/config.fidl From c4b01172e8e6541fe801d4ee03422563addea537 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 02:39:36 -0400 Subject: [PATCH 420/558] Roll Skia from c805263f1697 to 95c86345480c (1 revision) (#35529) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 580ea6f9c1f6a..2b9f2936f45f7 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': 'c805263f16973c011d9d8bf89da77024fc549d42', + 'skia_revision': '95c86345480c5c4cdbfd5596887ef0fdf71fc56c', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 8c8d0e93b23be..9d307ce7c42a4 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 36eac77f6ac07a55ce85cc08fb7a14f3 +Signature: f99e84e2100ff8b62023bc37a7622ddf UNUSED LICENSES: From 1d31079a67527939c4d63fe952b33f32e15cf9bf Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 04:05:26 -0400 Subject: [PATCH 421/558] Roll Skia from 95c86345480c to 657a0ab4bfc5 (1 revision) (#35530) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 2b9f2936f45f7..c833e7ff54a92 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': '95c86345480c5c4cdbfd5596887ef0fdf71fc56c', + 'skia_revision': '657a0ab4bfc512c3acfbec99ff7500a302a5c232', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 9d307ce7c42a4..4c4f196b21f3e 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: f99e84e2100ff8b62023bc37a7622ddf +Signature: 560fd83ed8cf8d936143a66bfe9ac5f1 UNUSED LICENSES: From a23517305f9510c4c9313698dc3653dec19f6b59 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 05:17:32 -0400 Subject: [PATCH 422/558] Roll Skia from 657a0ab4bfc5 to 38cd049145b2 (1 revision) (#35531) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c833e7ff54a92..b1f1bcd4136b1 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': '657a0ab4bfc512c3acfbec99ff7500a302a5c232', + 'skia_revision': '38cd049145b2b22f2e6e89b10c3a80d1c19b92ff', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 4c4f196b21f3e..fd00ffb32108b 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 560fd83ed8cf8d936143a66bfe9ac5f1 +Signature: f63f699b39764bc0710ac78bcc86983e UNUSED LICENSES: From 64d969ed11fd198682aa3084cae28f7cef4ad6dd Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 05:31:27 -0400 Subject: [PATCH 423/558] Roll Fuchsia Mac SDK from 5jtXFOH7XU5RNDLkY... to MQoH-sefjYwKG_X2h... (#35532) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index b1f1bcd4136b1..9a55c31eebc7e 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': '5jtXFOH7XU5RNDLkYQJgiQYkr0OQ715MInl58Qho0Q0C' + 'version': 'MQoH-sefjYwKG_X2hv8qKJfSW15nnrtuAJbJMEHFsOsC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 29fe33348b9e39282fa5e06beeee797253084d9f Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Fri, 19 Aug 2022 05:58:19 -0700 Subject: [PATCH 424/558] Revert "[canvaskit] Generate fallback font data file (#34729)" (#35533) This reverts commit 3e9fcf4f4a74a03ee81cd7ff0e8a2c3a36e0003c. --- ci/licenses_golden/licenses_flutter | 2 - lib/web_ui/README.md | 13 - lib/web_ui/dev/felt.dart | 2 - .../dev/generate_fallback_font_data.dart | 289 --------- lib/web_ui/lib/src/engine.dart | 2 - .../engine/canvaskit/font_fallback_data.dart | 151 ----- .../src/engine/canvaskit/font_fallbacks.dart | 599 ++++++++++++++++-- .../src/engine/canvaskit/interval_tree.dart | 2 +- .../lib/src/engine/canvaskit/noto_font.dart | 98 --- .../test/canvaskit/canvas_golden_test.dart | 5 +- .../canvaskit/fallback_fonts_golden_test.dart | 278 +++----- 11 files changed, 644 insertions(+), 797 deletions(-) delete mode 100644 lib/web_ui/dev/generate_fallback_font_data.dart delete mode 100644 lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart delete mode 100644 lib/web_ui/lib/src/engine/canvaskit/noto_font.dart diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 03a7ee396ef44..e32f53958103f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1135,7 +1135,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/color_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views_diff.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/fonts.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -1149,7 +1148,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.d FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/mask_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/n_way_canvas.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/painting.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path_metrics.dart diff --git a/lib/web_ui/README.md b/lib/web_ui/README.md index f4e87cb31c6eb..d13e1ee6b145d 100644 --- a/lib/web_ui/README.md +++ b/lib/web_ui/README.md @@ -205,19 +205,6 @@ directly), follow these steps to roll to the new version: If you have questions, contact the Flutter Web team on Flutter Discord on the #hackers-web-🌍 channel. -### Rolling Noto Font Data - -In order to generate new data for the Noto fallback fonts, you will need -a GoogleFonts API key. Once you have one, run: - -``` -./dev/felt generate-fallback-font-data --key= -``` - -This will generate the file `lib/src/engine/canvaskit/font_fallback_data.dart` with -the latest data from GoogleFonts. This generated file should then be rolled in with -a PR to the engine. - ### Configuration files `browser_lock.yaml` contains the version of browsers we use to test Flutter for diff --git a/lib/web_ui/dev/felt.dart b/lib/web_ui/dev/felt.dart index 2e6e6d156cf46..1048c8bdcf3a6 100644 --- a/lib/web_ui/dev/felt.dart +++ b/lib/web_ui/dev/felt.dart @@ -9,7 +9,6 @@ import 'package:args/command_runner.dart'; import 'build.dart'; import 'clean.dart'; import 'exceptions.dart'; -import 'generate_fallback_font_data.dart'; import 'licenses.dart'; import 'run.dart'; import 'test_runner.dart'; @@ -21,7 +20,6 @@ CommandRunner runner = CommandRunner( ) ..addCommand(BuildCommand()) ..addCommand(CleanCommand()) - ..addCommand(GenerateFallbackFontDataCommand()) ..addCommand(LicensesCommand()) ..addCommand(RunCommand()) ..addCommand(TestCommand()); diff --git a/lib/web_ui/dev/generate_fallback_font_data.dart b/lib/web_ui/dev/generate_fallback_font_data.dart deleted file mode 100644 index 7ae4aae65eb8c..0000000000000 --- a/lib/web_ui/dev/generate_fallback_font_data.dart +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert' show jsonDecode; -import 'dart:io' as io; - -import 'package:args/command_runner.dart'; -import 'package:http/http.dart' as http; -import 'package:path/path.dart' as path; - -import 'environment.dart'; -import 'exceptions.dart'; -import 'utils.dart'; - -class GenerateFallbackFontDataCommand extends Command - with ArgUtils { - GenerateFallbackFontDataCommand() { - argParser.addOption( - 'key', - defaultsTo: '', - help: 'The Google Fonts API key. Used to get data about fonts hosted on ' - 'Google Fonts.', - ); - argParser.addFlag( - 'download-test-fonts', - defaultsTo: true, - help: 'Whether to download the Noto fonts into a local folder to use in' - 'tests.', - ); - } - - @override - final String name = 'generate-fallback-font-data'; - - @override - final String description = 'Generate fallback font data from GoogleFonts'; - - String get apiKey => stringArg('key'); - - bool get downloadTestFonts => boolArg('download-test-fonts'); - - @override - Future run() async { - await _generateFallbackFontData(); - return true; - } - - Future _generateFallbackFontData() async { - if (apiKey.isEmpty) { - throw UsageException('No Google Fonts API key provided', argParser.usage); - } - final http.Client client = http.Client(); - final http.Response response = await client.get(Uri.parse( - 'https://www.googleapis.com/webfonts/v1/webfonts?key=$apiKey')); - if (response.statusCode != 200) { - throw ToolExit('Failed to download Google Fonts list.'); - } - final Map googleFontsResult = - jsonDecode(response.body) as Map; - final List> fontDatas = - (googleFontsResult['items'] as List) - .cast>(); - final Map urlForFamily = {}; - for (final Map fontData in fontDatas) { - if (fallbackFonts.contains(fontData['family'])) { - final Uri uri = Uri.parse(fontData['files']['regular'] as String); - urlForFamily[fontData['family'] as String] = uri; - } - } - final Map charsetForFamily = {}; - final io.Directory fontDir = downloadTestFonts - ? await io.Directory(path.join( - environment.webUiBuildDir.path, - 'assets', - 'noto', - )).create(recursive: true) - : await io.Directory.systemTemp.createTemp('fonts'); - // Delete old fonts in the font directory. - await for (final io.FileSystemEntity file in fontDir.list()) { - await file.delete(); - } - for (final String family in fallbackFonts) { - print('Downloading $family...'); - final Uri uri = urlForFamily[family]!; - final http.Response fontResponse = await client.get(uri); - if (fontResponse.statusCode != 200) { - throw ToolExit('Failed to download font for $family'); - } - final io.File fontFile = - io.File(path.join(fontDir.path, path.basename(uri.path))); - await fontFile.writeAsBytes(fontResponse.bodyBytes); - final io.ProcessResult fcQueryResult = - await io.Process.run('fc-query', [ - '--format=%{charset}', - '--', - fontFile.path, - ]); - final String encodedCharset = fcQueryResult.stdout as String; - charsetForFamily[family] = encodedCharset; - } - - final StringBuffer sb = StringBuffer(); - - sb.writeln('// Copyright 2013 The Flutter Authors. All rights reserved.'); - sb.writeln('// Use of this source code is governed by a BSD-style license ' - 'that can be'); - sb.writeln('// found in the LICENSE file.'); - sb.writeln(); - sb.writeln('// DO NOT EDIT! This file is generated. See:'); - sb.writeln('// dev/generate_fallback_font_data.dart'); - sb.writeln("import 'noto_font.dart';"); - sb.writeln(); - sb.writeln('final List fallbackFonts = ['); - for (final String family in fallbackFonts) { - sb.write(" NotoFont.fromFlatRanges('$family', '${urlForFamily[family]!}', " - '['); - for (final String range in charsetForFamily[family]!.split(' ')) { - String? start; - String? end; - final List parts = range.split('-'); - if (parts.length == 1) { - start = parts[0]; - end = parts[0]; - } else { - start = parts[0]; - end = parts[1]; - } - sb.write('0x$start,0x$end,'); - } - sb.writeln(']),'); - } - sb.writeln('];'); - - final io.File fontDataFile = io.File(path.join( - environment.webUiRootDir.path, - 'lib', - 'src', - 'engine', - 'canvaskit', - 'font_fallback_data.dart', - )); - await fontDataFile.writeAsString(sb.toString()); - } -} - -const List fallbackFonts = [ - 'Noto Sans', - 'Noto Emoji', - 'Noto Sans Symbols', - 'Noto Sans Symbols 2', - 'Noto Sans Adlam', - 'Noto Sans Anatolian Hieroglyphs', - 'Noto Sans Arabic', - 'Noto Sans Armenian', - 'Noto Sans Avestan', - 'Noto Sans Balinese', - 'Noto Sans Bamum', - 'Noto Sans Bassa Vah', - 'Noto Sans Batak', - 'Noto Sans Bengali', - 'Noto Sans Bhaiksuki', - 'Noto Sans Brahmi', - 'Noto Sans Buginese', - 'Noto Sans Buhid', - 'Noto Sans Canadian Aboriginal', - 'Noto Sans Carian', - 'Noto Sans Caucasian Albanian', - 'Noto Sans Chakma', - 'Noto Sans Cham', - 'Noto Sans Cherokee', - 'Noto Sans Coptic', - 'Noto Sans Cuneiform', - 'Noto Sans Cypriot', - 'Noto Sans Deseret', - 'Noto Sans Devanagari', - 'Noto Sans Duployan', - 'Noto Sans Egyptian Hieroglyphs', - 'Noto Sans Elbasan', - 'Noto Sans Elymaic', - 'Noto Sans Georgian', - 'Noto Sans Glagolitic', - 'Noto Sans Gothic', - 'Noto Sans Grantha', - 'Noto Sans Gujarati', - 'Noto Sans Gunjala Gondi', - 'Noto Sans Gurmukhi', - 'Noto Sans HK', - 'Noto Sans Hanunoo', - 'Noto Sans Hatran', - 'Noto Sans Hebrew', - 'Noto Sans Imperial Aramaic', - 'Noto Sans Indic Siyaq Numbers', - 'Noto Sans Inscriptional Pahlavi', - 'Noto Sans Inscriptional Parthian', - 'Noto Sans JP', - 'Noto Sans Javanese', - 'Noto Sans KR', - 'Noto Sans Kaithi', - 'Noto Sans Kannada', - 'Noto Sans Kayah Li', - 'Noto Sans Kharoshthi', - 'Noto Sans Khmer', - 'Noto Sans Khojki', - 'Noto Sans Khudawadi', - 'Noto Sans Lao', - 'Noto Sans Lepcha', - 'Noto Sans Limbu', - 'Noto Sans Linear A', - 'Noto Sans Linear B', - 'Noto Sans Lisu', - 'Noto Sans Lycian', - 'Noto Sans Lydian', - 'Noto Sans Mahajani', - 'Noto Sans Malayalam', - 'Noto Sans Mandaic', - 'Noto Sans Manichaean', - 'Noto Sans Marchen', - 'Noto Sans Masaram Gondi', - 'Noto Sans Math', - 'Noto Sans Mayan Numerals', - 'Noto Sans Medefaidrin', - 'Noto Sans Meetei Mayek', - 'Noto Sans Meroitic', - 'Noto Sans Miao', - 'Noto Sans Modi', - 'Noto Sans Mongolian', - 'Noto Sans Mro', - 'Noto Sans Multani', - 'Noto Sans Myanmar', - 'Noto Sans N Ko', - 'Noto Sans Nabataean', - 'Noto Sans New Tai Lue', - 'Noto Sans Newa', - 'Noto Sans Nushu', - 'Noto Sans Ogham', - 'Noto Sans Ol Chiki', - 'Noto Sans Old Hungarian', - 'Noto Sans Old Italic', - 'Noto Sans Old North Arabian', - 'Noto Sans Old Permic', - 'Noto Sans Old Persian', - 'Noto Sans Old Sogdian', - 'Noto Sans Old South Arabian', - 'Noto Sans Old Turkic', - 'Noto Sans Oriya', - 'Noto Sans Osage', - 'Noto Sans Osmanya', - 'Noto Sans Pahawh Hmong', - 'Noto Sans Palmyrene', - 'Noto Sans Pau Cin Hau', - 'Noto Sans Phags Pa', - 'Noto Sans Phoenician', - 'Noto Sans Psalter Pahlavi', - 'Noto Sans Rejang', - 'Noto Sans Runic', - 'Noto Sans SC', - 'Noto Sans Saurashtra', - 'Noto Sans Sharada', - 'Noto Sans Shavian', - 'Noto Sans Siddham', - 'Noto Sans Sinhala', - 'Noto Sans Sogdian', - 'Noto Sans Sora Sompeng', - 'Noto Sans Soyombo', - 'Noto Sans Sundanese', - 'Noto Sans Syloti Nagri', - 'Noto Sans Syriac', - 'Noto Sans TC', - 'Noto Sans Tagalog', - 'Noto Sans Tagbanwa', - 'Noto Sans Tai Le', - 'Noto Sans Tai Tham', - 'Noto Sans Tai Viet', - 'Noto Sans Takri', - 'Noto Sans Tamil', - 'Noto Sans Tamil Supplement', - 'Noto Sans Telugu', - 'Noto Sans Thaana', - 'Noto Sans Thai', - 'Noto Sans Tifinagh', - 'Noto Sans Tirhuta', - 'Noto Sans Ugaritic', - 'Noto Sans Vai', - 'Noto Sans Wancho', - 'Noto Sans Warang Citi', - 'Noto Sans Yi', - 'Noto Sans Zanabazar Square', -]; diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 592f364c3cbee..166f78ffac659 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -26,7 +26,6 @@ export 'engine/canvaskit/canvaskit_canvas.dart'; export 'engine/canvaskit/color_filter.dart'; export 'engine/canvaskit/embedded_views.dart'; export 'engine/canvaskit/embedded_views_diff.dart'; -export 'engine/canvaskit/font_fallback_data.dart'; export 'engine/canvaskit/font_fallbacks.dart'; export 'engine/canvaskit/fonts.dart'; export 'engine/canvaskit/image.dart'; @@ -40,7 +39,6 @@ export 'engine/canvaskit/layer_scene_builder.dart'; export 'engine/canvaskit/layer_tree.dart'; export 'engine/canvaskit/mask_filter.dart'; export 'engine/canvaskit/n_way_canvas.dart'; -export 'engine/canvaskit/noto_font.dart'; export 'engine/canvaskit/painting.dart'; export 'engine/canvaskit/path.dart'; export 'engine/canvaskit/path_metrics.dart'; diff --git a/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart b/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart deleted file mode 100644 index 41c64cf61c7c6..0000000000000 --- a/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart +++ /dev/null @@ -1,151 +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. - -// DO NOT EDIT! This file is generated. See: -// dev/generate_fallback_font_data.dart -import 'noto_font.dart'; - -final List fallbackFonts = [ - NotoFont.fromFlatRanges('Noto Sans', 'http://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNb4j5Ba_2c7A.ttf', [0x20,0x7e,0xa0,0x377,0x37a,0x37f,0x384,0x38a,0x38c,0x38c,0x38e,0x3a1,0x3a3,0x3e1,0x3f0,0x52f,0x900,0x97f,0x1ab0,0x1ac0,0x1c80,0x1c88,0x1cd0,0x1cf6,0x1cf8,0x1cf9,0x1d00,0x1df9,0x1dfb,0x1f15,0x1f18,0x1f1d,0x1f20,0x1f45,0x1f48,0x1f4d,0x1f50,0x1f57,0x1f59,0x1f59,0x1f5b,0x1f5b,0x1f5d,0x1f5d,0x1f5f,0x1f7d,0x1f80,0x1fb4,0x1fb6,0x1fc4,0x1fc6,0x1fd3,0x1fd6,0x1fdb,0x1fdd,0x1fef,0x1ff2,0x1ff4,0x1ff6,0x1ffe,0x2000,0x2064,0x2066,0x2071,0x2074,0x208e,0x2090,0x209c,0x20a0,0x20bf,0x20f0,0x20f0,0x2100,0x215f,0x2184,0x2184,0x2189,0x2189,0x2212,0x2212,0x2215,0x2215,0x25cc,0x25cc,0x2c60,0x2c7f,0x2de0,0x2e52,0xa640,0xa69f,0xa700,0xa7bf,0xa7c2,0xa7ca,0xa7f5,0xa7ff,0xa830,0xa839,0xa8e0,0xa8ff,0xa92e,0xa92e,0xab30,0xab6b,0xfb00,0xfb06,0xfe00,0xfe00,0xfe20,0xfe2f,0xfeff,0xfeff,0xfffc,0xfffd,]), - NotoFont.fromFlatRanges('Noto Emoji', 'http://fonts.gstatic.com/s/notoemoji/v26/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-r0jwvS-FGJCMY.ttf', [0x20,0x20,0x23,0x23,0x2a,0x2a,0x30,0x39,0xa9,0xa9,0xae,0xae,0x200d,0x200d,0x203c,0x203c,0x2049,0x2049,0x20e3,0x20e3,0x2122,0x2122,0x2139,0x2139,0x2194,0x2199,0x21a9,0x21aa,0x231a,0x231b,0x2328,0x2328,0x23cf,0x23cf,0x23e9,0x23f3,0x23f8,0x23fa,0x24c2,0x24c2,0x25aa,0x25ab,0x25b6,0x25b6,0x25c0,0x25c0,0x25fb,0x25fe,0x2600,0x2604,0x260e,0x260e,0x2611,0x2611,0x2614,0x2615,0x2618,0x2618,0x261d,0x261d,0x2620,0x2620,0x2622,0x2623,0x2626,0x2626,0x262a,0x262a,0x262e,0x262f,0x2638,0x263a,0x2640,0x2640,0x2642,0x2642,0x2648,0x2653,0x265f,0x2660,0x2663,0x2663,0x2665,0x2666,0x2668,0x2668,0x267b,0x267b,0x267e,0x267f,0x2692,0x2697,0x2699,0x2699,0x269b,0x269c,0x26a0,0x26a1,0x26a7,0x26a7,0x26aa,0x26ab,0x26b0,0x26b1,0x26bd,0x26be,0x26c4,0x26c5,0x26c8,0x26c8,0x26ce,0x26cf,0x26d1,0x26d1,0x26d3,0x26d4,0x26e9,0x26ea,0x26f0,0x26f5,0x26f7,0x26fa,0x26fd,0x26fd,0x2702,0x2702,0x2705,0x2705,0x2708,0x270d,0x270f,0x270f,0x2712,0x2712,0x2714,0x2714,0x2716,0x2716,0x271d,0x271d,0x2721,0x2721,0x2728,0x2728,0x2733,0x2734,0x2744,0x2744,0x2747,0x2747,0x274c,0x274c,0x274e,0x274e,0x2753,0x2755,0x2757,0x2757,0x2763,0x2764,0x2795,0x2797,0x27a1,0x27a1,0x27b0,0x27b0,0x27bf,0x27bf,0x2934,0x2935,0x2b05,0x2b07,0x2b1b,0x2b1c,0x2b50,0x2b50,0x2b55,0x2b55,0x3030,0x3030,0x303d,0x303d,0x3297,0x3297,0x3299,0x3299,0xfe0e,0xfe0f,0x1f004,0x1f004,0x1f0cf,0x1f0cf,0x1f170,0x1f171,0x1f17e,0x1f17f,0x1f18e,0x1f18e,0x1f191,0x1f19a,0x1f1e6,0x1f1ff,0x1f201,0x1f202,0x1f21a,0x1f21a,0x1f22f,0x1f22f,0x1f232,0x1f23a,0x1f250,0x1f251,0x1f300,0x1f321,0x1f324,0x1f393,0x1f396,0x1f397,0x1f399,0x1f39b,0x1f39e,0x1f3f0,0x1f3f3,0x1f3f5,0x1f3f7,0x1f4fd,0x1f4ff,0x1f53d,0x1f549,0x1f54e,0x1f550,0x1f567,0x1f56f,0x1f570,0x1f573,0x1f57a,0x1f587,0x1f587,0x1f58a,0x1f58d,0x1f590,0x1f590,0x1f595,0x1f596,0x1f5a4,0x1f5a5,0x1f5a8,0x1f5a8,0x1f5b1,0x1f5b2,0x1f5bc,0x1f5bc,0x1f5c2,0x1f5c4,0x1f5d1,0x1f5d3,0x1f5dc,0x1f5de,0x1f5e1,0x1f5e1,0x1f5e3,0x1f5e3,0x1f5e8,0x1f5e8,0x1f5ef,0x1f5ef,0x1f5f3,0x1f5f3,0x1f5fa,0x1f64f,0x1f680,0x1f6c5,0x1f6cb,0x1f6d2,0x1f6d5,0x1f6d7,0x1f6dd,0x1f6e5,0x1f6e9,0x1f6e9,0x1f6eb,0x1f6ec,0x1f6f0,0x1f6f0,0x1f6f3,0x1f6fc,0x1f7e0,0x1f7eb,0x1f7f0,0x1f7f0,0x1f90c,0x1f93a,0x1f93c,0x1f945,0x1f947,0x1f9ff,0x1fa70,0x1fa74,0x1fa78,0x1fa7c,0x1fa80,0x1fa86,0x1fa90,0x1faac,0x1fab0,0x1faba,0x1fac0,0x1fac5,0x1fad0,0x1fad9,0x1fae0,0x1fae7,0x1faf0,0x1faf6,0xe0030,0xe0039,0xe0061,0xe007a,0xe007f,0xe007f,0xfe4e5,0xfe4ee,0xfe82c,0xfe82c,0xfe82e,0xfe837,]), - NotoFont.fromFlatRanges('Noto Sans Symbols', 'http://fonts.gstatic.com/s/notosanssymbols/v34/rP2up3q65FkAtHfwd-eIS2brbDN6gxP34F9jRRCe4W3gfQ8gavVFRkzrbQ.ttf', [0x20,0x20,0x30,0x39,0x41,0x5a,0x61,0x7a,0xa0,0xa0,0x20dd,0x20e0,0x20e2,0x20e4,0x2160,0x2183,0x2185,0x2188,0x218a,0x218b,0x2190,0x2199,0x2300,0x230f,0x2311,0x2315,0x2317,0x2317,0x231c,0x231f,0x2322,0x2323,0x2329,0x232a,0x232c,0x2335,0x237c,0x237c,0x2380,0x2394,0x2396,0x239a,0x23af,0x23af,0x23be,0x23cd,0x23d0,0x23db,0x23e2,0x23e8,0x2460,0x24ff,0x25cc,0x25cc,0x260a,0x260d,0x2613,0x2613,0x2624,0x262f,0x2638,0x263b,0x263d,0x2653,0x2669,0x267e,0x2690,0x269d,0x26a2,0x26a9,0x26ad,0x26bc,0x26ce,0x26ce,0x26e2,0x26ff,0x271d,0x2721,0x2776,0x2793,0x2921,0x2922,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f190,0x1f19b,0x1f1ac,0x1f546,0x1f549,0x1f54f,0x1f54f,0x1f610,0x1f610,0x1f700,0x1f773,]), - NotoFont.fromFlatRanges('Noto Sans Symbols 2', 'http://fonts.gstatic.com/s/notosanssymbols2/v15/I_uyMoGduATTei9eI8daxVHDyfisHr71ypPqfX71-AI.ttf', [0x20,0x20,0x23,0x23,0x2a,0x2a,0x30,0x39,0x7f,0xa0,0x2022,0x2022,0x20e2,0x20e3,0x21af,0x21af,0x21e6,0x21f0,0x21f3,0x21f3,0x2218,0x2219,0x2299,0x2299,0x22c4,0x22c6,0x2316,0x2316,0x2318,0x2318,0x231a,0x231b,0x2324,0x2328,0x232b,0x232b,0x237b,0x237b,0x237d,0x237f,0x2394,0x2394,0x23ce,0x23cf,0x23e9,0x23ea,0x23ed,0x23ef,0x23f1,0x2426,0x2440,0x244a,0x25a0,0x2609,0x260e,0x2612,0x2614,0x2623,0x2630,0x2637,0x263c,0x263c,0x2654,0x2668,0x267f,0x268f,0x269e,0x26a1,0x26aa,0x26ac,0x26bd,0x26cd,0x26cf,0x26e1,0x2700,0x2704,0x2706,0x2709,0x270b,0x271c,0x2722,0x2727,0x2729,0x274b,0x274d,0x274d,0x274f,0x2753,0x2756,0x2775,0x2794,0x2794,0x2798,0x27af,0x27b1,0x27be,0x2800,0x28ff,0x2981,0x2981,0x29bf,0x29bf,0x29eb,0x29eb,0x2b00,0x2b0d,0x2b12,0x2b2f,0x2b4d,0x2b73,0x2b76,0x2b95,0x2b97,0x2bfd,0x2bff,0x2bff,0x4dc0,0x4dff,0xfff9,0xfffb,0x10140,0x1018e,0x10190,0x1019c,0x101a0,0x101a0,0x101d0,0x101fd,0x102e0,0x102fb,0x10e60,0x10e7e,0x1d2e0,0x1d2f3,0x1d300,0x1d356,0x1d360,0x1d378,0x1f000,0x1f02b,0x1f030,0x1f093,0x1f0a0,0x1f0ae,0x1f0b1,0x1f0bf,0x1f0c1,0x1f0cf,0x1f0d1,0x1f0f5,0x1f30d,0x1f30f,0x1f315,0x1f315,0x1f31c,0x1f31c,0x1f321,0x1f32c,0x1f336,0x1f336,0x1f378,0x1f378,0x1f37d,0x1f37d,0x1f393,0x1f39f,0x1f3a7,0x1f3a7,0x1f3ac,0x1f3ae,0x1f3c2,0x1f3c2,0x1f3c4,0x1f3c4,0x1f3c6,0x1f3c6,0x1f3ca,0x1f3ce,0x1f3d4,0x1f3e0,0x1f3ed,0x1f3ed,0x1f3f1,0x1f3f3,0x1f3f5,0x1f3f7,0x1f408,0x1f408,0x1f415,0x1f415,0x1f41f,0x1f41f,0x1f426,0x1f426,0x1f43f,0x1f43f,0x1f441,0x1f442,0x1f446,0x1f449,0x1f44c,0x1f44e,0x1f453,0x1f453,0x1f46a,0x1f46a,0x1f47d,0x1f47d,0x1f4a3,0x1f4a3,0x1f4b0,0x1f4b0,0x1f4b3,0x1f4b3,0x1f4b9,0x1f4b9,0x1f4bb,0x1f4bb,0x1f4bf,0x1f4bf,0x1f4c8,0x1f4cb,0x1f4da,0x1f4da,0x1f4df,0x1f4df,0x1f4e4,0x1f4e6,0x1f4ea,0x1f4ed,0x1f4f7,0x1f4f7,0x1f4f9,0x1f4fb,0x1f4fd,0x1f4fe,0x1f503,0x1f503,0x1f507,0x1f50a,0x1f50d,0x1f50d,0x1f512,0x1f513,0x1f53e,0x1f545,0x1f54a,0x1f54a,0x1f550,0x1f579,0x1f57b,0x1f594,0x1f597,0x1f5a3,0x1f5a5,0x1f5fa,0x1f650,0x1f67f,0x1f687,0x1f687,0x1f68d,0x1f68d,0x1f691,0x1f691,0x1f694,0x1f694,0x1f698,0x1f698,0x1f6ad,0x1f6ad,0x1f6b2,0x1f6b2,0x1f6b9,0x1f6ba,0x1f6bc,0x1f6bc,0x1f6c6,0x1f6cb,0x1f6cd,0x1f6cf,0x1f6d3,0x1f6d7,0x1f6e0,0x1f6ea,0x1f6f0,0x1f6f3,0x1f6f7,0x1f6fc,0x1f780,0x1f7d8,0x1f7e0,0x1f7eb,0x1f800,0x1f80b,0x1f810,0x1f847,0x1f850,0x1f859,0x1f860,0x1f887,0x1f890,0x1f8ad,0x1f8b0,0x1f8b1,0x1f93b,0x1f93b,0x1f946,0x1f946,0x1fa00,0x1fa53,0x1fa60,0x1fa6d,0x1fa70,0x1fa74,0x1fa78,0x1fa7a,0x1fa80,0x1fa86,0x1fa90,0x1faa8,0x1fab0,0x1fab6,0x1fac0,0x1fac2,0x1fad0,0x1fad6,0x1fb00,0x1fb92,0x1fb94,0x1fbca,0x1fbf0,0x1fbf9,]), - NotoFont.fromFlatRanges('Noto Sans Adlam', 'http://fonts.gstatic.com/s/notosansadlam/v19/neIczCCpqp0s5pPusPamd81eMfjPonvqdbYxxpgufnv0TGnBZLwhuvk.ttf', [0x20,0x2f,0x3a,0x40,0x5b,0x5f,0x7b,0x7d,0xa0,0xa0,0xab,0xab,0xbb,0xbb,0x61f,0x61f,0x640,0x640,0x2013,0x2015,0x2018,0x201e,0x2020,0x2022,0x2026,0x2026,0x2030,0x2030,0x2039,0x203a,0x2044,0x2044,0x204f,0x204f,0x25cc,0x25cc,0x2e28,0x2e29,0x2e41,0x2e41,0x1e900,0x1e94b,0x1e950,0x1e959,0x1e95e,0x1e95f,]), - NotoFont.fromFlatRanges('Noto Sans Anatolian Hieroglyphs', 'http://fonts.gstatic.com/s/notosansanatolianhieroglyphs/v14/ijw9s4roRME5LLRxjsRb8A0gKPSWq4BbDmHHu6j2pEtUJzZWXybIymc5QYo.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200b,0x14400,0x14646,]), - NotoFont.fromFlatRanges('Noto Sans Arabic', 'http://fonts.gstatic.com/s/notosansarabic/v18/nwpxtLGrOAZMl5nJ_wfgRg3DrWFZWsnVBJ_sS6tlqHHFlhQ5l3sQWIHPqzCfyGyvu3CBFQLaig.ttf', [0x20,0x21,0x2c,0x2e,0x30,0x3a,0xa0,0xa0,0xab,0xab,0xbb,0xbb,0x34f,0x34f,0x600,0x61c,0x61e,0x6ff,0x750,0x77f,0x8a0,0x8b4,0x8b6,0x8be,0x8d3,0x8ff,0x200b,0x2011,0x204f,0x204f,0x25cc,0x25cc,0x2e41,0x2e41,0xfb50,0xfbc1,0xfbd3,0xfd3f,0xfd50,0xfd8f,0xfd92,0xfdc7,0xfdf0,0xfdfd,0xfe70,0xfe74,0xfe76,0xfefc,]), - NotoFont.fromFlatRanges('Noto Sans Armenian', 'http://fonts.gstatic.com/s/notosansarmenian/v32/ZgN0jOZKPa7CHqq0h37c7ReDUubm2SEdFXp7ig73qtTY5idb74R9UdM3y2nZLorxb60iYy6zF3Eg.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x308,0x308,0x531,0x556,0x559,0x58a,0x58d,0x58f,0x2010,0x2010,0x25cc,0x25cc,0xfb13,0xfb17,]), - NotoFont.fromFlatRanges('Noto Sans Avestan', 'http://fonts.gstatic.com/s/notosansavestan/v17/bWti7ejKfBziStx7lIzKOLQZKhIJkyu9SASLji8U.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200c,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x2e30,0x2e31,0x10b00,0x10b35,0x10b39,0x10b3f,]), - NotoFont.fromFlatRanges('Noto Sans Balinese', 'http://fonts.gstatic.com/s/notosansbalinese/v18/NaPwcYvSBuhTirw6IaFn6UrRDaqje-lpbbRtYf-Fwu2Ov7fdhE5Vd222PPY.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1b00,0x1b4b,0x1b50,0x1b7c,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Bamum', 'http://fonts.gstatic.com/s/notosansbamum/v18/uk-0EGK3o6EruUbnwovcbBTkkklK_Ya_PBHfNGTPEddO-_gLykxEkxA.ttf', [0x20,0x20,0xa0,0xa0,0xa6a0,0xa6f7,0x16800,0x16a38,]), - NotoFont.fromFlatRanges('Noto Sans Bassa Vah', 'http://fonts.gstatic.com/s/notosansbassavah/v15/PN_sRee-r3f7LnqsD5sax12gjZn7mBpL_4c2VNUQptE.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x16ad0,0x16aed,0x16af0,0x16af5,]), - NotoFont.fromFlatRanges('Noto Sans Batak', 'http://fonts.gstatic.com/s/notosansbatak/v15/gok2H6TwAEdtF9N8-mdTCQvT-Zdgo4_PHuk74A.ttf', [0x20,0x20,0xa0,0xa0,0x1bc0,0x1bf3,0x1bfc,0x1bff,0x200b,0x200d,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Bengali', 'http://fonts.gstatic.com/s/notosansbengali/v20/Cn-SJsCGWQxOjaGwMQ6fIiMywrNJIky6nvd8BjzVMvJx2mcSPVFpVEqE-6KmsolLudCk8izI0lc.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0x980,0x983,0x985,0x98c,0x98f,0x990,0x993,0x9a8,0x9aa,0x9b0,0x9b2,0x9b2,0x9b6,0x9b9,0x9bc,0x9c4,0x9c7,0x9c8,0x9cb,0x9ce,0x9d7,0x9d7,0x9dc,0x9dd,0x9df,0x9e3,0x9e6,0x9fe,0x1cd0,0x1cd0,0x1cd2,0x1cd2,0x1cd5,0x1cd6,0x1cd8,0x1cd8,0x1ce1,0x1ce1,0x1cea,0x1cea,0x1ced,0x1ced,0x1cf2,0x1cf2,0x1cf5,0x1cf7,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa8f1,0xa8f1,]), - NotoFont.fromFlatRanges('Noto Sans Bhaiksuki', 'http://fonts.gstatic.com/s/notosansbhaiksuki/v15/UcC63EosKniBH4iELXATsSBWdvUHXxhj8rLUdU4wh9U.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200b,0x25cc,0x25cc,0x11c00,0x11c08,0x11c0a,0x11c36,0x11c38,0x11c45,0x11c50,0x11c6c,]), - NotoFont.fromFlatRanges('Noto Sans Brahmi', 'http://fonts.gstatic.com/s/notosansbrahmi/v15/vEFK2-VODB8RrNDvZSUmQQIIByV18tK1W77HtMo.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0x11000,0x1104d,0x11052,0x1106f,0x1107f,0x1107f,]), - NotoFont.fromFlatRanges('Noto Sans Buginese', 'http://fonts.gstatic.com/s/notosansbuginese/v15/esDM30ldNv-KYGGJpKGk18phe_7Da6_gtfuEXLmNtw.ttf', [0x20,0x20,0xa0,0xa0,0x1a00,0x1a1b,0x1a1e,0x1a1f,0x200b,0x200d,0x25cc,0x25cc,0xa9cf,0xa9cf,]), - NotoFont.fromFlatRanges('Noto Sans Buhid', 'http://fonts.gstatic.com/s/notosansbuhid/v17/Dxxy8jiXMW75w3OmoDXVWJD7YwzAe6tgnaFoGA.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1735,0x1736,0x1740,0x1753,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Canadian Aboriginal', 'http://fonts.gstatic.com/s/notosanscanadianaboriginal/v19/4C_TLjTuEqPj-8J01CwaGkiZ9os0iGVkezM1mUT-j_Lmlzda6uH_nnX1bzigWLn_yAsg0q0uhQ.ttf', [0x20,0x20,0xa0,0xa0,0x131,0x131,0x2c7,0x2c7,0x2d8,0x2db,0x307,0x307,0x1400,0x167f,0x18b0,0x18f5,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Carian', 'http://fonts.gstatic.com/s/notosanscarian/v15/LDIpaoiONgYwA9Yc6f0gUILeMIOgs7ob9yGLmfI.ttf', [0x20,0x20,0xa0,0xa0,0x102a0,0x102d0,]), - NotoFont.fromFlatRanges('Noto Sans Caucasian Albanian', 'http://fonts.gstatic.com/s/notosanscaucasianalbanian/v16/nKKA-HM_FYFRJvXzVXaANsU0VzsAc46QGOkWytlTs-TXrYDmoVmRSZo.ttf', [0x20,0x20,0xa0,0xa0,0x304,0x304,0x331,0x331,0x25cc,0x25cc,0xfe20,0xfe2f,0x10530,0x10563,0x1056f,0x1056f,]), - NotoFont.fromFlatRanges('Noto Sans Chakma', 'http://fonts.gstatic.com/s/notosanschakma/v15/Y4GQYbJ8VTEp4t3MKJSMjg5OIzhi4JjTQhYBeYo.ttf', [0x20,0x20,0xa0,0xa0,0x9e6,0x9ef,0x1040,0x1049,0x200c,0x200d,0x25cc,0x25cc,0x11100,0x11134,0x11136,0x11146,]), - NotoFont.fromFlatRanges('Noto Sans Cham', 'http://fonts.gstatic.com/s/notosanscham/v19/pe06MIySN5pO62Z5YkFyQb_bbuRhe6D4yip43qfcERwcv7GykboaLg.ttf', [0x20,0x22,0x27,0x29,0x2c,0x2f,0x3a,0x3b,0x3f,0x3f,0xa0,0xa0,0xad,0xad,0x200c,0x200d,0x2010,0x2010,0x25cc,0x25cc,0xaa00,0xaa36,0xaa40,0xaa4d,0xaa50,0xaa59,0xaa5c,0xaa5f,]), - NotoFont.fromFlatRanges('Noto Sans Cherokee', 'http://fonts.gstatic.com/s/notosanscherokee/v17/KFOPCm6Yu8uF-29fiz9vQF9YWK6Z8O10cHNA0cSkZCHYWi5PDkm5rAffjl0.ttf', [0x20,0x20,0xa0,0xa0,0x300,0x302,0x304,0x304,0x30b,0x30c,0x323,0x324,0x330,0x331,0x13a0,0x13f5,0x13f8,0x13fd,0xab70,0xabbf,]), - NotoFont.fromFlatRanges('Noto Sans Coptic', 'http://fonts.gstatic.com/s/notosanscoptic/v15/iJWfBWmUZi_OHPqn4wq6kgqumOEd78u_VG0xR4Y.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x300,0x302,0x304,0x305,0x307,0x308,0x323,0x323,0x33f,0x33f,0x361,0x361,0x374,0x375,0x3e2,0x3ef,0x1dcd,0x1dcd,0x2010,0x2010,0x25cc,0x25cc,0x2c80,0x2cf3,0x2cf9,0x2cff,0xfe24,0xfe26,0x102e0,0x102fb,]), - NotoFont.fromFlatRanges('Noto Sans Cuneiform', 'http://fonts.gstatic.com/s/notosanscuneiform/v15/bMrrmTWK7YY-MF22aHGGd7H8PhJtvBDWgb9JlRQueeQ.ttf', [0x20,0x20,0xa0,0xa0,0x12000,0x12399,0x12400,0x1246e,0x12470,0x12474,0x12480,0x12543,]), - NotoFont.fromFlatRanges('Noto Sans Cypriot', 'http://fonts.gstatic.com/s/notosanscypriot/v15/8AtzGta9PYqQDjyp79a6f8Cj-3a3cxIsK5MPpahF.ttf', [0x20,0x20,0xa0,0xa0,0x10800,0x10805,0x10808,0x10808,0x1080a,0x10835,0x10837,0x10838,0x1083c,0x1083c,0x1083f,0x1083f,]), - NotoFont.fromFlatRanges('Noto Sans Deseret', 'http://fonts.gstatic.com/s/notosansdeseret/v15/MwQsbgPp1eKH6QsAVuFb9AZM6MMr2Vq9ZnJSZtQG.ttf', [0x20,0x20,0xa0,0xa0,0x10400,0x1044f,]), - NotoFont.fromFlatRanges('Noto Sans Devanagari', 'http://fonts.gstatic.com/s/notosansdevanagari/v19/TuGoUUFzXI5FBtUq5a8bjKYTZjtRU6Sgv3NaV_SNmI0b8QQCQmHn6B2OHjbL_08AlXQly-AzoFoW4Ow.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x900,0x97f,0x1cd0,0x1cf6,0x1cf8,0x1cf9,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x20f0,0x20f0,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa839,0xa8e0,0xa8ff,]), - NotoFont.fromFlatRanges('Noto Sans Duployan', 'http://fonts.gstatic.com/s/notosansduployan/v16/gokzH7nwAEdtF9N8-mdTDx_X9JM5wsvrFsIn6WYDvA.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x1bc00,0x1bc6a,0x1bc70,0x1bc7c,0x1bc80,0x1bc88,0x1bc90,0x1bc99,0x1bc9c,0x1bca3,]), - NotoFont.fromFlatRanges('Noto Sans Egyptian Hieroglyphs', 'http://fonts.gstatic.com/s/notosansegyptianhieroglyphs/v26/vEF42-tODB8RrNDvZSUmRhcQHzx1s7y_F9-j3qSzEcbEYindSVK8xRg7iw.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x13000,0x1342e,]), - NotoFont.fromFlatRanges('Noto Sans Elbasan', 'http://fonts.gstatic.com/s/notosanselbasan/v15/-F6rfiZqLzI2JPCgQBnw400qp1trvHdlre4dFcFh.ttf', [0x20,0x20,0xa0,0xa0,0xb7,0xb7,0x305,0x305,0x391,0x3a1,0x3a3,0x3a9,0x3da,0x3da,0x3dc,0x3dc,0x3de,0x3de,0x25cc,0x25cc,0x10500,0x10527,]), - NotoFont.fromFlatRanges('Noto Sans Elymaic', 'http://fonts.gstatic.com/s/notosanselymaic/v15/UqyKK9YTJW5liNMhTMqe9vUFP65ZD4AjWOT0zi2V.ttf', [0x20,0x20,0xa0,0xa0,0x10fe0,0x10ff6,]), - NotoFont.fromFlatRanges('Noto Sans Georgian', 'http://fonts.gstatic.com/s/notosansgeorgian/v36/PlIaFke5O6RzLfvNNVSitxkr76PRHBC4Ytyq-Gof7PUs4S7zWn-8YDB09HFNdpvnzFj-f5WK0OQV.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x589,0x589,0x10a0,0x10c5,0x10c7,0x10c7,0x10cd,0x10cd,0x10d0,0x10ff,0x1c90,0x1cba,0x1cbd,0x1cbf,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20be,0x20be,0x2122,0x2122,0x2212,0x2212,0x2d00,0x2d25,0x2d27,0x2d27,0x2d2d,0x2d2d,]), - NotoFont.fromFlatRanges('Noto Sans Glagolitic', 'http://fonts.gstatic.com/s/notosansglagolitic/v15/1q2ZY4-BBFBst88SU_tOj4J-4yuNF_HI4ERK4Amu7nM1.ttf', [0x20,0x20,0xa0,0xa0,0x303,0x303,0x305,0x305,0x484,0x484,0x487,0x487,0x2c00,0x2c2e,0x2c30,0x2c5e,0xa66f,0xa66f,0x1e000,0x1e006,0x1e008,0x1e018,0x1e01b,0x1e021,0x1e023,0x1e024,0x1e026,0x1e02a,]), - NotoFont.fromFlatRanges('Noto Sans Gothic', 'http://fonts.gstatic.com/s/notosansgothic/v15/TuGKUUVzXI5FBtUq5a8bj6wRbzxTFMX40kFQRx0.ttf', [0x20,0x20,0xa0,0xa0,0x304,0x305,0x308,0x308,0x331,0x331,0x10330,0x1034a,]), - NotoFont.fromFlatRanges('Noto Sans Grantha', 'http://fonts.gstatic.com/s/notosansgrantha/v15/3y976akwcCjmsU8NDyrKo3IQfQ4o-r8cFeulHc6N.ttf', [0x20,0x20,0xa0,0xa0,0x951,0x952,0x964,0x965,0xbaa,0xbaa,0xbb5,0xbb5,0xbe6,0xbf2,0x1cd0,0x1cd0,0x1cd2,0x1cd3,0x1cf2,0x1cf4,0x1cf8,0x1cf9,0x200c,0x200d,0x20f0,0x20f0,0x25cc,0x25cc,0x11300,0x11303,0x11305,0x1130c,0x1130f,0x11310,0x11313,0x11328,0x1132a,0x11330,0x11332,0x11333,0x11335,0x11339,0x1133b,0x11344,0x11347,0x11348,0x1134b,0x1134d,0x11350,0x11350,0x11357,0x11357,0x1135d,0x11363,0x11366,0x1136c,0x11370,0x11374,]), - NotoFont.fromFlatRanges('Noto Sans Gujarati', 'http://fonts.gstatic.com/s/notosansgujarati/v19/wlpWgx_HC1ti5ViekvcxnhMlCVo3f5pv17ivlzsUB14gg1TMR2Gw4VceEl7MA_ypFwPM_OdiEH0s.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xa81,0xa83,0xa85,0xa8d,0xa8f,0xa91,0xa93,0xaa8,0xaaa,0xab0,0xab2,0xab3,0xab5,0xab9,0xabc,0xac5,0xac7,0xac9,0xacb,0xacd,0xad0,0xad0,0xae0,0xae3,0xae6,0xaf1,0xaf9,0xaff,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa839,]), - NotoFont.fromFlatRanges('Noto Sans Gunjala Gondi', 'http://fonts.gstatic.com/s/notosansgunjalagondi/v15/bWto7e7KfBziStx7lIzKPrcSMwcEnCv6DW7n5hcVXYMTK4q1.ttf', [0x20,0x21,0x25,0x25,0x27,0x2f,0x3a,0x3a,0x3c,0x3f,0xa0,0xa0,0xd7,0xd7,0xf7,0xf7,0x200c,0x200d,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x2212,0x2212,0x25cc,0x25cc,0x11d60,0x11d65,0x11d67,0x11d68,0x11d6a,0x11d8e,0x11d90,0x11d91,0x11d93,0x11d98,0x11da0,0x11da9,]), - NotoFont.fromFlatRanges('Noto Sans Gurmukhi', 'http://fonts.gstatic.com/s/notosansgurmukhi/v18/w8g9H3EvQP81sInb43inmyN9zZ7hb7ATbSWo4q8dJ74a3cVrYFQ_bogT0-gPeG1OenbxZ_trdp7h.ttf', [0x20,0x23,0x25,0x25,0x27,0x3f,0x5b,0x5f,0x7b,0x7e,0xa0,0xa0,0xad,0xad,0xd7,0xd7,0xf7,0xf7,0x951,0x952,0x964,0x965,0xa01,0xa03,0xa05,0xa0a,0xa0f,0xa10,0xa13,0xa28,0xa2a,0xa30,0xa32,0xa33,0xa35,0xa36,0xa38,0xa39,0xa3c,0xa3c,0xa3e,0xa42,0xa47,0xa48,0xa4b,0xa4d,0xa51,0xa51,0xa59,0xa5c,0xa5e,0xa5e,0xa66,0xa76,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x20b9,0x20b9,0x2212,0x2212,0x25cc,0x25cc,0x262c,0x262c,0xa830,0xa839,]), - NotoFont.fromFlatRanges('Noto Sans HK', 'http://fonts.gstatic.com/s/notosanshk/v21/nKKQ-GM_FYFRJvXzVXaAPe9hMnB3Eu7mOQ.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x3435,0x3435,0x3440,0x3440,0x344a,0x344a,0x344c,0x344c,0x3464,0x3464,0x3473,0x3473,0x347a,0x347a,0x347d,0x347e,0x3493,0x3493,0x3496,0x3496,0x34a5,0x34a5,0x34af,0x34af,0x34bc,0x34bc,0x34c1,0x34c1,0x34c8,0x34c8,0x34df,0x34df,0x34e4,0x34e4,0x34e6,0x34e6,0x34fb,0x34fb,0x3506,0x3506,0x353e,0x353e,0x3551,0x3551,0x3553,0x3553,0x3559,0x3559,0x3561,0x3561,0x356d,0x356d,0x3570,0x3570,0x3572,0x3572,0x3577,0x3578,0x3584,0x3584,0x3597,0x3598,0x35a1,0x35a1,0x35a5,0x35a5,0x35ad,0x35ad,0x35bf,0x35bf,0x35c1,0x35c1,0x35c5,0x35c5,0x35c7,0x35c7,0x35ca,0x35ca,0x35ce,0x35ce,0x35d2,0x35d2,0x35d6,0x35d6,0x35db,0x35db,0x35dd,0x35dd,0x35f1,0x35f3,0x35fb,0x35fb,0x35fe,0x35fe,0x3609,0x3609,0x3618,0x3618,0x361a,0x361a,0x3623,0x3623,0x3625,0x3625,0x362d,0x362d,0x3635,0x3635,0x3639,0x3639,0x363e,0x363e,0x3647,0x3649,0x364e,0x364e,0x365f,0x365f,0x3661,0x3661,0x367a,0x367a,0x3681,0x3681,0x369a,0x369a,0x36a5,0x36a5,0x36aa,0x36aa,0x36ac,0x36ac,0x36b0,0x36b1,0x36b5,0x36b5,0x36b9,0x36b9,0x36bc,0x36bc,0x36c1,0x36c1,0x36c3,0x36c5,0x36c7,0x36c8,0x36d3,0x36d4,0x36d6,0x36d6,0x36dd,0x36dd,0x36e1,0x36e2,0x36e5,0x36e6,0x36f5,0x36f5,0x3701,0x3701,0x3703,0x3703,0x3708,0x3708,0x370a,0x370a,0x370d,0x370d,0x371c,0x371c,0x3722,0x3723,0x3725,0x3725,0x372c,0x372d,0x3730,0x3730,0x3732,0x3733,0x373a,0x373a,0x3740,0x3740,0x3743,0x3743,0x3762,0x3762,0x376f,0x376f,0x3797,0x3797,0x37a0,0x37a0,0x37b9,0x37b9,0x37be,0x37be,0x37d6,0x37d6,0x37f2,0x37f2,0x37f8,0x37f8,0x37fb,0x37fb,0x380f,0x380f,0x3819,0x3819,0x3820,0x3820,0x382d,0x382d,0x3836,0x3836,0x3838,0x3838,0x3863,0x3863,0x3875,0x3875,0x38a0,0x38a0,0x38c3,0x38c3,0x38cc,0x38cc,0x38d1,0x38d1,0x38d4,0x38d4,0x38fa,0x38fa,0x3908,0x3908,0x3914,0x3914,0x3927,0x3927,0x3932,0x3932,0x393f,0x393f,0x394d,0x394d,0x3963,0x3963,0x3978,0x3978,0x3980,0x3980,0x3989,0x398a,0x3992,0x3992,0x3999,0x3999,0x399b,0x399b,0x39a1,0x39a1,0x39a4,0x39a4,0x39b8,0x39b8,0x39dc,0x39dc,0x39e2,0x39e2,0x39e5,0x39e5,0x39ec,0x39ec,0x39f8,0x39f8,0x39fb,0x39fb,0x39fe,0x39fe,0x3a01,0x3a01,0x3a03,0x3a03,0x3a06,0x3a06,0x3a17,0x3a18,0x3a29,0x3a2a,0x3a34,0x3a34,0x3a4b,0x3a4b,0x3a52,0x3a52,0x3a57,0x3a57,0x3a5c,0x3a5c,0x3a5e,0x3a5e,0x3a66,0x3a67,0x3a97,0x3a97,0x3aab,0x3aab,0x3abd,0x3abd,0x3ade,0x3ade,0x3ae0,0x3ae0,0x3af0,0x3af0,0x3af2,0x3af2,0x3af5,0x3af5,0x3afb,0x3afb,0x3b0e,0x3b0e,0x3b19,0x3b19,0x3b22,0x3b22,0x3b2b,0x3b2b,0x3b39,0x3b39,0x3b42,0x3b42,0x3b58,0x3b58,0x3b60,0x3b60,0x3b71,0x3b72,0x3b7b,0x3b7c,0x3b80,0x3b80,0x3b95,0x3b96,0x3b99,0x3b99,0x3ba1,0x3ba1,0x3bbc,0x3bbc,0x3bbe,0x3bbe,0x3bc2,0x3bc2,0x3bc4,0x3bc4,0x3bd7,0x3bd7,0x3bdd,0x3bdd,0x3bec,0x3bec,0x3bf2,0x3bf4,0x3c0d,0x3c0d,0x3c11,0x3c11,0x3c15,0x3c15,0x3c18,0x3c18,0x3c54,0x3c54,0x3c8b,0x3c8b,0x3ccb,0x3ccb,0x3ccd,0x3ccd,0x3cd1,0x3cd1,0x3cd6,0x3cd6,0x3cdc,0x3cdc,0x3ceb,0x3ceb,0x3cef,0x3cef,0x3d12,0x3d13,0x3d1d,0x3d1d,0x3d32,0x3d32,0x3d3b,0x3d3b,0x3d46,0x3d46,0x3d4c,0x3d4c,0x3d4e,0x3d4e,0x3d51,0x3d51,0x3d5f,0x3d5f,0x3d62,0x3d62,0x3d69,0x3d6a,0x3d6f,0x3d6f,0x3d75,0x3d75,0x3d7d,0x3d7d,0x3d85,0x3d85,0x3d88,0x3d88,0x3d8a,0x3d8a,0x3d8f,0x3d8f,0x3d91,0x3d91,0x3da5,0x3da5,0x3dad,0x3dad,0x3db4,0x3db4,0x3dbf,0x3dbf,0x3dc6,0x3dc7,0x3dc9,0x3dc9,0x3dcc,0x3dcd,0x3dd3,0x3dd3,0x3ddb,0x3ddb,0x3de7,0x3de8,0x3deb,0x3deb,0x3df3,0x3df4,0x3df7,0x3df7,0x3dfc,0x3dfd,0x3e06,0x3e06,0x3e40,0x3e40,0x3e43,0x3e43,0x3e48,0x3e48,0x3e55,0x3e55,0x3e74,0x3e74,0x3ea8,0x3eaa,0x3ead,0x3ead,0x3eb1,0x3eb1,0x3eb8,0x3eb8,0x3ebf,0x3ebf,0x3ec2,0x3ec2,0x3ec7,0x3ec7,0x3eca,0x3eca,0x3ecc,0x3ecc,0x3ed0,0x3ed1,0x3ed6,0x3ed7,0x3eda,0x3edb,0x3ede,0x3ede,0x3ee1,0x3ee2,0x3ee7,0x3ee7,0x3ee9,0x3ee9,0x3eeb,0x3eec,0x3ef0,0x3ef0,0x3ef3,0x3ef4,0x3efa,0x3efa,0x3efc,0x3efc,0x3eff,0x3f00,0x3f04,0x3f04,0x3f06,0x3f07,0x3f0e,0x3f0e,0x3f53,0x3f53,0x3f58,0x3f59,0x3f63,0x3f63,0x3f7c,0x3f7c,0x3f93,0x3f93,0x3fc0,0x3fc0,0x3fc8,0x3fc8,0x3fd7,0x3fd7,0x3fdc,0x3fdc,0x3fe5,0x3fe5,0x3fed,0x3fed,0x3ff9,0x3ffa,0x4004,0x4004,0x4009,0x4009,0x401d,0x401d,0x4039,0x4039,0x4045,0x4045,0x4053,0x4053,0x4057,0x4057,0x4062,0x4062,0x4065,0x4065,0x406a,0x406a,0x406f,0x406f,0x4071,0x4071,0x40a8,0x40a8,0x40b4,0x40b4,0x40bb,0x40bb,0x40bf,0x40bf,0x40c8,0x40c8,0x40d8,0x40d8,0x40df,0x40df,0x40f8,0x40f8,0x40fa,0x40fa,0x4102,0x4104,0x4109,0x4109,0x410e,0x410e,0x4131,0x4132,0x4167,0x4167,0x416c,0x416c,0x416e,0x416e,0x417c,0x417c,0x417f,0x417f,0x4181,0x4181,0x4190,0x4190,0x41b2,0x41b2,0x41c4,0x41c4,0x41ca,0x41ca,0x41cf,0x41cf,0x41db,0x41db,0x41ed,0x41ed,0x41ef,0x41ef,0x41f9,0x41f9,0x4211,0x4211,0x4223,0x4223,0x4240,0x4240,0x4260,0x4260,0x426a,0x426a,0x4276,0x4276,0x427a,0x427a,0x428c,0x428c,0x4294,0x4294,0x42a2,0x42a2,0x42b5,0x42b5,0x42b9,0x42b9,0x42bc,0x42bc,0x42f4,0x42f4,0x42fb,0x42fc,0x430a,0x430a,0x432b,0x432b,0x436e,0x436e,0x4397,0x4397,0x439a,0x439a,0x43ba,0x43ba,0x43c1,0x43c1,0x43d9,0x43d9,0x43df,0x43df,0x43ed,0x43ed,0x43f0,0x43f0,0x43f2,0x43f2,0x4401,0x4402,0x4413,0x4413,0x4425,0x4425,0x442d,0x442d,0x447a,0x447a,0x448f,0x448f,0x4491,0x4491,0x449f,0x44a0,0x44a2,0x44a2,0x44b0,0x44b0,0x44b7,0x44b7,0x44bd,0x44bd,0x44c0,0x44c0,0x44c3,0x44c3,0x44c5,0x44c5,0x44ce,0x44ce,0x44dd,0x44df,0x44e1,0x44e1,0x44e4,0x44e4,0x44e9,0x44ec,0x44f4,0x44f4,0x4503,0x4504,0x4509,0x4509,0x450b,0x450b,0x4516,0x4516,0x451b,0x451b,0x451d,0x451d,0x4527,0x4527,0x452e,0x452e,0x4533,0x4533,0x4536,0x4536,0x453b,0x453b,0x453d,0x453d,0x453f,0x453f,0x4543,0x4543,0x4551,0x4552,0x4555,0x4555,0x4558,0x4558,0x455c,0x455c,0x4561,0x4562,0x456a,0x456a,0x456d,0x456d,0x4577,0x4578,0x4585,0x4585,0x45a6,0x45a6,0x45b3,0x45b3,0x45da,0x45da,0x45e9,0x45ea,0x4603,0x4603,0x4606,0x4606,0x460f,0x460f,0x4615,0x4615,0x4617,0x4617,0x465b,0x465b,0x467a,0x467a,0x4680,0x4680,0x46a1,0x46a1,0x46ae,0x46ae,0x46bb,0x46bb,0x46cf,0x46d0,0x46f5,0x46f5,0x46f7,0x46f7,0x4713,0x4713,0x4718,0x4718,0x4736,0x4736,0x4744,0x4744,0x474e,0x474f,0x477c,0x477c,0x4798,0x4798,0x47a6,0x47a6,0x47d5,0x47d5,0x47ed,0x47ed,0x47f4,0x47f4,0x4800,0x4800,0x480b,0x480b,0x4837,0x4837,0x485d,0x485d,0x4871,0x4871,0x489b,0x489b,0x48ad,0x48ae,0x48d0,0x48d0,0x48dd,0x48dd,0x48ed,0x48ed,0x48f3,0x48f3,0x48fa,0x48fa,0x4906,0x4906,0x4911,0x4911,0x491e,0x491e,0x4925,0x4925,0x492a,0x492a,0x492d,0x492d,0x492f,0x4930,0x4935,0x4935,0x493c,0x493c,0x493e,0x493e,0x4945,0x4945,0x4951,0x4951,0x4953,0x4953,0x4965,0x4965,0x496a,0x496a,0x4972,0x4972,0x4989,0x4989,0x49a1,0x49a1,0x49a7,0x49a7,0x49df,0x49df,0x49e5,0x49e5,0x49e7,0x49e7,0x4a0f,0x4a0f,0x4a1d,0x4a1d,0x4a24,0x4a24,0x4a35,0x4a35,0x4a96,0x4a96,0x4aa4,0x4aa4,0x4ab4,0x4ab4,0x4ab8,0x4ab8,0x4ad1,0x4ad1,0x4ae4,0x4ae4,0x4aff,0x4aff,0x4b10,0x4b10,0x4b19,0x4b19,0x4b20,0x4b20,0x4b2c,0x4b2c,0x4b37,0x4b37,0x4b6f,0x4b70,0x4b72,0x4b72,0x4b7b,0x4b7b,0x4b7e,0x4b7e,0x4b8e,0x4b8e,0x4b90,0x4b90,0x4b93,0x4b93,0x4b96,0x4b97,0x4b9d,0x4b9d,0x4bbd,0x4bbe,0x4bc0,0x4bc0,0x4c04,0x4c04,0x4c07,0x4c07,0x4c0e,0x4c0e,0x4c32,0x4c32,0x4c3b,0x4c3b,0x4c3e,0x4c3e,0x4c40,0x4c40,0x4c47,0x4c47,0x4c57,0x4c57,0x4c5b,0x4c5b,0x4c6d,0x4c6d,0x4c77,0x4c77,0x4c7b,0x4c7b,0x4c7d,0x4c7d,0x4c81,0x4c81,0x4c85,0x4c85,0x4ca4,0x4ca4,0x4cae,0x4cae,0x4cb0,0x4cb0,0x4cb7,0x4cb7,0x4ccd,0x4ccd,0x4ce1,0x4ce2,0x4ced,0x4ced,0x4d07,0x4d07,0x4d09,0x4d09,0x4d10,0x4d10,0x4d34,0x4d34,0x4d76,0x4d77,0x4d89,0x4d89,0x4d91,0x4d91,0x4d9c,0x4d9c,0x4e00,0x4e01,0x4e03,0x4e04,0x4e07,0x4e11,0x4e14,0x4e16,0x4e18,0x4e1a,0x4e1c,0x4e1c,0x4e1e,0x4e1f,0x4e21,0x4e22,0x4e24,0x4e24,0x4e26,0x4e26,0x4e28,0x4e28,0x4e2a,0x4e33,0x4e36,0x4e39,0x4e3b,0x4e3d,0x4e3f,0x4e3f,0x4e42,0x4e43,0x4e45,0x4e45,0x4e47,0x4e49,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e52,0x4e53,0x4e56,0x4e56,0x4e58,0x4e5f,0x4e69,0x4e6a,0x4e73,0x4e73,0x4e78,0x4e78,0x4e7e,0x4e89,0x4e8b,0x4e8e,0x4e91,0x4e95,0x4e98,0x4e9b,0x4e9e,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eae,0x4eb3,0x4eb3,0x4eb6,0x4eb7,0x4eb9,0x4ebc,0x4ebf,0x4ec4,0x4ec6,0x4ecb,0x4ecd,0x4ece,0x4ed4,0x4eda,0x4edc,0x4edf,0x4ee1,0x4ee1,0x4ee3,0x4ee5,0x4ee8,0x4eeb,0x4eee,0x4eee,0x4ef0,0x4ef8,0x4efb,0x4efb,0x4efd,0x4efd,0x4eff,0x4f05,0x4f08,0x4f0b,0x4f0d,0x4f15,0x4f17,0x4f1a,0x4f1d,0x4f1d,0x4f22,0x4f22,0x4f28,0x4f29,0x4f2c,0x4f2d,0x4f2f,0x4f30,0x4f32,0x4f34,0x4f36,0x4f3f,0x4f41,0x4f43,0x4f45,0x4f49,0x4f4b,0x4f64,0x4f67,0x4f67,0x4f69,0x4f6c,0x4f6e,0x4f70,0x4f72,0x4f8b,0x4f8d,0x4f8d,0x4f8f,0x4f92,0x4f94,0x4f98,0x4f9a,0x4f9e,0x4fa2,0x4fa2,0x4fa8,0x4fa8,0x4fab,0x4fab,0x4fae,0x4fb0,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbd,0x4fbd,0x4fbf,0x4fc5,0x4fc7,0x4fd1,0x4fd3,0x4fd4,0x4fd6,0x4fe1,0x4fe4,0x4fe5,0x4fec,0x4fec,0x4fee,0x4ffa,0x4ffd,0x4ffe,0x5000,0x5000,0x5003,0x5003,0x5005,0x5009,0x500b,0x500f,0x5011,0x501c,0x501e,0x5023,0x5025,0x5031,0x5033,0x5035,0x5037,0x5037,0x503b,0x503c,0x5040,0x5041,0x5043,0x5043,0x5045,0x504f,0x5051,0x5051,0x5053,0x5053,0x5055,0x5058,0x505a,0x5066,0x5068,0x5070,0x5072,0x5077,0x507a,0x507a,0x507d,0x507d,0x5080,0x5083,0x5085,0x5085,0x5087,0x5088,0x508b,0x508e,0x5090,0x5092,0x5094,0x5096,0x5098,0x509e,0x50a2,0x50a3,0x50a6,0x50a6,0x50ac,0x50b8,0x50ba,0x50bf,0x50c1,0x50c2,0x50c4,0x50cb,0x50cd,0x50d1,0x50d3,0x50d7,0x50d9,0x50db,0x50dd,0x50dd,0x50df,0x50e1,0x50e3,0x50ea,0x50ec,0x50f1,0x50f3,0x50f6,0x50f8,0x50f9,0x50fb,0x510e,0x5110,0x5115,0x5117,0x5118,0x511a,0x511a,0x511c,0x511c,0x511f,0x5122,0x5124,0x5126,0x5129,0x512b,0x512d,0x512e,0x5130,0x5135,0x5137,0x513d,0x513f,0x5141,0x5143,0x5149,0x514b,0x514d,0x5151,0x5152,0x5154,0x5157,0x5159,0x5163,0x5165,0x5165,0x5167,0x516e,0x5171,0x5171,0x5174,0x5179,0x517c,0x517c,0x5180,0x5180,0x5182,0x5182,0x5186,0x518a,0x518d,0x518d,0x518f,0x518f,0x5191,0x5198,0x519a,0x519a,0x519c,0x519c,0x519e,0x519e,0x51a0,0x51a0,0x51a2,0x51a2,0x51a4,0x51a5,0x51a7,0x51a8,0x51aa,0x51ac,0x51ae,0x51ae,0x51b0,0x51b9,0x51bc,0x51be,0x51c3,0x51d4,0x51d7,0x51d8,0x51db,0x51e2,0x51e4,0x51e4,0x51ed,0x51ed,0x51f0,0x51f1,0x51f3,0x51f6,0x51f8,0x51fa,0x51fc,0x51fe,0x5200,0x5203,0x5205,0x520c,0x520e,0x520e,0x5210,0x5213,0x5216,0x5217,0x521c,0x5221,0x5224,0x522a,0x522e,0x522e,0x5230,0x5238,0x523a,0x523c,0x5241,0x5241,0x5243,0x5244,0x5246,0x5247,0x5249,0x524f,0x5252,0x5252,0x5254,0x5257,0x5259,0x5262,0x5268,0x526f,0x5272,0x5275,0x5277,0x527d,0x527f,0x5284,0x5287,0x528d,0x528f,0x5291,0x5293,0x5294,0x5296,0x529b,0x529f,0x52a1,0x52a3,0x52a4,0x52a6,0x52a6,0x52a8,0x52ae,0x52b5,0x52b5,0x52b9,0x52b9,0x52bb,0x52bc,0x52be,0x52be,0x52c0,0x52c3,0x52c5,0x52c5,0x52c7,0x52c7,0x52c9,0x52c9,0x52cc,0x52cd,0x52d0,0x52d3,0x52d5,0x52d9,0x52db,0x52db,0x52dd,0x52e4,0x52e6,0x52e6,0x52e9,0x52e9,0x52eb,0x52eb,0x52ef,0x52f1,0x52f3,0x52f5,0x52f7,0x52fc,0x52fe,0x52ff,0x5301,0x5301,0x5305,0x5306,0x5308,0x530b,0x530d,0x5312,0x5315,0x5317,0x5319,0x531a,0x531c,0x531d,0x531f,0x5324,0x5327,0x5327,0x532a,0x532a,0x532c,0x532d,0x532f,0x5334,0x5337,0x5339,0x533b,0x5345,0x5347,0x534a,0x534c,0x534e,0x5351,0x5354,0x5357,0x5357,0x535a,0x535a,0x535c,0x5361,0x5363,0x5364,0x5366,0x5367,0x5369,0x5369,0x536c,0x5375,0x5377,0x5379,0x537b,0x537f,0x5382,0x5382,0x5384,0x5384,0x538a,0x538a,0x538e,0x538f,0x5392,0x5394,0x5396,0x539a,0x539c,0x53a0,0x53a2,0x53a2,0x53a4,0x53ae,0x53b0,0x53b0,0x53b2,0x53b2,0x53b4,0x53b4,0x53b6,0x53b6,0x53b9,0x53b9,0x53bb,0x53bb,0x53c1,0x53c3,0x53c5,0x53c5,0x53c8,0x53cd,0x53d0,0x53d2,0x53d4,0x53d4,0x53d6,0x53db,0x53df,0x53e6,0x53e8,0x53f3,0x53f5,0x53f8,0x53fb,0x53fc,0x53fe,0x53fe,0x5401,0x5401,0x5403,0x5404,0x5406,0x5414,0x5416,0x5416,0x5418,0x5421,0x5423,0x5439,0x543b,0x5443,0x5445,0x5448,0x544a,0x544f,0x5454,0x5454,0x5460,0x546d,0x546f,0x5478,0x547a,0x5482,0x5484,0x5488,0x548b,0x5498,0x549a,0x549a,0x549c,0x549c,0x549e,0x549e,0x54a0,0x54b4,0x54b6,0x54c9,0x54cb,0x54d0,0x54d6,0x54d6,0x54da,0x54da,0x54de,0x54de,0x54e0,0x54eb,0x54ed,0x54ef,0x54f1,0x54f3,0x54f7,0x54f8,0x54fa,0x54fd,0x54ff,0x54ff,0x5501,0x5514,0x5517,0x5518,0x551a,0x551a,0x551e,0x551e,0x5523,0x5523,0x5525,0x5528,0x552a,0x5539,0x553b,0x553c,0x553e,0x5541,0x5543,0x554b,0x554d,0x5553,0x5555,0x5557,0x555c,0x555f,0x5561,0x5566,0x5569,0x556b,0x5571,0x5573,0x5575,0x5577,0x5579,0x5579,0x557b,0x5584,0x5586,0x5595,0x5598,0x559a,0x559c,0x559d,0x559f,0x559f,0x55a1,0x55ae,0x55b0,0x55b5,0x55b9,0x55bc,0x55bf,0x55df,0x55e1,0x55ea,0x55ec,0x55ec,0x55ee,0x55f2,0x55f5,0x55f7,0x55f9,0x5602,0x5604,0x5606,0x5608,0x5609,0x560c,0x5617,0x561b,0x5623,0x5625,0x5625,0x5627,0x5627,0x5629,0x562a,0x562c,0x5630,0x5632,0x563b,0x563d,0x5643,0x5645,0x5646,0x5648,0x564a,0x564c,0x5650,0x5652,0x5654,0x5657,0x565a,0x565d,0x565e,0x5660,0x5666,0x5668,0x5674,0x5676,0x567c,0x567e,0x5687,0x5689,0x5690,0x5692,0x5693,0x5695,0x5695,0x5697,0x569a,0x569c,0x569f,0x56a1,0x56a1,0x56a4,0x56a8,0x56aa,0x56af,0x56b1,0x56b7,0x56b9,0x56b9,0x56bc,0x56c3,0x56c5,0x56c6,0x56c8,0x56cd,0x56d1,0x56d1,0x56d3,0x56d4,0x56d6,0x56d7,0x56da,0x56db,0x56dd,0x56e2,0x56e4,0x56e5,0x56e7,0x56e7,0x56ea,0x56eb,0x56ed,0x56f1,0x56f7,0x56f7,0x56f9,0x56fb,0x56fd,0x56fd,0x56ff,0x5704,0x5707,0x570d,0x5712,0x5716,0x5718,0x5718,0x571a,0x5720,0x5722,0x5723,0x5728,0x572a,0x572c,0x5730,0x5732,0x5734,0x573b,0x573b,0x573d,0x5743,0x5745,0x5747,0x5749,0x5752,0x5754,0x5754,0x5757,0x5757,0x575b,0x575b,0x575f,0x575f,0x5761,0x5762,0x5764,0x5764,0x5766,0x576b,0x576d,0x576d,0x576f,0x5777,0x577a,0x5780,0x5782,0x5783,0x5788,0x5788,0x578a,0x578d,0x578f,0x5790,0x5793,0x5795,0x5797,0x57a5,0x57a7,0x57a7,0x57aa,0x57aa,0x57ae,0x57ae,0x57b3,0x57b6,0x57b8,0x57bf,0x57c1,0x57c4,0x57c6,0x57c8,0x57cb,0x57cc,0x57ce,0x57d0,0x57d2,0x57d2,0x57d4,0x57d5,0x57d7,0x57d7,0x57dc,0x57e7,0x57e9,0x57e9,0x57ec,0x57fe,0x5800,0x580e,0x5810,0x5810,0x5812,0x5812,0x5814,0x5814,0x5818,0x5819,0x581b,0x581e,0x5820,0x582a,0x582c,0x583b,0x583d,0x583d,0x583f,0x5840,0x5844,0x5844,0x5847,0x584f,0x5851,0x5855,0x5857,0x585f,0x5862,0x5865,0x5868,0x5869,0x586b,0x586d,0x586f,0x586f,0x5871,0x5876,0x5879,0x5883,0x5885,0x588b,0x588e,0x5894,0x5896,0x5896,0x5898,0x589a,0x589c,0x58a1,0x58a3,0x58a3,0x58a5,0x58ac,0x58ae,0x58b1,0x58b3,0x58b3,0x58b5,0x58b6,0x58ba,0x58bf,0x58c1,0x58c2,0x58c5,0x58c9,0x58cb,0x58cb,0x58ce,0x58d6,0x58d8,0x58e0,0x58e2,0x58e4,0x58e7,0x58e9,0x58eb,0x58ec,0x58ef,0x58f0,0x58f2,0x58f4,0x58f9,0x58ff,0x5902,0x5907,0x590a,0x590a,0x590c,0x590f,0x5911,0x5912,0x5914,0x5917,0x5919,0x591a,0x591c,0x591d,0x591f,0x5920,0x5922,0x5922,0x5924,0x5925,0x5927,0x5927,0x5929,0x592f,0x5931,0x5932,0x5934,0x5934,0x5937,0x5938,0x593c,0x593c,0x593e,0x593e,0x5940,0x5940,0x5944,0x5945,0x5947,0x594a,0x594e,0x5951,0x5953,0x5955,0x5957,0x5958,0x595a,0x595a,0x595c,0x595c,0x5960,0x5962,0x5965,0x5965,0x5967,0x5967,0x5969,0x596e,0x5970,0x5979,0x597b,0x5985,0x5989,0x598a,0x598d,0x5990,0x5992,0x5994,0x5996,0x599a,0x599d,0x59a8,0x59ac,0x59ac,0x59ae,0x59c1,0x59c3,0x59d4,0x59d6,0x59d6,0x59d8,0x59de,0x59e0,0x59e1,0x59e3,0x59e6,0x59e8,0x5a03,0x5a09,0x5a0d,0x5a0f,0x5a0f,0x5a11,0x5a13,0x5a15,0x5a1c,0x5a1e,0x5a21,0x5a23,0x5a25,0x5a27,0x5a27,0x5a29,0x5a2e,0x5a33,0x5a33,0x5a35,0x5a39,0x5a3c,0x5a3e,0x5a40,0x5a4a,0x5a4c,0x5a4d,0x5a50,0x5a6e,0x5a70,0x5a71,0x5a77,0x5a7f,0x5a81,0x5a84,0x5a86,0x5a86,0x5a88,0x5a88,0x5a8a,0x5a8c,0x5a8e,0x5a97,0x5a99,0x5aa2,0x5aa4,0x5aa7,0x5aa9,0x5aac,0x5aae,0x5ac4,0x5ac6,0x5acf,0x5ad1,0x5ad1,0x5ad3,0x5ad3,0x5ad5,0x5ae6,0x5ae8,0x5aee,0x5af0,0x5af0,0x5af2,0x5afb,0x5afd,0x5aff,0x5b01,0x5b03,0x5b05,0x5b05,0x5b07,0x5b09,0x5b0b,0x5b0d,0x5b0f,0x5b11,0x5b13,0x5b17,0x5b19,0x5b1b,0x5b1d,0x5b21,0x5b23,0x5b28,0x5b2a,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b38,0x5b38,0x5b3c,0x5b41,0x5b43,0x5b48,0x5b4a,0x5b51,0x5b53,0x5b58,0x5b5a,0x5b5d,0x5b5f,0x5b5f,0x5b62,0x5b66,0x5b68,0x5b69,0x5b6b,0x5b6e,0x5b70,0x5b78,0x5b7a,0x5b7d,0x5b7f,0x5b85,0x5b87,0x5b89,0x5b8b,0x5b8c,0x5b8e,0x5b90,0x5b92,0x5b93,0x5b95,0x5b9f,0x5ba2,0x5ba8,0x5baa,0x5baa,0x5bac,0x5bae,0x5bb0,0x5bb0,0x5bb3,0x5bb9,0x5bbf,0x5bc7,0x5bca,0x5bce,0x5bd0,0x5bd9,0x5bdb,0x5bdb,0x5bde,0x5bec,0x5bee,0x5bf3,0x5bf5,0x5bf6,0x5bf8,0x5bf8,0x5bfa,0x5bfa,0x5bff,0x5bff,0x5c01,0x5c01,0x5c03,0x5c05,0x5c07,0x5c16,0x5c1a,0x5c1a,0x5c1c,0x5c1c,0x5c1e,0x5c20,0x5c22,0x5c25,0x5c28,0x5c28,0x5c2a,0x5c2a,0x5c2c,0x5c2c,0x5c30,0x5c31,0x5c33,0x5c33,0x5c37,0x5c3c,0x5c3e,0x5c41,0x5c44,0x5c51,0x5c53,0x5c56,0x5c58,0x5c59,0x5c5c,0x5c5e,0x5c60,0x5c60,0x5c62,0x5c65,0x5c67,0x5c6a,0x5c6c,0x5c6f,0x5c71,0x5c71,0x5c73,0x5c74,0x5c78,0x5c7c,0x5c7e,0x5c7e,0x5c83,0x5c83,0x5c85,0x5c86,0x5c88,0x5c8d,0x5c8f,0x5c95,0x5c99,0x5c9a,0x5c9c,0x5cb1,0x5cb3,0x5cb3,0x5cb5,0x5cb8,0x5cba,0x5cba,0x5cc1,0x5cc2,0x5cc6,0x5ccc,0x5cce,0x5cdb,0x5cde,0x5cdf,0x5ce5,0x5ce5,0x5ce8,0x5cea,0x5cec,0x5cf1,0x5cf4,0x5cf9,0x5cfb,0x5cfd,0x5cff,0x5d01,0x5d06,0x5d07,0x5d0b,0x5d12,0x5d14,0x5d1b,0x5d1d,0x5d20,0x5d22,0x5d29,0x5d2c,0x5d2c,0x5d2e,0x5d3a,0x5d3c,0x5d43,0x5d45,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d52,0x5d55,0x5d57,0x5d59,0x5d59,0x5d5b,0x5d5b,0x5d5e,0x5d5e,0x5d62,0x5d63,0x5d65,0x5d65,0x5d67,0x5d69,0x5d6b,0x5d6c,0x5d6f,0x5d72,0x5d74,0x5d74,0x5d77,0x5d82,0x5d84,0x5d8b,0x5d8d,0x5d8e,0x5d92,0x5d95,0x5d97,0x5d97,0x5d99,0x5d9a,0x5d9c,0x5da2,0x5da4,0x5da4,0x5da7,0x5db2,0x5db4,0x5dba,0x5dbc,0x5dbd,0x5dc0,0x5dc3,0x5dc6,0x5dc7,0x5dc9,0x5dc9,0x5dcb,0x5dcb,0x5dcd,0x5dcd,0x5dcf,0x5dcf,0x5dd1,0x5dd2,0x5dd4,0x5dd8,0x5ddb,0x5ddb,0x5ddd,0x5de2,0x5de5,0x5de8,0x5deb,0x5deb,0x5dee,0x5dee,0x5df0,0x5df5,0x5df7,0x5df7,0x5df9,0x5df9,0x5dfd,0x5dff,0x5e02,0x5e04,0x5e06,0x5e06,0x5e09,0x5e0c,0x5e0e,0x5e0e,0x5e11,0x5e12,0x5e14,0x5e1b,0x5e1d,0x5e1d,0x5e1f,0x5e25,0x5e28,0x5e29,0x5e2b,0x5e2b,0x5e2d,0x5e2e,0x5e33,0x5e34,0x5e36,0x5e38,0x5e3d,0x5e3e,0x5e40,0x5e45,0x5e48,0x5e48,0x5e4a,0x5e4f,0x5e53,0x5e55,0x5e57,0x5e59,0x5e5b,0x5e63,0x5e66,0x5e70,0x5e72,0x5e76,0x5e78,0x5e80,0x5e82,0x5e84,0x5e86,0x5e8d,0x5e8f,0x5e8f,0x5e92,0x5e92,0x5e95,0x5e97,0x5e99,0x5e9c,0x5ea0,0x5ea0,0x5ea2,0x5ea8,0x5eaa,0x5eae,0x5eb0,0x5eb9,0x5ebd,0x5ebe,0x5ec1,0x5ec2,0x5ec4,0x5ece,0x5ed0,0x5ee3,0x5ee5,0x5ee9,0x5eec,0x5eec,0x5eee,0x5eef,0x5ef1,0x5ef4,0x5ef6,0x5efc,0x5efe,0x5eff,0x5f01,0x5f02,0x5f04,0x5f05,0x5f07,0x5f08,0x5f0a,0x5f0f,0x5f12,0x5f15,0x5f17,0x5f18,0x5f1a,0x5f1b,0x5f1d,0x5f1d,0x5f1f,0x5f1f,0x5f22,0x5f29,0x5f2d,0x5f2e,0x5f30,0x5f31,0x5f33,0x5f33,0x5f35,0x5f38,0x5f3a,0x5f3c,0x5f40,0x5f40,0x5f43,0x5f46,0x5f48,0x5f51,0x5f54,0x5f54,0x5f56,0x5f59,0x5f5c,0x5f5e,0x5f61,0x5f65,0x5f67,0x5f67,0x5f69,0x5f6d,0x5f6f,0x5f74,0x5f76,0x5f79,0x5f7b,0x5f83,0x5f85,0x5f8c,0x5f90,0x5f92,0x5f96,0x5f99,0x5f9b,0x5f9c,0x5f9e,0x5fa1,0x5fa4,0x5faf,0x5fb1,0x5fb2,0x5fb5,0x5fb7,0x5fb9,0x5fc5,0x5fc9,0x5fc9,0x5fcc,0x5fcd,0x5fcf,0x5fd2,0x5fd4,0x5fd9,0x5fdb,0x5fdb,0x5fdd,0x5fe1,0x5fe3,0x5fe5,0x5fe8,0x5fe8,0x5fea,0x5feb,0x5fed,0x5fef,0x5ff1,0x5ff1,0x5ff3,0x5ff5,0x5ff7,0x5ff8,0x5ffa,0x5ffb,0x5ffd,0x5ffd,0x5fff,0x6000,0x6009,0x6017,0x6019,0x601e,0x6020,0x602f,0x6031,0x6035,0x6037,0x6037,0x6039,0x6039,0x603b,0x603b,0x6040,0x6047,0x6049,0x604d,0x6050,0x6050,0x6052,0x6055,0x6058,0x605b,0x605d,0x605f,0x6062,0x6070,0x6072,0x6072,0x6075,0x6075,0x6077,0x6077,0x607e,0x6081,0x6083,0x608a,0x608c,0x608e,0x6090,0x6090,0x6092,0x6092,0x6094,0x6097,0x609a,0x60a0,0x60a2,0x60a4,0x60a6,0x60a8,0x60b0,0x60c1,0x60c3,0x60cf,0x60d1,0x60d1,0x60d3,0x60d5,0x60d7,0x60e4,0x60e6,0x60e9,0x60f0,0x6101,0x6103,0x6110,0x6112,0x6116,0x6118,0x611d,0x611f,0x6120,0x6122,0x6123,0x6127,0x6129,0x612b,0x612c,0x612e,0x6130,0x6132,0x6132,0x6134,0x6134,0x6136,0x6137,0x613b,0x613b,0x613d,0x6142,0x6144,0x6150,0x6152,0x6156,0x6158,0x6168,0x616a,0x616c,0x616e,0x6177,0x6179,0x617a,0x617c,0x617e,0x6180,0x6183,0x6187,0x6187,0x6189,0x618e,0x6190,0x6196,0x6198,0x619d,0x619f,0x619f,0x61a1,0x61a2,0x61a4,0x61a4,0x61a7,0x61ba,0x61bc,0x61bc,0x61be,0x61c3,0x61c5,0x61cd,0x61cf,0x61d0,0x61d3,0x61d3,0x61d6,0x61d6,0x61d8,0x61d8,0x61da,0x61da,0x61de,0x61e0,0x61e2,0x61eb,0x61ed,0x61ee,0x61f0,0x61f2,0x61f5,0x6201,0x6203,0x6204,0x6207,0x620a,0x620c,0x620e,0x6210,0x6212,0x6214,0x6216,0x6219,0x621b,0x621f,0x6225,0x6227,0x6227,0x6229,0x622e,0x6230,0x6230,0x6232,0x6234,0x6236,0x6237,0x6239,0x623a,0x623d,0x6243,0x6246,0x624e,0x6250,0x6254,0x6258,0x625c,0x625e,0x625e,0x6260,0x6266,0x6268,0x6268,0x626d,0x6274,0x6276,0x6277,0x6279,0x628a,0x628c,0x628c,0x628e,0x6298,0x629d,0x629d,0x62a4,0x62a4,0x62a6,0x62a6,0x62a8,0x62b1,0x62b3,0x62b6,0x62b8,0x62b9,0x62bb,0x62bf,0x62c1,0x62dc,0x62df,0x62df,0x62e5,0x62e5,0x62eb,0x6303,0x6307,0x6309,0x630b,0x6311,0x6313,0x6316,0x6318,0x6318,0x6328,0x632f,0x6331,0x633e,0x6340,0x6351,0x6354,0x635a,0x635d,0x635d,0x6364,0x6365,0x6367,0x6369,0x636b,0x6372,0x6375,0x637d,0x637f,0x6385,0x6387,0x6392,0x6394,0x6394,0x6396,0x6399,0x639b,0x63a5,0x63a7,0x63b1,0x63b9,0x63b9,0x63bd,0x63be,0x63c0,0x63d3,0x63d5,0x63eb,0x63ed,0x63f6,0x63f8,0x63f9,0x63fb,0x63fc,0x63fe,0x63fe,0x6406,0x6407,0x6409,0x6410,0x6412,0x6418,0x641a,0x641c,0x641e,0x6428,0x642a,0x6430,0x6432,0x643b,0x643d,0x6441,0x6443,0x6443,0x644b,0x644b,0x644d,0x644e,0x6450,0x6454,0x6458,0x6461,0x6465,0x6469,0x646b,0x647d,0x647f,0x647f,0x6482,0x6482,0x6485,0x6485,0x6487,0x648d,0x648f,0x6493,0x6495,0x649a,0x649c,0x64a0,0x64a2,0x64a6,0x64a9,0x64a9,0x64ab,0x64b4,0x64b6,0x64b6,0x64bb,0x64c5,0x64c7,0x64c7,0x64c9,0x64cb,0x64cd,0x64d0,0x64d2,0x64d4,0x64d6,0x64db,0x64dd,0x64dd,0x64e0,0x64ed,0x64ef,0x64f4,0x64f7,0x64f8,0x64fa,0x6501,0x6503,0x6504,0x6506,0x6507,0x6509,0x650a,0x650c,0x6511,0x6513,0x6519,0x651b,0x6526,0x6529,0x6530,0x6532,0x6539,0x653b,0x653b,0x653d,0x653f,0x6541,0x6541,0x6543,0x6543,0x6545,0x6546,0x6548,0x654a,0x654d,0x654d,0x654f,0x654f,0x6551,0x6551,0x6553,0x655a,0x655c,0x655f,0x6562,0x6568,0x656a,0x656d,0x656f,0x656f,0x6572,0x657c,0x657f,0x6589,0x658b,0x658c,0x6590,0x6592,0x6594,0x6597,0x6599,0x6599,0x659b,0x65a2,0x65a4,0x65a5,0x65a7,0x65a8,0x65aa,0x65ac,0x65ae,0x65b0,0x65b2,0x65b3,0x65b5,0x65b9,0x65bb,0x65bf,0x65c1,0x65c6,0x65cb,0x65d4,0x65d6,0x65d7,0x65da,0x65db,0x65dd,0x65e3,0x65e5,0x65e6,0x65e8,0x65e9,0x65ec,0x65f5,0x65fa,0x65fd,0x65ff,0x6600,0x6602,0x6615,0x6618,0x6618,0x661c,0x6628,0x662b,0x662b,0x662d,0x6636,0x6639,0x663a,0x6641,0x6645,0x6647,0x664d,0x664f,0x664f,0x6651,0x6653,0x6657,0x6657,0x6659,0x6668,0x666a,0x666c,0x666e,0x6674,0x6676,0x667e,0x6680,0x6680,0x6684,0x668e,0x6690,0x6692,0x6694,0x669a,0x669d,0x669d,0x669f,0x66a2,0x66a4,0x66a4,0x66a8,0x66ab,0x66ad,0x66bb,0x66bd,0x66c0,0x66c4,0x66c4,0x66c6,0x66cf,0x66d2,0x66d2,0x66d6,0x66d6,0x66d8,0x66de,0x66e0,0x66e0,0x66e3,0x66e4,0x66e6,0x66e9,0x66eb,0x66ee,0x66f0,0x66f4,0x66f6,0x66f9,0x66fc,0x66fc,0x66fe,0x6705,0x6708,0x6710,0x6712,0x6719,0x671b,0x671b,0x671d,0x6723,0x6725,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6736,0x6738,0x673f,0x6744,0x6749,0x674b,0x6751,0x6753,0x6753,0x6755,0x6757,0x6759,0x675a,0x675c,0x6762,0x6767,0x6767,0x676a,0x677f,0x6781,0x6787,0x6789,0x6789,0x678b,0x6795,0x6797,0x679a,0x679c,0x679d,0x679f,0x67a0,0x67a4,0x67a4,0x67ac,0x67ac,0x67ae,0x67bb,0x67bf,0x67c6,0x67c8,0x67d4,0x67d6,0x67df,0x67e2,0x67e7,0x67e9,0x67fa,0x67fc,0x67fc,0x67fe,0x6804,0x680d,0x680d,0x6810,0x6810,0x6812,0x6814,0x6816,0x6818,0x681a,0x6822,0x6825,0x6826,0x6828,0x682b,0x682d,0x682f,0x6831,0x683e,0x6840,0x6851,0x6853,0x6856,0x685d,0x685d,0x6865,0x6865,0x686b,0x686b,0x686d,0x686f,0x6871,0x6872,0x6874,0x6879,0x687b,0x688c,0x688f,0x6894,0x6896,0x6898,0x689b,0x689d,0x689f,0x68a4,0x68a6,0x68b6,0x68b9,0x68b9,0x68bd,0x68bd,0x68c1,0x68c1,0x68c3,0x68ce,0x68d0,0x68d8,0x68da,0x68da,0x68dc,0x68e1,0x68e3,0x68e4,0x68e6,0x68ec,0x68ee,0x68fd,0x6900,0x6915,0x6917,0x691b,0x6925,0x6925,0x692a,0x692a,0x692c,0x692c,0x692f,0x6930,0x6932,0x6939,0x693b,0x6946,0x6948,0x694c,0x694e,0x694f,0x6951,0x697b,0x6980,0x6980,0x6982,0x6983,0x6985,0x6986,0x698a,0x698a,0x698d,0x698e,0x6990,0x6991,0x6993,0x699c,0x699e,0x69b7,0x69b9,0x69b9,0x69bb,0x69c4,0x69c6,0x69c6,0x69c9,0x69d1,0x69d3,0x69d6,0x69d9,0x69d9,0x69e1,0x69e2,0x69e4,0x69e9,0x69eb,0x69ee,0x69f1,0x69f4,0x69f6,0x6a0d,0x6a0f,0x6a0f,0x6a11,0x6a11,0x6a13,0x6a21,0x6a23,0x6a23,0x6a25,0x6a29,0x6a2b,0x6a2d,0x6a32,0x6a35,0x6a38,0x6a41,0x6a43,0x6a49,0x6a4b,0x6a5b,0x6a5d,0x6a6b,0x6a6d,0x6a6d,0x6a6f,0x6a6f,0x6a71,0x6a71,0x6a74,0x6a74,0x6a76,0x6a76,0x6a7a,0x6a7a,0x6a7e,0x6a85,0x6a87,0x6a87,0x6a89,0x6a8a,0x6a8c,0x6a97,0x6a99,0x6aa8,0x6aab,0x6aaf,0x6ab1,0x6abb,0x6abd,0x6abe,0x6ac2,0x6ac3,0x6ac5,0x6acd,0x6acf,0x6ad1,0x6ad3,0x6ad4,0x6ad8,0x6ae1,0x6ae5,0x6ae5,0x6ae7,0x6ae8,0x6aea,0x6aec,0x6aee,0x6af1,0x6af3,0x6af3,0x6af6,0x6af6,0x6af8,0x6afc,0x6b00,0x6b00,0x6b02,0x6b05,0x6b08,0x6b0b,0x6b0f,0x6b13,0x6b16,0x6b1a,0x6b1d,0x6b1e,0x6b20,0x6b21,0x6b23,0x6b23,0x6b25,0x6b25,0x6b28,0x6b28,0x6b2c,0x6b2d,0x6b2f,0x6b2f,0x6b31,0x6b3f,0x6b41,0x6b43,0x6b45,0x6b4e,0x6b50,0x6b52,0x6b54,0x6b57,0x6b59,0x6b59,0x6b5b,0x6b5c,0x6b5e,0x6b67,0x6b6a,0x6b6a,0x6b6d,0x6b6d,0x6b6f,0x6b6f,0x6b72,0x6b72,0x6b74,0x6b74,0x6b76,0x6b7b,0x6b7e,0x6b84,0x6b86,0x6b86,0x6b88,0x6b8a,0x6b8c,0x6b8f,0x6b91,0x6b91,0x6b94,0x6b99,0x6b9b,0x6b9b,0x6b9e,0x6ba0,0x6ba2,0x6ba7,0x6baa,0x6bab,0x6bad,0x6bb0,0x6bb2,0x6bb3,0x6bb5,0x6bb7,0x6bba,0x6bba,0x6bbc,0x6bbd,0x6bbf,0x6bc1,0x6bc3,0x6bcd,0x6bcf,0x6bd0,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdc,0x6bde,0x6bde,0x6be0,0x6be4,0x6be6,0x6be8,0x6bea,0x6bec,0x6bef,0x6bf0,0x6bf2,0x6bf3,0x6bf7,0x6c06,0x6c08,0x6c09,0x6c0b,0x6c0d,0x6c0f,0x6c11,0x6c13,0x6c16,0x6c18,0x6c1d,0x6c1f,0x6c21,0x6c23,0x6c28,0x6c2a,0x6c2c,0x6c2e,0x6c3b,0x6c3d,0x6c43,0x6c46,0x6c46,0x6c49,0x6c50,0x6c52,0x6c52,0x6c54,0x6c55,0x6c57,0x6c61,0x6c65,0x6c6b,0x6c6d,0x6c76,0x6c78,0x6c7b,0x6c7d,0x6c90,0x6c92,0x6c96,0x6c98,0x6c9d,0x6c9f,0x6c9f,0x6ca2,0x6ca2,0x6caa,0x6cb4,0x6cb6,0x6cc7,0x6cc9,0x6cd7,0x6cd9,0x6ce3,0x6ce5,0x6ce5,0x6ce7,0x6cf3,0x6cf5,0x6cf5,0x6cf9,0x6cf9,0x6cff,0x6d12,0x6d16,0x6d1b,0x6d1d,0x6d20,0x6d22,0x6d22,0x6d24,0x6d42,0x6d4e,0x6d4e,0x6d57,0x6d5c,0x6d5e,0x6d6a,0x6d6c,0x6d72,0x6d74,0x6d98,0x6d9a,0x6d9a,0x6da4,0x6da5,0x6daa,0x6dac,0x6dae,0x6daf,0x6db1,0x6db5,0x6db7,0x6dc0,0x6dc2,0x6dc2,0x6dc4,0x6dcd,0x6dcf,0x6de6,0x6de8,0x6df7,0x6df9,0x6dfe,0x6e00,0x6e00,0x6e02,0x6e05,0x6e0a,0x6e0a,0x6e0f,0x6e0f,0x6e15,0x6e15,0x6e18,0x6e1d,0x6e1f,0x6e36,0x6e38,0x6e41,0x6e43,0x6e47,0x6e49,0x6e4b,0x6e4d,0x6e69,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e71,0x6e74,0x6e76,0x6e79,0x6e7c,0x6e7c,0x6e86,0x6e86,0x6e88,0x6e89,0x6e8b,0x6e8b,0x6e8d,0x6e90,0x6e92,0x6e94,0x6e96,0x6ea7,0x6eaa,0x6eab,0x6eae,0x6ed6,0x6ed8,0x6edd,0x6ee2,0x6ee2,0x6ee8,0x6ee9,0x6eeb,0x6eef,0x6ef1,0x6ef2,0x6ef4,0x6f0f,0x6f12,0x6f1a,0x6f1c,0x6f1c,0x6f1e,0x6f27,0x6f29,0x6f41,0x6f43,0x6f44,0x6f4e,0x6f58,0x6f5a,0x6f64,0x6f66,0x6f67,0x6f69,0x6f70,0x6f72,0x6f74,0x6f76,0x6f82,0x6f84,0x6f8e,0x6f90,0x6f90,0x6f92,0x6f97,0x6f9d,0x6fb6,0x6fb8,0x6fc4,0x6fc6,0x6fcf,0x6fd3,0x6fd5,0x6fd8,0x6fe4,0x6fe6,0x6fe9,0x6feb,0x6ff2,0x6ff4,0x6ff4,0x6ff6,0x6ff8,0x6ffa,0x6ffc,0x6ffe,0x7001,0x7003,0x7007,0x7009,0x700f,0x7011,0x7011,0x7014,0x7024,0x7026,0x702c,0x702f,0x7035,0x7037,0x703c,0x703e,0x7046,0x7048,0x704d,0x7050,0x7052,0x7054,0x7058,0x705a,0x706c,0x706e,0x7071,0x7074,0x707a,0x707c,0x707f,0x7081,0x7086,0x7089,0x708b,0x708e,0x708f,0x7091,0x7096,0x7098,0x709a,0x709f,0x70a1,0x70a3,0x70a7,0x70a9,0x70a9,0x70ab,0x70b1,0x70b3,0x70b5,0x70b7,0x70be,0x70c0,0x70c0,0x70c4,0x70c8,0x70ca,0x70da,0x70dc,0x70e2,0x70e4,0x70e4,0x70ef,0x70f1,0x70f3,0x7100,0x7102,0x7102,0x7104,0x7106,0x7109,0x710e,0x7110,0x7110,0x7113,0x7113,0x7117,0x7117,0x7119,0x7123,0x7125,0x7126,0x7128,0x7129,0x712b,0x712c,0x712e,0x7136,0x713a,0x713b,0x713e,0x713e,0x7140,0x7147,0x7149,0x7154,0x7156,0x715a,0x715c,0x716c,0x716e,0x716e,0x7170,0x7178,0x717a,0x717e,0x7180,0x7182,0x7184,0x718a,0x718c,0x718c,0x718e,0x7192,0x7194,0x7194,0x7196,0x71a5,0x71a7,0x71aa,0x71ac,0x71ad,0x71af,0x71b5,0x71b7,0x71ba,0x71bc,0x71cb,0x71ce,0x71d2,0x71d4,0x71d6,0x71d8,0x71dd,0x71df,0x71e2,0x71e4,0x71e8,0x71eb,0x71ee,0x71f0,0x71f2,0x71f4,0x71f6,0x71f8,0x71f9,0x71fb,0x7203,0x7205,0x7207,0x7209,0x720a,0x720c,0x7210,0x7213,0x7217,0x7219,0x721b,0x721d,0x721f,0x7222,0x722e,0x7230,0x7230,0x7235,0x7236,0x7238,0x723b,0x723d,0x7242,0x7244,0x7244,0x7246,0x724c,0x724f,0x7250,0x7252,0x7253,0x7255,0x7263,0x7266,0x7267,0x7269,0x726a,0x726c,0x726c,0x726e,0x7270,0x7272,0x7274,0x7276,0x7279,0x727b,0x7282,0x7284,0x7289,0x728b,0x7298,0x729a,0x729b,0x729d,0x729f,0x72a1,0x72aa,0x72ac,0x72b0,0x72b2,0x72b2,0x72b4,0x72b5,0x72ba,0x72ba,0x72bd,0x72bd,0x72bf,0x72c6,0x72c9,0x72ce,0x72d0,0x72d2,0x72d4,0x72d4,0x72d6,0x72da,0x72dc,0x72dc,0x72df,0x72e4,0x72e6,0x72e6,0x72e8,0x72eb,0x72f3,0x72f4,0x72f6,0x7302,0x7304,0x7304,0x7307,0x7308,0x730a,0x730c,0x730f,0x7313,0x7316,0x7319,0x731b,0x731e,0x7322,0x7323,0x7325,0x732e,0x7330,0x733c,0x733e,0x7345,0x7348,0x734a,0x734c,0x7352,0x7357,0x735b,0x735d,0x7362,0x7365,0x736c,0x736e,0x7378,0x737a,0x738c,0x738e,0x738f,0x7392,0x7398,0x739c,0x73a2,0x73a4,0x73ad,0x73b2,0x73bc,0x73be,0x73c0,0x73c2,0x73d0,0x73d2,0x73de,0x73e0,0x73eb,0x73ed,0x73ef,0x73f3,0x740d,0x7411,0x7412,0x7414,0x7417,0x7419,0x7426,0x7428,0x743a,0x743c,0x743c,0x743f,0x7457,0x7459,0x7465,0x7467,0x7476,0x7479,0x747a,0x747c,0x7483,0x7485,0x748d,0x7490,0x7490,0x7492,0x7492,0x7494,0x7495,0x7497,0x74a1,0x74a3,0x74ab,0x74ad,0x74ad,0x74af,0x74b2,0x74b4,0x74bb,0x74bd,0x74c3,0x74c5,0x74c6,0x74c8,0x74c8,0x74ca,0x74cc,0x74cf,0x74d0,0x74d3,0x74e9,0x74ec,0x74ec,0x74ee,0x74ee,0x74f0,0x74f2,0x74f4,0x74f8,0x74fb,0x74fb,0x74fd,0x7500,0x7502,0x7505,0x7507,0x7508,0x750b,0x751a,0x751c,0x751f,0x7521,0x7522,0x7525,0x7526,0x7528,0x7535,0x7537,0x753b,0x753d,0x7540,0x7542,0x7542,0x7546,0x7548,0x754a,0x754f,0x7551,0x7551,0x7553,0x7555,0x7559,0x755d,0x755f,0x7560,0x7562,0x7567,0x756a,0x7570,0x7572,0x7572,0x7576,0x757a,0x757d,0x7580,0x7583,0x7584,0x7586,0x7587,0x758a,0x7592,0x7594,0x7595,0x7598,0x759a,0x759d,0x759e,0x75a2,0x75a5,0x75a7,0x75a7,0x75aa,0x75ab,0x75b0,0x75b6,0x75b8,0x75c5,0x75c7,0x75c8,0x75ca,0x75d2,0x75d4,0x75d5,0x75d7,0x75e4,0x75e6,0x75e7,0x75ed,0x75ed,0x75ef,0x7603,0x7607,0x760d,0x760f,0x7611,0x7613,0x7616,0x7619,0x7629,0x762c,0x762d,0x762f,0x7635,0x7638,0x7638,0x763a,0x763d,0x7640,0x7640,0x7642,0x7643,0x7646,0x7649,0x764c,0x7654,0x7656,0x765a,0x765c,0x765c,0x765f,0x7662,0x7664,0x7667,0x7669,0x766a,0x766c,0x7676,0x7678,0x767f,0x7681,0x7682,0x7684,0x7684,0x7686,0x768b,0x768e,0x7690,0x7692,0x7693,0x7695,0x7696,0x7699,0x769e,0x76a1,0x76a1,0x76a4,0x76a6,0x76aa,0x76ab,0x76ad,0x76b0,0x76b4,0x76b5,0x76b7,0x76b8,0x76ba,0x76bb,0x76bd,0x76bf,0x76c2,0x76c6,0x76c8,0x76ca,0x76cc,0x76ce,0x76d2,0x76d4,0x76d6,0x76d6,0x76d9,0x76df,0x76e1,0x76e1,0x76e3,0x76e7,0x76e9,0x76ea,0x76ec,0x76f5,0x76f7,0x76fc,0x76fe,0x76fe,0x7701,0x7701,0x7703,0x7705,0x7707,0x770c,0x770e,0x7713,0x7715,0x7715,0x7719,0x771b,0x771d,0x7720,0x7722,0x7729,0x772b,0x772b,0x772d,0x772d,0x772f,0x772f,0x7731,0x773e,0x7740,0x7740,0x7743,0x7747,0x774a,0x774f,0x7752,0x7752,0x7754,0x7756,0x7758,0x775c,0x775e,0x7763,0x7765,0x776f,0x7772,0x7772,0x7777,0x7785,0x7787,0x7789,0x778b,0x778f,0x7791,0x7791,0x7793,0x7793,0x7795,0x7795,0x7797,0x77a3,0x77a5,0x77a5,0x77a7,0x77a8,0x77aa,0x77ad,0x77af,0x77b7,0x77b9,0x77bf,0x77c2,0x77c5,0x77c7,0x77c7,0x77c9,0x77d0,0x77d3,0x77d5,0x77d7,0x77de,0x77e0,0x77e0,0x77e2,0x77e3,0x77e5,0x77e9,0x77ec,0x77f4,0x77f7,0x77fe,0x7802,0x7803,0x7805,0x7806,0x7808,0x7809,0x780c,0x7814,0x7818,0x7818,0x781c,0x7823,0x7825,0x7835,0x7837,0x7839,0x783c,0x783d,0x7842,0x7845,0x7847,0x784e,0x7850,0x7854,0x785c,0x785e,0x7860,0x7860,0x7862,0x7862,0x7864,0x7866,0x7868,0x7871,0x7879,0x787c,0x787e,0x7881,0x7883,0x7889,0x788c,0x788f,0x7891,0x7891,0x7893,0x789a,0x789e,0x78a5,0x78a7,0x78ad,0x78af,0x78b4,0x78b6,0x78b6,0x78b8,0x78bc,0x78be,0x78be,0x78c1,0x78c1,0x78c3,0x78c5,0x78c7,0x78d5,0x78d7,0x78d8,0x78da,0x78db,0x78dd,0x78e5,0x78e7,0x78ea,0x78ec,0x78f5,0x78f7,0x78f7,0x78f9,0x78ff,0x7901,0x7902,0x7904,0x7906,0x7909,0x7909,0x790c,0x790c,0x790e,0x790e,0x7910,0x7914,0x7917,0x7917,0x7919,0x7919,0x791b,0x791e,0x7921,0x7921,0x7923,0x792f,0x7931,0x7936,0x7938,0x7942,0x7944,0x794c,0x794f,0x7965,0x7967,0x796b,0x796d,0x796d,0x7970,0x7974,0x7979,0x797a,0x797c,0x7983,0x7986,0x7988,0x798a,0x798b,0x798d,0x799d,0x799f,0x79a2,0x79a4,0x79ae,0x79b0,0x79b4,0x79b6,0x79bb,0x79bd,0x79c1,0x79c4,0x79c6,0x79c8,0x79d2,0x79d4,0x79d6,0x79d8,0x79d8,0x79dc,0x79e0,0x79e2,0x79e4,0x79e6,0x79e7,0x79e9,0x79ee,0x79f1,0x79f1,0x79f4,0x79f4,0x79f6,0x79f8,0x79fa,0x79fb,0x7a00,0x7a00,0x7a02,0x7a06,0x7a08,0x7a08,0x7a0a,0x7a0e,0x7a10,0x7a15,0x7a17,0x7a1c,0x7a1e,0x7a20,0x7a22,0x7a22,0x7a26,0x7a26,0x7a28,0x7a28,0x7a2a,0x7a32,0x7a37,0x7a37,0x7a39,0x7a40,0x7a43,0x7a4e,0x7a54,0x7a54,0x7a56,0x7a58,0x7a5a,0x7a5c,0x7a5f,0x7a62,0x7a65,0x7a65,0x7a67,0x7a69,0x7a6b,0x7a6e,0x7a70,0x7a72,0x7a74,0x7a76,0x7a78,0x7a7b,0x7a7d,0x7a81,0x7a83,0x7a8c,0x7a8f,0x7a99,0x7a9e,0x7aa0,0x7aa2,0x7aa3,0x7aa8,0x7aac,0x7aae,0x7ab8,0x7aba,0x7abc,0x7abe,0x7ac5,0x7ac7,0x7acb,0x7acf,0x7acf,0x7ad1,0x7ad1,0x7ad3,0x7ad3,0x7ad8,0x7add,0x7adf,0x7ae0,0x7ae2,0x7ae7,0x7ae9,0x7aeb,0x7aed,0x7aef,0x7af6,0x7af7,0x7af9,0x7b01,0x7b04,0x7b06,0x7b08,0x7b0c,0x7b0e,0x7b14,0x7b18,0x7b1b,0x7b1d,0x7b20,0x7b22,0x7b35,0x7b38,0x7b39,0x7b3b,0x7b3b,0x7b40,0x7b40,0x7b42,0x7b52,0x7b54,0x7b56,0x7b58,0x7b58,0x7b60,0x7b67,0x7b69,0x7b69,0x7b6c,0x7b78,0x7b7b,0x7b7b,0x7b82,0x7b82,0x7b84,0x7b85,0x7b87,0x7b88,0x7b8a,0x7b92,0x7b94,0x7b9d,0x7ba0,0x7ba4,0x7bac,0x7baf,0x7bb1,0x7bb2,0x7bb4,0x7bb5,0x7bb7,0x7bb9,0x7bbe,0x7bbe,0x7bc0,0x7bc1,0x7bc4,0x7bc7,0x7bc9,0x7bcc,0x7bce,0x7bd0,0x7bd4,0x7bd5,0x7bd8,0x7bec,0x7bf0,0x7bf4,0x7bf7,0x7c03,0x7c05,0x7c07,0x7c09,0x7c12,0x7c15,0x7c15,0x7c19,0x7c19,0x7c1b,0x7c23,0x7c25,0x7c2d,0x7c30,0x7c30,0x7c33,0x7c33,0x7c35,0x7c35,0x7c37,0x7c39,0x7c3b,0x7c40,0x7c42,0x7c45,0x7c47,0x7c4a,0x7c4c,0x7c4d,0x7c50,0x7c51,0x7c53,0x7c54,0x7c56,0x7c57,0x7c59,0x7c5d,0x7c5f,0x7c60,0x7c63,0x7c67,0x7c69,0x7c70,0x7c72,0x7c75,0x7c78,0x7c81,0x7c83,0x7c86,0x7c88,0x7c8a,0x7c8c,0x7c8e,0x7c91,0x7c92,0x7c94,0x7c98,0x7c9c,0x7c9c,0x7c9e,0x7c9f,0x7ca1,0x7ca3,0x7ca5,0x7ca8,0x7cac,0x7cac,0x7cae,0x7caf,0x7cb1,0x7cb5,0x7cb8,0x7cbf,0x7cc2,0x7cc3,0x7cc5,0x7cc5,0x7cc7,0x7cce,0x7cd0,0x7cd7,0x7cd9,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce6,0x7ce8,0x7cea,0x7cea,0x7cec,0x7cf9,0x7cfb,0x7cfe,0x7d00,0x7d22,0x7d25,0x7d25,0x7d28,0x7d29,0x7d2b,0x7d2c,0x7d2e,0x7d33,0x7d35,0x7d36,0x7d38,0x7d47,0x7d4a,0x7d4a,0x7d4d,0x7d56,0x7d58,0x7d58,0x7d5a,0x7d5f,0x7d61,0x7d63,0x7d66,0x7d6b,0x7d6d,0x7d73,0x7d79,0x7d7d,0x7d7f,0x7d81,0x7d83,0x7d86,0x7d88,0x7d89,0x7d8b,0x7d8f,0x7d91,0x7d97,0x7d9c,0x7da4,0x7da6,0x7db5,0x7db7,0x7dc2,0x7dc4,0x7dc7,0x7dc9,0x7dd0,0x7dd2,0x7dd4,0x7dd7,0x7de1,0x7de3,0x7dea,0x7dec,0x7dec,0x7dee,0x7df7,0x7df9,0x7dfe,0x7e03,0x7e03,0x7e07,0x7e17,0x7e1a,0x7e25,0x7e27,0x7e27,0x7e29,0x7e2b,0x7e2d,0x7e49,0x7e4c,0x7e4c,0x7e50,0x7e5c,0x7e5e,0x7e63,0x7e65,0x7e65,0x7e67,0x7e70,0x7e72,0x7e82,0x7e86,0x7e88,0x7e8a,0x7e8f,0x7e91,0x7e9c,0x7e9f,0x7e9f,0x7ea4,0x7ea4,0x7eac,0x7eac,0x7eba,0x7eba,0x7ec7,0x7ec7,0x7ecf,0x7ecf,0x7edf,0x7edf,0x7f06,0x7f06,0x7f36,0x7f3a,0x7f3d,0x7f41,0x7f43,0x7f45,0x7f47,0x7f55,0x7f58,0x7f58,0x7f5b,0x7f61,0x7f63,0x7f63,0x7f65,0x7f6e,0x7f70,0x7f73,0x7f75,0x7f7f,0x7f83,0x7f83,0x7f85,0x7f8f,0x7f91,0x7f97,0x7f9a,0x7f9e,0x7fa0,0x7fa9,0x7fac,0x7fc3,0x7fc5,0x7fc5,0x7fc7,0x7fc7,0x7fc9,0x7fd2,0x7fd4,0x7fd5,0x7fd7,0x7fd7,0x7fdb,0x7fe3,0x7fe5,0x7ff5,0x7ff7,0x8008,0x800b,0x8012,0x8014,0x8019,0x801b,0x8021,0x8024,0x8026,0x8028,0x802a,0x802c,0x802c,0x802e,0x8031,0x8033,0x8037,0x8039,0x8039,0x803b,0x803f,0x8043,0x8043,0x8046,0x8048,0x804a,0x804a,0x804f,0x8052,0x8054,0x8054,0x8056,0x8056,0x8058,0x8058,0x805a,0x805e,0x8061,0x8064,0x8066,0x8067,0x806c,0x806c,0x806f,0x8073,0x8075,0x8079,0x807d,0x8080,0x8082,0x8082,0x8084,0x8087,0x8089,0x808c,0x808f,0x8090,0x8092,0x8093,0x8095,0x8096,0x8098,0x809d,0x809f,0x809f,0x80a1,0x80a3,0x80a5,0x80a5,0x80a7,0x80a7,0x80a9,0x80ab,0x80ad,0x80af,0x80b1,0x80b2,0x80b4,0x80b8,0x80ba,0x80ba,0x80bc,0x80bd,0x80c2,0x80ca,0x80cc,0x80d1,0x80d4,0x80de,0x80e0,0x80e1,0x80e3,0x80e6,0x80e9,0x80e9,0x80ec,0x80ed,0x80ef,0x80f6,0x80f8,0x80fe,0x8100,0x8103,0x8105,0x810a,0x810c,0x810c,0x810e,0x810e,0x8112,0x8112,0x8114,0x811b,0x811d,0x811f,0x8121,0x8125,0x8127,0x8127,0x8129,0x812d,0x812f,0x8132,0x8134,0x8134,0x8137,0x8137,0x8139,0x813a,0x813d,0x813e,0x8142,0x8144,0x8146,0x8148,0x814a,0x8156,0x8159,0x815c,0x815e,0x815e,0x8160,0x8162,0x8164,0x8167,0x8169,0x8169,0x816b,0x8174,0x8176,0x817a,0x817c,0x817d,0x817f,0x8180,0x8182,0x8184,0x8186,0x818d,0x818f,0x818f,0x8193,0x8193,0x8195,0x8195,0x8197,0x81a0,0x81a2,0x81a3,0x81a5,0x81ac,0x81ae,0x81ae,0x81b0,0x81b7,0x81b9,0x81ca,0x81cc,0x81cd,0x81cf,0x81d2,0x81d5,0x81d5,0x81d7,0x81db,0x81dd,0x81ea,0x81ec,0x81ef,0x81f2,0x81f4,0x81f6,0x81fc,0x81fe,0x8202,0x8204,0x8205,0x8207,0x820d,0x8210,0x8212,0x8214,0x8216,0x8218,0x8218,0x821a,0x8222,0x8225,0x8226,0x8228,0x822d,0x822f,0x822f,0x8232,0x823a,0x823c,0x8240,0x8242,0x8242,0x8244,0x8245,0x8247,0x8247,0x8249,0x8249,0x824b,0x824b,0x824e,0x825c,0x825e,0x825f,0x8261,0x8266,0x8268,0x8269,0x826b,0x826f,0x8271,0x8272,0x8274,0x8280,0x8283,0x8285,0x8287,0x8287,0x828a,0x828b,0x828d,0x8294,0x8298,0x829b,0x829d,0x82b1,0x82b3,0x82c0,0x82c2,0x82c4,0x82ca,0x82ca,0x82cf,0x82d9,0x82db,0x82dc,0x82de,0x82e8,0x82ea,0x8309,0x830b,0x830d,0x8316,0x831e,0x8320,0x8320,0x8322,0x8322,0x8324,0x832d,0x832f,0x832f,0x8331,0x833d,0x833f,0x8345,0x8347,0x8354,0x8356,0x8357,0x8362,0x8363,0x8366,0x8366,0x836f,0x836f,0x8373,0x8378,0x837a,0x837f,0x8381,0x8381,0x8383,0x8383,0x8385,0x839e,0x83a0,0x83a0,0x83a2,0x83ac,0x83ae,0x83b0,0x83b9,0x83b9,0x83bd,0x83cf,0x83d1,0x83d1,0x83d3,0x83d9,0x83db,0x83e5,0x83e7,0x83f6,0x83f8,0x83ff,0x8401,0x8401,0x8403,0x8407,0x8409,0x8414,0x8416,0x8416,0x8418,0x8418,0x841b,0x841c,0x8420,0x8421,0x8423,0x8424,0x8426,0x8426,0x8429,0x8429,0x842b,0x8440,0x8442,0x844e,0x8450,0x8469,0x846b,0x847a,0x847d,0x8480,0x8482,0x8482,0x8484,0x8484,0x8486,0x8486,0x8488,0x8488,0x848d,0x8494,0x8496,0x84a4,0x84a7,0x84b2,0x84b4,0x84b4,0x84b6,0x84b6,0x84b8,0x84c2,0x84c4,0x84c7,0x84c9,0x84d4,0x84d6,0x84d7,0x84da,0x84db,0x84de,0x84de,0x84e1,0x84e2,0x84e4,0x84e5,0x84e7,0x84ec,0x84ee,0x84f4,0x84f6,0x8500,0x8502,0x851a,0x851c,0x8521,0x8523,0x8531,0x8533,0x8534,0x8538,0x8538,0x853b,0x853b,0x853d,0x853e,0x8540,0x854e,0x8551,0x855b,0x855d,0x8571,0x8573,0x8573,0x8575,0x857c,0x857e,0x857e,0x8580,0x8591,0x8593,0x85a4,0x85a6,0x85aa,0x85af,0x85b1,0x85b3,0x85ba,0x85bd,0x85c9,0x85cb,0x85cb,0x85cd,0x85d2,0x85d5,0x85da,0x85dc,0x85e6,0x85e8,0x85f2,0x85f4,0x85f4,0x85f6,0x8602,0x8604,0x8607,0x8609,0x860d,0x860f,0x8611,0x8613,0x8614,0x8616,0x861c,0x861e,0x862a,0x862c,0x862f,0x8631,0x8636,0x8638,0x863c,0x863e,0x8640,0x8642,0x8643,0x8645,0x8648,0x864b,0x864e,0x8650,0x8650,0x8652,0x8656,0x8659,0x8659,0x865b,0x865c,0x865e,0x865f,0x8661,0x8665,0x8667,0x8674,0x8677,0x8677,0x8679,0x867c,0x867e,0x867e,0x8685,0x8687,0x868a,0x868e,0x8690,0x869a,0x869c,0x869e,0x86a0,0x86a5,0x86a7,0x86aa,0x86ad,0x86ad,0x86af,0x86c9,0x86cb,0x86cc,0x86d0,0x86d1,0x86d3,0x86d4,0x86d6,0x86df,0x86e2,0x86e4,0x86e6,0x86e6,0x86e8,0x86ed,0x86ef,0x86ef,0x86f5,0x86fb,0x86fe,0x86fe,0x8700,0x870e,0x8711,0x8713,0x8715,0x8715,0x8718,0x871c,0x871e,0x871e,0x8720,0x872a,0x872c,0x872e,0x8730,0x8735,0x8737,0x8738,0x873a,0x873c,0x873e,0x8743,0x8746,0x8746,0x874c,0x8771,0x8773,0x877b,0x877d,0x877d,0x8781,0x8789,0x878b,0x878d,0x878f,0x8794,0x8796,0x8798,0x879a,0x879f,0x87a2,0x87a5,0x87a9,0x87c6,0x87c8,0x87cc,0x87ce,0x87ce,0x87d1,0x87d4,0x87d6,0x87e8,0x87ea,0x87ef,0x87f2,0x87f7,0x87f9,0x87fc,0x87fe,0x8806,0x8808,0x880d,0x880f,0x8811,0x8813,0x8819,0x881b,0x881d,0x881f,0x8833,0x8835,0x8839,0x883b,0x8846,0x8848,0x8848,0x884a,0x884f,0x8852,0x8853,0x8855,0x8857,0x8859,0x885b,0x885d,0x885e,0x8860,0x8865,0x8867,0x886b,0x886d,0x8872,0x8874,0x8877,0x8879,0x8879,0x887c,0x8884,0x8887,0x8889,0x888b,0x8893,0x8895,0x88a2,0x88a4,0x88a4,0x88a7,0x88a8,0x88aa,0x88ac,0x88ae,0x88ae,0x88b1,0x88b2,0x88b4,0x88ba,0x88bc,0x88c2,0x88c5,0x88c5,0x88c7,0x88c7,0x88c9,0x88d0,0x88d2,0x88d2,0x88d4,0x88df,0x88e1,0x88e1,0x88e6,0x88e8,0x88eb,0x88ec,0x88ee,0x8902,0x8905,0x8907,0x8909,0x890c,0x890e,0x890e,0x8910,0x891a,0x891e,0x891f,0x8921,0x8927,0x8929,0x8933,0x8935,0x8938,0x893b,0x893e,0x8941,0x8944,0x8946,0x8947,0x8949,0x8949,0x894b,0x894d,0x894f,0x8954,0x8956,0x8966,0x8969,0x896f,0x8971,0x8974,0x8976,0x8977,0x8979,0x897c,0x897e,0x8983,0x8985,0x898b,0x898f,0x898f,0x8991,0x8991,0x8993,0x8998,0x899b,0x899f,0x89a1,0x89a7,0x89a9,0x89aa,0x89ac,0x89af,0x89b2,0x89b2,0x89b6,0x89b7,0x89b9,0x89ba,0x89bc,0x89c1,0x89c6,0x89c6,0x89d2,0x89d6,0x89d9,0x89dd,0x89df,0x89e9,0x89eb,0x89ed,0x89f0,0x89f4,0x89f6,0x89f8,0x89fa,0x89fc,0x89fe,0x8a00,0x8a02,0x8a04,0x8a07,0x8a08,0x8a0a,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a13,0x8a15,0x8a18,0x8a1b,0x8a1f,0x8a22,0x8a23,0x8a25,0x8a25,0x8a27,0x8a27,0x8a29,0x8a2d,0x8a30,0x8a31,0x8a34,0x8a34,0x8a36,0x8a36,0x8a38,0x8a41,0x8a44,0x8a46,0x8a48,0x8a4a,0x8a4c,0x8a52,0x8a54,0x8a59,0x8a5b,0x8a5b,0x8a5e,0x8a5e,0x8a60,0x8a63,0x8a66,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a77,0x8a79,0x8a7c,0x8a7e,0x8a7f,0x8a81,0x8a87,0x8a8b,0x8a8d,0x8a8f,0x8a96,0x8a98,0x8a9a,0x8a9c,0x8a9c,0x8a9e,0x8a9e,0x8aa0,0x8aa1,0x8aa3,0x8aac,0x8aaf,0x8ab0,0x8ab2,0x8ab2,0x8ab4,0x8ab4,0x8ab6,0x8ab6,0x8ab8,0x8ac0,0x8ac2,0x8ac9,0x8acb,0x8acd,0x8acf,0x8acf,0x8ad1,0x8ae2,0x8ae4,0x8ae4,0x8ae6,0x8ae8,0x8aea,0x8aeb,0x8aed,0x8afc,0x8afe,0x8b02,0x8b04,0x8b08,0x8b0a,0x8b20,0x8b22,0x8b28,0x8b2a,0x8b31,0x8b33,0x8b33,0x8b35,0x8b37,0x8b39,0x8b43,0x8b45,0x8b5a,0x8b5c,0x8b60,0x8b62,0x8b63,0x8b65,0x8b6d,0x8b6f,0x8b70,0x8b74,0x8b74,0x8b77,0x8b7b,0x8b7d,0x8b86,0x8b88,0x8b88,0x8b8a,0x8b8c,0x8b8e,0x8b90,0x8b92,0x8b96,0x8b98,0x8b9c,0x8b9e,0x8ba0,0x8bbe,0x8bbe,0x8be2,0x8be2,0x8c37,0x8c37,0x8c39,0x8c39,0x8c3b,0x8c3f,0x8c41,0x8c43,0x8c45,0x8c51,0x8c54,0x8c57,0x8c5a,0x8c5a,0x8c5c,0x8c5d,0x8c5f,0x8c5f,0x8c61,0x8c62,0x8c64,0x8c66,0x8c68,0x8c6d,0x8c6f,0x8c73,0x8c75,0x8c7b,0x8c7d,0x8c7d,0x8c80,0x8c82,0x8c84,0x8c86,0x8c89,0x8c8a,0x8c8c,0x8c8d,0x8c8f,0x8c95,0x8c97,0x8ca5,0x8ca7,0x8cad,0x8caf,0x8cb0,0x8cb2,0x8cc5,0x8cc7,0x8cc8,0x8cca,0x8cca,0x8ccc,0x8ccd,0x8ccf,0x8ccf,0x8cd1,0x8cd7,0x8cd9,0x8cee,0x8cf0,0x8cf5,0x8cf7,0x8cfe,0x8d00,0x8d00,0x8d02,0x8d0d,0x8d0f,0x8d19,0x8d1b,0x8d1d,0x8d64,0x8d64,0x8d66,0x8d69,0x8d6b,0x8d70,0x8d72,0x8d74,0x8d76,0x8d7b,0x8d7d,0x8d7d,0x8d80,0x8d82,0x8d84,0x8d85,0x8d89,0x8d8a,0x8d8c,0x8d96,0x8d99,0x8d99,0x8d9b,0x8d9c,0x8d9f,0x8da1,0x8da3,0x8da3,0x8da5,0x8daf,0x8db2,0x8db7,0x8db9,0x8dba,0x8dbc,0x8dbc,0x8dbe,0x8dc3,0x8dc5,0x8dc8,0x8dcb,0x8dd1,0x8dd3,0x8ddd,0x8ddf,0x8de4,0x8de6,0x8dec,0x8dee,0x8df4,0x8dfa,0x8dfa,0x8dfc,0x8e07,0x8e09,0x8e0a,0x8e0d,0x8e2b,0x8e2d,0x8e2e,0x8e30,0x8e31,0x8e33,0x8e36,0x8e38,0x8e3a,0x8e3c,0x8e42,0x8e44,0x8e50,0x8e53,0x8e57,0x8e59,0x8e6a,0x8e6c,0x8e6d,0x8e6f,0x8e6f,0x8e71,0x8e78,0x8e7a,0x8e7c,0x8e7e,0x8e7e,0x8e80,0x8e82,0x8e84,0x8e8e,0x8e90,0x8e98,0x8e9a,0x8e9a,0x8e9d,0x8ea1,0x8ea3,0x8ead,0x8eb0,0x8eb0,0x8eb2,0x8eb2,0x8eb6,0x8eb6,0x8eb9,0x8eba,0x8ebc,0x8ebd,0x8ec0,0x8ec0,0x8ec2,0x8ec3,0x8ec9,0x8ecf,0x8ed1,0x8ed4,0x8ed7,0x8ed8,0x8eda,0x8ee2,0x8ee4,0x8ee9,0x8eeb,0x8eef,0x8ef1,0x8ef2,0x8ef4,0x8efc,0x8efe,0x8f03,0x8f05,0x8f0b,0x8f0d,0x8f0e,0x8f10,0x8f20,0x8f23,0x8f26,0x8f29,0x8f2a,0x8f2c,0x8f30,0x8f32,0x8f39,0x8f3b,0x8f3c,0x8f3e,0x8f4b,0x8f4d,0x8f64,0x8f66,0x8f67,0x8f6e,0x8f6e,0x8f93,0x8f93,0x8f9b,0x8f9c,0x8f9f,0x8fa0,0x8fa3,0x8fa3,0x8fa5,0x8fa8,0x8fad,0x8fbc,0x8fbe,0x8fbf,0x8fc1,0x8fc2,0x8fc4,0x8fc6,0x8fc9,0x8fd7,0x8fda,0x8fda,0x8fe0,0x8fe6,0x8fe8,0x8fe8,0x8fea,0x8feb,0x8fed,0x8fee,0x8ff0,0x8ff0,0x8ff4,0x9006,0x9008,0x9008,0x900b,0x900d,0x900f,0x9012,0x9014,0x9017,0x9019,0x9024,0x902d,0x902f,0x9031,0x9038,0x903c,0x903f,0x9041,0x9042,0x9044,0x9044,0x9046,0x9047,0x9049,0x9056,0x9058,0x9059,0x905b,0x905e,0x9060,0x9064,0x9067,0x9069,0x906b,0x9070,0x9072,0x9088,0x908a,0x908b,0x908d,0x908d,0x908f,0x9091,0x9094,0x9095,0x9097,0x9099,0x909b,0x909b,0x909e,0x90a3,0x90a5,0x90a8,0x90aa,0x90aa,0x90ae,0x90b6,0x90b8,0x90b8,0x90bb,0x90bb,0x90bd,0x90bf,0x90c1,0x90c1,0x90c3,0x90c5,0x90c7,0x90c8,0x90ca,0x90cb,0x90ce,0x90ce,0x90d4,0x90dd,0x90df,0x90e5,0x90e8,0x90ed,0x90ef,0x90f5,0x90f9,0x9109,0x910b,0x910b,0x910d,0x9112,0x9114,0x9114,0x9116,0x9124,0x9126,0x9136,0x9138,0x913b,0x913e,0x9141,0x9143,0x9153,0x9155,0x915a,0x915c,0x915c,0x915e,0x9165,0x9167,0x916a,0x916c,0x916c,0x916e,0x9170,0x9172,0x917a,0x917c,0x917c,0x9180,0x9187,0x9189,0x9193,0x9196,0x9196,0x9199,0x91a3,0x91a5,0x91a5,0x91a7,0x91b7,0x91b9,0x91be,0x91c0,0x91c7,0x91c9,0x91c9,0x91cb,0x91d1,0x91d3,0x91da,0x91dc,0x91dd,0x91df,0x91df,0x91e2,0x91ee,0x91f1,0x91f1,0x91f3,0x91fa,0x91fd,0x920a,0x920c,0x921a,0x921c,0x921c,0x921e,0x921e,0x9221,0x9221,0x9223,0x9228,0x922a,0x922b,0x922d,0x922e,0x9230,0x923a,0x923c,0x9241,0x9244,0x9246,0x9248,0x9258,0x925a,0x925b,0x925d,0x9267,0x926b,0x9270,0x9272,0x9272,0x9276,0x928f,0x9291,0x9291,0x9293,0x929d,0x92a0,0x92ac,0x92ae,0x92ae,0x92b1,0x92b7,0x92b9,0x92bc,0x92be,0x92d5,0x92d7,0x92d9,0x92db,0x92db,0x92dd,0x92e1,0x92e3,0x92f4,0x92f6,0x9304,0x9306,0x9309,0x930b,0x9310,0x9312,0x9316,0x9318,0x931b,0x931d,0x9331,0x9333,0x9336,0x9338,0x9339,0x933c,0x933c,0x9340,0x9352,0x9354,0x935c,0x935e,0x936e,0x9370,0x9371,0x9373,0x937e,0x9380,0x938a,0x938c,0x9392,0x9394,0x93aa,0x93ac,0x93b5,0x93b7,0x93b8,0x93bb,0x93bb,0x93bd,0x93bd,0x93bf,0x93c0,0x93c2,0x93c4,0x93c6,0x93c8,0x93ca,0x93e4,0x93e6,0x93e8,0x93ec,0x93ec,0x93ee,0x93ee,0x93f0,0x93f1,0x93f3,0x9401,0x9403,0x9404,0x9406,0x9419,0x941b,0x941b,0x941d,0x941d,0x9420,0x9420,0x9424,0x9433,0x9435,0x9440,0x9442,0x944d,0x944f,0x9452,0x9454,0x9455,0x9457,0x9458,0x945b,0x945b,0x945d,0x945e,0x9460,0x9460,0x9462,0x9465,0x9467,0x9479,0x947b,0x9483,0x9485,0x9485,0x949f,0x949f,0x94a2,0x94a2,0x94c1,0x94c1,0x94c3,0x94c3,0x94dc,0x94dc,0x94f6,0x94f6,0x952d,0x952d,0x9547,0x9547,0x9577,0x9578,0x957a,0x957d,0x957f,0x9580,0x9582,0x9583,0x9585,0x9586,0x9588,0x9589,0x958b,0x9594,0x9596,0x9599,0x959b,0x959c,0x959e,0x95ae,0x95b0,0x95b2,0x95b5,0x95b7,0x95b9,0x95c0,0x95c3,0x95c3,0x95c5,0x95cd,0x95d0,0x95d6,0x95da,0x95dc,0x95de,0x95e5,0x95e8,0x95e8,0x95f4,0x95f4,0x961c,0x961e,0x9620,0x9624,0x9628,0x9628,0x962a,0x962a,0x962c,0x9633,0x9638,0x963d,0x963f,0x9645,0x964a,0x9651,0x9653,0x9654,0x9656,0x9656,0x9658,0x9658,0x965b,0x965f,0x9661,0x9664,0x9669,0x966d,0x966f,0x9678,0x967b,0x967e,0x9680,0x9681,0x9683,0x968b,0x968d,0x968f,0x9691,0x9699,0x969b,0x969c,0x969e,0x969e,0x96a1,0x96a5,0x96a7,0x96aa,0x96ac,0x96ac,0x96ae,0x96ae,0x96b0,0x96b1,0x96b3,0x96b4,0x96b6,0x96b6,0x96b8,0x96b9,0x96bb,0x96bd,0x96bf,0x96ce,0x96d2,0x96df,0x96e1,0x96e3,0x96e5,0x96e5,0x96e8,0x96ea,0x96ef,0x96f2,0x96f4,0x96fb,0x96fd,0x96fd,0x96ff,0x9700,0x9702,0x9709,0x970b,0x970b,0x970d,0x9713,0x9716,0x9716,0x9718,0x9719,0x971b,0x972c,0x972e,0x9732,0x9734,0x9736,0x9738,0x973a,0x973d,0x9744,0x9746,0x974b,0x9751,0x9752,0x9755,0x9758,0x975a,0x9762,0x9766,0x9766,0x9768,0x976a,0x976c,0x976e,0x9770,0x9774,0x9776,0x9778,0x977a,0x9785,0x9787,0x978b,0x978d,0x978f,0x9794,0x9794,0x9797,0x97a6,0x97a8,0x97a8,0x97aa,0x97ae,0x97b1,0x97b4,0x97b6,0x97bb,0x97bd,0x97c9,0x97cb,0x97d0,0x97d2,0x97d9,0x97dc,0x97e1,0x97e3,0x97e3,0x97e5,0x97e6,0x97ed,0x97ee,0x97f0,0x97f3,0x97f5,0x97f6,0x97f8,0x97fb,0x97fd,0x9808,0x980a,0x980a,0x980c,0x9818,0x981b,0x9821,0x9823,0x9824,0x9826,0x9829,0x982b,0x982b,0x982d,0x9830,0x9832,0x9835,0x9837,0x9839,0x983b,0x983b,0x9841,0x9841,0x9843,0x9853,0x9856,0x9859,0x985b,0x9860,0x9862,0x986c,0x986f,0x9875,0x98a8,0x98a9,0x98ac,0x98af,0x98b1,0x98b4,0x98b6,0x98c4,0x98c6,0x98cc,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e3,0x98e5,0x98e7,0x98e9,0x98ed,0x98ef,0x98ef,0x98f1,0x98f2,0x98f4,0x98f6,0x98f9,0x98fa,0x98fc,0x98fe,0x9900,0x9900,0x9902,0x9903,0x9905,0x9905,0x9907,0x990a,0x990c,0x990c,0x990e,0x990e,0x9910,0x991c,0x991e,0x991f,0x9921,0x9921,0x9924,0x9925,0x9927,0x9933,0x9935,0x9935,0x9937,0x9943,0x9945,0x9945,0x9947,0x994e,0x9950,0x9959,0x995b,0x995f,0x9961,0x9963,0x9996,0x9999,0x999b,0x999e,0x99a1,0x99a1,0x99a3,0x99a8,0x99aa,0x99b5,0x99b8,0x99bd,0x99c1,0x99c5,0x99c7,0x99c7,0x99c9,0x99c9,0x99cb,0x99dd,0x99df,0x99e7,0x99e9,0x99ea,0x99ec,0x99ee,0x99f0,0x99f1,0x99f4,0x99ff,0x9a01,0x9a07,0x9a09,0x9a11,0x9a14,0x9a16,0x9a19,0x9a27,0x9a29,0x9a32,0x9a34,0x9a46,0x9a48,0x9a4a,0x9a4c,0x9a50,0x9a52,0x9a5c,0x9a5e,0x9a60,0x9a62,0x9a6c,0x9a8f,0x9a8f,0x9aa8,0x9aa8,0x9aab,0x9aab,0x9aad,0x9aad,0x9aaf,0x9ab4,0x9ab6,0x9ac2,0x9ac6,0x9ac7,0x9aca,0x9aca,0x9acd,0x9acd,0x9acf,0x9ad8,0x9adc,0x9adc,0x9adf,0x9ae3,0x9ae6,0x9ae7,0x9aeb,0x9aef,0x9af1,0x9af4,0x9af6,0x9af7,0x9af9,0x9aff,0x9b01,0x9b06,0x9b08,0x9b12,0x9b14,0x9b1a,0x9b1e,0x9b20,0x9b22,0x9b25,0x9b27,0x9b2b,0x9b2d,0x9b2f,0x9b31,0x9b35,0x9b37,0x9b37,0x9b39,0x9b3c,0x9b3e,0x9b46,0x9b48,0x9b48,0x9b4a,0x9b52,0x9b54,0x9b56,0x9b58,0x9b5b,0x9b5f,0x9b61,0x9b64,0x9b64,0x9b66,0x9b69,0x9b6c,0x9b6c,0x9b6f,0x9b71,0x9b74,0x9b77,0x9b7a,0x9b83,0x9b85,0x9b88,0x9b8b,0x9b8b,0x9b8d,0x9b93,0x9b95,0x9b95,0x9b97,0x9b97,0x9b9a,0x9b9b,0x9b9d,0x9ba2,0x9ba4,0x9ba6,0x9ba8,0x9ba8,0x9baa,0x9bab,0x9bad,0x9bb0,0x9bb5,0x9bb6,0x9bb8,0x9bb9,0x9bbd,0x9bbd,0x9bbf,0x9bc1,0x9bc3,0x9bc4,0x9bc6,0x9bca,0x9bcf,0x9bcf,0x9bd3,0x9bd7,0x9bd9,0x9bde,0x9be0,0x9be2,0x9be4,0x9bed,0x9bf0,0x9bf1,0x9bf4,0x9bf4,0x9bf7,0x9bf8,0x9bfd,0x9bfd,0x9bff,0x9bff,0x9c02,0x9c02,0x9c05,0x9c0e,0x9c10,0x9c10,0x9c12,0x9c15,0x9c17,0x9c17,0x9c1b,0x9c1d,0x9c1f,0x9c21,0x9c23,0x9c26,0x9c28,0x9c29,0x9c2b,0x9c2d,0x9c2f,0x9c2f,0x9c31,0x9c37,0x9c39,0x9c41,0x9c44,0x9c50,0x9c52,0x9c59,0x9c5d,0x9c60,0x9c62,0x9c63,0x9c66,0x9c68,0x9c6d,0x9c6e,0x9c71,0x9c75,0x9c77,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9cea,0x9ced,0x9ced,0x9cf1,0x9cf7,0x9cf9,0x9cfd,0x9cff,0x9d00,0x9d02,0x9d09,0x9d0c,0x9d0c,0x9d10,0x9d10,0x9d12,0x9d12,0x9d14,0x9d19,0x9d1b,0x9d1b,0x9d1d,0x9d23,0x9d25,0x9d26,0x9d28,0x9d29,0x9d2d,0x9d31,0x9d33,0x9d34,0x9d36,0x9d39,0x9d3b,0x9d3b,0x9d3d,0x9d45,0x9d49,0x9d4c,0x9d4e,0x9d54,0x9d56,0x9d61,0x9d67,0x9d75,0x9d77,0x9d79,0x9d7b,0x9d8c,0x9d90,0x9d90,0x9d92,0x9d94,0x9d96,0x9dad,0x9daf,0x9daf,0x9db1,0x9dc5,0x9dc7,0x9ddf,0x9de1,0x9de6,0x9de8,0x9de9,0x9deb,0x9df0,0x9df2,0x9e07,0x9e09,0x9e15,0x9e17,0x9e1f,0x9e75,0x9e75,0x9e79,0x9e7d,0x9e7f,0x9e8e,0x9e90,0x9ea2,0x9ea4,0x9eb1,0x9eb4,0x9eb7,0x9ebb,0x9ec4,0x9ec6,0x9ec8,0x9ecc,0x9ed1,0x9ed3,0x9ed6,0x9ed8,0x9ed8,0x9eda,0x9ee0,0x9ee2,0x9ee2,0x9ee4,0x9ee8,0x9eeb,0x9eeb,0x9eed,0x9f02,0x9f06,0x9f0a,0x9f0e,0x9f10,0x9f12,0x9f13,0x9f15,0x9f1c,0x9f1e,0x9f1e,0x9f20,0x9f20,0x9f22,0x9f39,0x9f3b,0x9f3b,0x9f3d,0x9f3e,0x9f40,0x9f50,0x9f52,0x9f67,0x9f69,0x9f6c,0x9f6e,0x9f72,0x9f74,0x9f7b,0x9f7e,0x9f7f,0x9f8d,0x9f8e,0x9f90,0x9f92,0x9f94,0x9f99,0x9f9c,0x9f9c,0x9f9f,0x9fa0,0x9fa2,0x9fa2,0x9fa4,0x9fb3,0x9fc7,0x9fcb,0x9fd0,0x9fd0,0xf900,0xf908,0xf90b,0xf90d,0xf915,0xf915,0xf917,0xf917,0xf91a,0xf91a,0xf922,0xf922,0xf92d,0xf92d,0xf934,0xf934,0xf937,0xf937,0xf93a,0xf93a,0xf943,0xf943,0xf947,0xf948,0xf94a,0xf94a,0xf952,0xf952,0xf95e,0xf95e,0xf962,0xf962,0xf965,0xf965,0xf967,0xf967,0xf96d,0xf96d,0xf972,0xf972,0xf976,0xf976,0xf978,0xf979,0xf97b,0xf97b,0xf97e,0xf97e,0xf980,0xf980,0xf986,0xf986,0xf98a,0xf98a,0xf98e,0xf98e,0xf995,0xf995,0xf99c,0xf99d,0xf99f,0xf99f,0xf9b5,0xf9b5,0xf9bb,0xf9bb,0xf9bd,0xf9be,0xf9c5,0xf9c6,0xf9c8,0xf9c8,0xf9d0,0xf9d0,0xf9d8,0xf9d9,0xf9dc,0xf9de,0xf9e0,0xf9e0,0xf9e2,0xf9e4,0xf9e7,0xf9e7,0xf9e9,0xf9e9,0xf9f4,0xf9f5,0xf9fa,0xf9fa,0xf9fd,0xf9fd,0xf9ff,0xf9ff,0xfa02,0xfa02,0xfa05,0xfa08,0xfa0a,0xfa0a,0xfa0c,0xfa0d,0xfa33,0xfa35,0xfa3a,0xfa3a,0xfa49,0xfa49,0xfa4b,0xfa4b,0xfa5d,0xfa5e,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x20021,0x20021,0x2003e,0x2003e,0x20046,0x20046,0x2004e,0x2004e,0x20068,0x20068,0x20086,0x20087,0x2008a,0x2008a,0x20094,0x20094,0x200ca,0x200cd,0x200d1,0x200d1,0x200ee,0x200ee,0x2010c,0x2010c,0x2010e,0x2010e,0x20118,0x20118,0x201a4,0x201a4,0x201a9,0x201a9,0x201ab,0x201ab,0x201c1,0x201c1,0x201d4,0x201d4,0x201f2,0x201f2,0x20204,0x20204,0x2020c,0x2020c,0x20214,0x20214,0x20239,0x20239,0x2025b,0x2025b,0x20274,0x20275,0x20299,0x20299,0x2029e,0x2029e,0x202a0,0x202a0,0x202b7,0x202b7,0x202bf,0x202c0,0x202e5,0x202e5,0x2030a,0x2030a,0x20325,0x20325,0x20341,0x20341,0x20345,0x20347,0x2037e,0x20380,0x203a0,0x203a0,0x203a7,0x203a7,0x203b5,0x203b5,0x203c9,0x203c9,0x203cb,0x203cb,0x203f5,0x203f5,0x203fc,0x203fc,0x20413,0x20414,0x2041f,0x2041f,0x20465,0x20465,0x20487,0x20487,0x2048e,0x2048e,0x20491,0x20492,0x204a3,0x204a3,0x204d7,0x204d7,0x204fc,0x204fc,0x204fe,0x204fe,0x20547,0x20547,0x2058e,0x2058e,0x205a5,0x205a5,0x205b3,0x205b3,0x205c3,0x205c3,0x205ca,0x205ca,0x205d0,0x205d0,0x205d5,0x205d5,0x205df,0x205e0,0x205eb,0x205eb,0x20611,0x20611,0x20615,0x20615,0x20619,0x2061a,0x20628,0x20628,0x20630,0x20630,0x20656,0x20656,0x20676,0x20676,0x2070e,0x2070e,0x20731,0x20731,0x20779,0x20779,0x2082c,0x2082c,0x20873,0x20873,0x208d5,0x208d5,0x20916,0x20916,0x20923,0x20923,0x20954,0x20954,0x20979,0x20979,0x209e7,0x209e7,0x20a11,0x20a11,0x20a50,0x20a50,0x20a6f,0x20a6f,0x20a8a,0x20a8a,0x20ab4,0x20ab4,0x20ac2,0x20ac2,0x20acd,0x20acd,0x20b0d,0x20b0d,0x20b8f,0x20b8f,0x20b9f,0x20b9f,0x20ba8,0x20ba9,0x20bbf,0x20bbf,0x20bc6,0x20bc6,0x20bcb,0x20bcb,0x20be2,0x20be2,0x20beb,0x20beb,0x20bfb,0x20bfb,0x20bff,0x20bff,0x20c0b,0x20c0b,0x20c0d,0x20c0d,0x20c20,0x20c20,0x20c34,0x20c34,0x20c3a,0x20c3b,0x20c41,0x20c43,0x20c53,0x20c53,0x20c65,0x20c65,0x20c77,0x20c78,0x20c7c,0x20c7c,0x20c8d,0x20c8d,0x20c96,0x20c96,0x20c9c,0x20c9c,0x20cb5,0x20cb5,0x20cb8,0x20cb8,0x20ccf,0x20ccf,0x20cd3,0x20cd6,0x20cdd,0x20cdd,0x20ced,0x20ced,0x20cff,0x20cff,0x20d15,0x20d15,0x20d28,0x20d28,0x20d31,0x20d32,0x20d46,0x20d49,0x20d4c,0x20d4e,0x20d6f,0x20d6f,0x20d71,0x20d71,0x20d74,0x20d74,0x20d7c,0x20d7c,0x20d7e,0x20d7f,0x20d96,0x20d96,0x20d9c,0x20d9c,0x20da7,0x20da7,0x20db2,0x20db2,0x20dc8,0x20dc8,0x20e04,0x20e04,0x20e09,0x20e0a,0x20e0d,0x20e11,0x20e16,0x20e16,0x20e1d,0x20e1d,0x20e4c,0x20e4c,0x20e6d,0x20e6d,0x20e73,0x20e73,0x20e75,0x20e7b,0x20e8c,0x20e8c,0x20e96,0x20e96,0x20e98,0x20e98,0x20e9d,0x20e9d,0x20ea2,0x20ea2,0x20eaa,0x20eac,0x20eb6,0x20eb6,0x20ed7,0x20ed8,0x20edd,0x20edd,0x20ef8,0x20efb,0x20f1d,0x20f1d,0x20f26,0x20f26,0x20f2d,0x20f2e,0x20f30,0x20f31,0x20f3b,0x20f3b,0x20f4c,0x20f4c,0x20f64,0x20f64,0x20f8d,0x20f8d,0x20f90,0x20f90,0x20fad,0x20fad,0x20fb4,0x20fb6,0x20fbc,0x20fbc,0x20fdf,0x20fdf,0x20fea,0x20fed,0x21014,0x21014,0x2101d,0x2101e,0x2104f,0x2104f,0x2105c,0x2105c,0x2106f,0x2106f,0x21075,0x21078,0x2107b,0x2107b,0x21088,0x21088,0x21096,0x21096,0x2109d,0x2109d,0x210b4,0x210b4,0x210bf,0x210c1,0x210c7,0x210c9,0x210cf,0x210cf,0x210d3,0x210d3,0x210e4,0x210e4,0x210f4,0x210f6,0x2112f,0x2112f,0x2113b,0x2113b,0x2113d,0x2113d,0x21145,0x21145,0x21148,0x21148,0x2114f,0x2114f,0x21180,0x21180,0x21187,0x21187,0x211d9,0x211d9,0x2123c,0x2123c,0x2124f,0x2124f,0x2127c,0x2127c,0x212a8,0x212a9,0x212b0,0x212b0,0x212e3,0x212e3,0x212fe,0x212fe,0x21302,0x21305,0x21336,0x21336,0x2133a,0x2133a,0x21375,0x21376,0x2138e,0x2138e,0x21398,0x21398,0x2139c,0x2139c,0x213c5,0x213c6,0x213ed,0x213ed,0x213fe,0x213fe,0x21413,0x21413,0x21416,0x21416,0x21424,0x21424,0x2143f,0x2143f,0x21452,0x21452,0x21454,0x21455,0x2148a,0x2148a,0x21497,0x21497,0x214b6,0x214b6,0x214e8,0x214e8,0x214fd,0x214fd,0x21577,0x21577,0x21582,0x21582,0x21596,0x21596,0x2160a,0x2160a,0x21613,0x21613,0x21619,0x21619,0x2163e,0x2163e,0x21661,0x21661,0x21692,0x21692,0x216b8,0x216b8,0x216ba,0x216ba,0x216c0,0x216c2,0x216d3,0x216d3,0x216d5,0x216d5,0x216df,0x216df,0x216e6,0x216e8,0x216fa,0x216fc,0x216fe,0x216fe,0x2170d,0x2170d,0x21710,0x21710,0x21726,0x21726,0x2173a,0x2173c,0x21757,0x21757,0x2176c,0x21771,0x21773,0x21774,0x217ab,0x217ab,0x217b0,0x217b5,0x217c3,0x217c3,0x217c7,0x217c7,0x217d9,0x217dc,0x217df,0x217df,0x217ef,0x217ef,0x217f5,0x217f6,0x217f8,0x217fc,0x21820,0x21820,0x21828,0x2182a,0x2182d,0x2182d,0x21839,0x2183b,0x21840,0x21840,0x21845,0x21845,0x21852,0x21852,0x2185e,0x2185e,0x21861,0x21864,0x21877,0x21877,0x2187b,0x2187b,0x21883,0x21885,0x2189e,0x218a2,0x218be,0x218bf,0x218d1,0x218d1,0x218d6,0x218d9,0x218fa,0x218fa,0x21903,0x21905,0x21910,0x21912,0x21915,0x21915,0x2191c,0x2191c,0x21922,0x21922,0x21927,0x21927,0x2193b,0x2193b,0x21944,0x21944,0x21958,0x21958,0x2196a,0x2196a,0x2197c,0x2197c,0x21980,0x21980,0x21983,0x21983,0x21988,0x21988,0x21996,0x21996,0x219db,0x219db,0x219f3,0x219f3,0x21a2d,0x21a2d,0x21a34,0x21a34,0x21a45,0x21a45,0x21a4b,0x21a4b,0x21a63,0x21a63,0x21b44,0x21b44,0x21bc1,0x21bc2,0x21c2a,0x21c2a,0x21c70,0x21c70,0x21ca2,0x21ca2,0x21ca5,0x21ca5,0x21cac,0x21cac,0x21d46,0x21d46,0x21d53,0x21d53,0x21d5e,0x21d5e,0x21d90,0x21d90,0x21db6,0x21db6,0x21dba,0x21dba,0x21dca,0x21dca,0x21dd1,0x21dd1,0x21deb,0x21deb,0x21df9,0x21df9,0x21e1c,0x21e1c,0x21e23,0x21e23,0x21e37,0x21e37,0x21e3d,0x21e3d,0x21e89,0x21e89,0x21ea4,0x21ea4,0x21ea8,0x21ea8,0x21ec8,0x21ec8,0x21ed5,0x21ed5,0x21f0f,0x21f0f,0x21f15,0x21f15,0x21f6a,0x21f6a,0x21f9e,0x21f9e,0x21fa1,0x21fa1,0x21fe8,0x21fe8,0x22045,0x22045,0x22049,0x22049,0x2207e,0x2207e,0x2209a,0x2209a,0x220c7,0x220c7,0x220fc,0x220fc,0x2212a,0x2212a,0x2215b,0x2215b,0x22173,0x22173,0x2217a,0x2217a,0x221a1,0x221a1,0x221c1,0x221c1,0x221c3,0x221c3,0x22208,0x22208,0x2227c,0x2227c,0x22321,0x22321,0x22325,0x22325,0x223bd,0x223bd,0x223d0,0x223d0,0x223d7,0x223d7,0x223fa,0x223fa,0x22465,0x22465,0x22471,0x22471,0x2248b,0x2248b,0x22491,0x22491,0x224b0,0x224b0,0x224bc,0x224bc,0x224c1,0x224c1,0x224c9,0x224c9,0x224cc,0x224cc,0x224ed,0x224ed,0x22513,0x22513,0x2251b,0x2251b,0x22530,0x22530,0x22554,0x22554,0x2258d,0x2258d,0x225af,0x225af,0x225be,0x225be,0x2261b,0x2261c,0x2262b,0x2262b,0x22668,0x22668,0x2267a,0x2267a,0x22696,0x22696,0x22698,0x22698,0x226f4,0x226f6,0x22712,0x22712,0x22714,0x22714,0x2271b,0x2271b,0x2271f,0x2271f,0x2272a,0x2272a,0x22775,0x22775,0x22781,0x22781,0x22796,0x22796,0x227b4,0x227b5,0x227cd,0x227cd,0x22803,0x22803,0x2285f,0x22860,0x22871,0x22871,0x228ad,0x228ad,0x228c1,0x228c1,0x228f7,0x228f7,0x22926,0x22926,0x22939,0x22939,0x2294f,0x2294f,0x22967,0x22967,0x2296b,0x2296b,0x22980,0x22980,0x22993,0x22993,0x22a66,0x22a66,0x22acf,0x22acf,0x22ad5,0x22ad5,0x22ae6,0x22ae6,0x22ae8,0x22ae8,0x22b0e,0x22b0e,0x22b22,0x22b22,0x22b3f,0x22b3f,0x22b43,0x22b43,0x22b6a,0x22b6a,0x22bca,0x22bca,0x22bce,0x22bce,0x22c26,0x22c27,0x22c38,0x22c38,0x22c4c,0x22c4c,0x22c51,0x22c51,0x22c55,0x22c55,0x22c62,0x22c62,0x22c88,0x22c88,0x22c9b,0x22c9b,0x22ca1,0x22ca1,0x22ca9,0x22ca9,0x22cb2,0x22cb2,0x22cb7,0x22cb7,0x22cc2,0x22cc2,0x22cc6,0x22cc6,0x22cc9,0x22cc9,0x22d07,0x22d08,0x22d12,0x22d12,0x22d44,0x22d44,0x22d4c,0x22d4c,0x22d67,0x22d67,0x22d8d,0x22d8d,0x22d95,0x22d95,0x22da0,0x22da0,0x22da3,0x22da4,0x22db7,0x22db7,0x22dee,0x22dee,0x22e0d,0x22e0d,0x22e36,0x22e36,0x22e42,0x22e42,0x22e78,0x22e78,0x22e8b,0x22e8b,0x22eb3,0x22eb3,0x22eef,0x22eef,0x22f74,0x22f74,0x22fcc,0x22fcc,0x22fe3,0x22fe3,0x23033,0x23033,0x23044,0x23044,0x2304b,0x2304b,0x23066,0x23066,0x2307d,0x2307e,0x2308e,0x2308e,0x230b7,0x230b7,0x230bc,0x230bc,0x230da,0x230da,0x23103,0x23103,0x2313d,0x2313d,0x2317d,0x2317d,0x23182,0x23182,0x231a4,0x231a5,0x231b3,0x231b3,0x231c8,0x231c9,0x231ea,0x231ea,0x231f7,0x231f9,0x2320f,0x2320f,0x23225,0x23225,0x2322f,0x2322f,0x23231,0x23234,0x23256,0x23256,0x2325e,0x2325e,0x23262,0x23262,0x23281,0x23281,0x23289,0x2328a,0x232ab,0x232ad,0x232d2,0x232d2,0x232e0,0x232e1,0x23300,0x23300,0x2330a,0x2330a,0x2331f,0x2331f,0x233b4,0x233b4,0x233cc,0x233cc,0x233de,0x233de,0x233e6,0x233e6,0x233f4,0x233f5,0x233f9,0x233fa,0x233fe,0x233fe,0x23400,0x23400,0x2343f,0x2343f,0x23450,0x23450,0x2346f,0x2346f,0x23472,0x23472,0x234e5,0x234e5,0x23519,0x23519,0x23530,0x23530,0x23551,0x23551,0x2355a,0x2355a,0x23567,0x23567,0x23595,0x23595,0x23599,0x23599,0x2359c,0x2359c,0x235bb,0x235bb,0x235cd,0x235cf,0x235f3,0x235f3,0x23600,0x23600,0x23617,0x23617,0x2361a,0x2361a,0x2363c,0x2363c,0x23640,0x23640,0x23659,0x23659,0x2365f,0x2365f,0x23677,0x23677,0x2368e,0x2368e,0x2369e,0x2369e,0x236a6,0x236a6,0x236ad,0x236ad,0x236ba,0x236ba,0x236df,0x236df,0x236ee,0x236ee,0x23703,0x23703,0x23716,0x23716,0x23720,0x23720,0x2372d,0x2372d,0x2372f,0x2372f,0x2373f,0x2373f,0x23766,0x23766,0x23781,0x23781,0x237a2,0x237a2,0x237bc,0x237bc,0x237c2,0x237c2,0x237d5,0x237d7,0x2383a,0x2383a,0x239c2,0x239c2,0x23aa7,0x23aa7,0x23adb,0x23adb,0x23aee,0x23aee,0x23afa,0x23afa,0x23b1a,0x23b1a,0x23b5a,0x23b5a,0x23c63,0x23c63,0x23c99,0x23c9b,0x23cb5,0x23cb5,0x23cb7,0x23cb7,0x23cc7,0x23cc9,0x23cfc,0x23cff,0x23d40,0x23d40,0x23d5b,0x23d5b,0x23d7e,0x23d7e,0x23d8f,0x23d8f,0x23db6,0x23dbd,0x23de3,0x23de3,0x23df8,0x23df8,0x23e06,0x23e06,0x23e11,0x23e11,0x23e2c,0x23e31,0x23e39,0x23e39,0x23e88,0x23e8b,0x23eb9,0x23eb9,0x23ebf,0x23ebf,0x23ed7,0x23ed7,0x23ef7,0x23efc,0x23f35,0x23f35,0x23f41,0x23f41,0x23f4a,0x23f4a,0x23f61,0x23f61,0x23f7f,0x23f82,0x23f8f,0x23f8f,0x23fb4,0x23fb4,0x23fb7,0x23fb7,0x23fc0,0x23fc0,0x23fc5,0x23fc5,0x23feb,0x23ff0,0x24011,0x24011,0x24039,0x2403d,0x24057,0x24057,0x24085,0x24085,0x2408b,0x2408d,0x24091,0x24091,0x240c9,0x240c9,0x240e1,0x240e1,0x240ec,0x240ec,0x24104,0x24104,0x2410f,0x2410f,0x24119,0x24119,0x2413f,0x24140,0x24144,0x24144,0x2414e,0x2414e,0x24155,0x24157,0x2415c,0x2415c,0x2415f,0x2415f,0x24161,0x24161,0x24177,0x24177,0x2417a,0x2417a,0x241a3,0x241a5,0x241ac,0x241ac,0x241b5,0x241b5,0x241cd,0x241cd,0x241e2,0x241e2,0x241fc,0x241fc,0x2421b,0x2421b,0x2424b,0x2424b,0x24256,0x24256,0x24259,0x24259,0x24276,0x24278,0x24284,0x24284,0x24293,0x24293,0x24295,0x24295,0x242a5,0x242a5,0x242bf,0x242bf,0x242c1,0x242c1,0x242c9,0x242ca,0x242ee,0x242ee,0x242fa,0x242fa,0x2430d,0x2430d,0x2431a,0x2431a,0x24334,0x24334,0x24348,0x24348,0x24362,0x24365,0x2438c,0x2438c,0x24396,0x24396,0x2439c,0x2439c,0x243bd,0x243bd,0x243c1,0x243c1,0x243e9,0x243ea,0x243f2,0x243f2,0x243f8,0x243f8,0x24404,0x24404,0x24435,0x24436,0x2445a,0x2445b,0x24473,0x24473,0x24487,0x24488,0x244b9,0x244b9,0x244bc,0x244bc,0x244ce,0x244ce,0x244d3,0x244d3,0x244d6,0x244d6,0x24505,0x24505,0x24521,0x24521,0x24578,0x24578,0x245c8,0x245c8,0x24618,0x24618,0x2462a,0x2462a,0x24665,0x24665,0x24674,0x24674,0x24697,0x24697,0x246d4,0x246d4,0x24706,0x24706,0x24725,0x24725,0x2472f,0x2472f,0x2478f,0x2478f,0x247e0,0x247e0,0x24812,0x24812,0x24823,0x24823,0x24882,0x24882,0x248e9,0x248e9,0x248f0,0x248f3,0x248fb,0x248fb,0x248ff,0x24901,0x2490c,0x2490c,0x24916,0x24917,0x24919,0x24919,0x2492f,0x2492f,0x24933,0x24934,0x2493e,0x24943,0x24962,0x24963,0x24974,0x24976,0x2497b,0x2497b,0x2497f,0x2497f,0x24982,0x24982,0x24988,0x2498f,0x24994,0x24994,0x249a4,0x249a4,0x249a7,0x249a7,0x249a9,0x249a9,0x249ab,0x249ad,0x249b7,0x249bb,0x249c5,0x249c5,0x249d0,0x249d0,0x249da,0x249da,0x249de,0x249df,0x249e3,0x249e3,0x249e5,0x249e5,0x249ec,0x249ed,0x249f6,0x249f9,0x249fb,0x249fb,0x24a0e,0x24a0e,0x24a12,0x24a13,0x24a15,0x24a15,0x24a21,0x24a2a,0x24a3e,0x24a3e,0x24a42,0x24a42,0x24a45,0x24a45,0x24a4a,0x24a4a,0x24a4e,0x24a51,0x24a5d,0x24a5d,0x24a65,0x24a67,0x24a71,0x24a71,0x24a77,0x24a7a,0x24a8c,0x24a8c,0x24a93,0x24a96,0x24aa4,0x24aa7,0x24ab1,0x24ab3,0x24aba,0x24abc,0x24ac0,0x24ac0,0x24ac7,0x24ac7,0x24aca,0x24aca,0x24ad1,0x24ad1,0x24adf,0x24adf,0x24ae2,0x24ae2,0x24ae9,0x24ae9,0x24b0f,0x24b0f,0x24b6e,0x24b6e,0x24bf5,0x24bf5,0x24c09,0x24c09,0x24c9e,0x24c9f,0x24cc9,0x24cc9,0x24cd9,0x24cd9,0x24d06,0x24d06,0x24d13,0x24d13,0x24db8,0x24db8,0x24dea,0x24deb,0x24e3b,0x24e3b,0x24e50,0x24e50,0x24ea5,0x24ea5,0x24ea7,0x24ea7,0x24f0e,0x24f0e,0x24f5c,0x24f5c,0x24f82,0x24f82,0x24f86,0x24f86,0x24f97,0x24f97,0x24f9a,0x24f9a,0x24fa9,0x24fa9,0x24fb8,0x24fb8,0x24fc2,0x24fc2,0x2502c,0x2502c,0x25052,0x25052,0x2509d,0x2509d,0x2512b,0x2512b,0x25148,0x25148,0x2517d,0x2517e,0x251cd,0x251cd,0x251e3,0x251e3,0x251e6,0x251e7,0x25220,0x25221,0x25250,0x25250,0x25299,0x25299,0x252c7,0x252c7,0x252d8,0x252d8,0x2530e,0x2530e,0x25311,0x25311,0x25313,0x25313,0x25419,0x25419,0x25425,0x25425,0x2542f,0x25430,0x25446,0x25446,0x2546c,0x2546c,0x2546e,0x2546e,0x2549a,0x2549a,0x25531,0x25531,0x25535,0x25535,0x2553f,0x2553f,0x2555b,0x2555e,0x25562,0x25562,0x25565,0x25566,0x25581,0x25581,0x25584,0x25584,0x2558f,0x2558f,0x255b9,0x255b9,0x255d5,0x255d5,0x255db,0x255db,0x255e0,0x255e0,0x25605,0x25605,0x25635,0x25635,0x25651,0x25651,0x25683,0x25683,0x25695,0x25695,0x256e3,0x256e3,0x256f6,0x256f6,0x25706,0x25706,0x2571d,0x2571d,0x25725,0x25725,0x2573d,0x2573d,0x25772,0x25772,0x257c7,0x257c7,0x257df,0x257e1,0x25857,0x25857,0x2585d,0x2585d,0x25872,0x25872,0x258c8,0x258c8,0x258de,0x258de,0x258e1,0x258e1,0x25903,0x25903,0x25946,0x25946,0x25956,0x25956,0x259ac,0x259ac,0x259cc,0x259cc,0x25a54,0x25a54,0x25a95,0x25a95,0x25a9c,0x25a9c,0x25aae,0x25aaf,0x25ad7,0x25ad7,0x25ae9,0x25ae9,0x25b74,0x25b74,0x25b89,0x25b89,0x25bb3,0x25bb4,0x25bc6,0x25bc6,0x25be4,0x25be4,0x25be8,0x25be8,0x25c01,0x25c01,0x25c06,0x25c06,0x25c21,0x25c21,0x25c4a,0x25c4a,0x25c65,0x25c65,0x25c91,0x25c91,0x25ca4,0x25ca4,0x25cc0,0x25cc1,0x25cfe,0x25cfe,0x25d20,0x25d20,0x25d30,0x25d30,0x25d43,0x25d43,0x25d99,0x25d99,0x25db9,0x25db9,0x25e0e,0x25e0e,0x25e49,0x25e49,0x25e81,0x25e83,0x25ea6,0x25ea6,0x25ebc,0x25ebc,0x25ed7,0x25ed8,0x25f1a,0x25f1a,0x25f4b,0x25f4b,0x25fe1,0x25fe2,0x26021,0x26021,0x26029,0x26029,0x26048,0x26048,0x26064,0x26064,0x26083,0x26083,0x26097,0x26097,0x260a4,0x260a5,0x26102,0x26102,0x26121,0x26121,0x26159,0x2615c,0x261ad,0x261ae,0x261b2,0x261b2,0x261dd,0x261dd,0x26258,0x26258,0x26261,0x26261,0x2626a,0x2626b,0x262d0,0x262d0,0x26335,0x26335,0x2634b,0x2634c,0x26351,0x26351,0x263be,0x263be,0x263f5,0x263f5,0x263f8,0x263f8,0x26402,0x26402,0x26410,0x26412,0x2644a,0x2644a,0x26469,0x26469,0x26484,0x26484,0x26488,0x26489,0x2648d,0x2648d,0x26498,0x26498,0x26512,0x26512,0x26572,0x26572,0x265a0,0x265a0,0x265ad,0x265ad,0x265bf,0x265bf,0x26612,0x26612,0x26626,0x26626,0x266af,0x266af,0x266b1,0x266b1,0x266b5,0x266b5,0x266da,0x266da,0x266e8,0x266e8,0x266fc,0x266fc,0x26716,0x26716,0x26741,0x26741,0x26799,0x26799,0x267b3,0x267b4,0x267cc,0x267cc,0x2681c,0x2681c,0x26846,0x26846,0x2685e,0x2685e,0x2686e,0x2686e,0x26888,0x26888,0x2688a,0x2688a,0x26893,0x26893,0x268c7,0x268c7,0x2690e,0x2690e,0x26911,0x26911,0x26926,0x26926,0x26939,0x26939,0x26951,0x26951,0x269a8,0x269a8,0x269b5,0x269b5,0x269f2,0x269f2,0x269fa,0x269fa,0x26a2d,0x26a2e,0x26a34,0x26a34,0x26a42,0x26a42,0x26a51,0x26a52,0x26b05,0x26b05,0x26b0a,0x26b0a,0x26b13,0x26b13,0x26b15,0x26b15,0x26b23,0x26b23,0x26b28,0x26b28,0x26b50,0x26b53,0x26b5b,0x26b5b,0x26b75,0x26b75,0x26b82,0x26b82,0x26b96,0x26b97,0x26b9d,0x26b9d,0x26bb3,0x26bb3,0x26bc0,0x26bc0,0x26bf7,0x26bf7,0x26c21,0x26c21,0x26c40,0x26c41,0x26c46,0x26c46,0x26c7e,0x26c82,0x26ca4,0x26ca4,0x26cb7,0x26cb8,0x26cbd,0x26cbd,0x26cc0,0x26cc0,0x26cc3,0x26cc3,0x26cd1,0x26cd1,0x26d22,0x26d2a,0x26d51,0x26d51,0x26d74,0x26d74,0x26da0,0x26da7,0x26dae,0x26dae,0x26ddc,0x26ddc,0x26dea,0x26deb,0x26df0,0x26df0,0x26e00,0x26e00,0x26e05,0x26e05,0x26e07,0x26e07,0x26e12,0x26e12,0x26e42,0x26e45,0x26e6e,0x26e6e,0x26e72,0x26e72,0x26e77,0x26e77,0x26e84,0x26e84,0x26e88,0x26e88,0x26e8b,0x26e8b,0x26e99,0x26e99,0x26ed0,0x26ed7,0x26f26,0x26f26,0x26f73,0x26f74,0x26f9f,0x26f9f,0x26fa1,0x26fa1,0x26fbe,0x26fbe,0x26fde,0x26fdf,0x2700e,0x2700e,0x2704b,0x2704b,0x27052,0x27053,0x27088,0x27088,0x270ad,0x270af,0x270cd,0x270cd,0x270d2,0x270d2,0x270f0,0x270f0,0x270f8,0x270f8,0x27109,0x27109,0x2710c,0x2710d,0x27126,0x27127,0x27164,0x27165,0x27175,0x27175,0x271cd,0x271cd,0x2721b,0x2721b,0x27267,0x27267,0x27280,0x27280,0x27285,0x27285,0x2728b,0x2728b,0x272b2,0x272b2,0x272b6,0x272b6,0x272e6,0x272e6,0x27352,0x27352,0x2739a,0x2739a,0x273ff,0x273ff,0x27422,0x27422,0x27450,0x27450,0x27484,0x27484,0x27486,0x27486,0x27574,0x27574,0x275a3,0x275a3,0x275e0,0x275e0,0x275e4,0x275e4,0x275fd,0x275fe,0x27607,0x27607,0x2760c,0x2760c,0x27632,0x27632,0x27639,0x27639,0x27655,0x27657,0x27694,0x27694,0x2770f,0x2770f,0x27735,0x27736,0x27741,0x27741,0x2775e,0x2775e,0x27784,0x27785,0x277cc,0x277cc,0x27858,0x27858,0x27870,0x27870,0x2789d,0x2789d,0x278b2,0x278b2,0x278c8,0x278c8,0x27924,0x27924,0x27967,0x27967,0x2797a,0x2797a,0x279a0,0x279a0,0x279dd,0x279dd,0x279fd,0x279fd,0x27a0a,0x27a0a,0x27a0e,0x27a0e,0x27a3e,0x27a3e,0x27a53,0x27a53,0x27a59,0x27a59,0x27a79,0x27a79,0x27a84,0x27a84,0x27abd,0x27abe,0x27af4,0x27af4,0x27b06,0x27b06,0x27b0b,0x27b0b,0x27b18,0x27b18,0x27b38,0x27b3a,0x27b48,0x27b48,0x27b65,0x27b65,0x27bef,0x27bef,0x27bf4,0x27bf4,0x27c12,0x27c12,0x27c6c,0x27c6c,0x27cb1,0x27cb1,0x27cc5,0x27cc5,0x27d2f,0x27d2f,0x27d53,0x27d54,0x27d66,0x27d66,0x27d73,0x27d73,0x27d84,0x27d84,0x27d8f,0x27d8f,0x27d98,0x27d98,0x27dbd,0x27dbd,0x27ddc,0x27ddc,0x27e4d,0x27e4d,0x27e4f,0x27e4f,0x27f2e,0x27f2e,0x27fb7,0x27fb7,0x27ff9,0x27ff9,0x28002,0x28002,0x28009,0x28009,0x2801e,0x2801e,0x28023,0x28024,0x28048,0x28048,0x28083,0x28083,0x28090,0x28090,0x280bd,0x280be,0x280e8,0x280e9,0x280f4,0x280f4,0x2812e,0x2812e,0x2814f,0x2814f,0x2815d,0x2815d,0x2816f,0x2816f,0x28189,0x28189,0x281af,0x281af,0x281bc,0x281bc,0x28207,0x28207,0x28218,0x28218,0x2821a,0x2821a,0x28256,0x28256,0x2827c,0x2827c,0x2829b,0x2829b,0x282cd,0x282cd,0x282e2,0x282e2,0x28306,0x28306,0x28318,0x28318,0x2832f,0x2832f,0x2833a,0x2833a,0x28365,0x28365,0x2836d,0x2836d,0x2837d,0x2837d,0x2838a,0x2838a,0x28412,0x28412,0x28468,0x28468,0x2846c,0x2846c,0x28473,0x28473,0x28482,0x28482,0x28501,0x28501,0x2853c,0x2853d,0x2856c,0x2856c,0x285e8,0x285e8,0x285f4,0x285f4,0x28600,0x28600,0x2860b,0x2860b,0x28625,0x28625,0x2863b,0x2863b,0x286aa,0x286ab,0x286b2,0x286b2,0x286bc,0x286bc,0x286d8,0x286d8,0x286e6,0x286e6,0x2870f,0x2870f,0x28713,0x28713,0x28804,0x28804,0x2882b,0x2882b,0x2890d,0x2890d,0x28933,0x28933,0x28948,0x28949,0x28956,0x28956,0x28964,0x28964,0x28968,0x28968,0x2896c,0x2896d,0x2897e,0x2897e,0x28989,0x28989,0x289a8,0x289a8,0x289aa,0x289ab,0x289b8,0x289b8,0x289bc,0x289bc,0x289c0,0x289c0,0x289dc,0x289dc,0x289de,0x289de,0x289e1,0x289e1,0x289e3,0x289e4,0x289e7,0x289e8,0x289f9,0x289fc,0x28a0f,0x28a0f,0x28a16,0x28a16,0x28a25,0x28a25,0x28a29,0x28a29,0x28a32,0x28a32,0x28a36,0x28a36,0x28a44,0x28a4b,0x28a59,0x28a5a,0x28a81,0x28a83,0x28a9a,0x28a9c,0x28ac0,0x28ac0,0x28ac6,0x28ac6,0x28acb,0x28acc,0x28ace,0x28ace,0x28ade,0x28ae3,0x28ae5,0x28ae5,0x28aea,0x28aea,0x28afc,0x28afc,0x28b0c,0x28b0c,0x28b13,0x28b13,0x28b21,0x28b22,0x28b2b,0x28b2d,0x28b2f,0x28b2f,0x28b46,0x28b46,0x28b4c,0x28b4c,0x28b4e,0x28b4e,0x28b50,0x28b50,0x28b63,0x28b66,0x28b6c,0x28b6c,0x28b8f,0x28b8f,0x28b99,0x28b99,0x28b9c,0x28b9d,0x28bb9,0x28bb9,0x28bc2,0x28bc2,0x28bc5,0x28bc5,0x28bd4,0x28bd4,0x28bd7,0x28bd7,0x28bd9,0x28bda,0x28be7,0x28bec,0x28bf5,0x28bf5,0x28bff,0x28bff,0x28c03,0x28c03,0x28c09,0x28c09,0x28c1c,0x28c1d,0x28c23,0x28c23,0x28c26,0x28c26,0x28c2b,0x28c2b,0x28c30,0x28c30,0x28c39,0x28c39,0x28c3b,0x28c3b,0x28cca,0x28cca,0x28ccd,0x28ccd,0x28cd2,0x28cd2,0x28d34,0x28d34,0x28d99,0x28d99,0x28db9,0x28db9,0x28e0f,0x28e0f,0x28e36,0x28e36,0x28e39,0x28e39,0x28e65,0x28e66,0x28e97,0x28e97,0x28eac,0x28eac,0x28eb2,0x28eb3,0x28ed9,0x28ed9,0x28ee7,0x28ee7,0x28fc5,0x28fc5,0x29079,0x29079,0x29088,0x29088,0x2908b,0x2908b,0x29093,0x29093,0x290af,0x290b1,0x290c0,0x290c0,0x290e4,0x290e5,0x290ec,0x290ed,0x2910d,0x2910d,0x29110,0x29110,0x2913c,0x2913c,0x2914d,0x2914d,0x2915b,0x2915b,0x2915e,0x2915e,0x29170,0x29170,0x2919c,0x2919c,0x291a8,0x291a8,0x291d5,0x291d5,0x291eb,0x291eb,0x2941d,0x2941d,0x29420,0x29420,0x29433,0x29433,0x2943f,0x2943f,0x29448,0x29448,0x294d0,0x294d0,0x294d9,0x294da,0x294e5,0x294e5,0x294e7,0x294e7,0x2959e,0x2959e,0x295b0,0x295b0,0x295b8,0x295b8,0x295d7,0x295d7,0x295e9,0x295e9,0x295f4,0x295f4,0x2967f,0x2967f,0x29720,0x29720,0x29732,0x29732,0x297d4,0x297d4,0x29810,0x29810,0x29857,0x29857,0x298a4,0x298a4,0x298d1,0x298d1,0x298ea,0x298ea,0x298f1,0x298f1,0x298fa,0x298fa,0x29903,0x29903,0x29905,0x29905,0x2992f,0x2992f,0x29945,0x29945,0x29947,0x29949,0x2995d,0x2995d,0x2996a,0x2996a,0x2999d,0x2999d,0x299c3,0x299c3,0x299c9,0x299c9,0x29a28,0x29a28,0x29a4d,0x29a4d,0x29b05,0x29b05,0x29b0e,0x29b0e,0x29bd5,0x29bd5,0x29c73,0x29c73,0x29cad,0x29cad,0x29d3e,0x29d3e,0x29d5a,0x29d5a,0x29d7c,0x29d7c,0x29d98,0x29d98,0x29d9b,0x29d9b,0x29df6,0x29df6,0x29e06,0x29e06,0x29e2d,0x29e2d,0x29e68,0x29e68,0x29eac,0x29eac,0x29eb0,0x29eb0,0x29ec3,0x29ec3,0x29ef8,0x29ef8,0x29f23,0x29f23,0x29f30,0x29f30,0x29fb7,0x29fb7,0x29fde,0x29fde,0x2a014,0x2a014,0x2a087,0x2a087,0x2a0b9,0x2a0b9,0x2a0e1,0x2a0e1,0x2a0ed,0x2a0ed,0x2a0f3,0x2a0f3,0x2a0f8,0x2a0f8,0x2a0fe,0x2a0fe,0x2a107,0x2a107,0x2a123,0x2a123,0x2a133,0x2a134,0x2a150,0x2a150,0x2a192,0x2a193,0x2a1ab,0x2a1ab,0x2a1b4,0x2a1b5,0x2a1df,0x2a1df,0x2a1f5,0x2a1f5,0x2a220,0x2a220,0x2a233,0x2a233,0x2a293,0x2a293,0x2a29f,0x2a29f,0x2a2b2,0x2a2b2,0x2a2b4,0x2a2b4,0x2a2b6,0x2a2b6,0x2a2ba,0x2a2ba,0x2a2bd,0x2a2bd,0x2a2df,0x2a2df,0x2a2ff,0x2a2ff,0x2a351,0x2a351,0x2a3a9,0x2a3a9,0x2a3ed,0x2a3ed,0x2a434,0x2a434,0x2a45b,0x2a45b,0x2a5c6,0x2a5c6,0x2a5cb,0x2a5cb,0x2a601,0x2a601,0x2a632,0x2a632,0x2a64a,0x2a64a,0x2a65b,0x2a65b,0x2a6a9,0x2a6a9,0x2adff,0x2adff,0x2d544,0x2d544,0x2f825,0x2f825,0x2f83b,0x2f83b,0x2f840,0x2f840,0x2f878,0x2f878,0x2f894,0x2f894,0x2f8a6,0x2f8a6,0x2f8cd,0x2f8cd,0x2f8db,0x2f8db,0x2f994,0x2f994,0x2f9b2,0x2f9b2,0x2f9bc,0x2f9bc,0x2f9d4,0x2f9d4,0x30ede,0x30ede,0x3106c,0x3106c,]), - NotoFont.fromFlatRanges('Noto Sans Hanunoo', 'http://fonts.gstatic.com/s/notosanshanunoo/v15/f0Xs0fCv8dxkDWlZSoXOj6CphMloFsEsEpgL_ix2.ttf', [0x20,0x20,0xa0,0xa0,0x1720,0x1736,0x200b,0x200d,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Hatran', 'http://fonts.gstatic.com/s/notosanshatran/v15/A2BBn4Ne0RgnVF3Lnko-0sOBIfL_mM83r1nwzDs.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200c,0x108e0,0x108f2,0x108f4,0x108f5,0x108fb,0x108ff,]), - NotoFont.fromFlatRanges('Noto Sans Hebrew', 'http://fonts.gstatic.com/s/notosanshebrew/v38/or3HQ7v33eiDljA1IufXTtVf7V6RvEEdhQlk0LlGxCyaeNKYZC0sqk3xXGiXd4qtoiJltutR2g.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x34f,0x34f,0x591,0x5c7,0x5d0,0x5ea,0x5f0,0x5f4,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200c,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20aa,0x20aa,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xfb1d,0xfb36,0xfb38,0xfb3c,0xfb3e,0xfb3e,0xfb40,0xfb41,0xfb43,0xfb44,0xfb46,0xfb4f,]), - NotoFont.fromFlatRanges('Noto Sans Imperial Aramaic', 'http://fonts.gstatic.com/s/notosansimperialaramaic/v15/a8IMNpjwKmHXpgXbMIsbTc_kvks91LlLetBr5itQrtdml3YfPNno.ttf', [0x20,0x20,0xa0,0xa0,0x10840,0x10855,0x10857,0x1085f,]), - NotoFont.fromFlatRanges('Noto Sans Indic Siyaq Numbers', 'http://fonts.gstatic.com/s/notosansindicsiyaqnumbers/v15/6xK5dTJFKcWIu4bpRBjRZRpsIYHabOeZ8UZLubTzpXNHKx2WPOpVd5Iu.ttf', [0x20,0x20,0xa0,0xa0,0x627,0x627,0x660,0x669,0x6f0,0x6f9,0x1ec71,0x1ecb4,]), - NotoFont.fromFlatRanges('Noto Sans Inscriptional Pahlavi', 'http://fonts.gstatic.com/s/notosansinscriptionalpahlavi/v15/ll8UK3GaVDuxR-TEqFPIbsR79Xxz9WEKbwsjpz7VklYlC7FCVtqVOAYK0QA.ttf', [0x20,0x20,0xa0,0xa0,0x10b60,0x10b72,0x10b78,0x10b7f,]), - NotoFont.fromFlatRanges('Noto Sans Inscriptional Parthian', 'http://fonts.gstatic.com/s/notosansinscriptionalparthian/v15/k3k7o-IMPvpLmixcA63oYi-yStDkgXuXncL7dzfW3P4TAJ2yklBJ2jNkLlLr.ttf', [0x20,0x20,0xa0,0xa0,0x10b40,0x10b55,0x10b58,0x10b5f,]), - NotoFont.fromFlatRanges('Noto Sans JP', 'http://fonts.gstatic.com/s/notosansjp/v42/-F62fjtqLzI2JPCgQBnw7HFowAIO2lZ9hg.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x3402,0x3402,0x3405,0x3406,0x3427,0x3427,0x342c,0x342c,0x342e,0x342e,0x3468,0x3468,0x346a,0x346a,0x3488,0x3488,0x3492,0x3492,0x34b5,0x34b5,0x34bc,0x34bc,0x34c1,0x34c1,0x34c7,0x34c7,0x34db,0x34db,0x351f,0x351f,0x353e,0x353e,0x355d,0x355e,0x3563,0x3563,0x356e,0x356e,0x35a6,0x35a6,0x35a8,0x35a8,0x35c5,0x35c5,0x35da,0x35da,0x35de,0x35de,0x35f4,0x35f4,0x3605,0x3605,0x3614,0x3614,0x364a,0x364a,0x3691,0x3691,0x3696,0x3696,0x3699,0x3699,0x36cf,0x36cf,0x3761,0x3762,0x376b,0x376c,0x3775,0x3775,0x378d,0x378d,0x37c1,0x37c1,0x37e2,0x37e2,0x37e8,0x37e8,0x37f4,0x37f4,0x37fd,0x37fd,0x3800,0x3800,0x382f,0x382f,0x3836,0x3836,0x3840,0x3840,0x385c,0x385c,0x3861,0x3861,0x38a1,0x38a1,0x38ad,0x38ad,0x38fa,0x38fa,0x3917,0x3917,0x391a,0x391a,0x396f,0x396f,0x39a4,0x39a4,0x39b8,0x39b8,0x3a5c,0x3a5c,0x3a6e,0x3a6e,0x3a73,0x3a73,0x3a85,0x3a85,0x3ac4,0x3ac4,0x3acb,0x3acb,0x3ad6,0x3ad7,0x3aea,0x3aea,0x3af3,0x3af3,0x3b0e,0x3b0e,0x3b1a,0x3b1a,0x3b1c,0x3b1c,0x3b22,0x3b22,0x3b35,0x3b35,0x3b6d,0x3b6d,0x3b77,0x3b77,0x3b87,0x3b88,0x3b8d,0x3b8d,0x3ba4,0x3ba4,0x3bb6,0x3bb6,0x3bc3,0x3bc3,0x3bcd,0x3bcd,0x3bf0,0x3bf0,0x3bf3,0x3bf3,0x3c0f,0x3c0f,0x3c26,0x3c26,0x3cc3,0x3cc3,0x3cd2,0x3cd2,0x3d11,0x3d11,0x3d1e,0x3d1e,0x3d31,0x3d31,0x3d4e,0x3d4e,0x3d64,0x3d64,0x3d9a,0x3d9a,0x3dc0,0x3dc0,0x3dcc,0x3dcc,0x3dd4,0x3dd4,0x3e05,0x3e05,0x3e3f,0x3e40,0x3e60,0x3e60,0x3e66,0x3e66,0x3e68,0x3e68,0x3e83,0x3e83,0x3e8a,0x3e8a,0x3e94,0x3e94,0x3eda,0x3eda,0x3f57,0x3f57,0x3f72,0x3f72,0x3f75,0x3f75,0x3f77,0x3f77,0x3fae,0x3fae,0x3fb1,0x3fb1,0x3fc9,0x3fc9,0x3fd7,0x3fd7,0x3fdc,0x3fdc,0x4039,0x4039,0x4058,0x4058,0x4093,0x4093,0x4103,0x4103,0x4105,0x4105,0x4148,0x4148,0x414f,0x414f,0x4163,0x4163,0x41b4,0x41b4,0x41bf,0x41bf,0x41e6,0x41e6,0x41ee,0x41ee,0x41f3,0x41f3,0x4207,0x4207,0x420e,0x420e,0x4264,0x4264,0x4293,0x4293,0x42c6,0x42c6,0x42d6,0x42d6,0x42dd,0x42dd,0x4302,0x4302,0x432b,0x432b,0x4343,0x4343,0x43ee,0x43ee,0x43f0,0x43f0,0x4408,0x4408,0x440c,0x440c,0x4417,0x4417,0x441c,0x441c,0x4422,0x4422,0x4453,0x4453,0x445b,0x445b,0x4476,0x4476,0x447a,0x447a,0x4491,0x4491,0x44b3,0x44b3,0x44be,0x44be,0x44d4,0x44d4,0x4508,0x4508,0x450d,0x450d,0x4525,0x4525,0x4543,0x4543,0x457a,0x457a,0x459d,0x459d,0x45b8,0x45b8,0x45be,0x45be,0x45e5,0x45e5,0x45ea,0x45ea,0x460f,0x4610,0x4641,0x4641,0x4665,0x4665,0x46a1,0x46a1,0x46ae,0x46af,0x470c,0x470c,0x471f,0x471f,0x4764,0x4764,0x47e6,0x47e6,0x47fd,0x47fd,0x4816,0x4816,0x481e,0x481e,0x4844,0x4844,0x484e,0x484e,0x48b5,0x48b5,0x49b0,0x49b0,0x49e7,0x49e7,0x49fa,0x49fa,0x4a04,0x4a04,0x4a29,0x4a29,0x4abc,0x4abc,0x4b38,0x4b38,0x4b3b,0x4b3b,0x4b7e,0x4b7e,0x4bc2,0x4bc2,0x4bca,0x4bca,0x4bd2,0x4bd2,0x4be8,0x4be8,0x4c17,0x4c17,0x4c20,0x4c20,0x4c38,0x4c38,0x4cc4,0x4cc4,0x4cd1,0x4cd1,0x4ce1,0x4ce1,0x4d07,0x4d07,0x4d77,0x4d77,0x4e00,0x4e05,0x4e07,0x4e12,0x4e14,0x4e19,0x4e1e,0x4e1f,0x4e21,0x4e21,0x4e23,0x4e24,0x4e26,0x4e26,0x4e28,0x4e32,0x4e35,0x4e39,0x4e3b,0x4e3c,0x4e3f,0x4e45,0x4e47,0x4e48,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e51,0x4e51,0x4e55,0x4e5f,0x4e62,0x4e63,0x4e68,0x4e69,0x4e71,0x4e71,0x4e73,0x4e75,0x4e79,0x4e79,0x4e7e,0x4e80,0x4e82,0x4e82,0x4e85,0x4e86,0x4e88,0x4e8e,0x4e91,0x4e92,0x4e94,0x4e99,0x4e9b,0x4ea2,0x4ea4,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eb0,0x4eb3,0x4eb3,0x4eb6,0x4eb6,0x4eb9,0x4ebc,0x4ec0,0x4ec4,0x4ec6,0x4ec8,0x4eca,0x4ecb,0x4ecd,0x4ed0,0x4ed4,0x4edb,0x4edd,0x4ee5,0x4ee8,0x4ee8,0x4eeb,0x4eeb,0x4eed,0x4ef3,0x4ef5,0x4ef7,0x4efb,0x4f03,0x4f08,0x4f12,0x4f15,0x4f17,0x4f19,0x4f1a,0x4f1c,0x4f1d,0x4f2b,0x4f2b,0x4f2e,0x4f31,0x4f33,0x4f3e,0x4f40,0x4f40,0x4f42,0x4f43,0x4f46,0x4f49,0x4f4b,0x4f60,0x4f63,0x4f64,0x4f69,0x4f6a,0x4f6c,0x4f6c,0x4f6e,0x4f71,0x4f73,0x4f73,0x4f75,0x4f7f,0x4f81,0x4f86,0x4f88,0x4f94,0x4f96,0x4f9b,0x4f9d,0x4fa1,0x4fab,0x4fab,0x4fad,0x4faf,0x4fb2,0x4fb2,0x4fb5,0x4fb7,0x4fb9,0x4fb9,0x4fbb,0x4fc6,0x4fc8,0x4fd4,0x4fd7,0x4fd8,0x4fda,0x4fdd,0x4fdf,0x4fe6,0x4fee,0x4ff3,0x4ff5,0x4ff6,0x4ff8,0x4ff8,0x4ffa,0x4ffa,0x4ffc,0x5002,0x5004,0x5007,0x5009,0x5014,0x5016,0x501f,0x5021,0x502e,0x5030,0x5030,0x5032,0x5033,0x5035,0x5036,0x5039,0x5039,0x503b,0x503b,0x5040,0x5043,0x5045,0x504a,0x504c,0x504c,0x504e,0x5053,0x5055,0x5057,0x5059,0x505a,0x505c,0x505c,0x505f,0x5060,0x5062,0x5063,0x5065,0x5067,0x506a,0x506a,0x506c,0x506d,0x5070,0x5072,0x5074,0x5078,0x507d,0x507d,0x5080,0x5081,0x5083,0x5086,0x5088,0x5088,0x508a,0x508a,0x508d,0x5096,0x5098,0x509c,0x509e,0x50a3,0x50aa,0x50aa,0x50ac,0x50ad,0x50af,0x50b5,0x50b7,0x50b7,0x50b9,0x50bb,0x50bd,0x50be,0x50c0,0x50c0,0x50c2,0x50c5,0x50c7,0x50c7,0x50c9,0x50ca,0x50cc,0x50d1,0x50d3,0x50d6,0x50d8,0x50da,0x50dc,0x50df,0x50e1,0x50e9,0x50ed,0x50f6,0x50f9,0x50fb,0x50fe,0x50fe,0x5100,0x5104,0x5106,0x5109,0x510b,0x510e,0x5110,0x5110,0x5112,0x5112,0x5114,0x511f,0x5121,0x5121,0x5123,0x5123,0x5127,0x5128,0x512a,0x512a,0x512c,0x512d,0x512f,0x512f,0x5131,0x5135,0x5137,0x513c,0x513f,0x5150,0x5152,0x5155,0x5157,0x5158,0x515a,0x515a,0x515c,0x515c,0x515f,0x5160,0x5162,0x5162,0x5164,0x516e,0x5171,0x5171,0x5173,0x5179,0x517b,0x517c,0x517e,0x517e,0x5180,0x5180,0x5182,0x5186,0x5189,0x5193,0x5195,0x5199,0x519d,0x519d,0x51a0,0x51a6,0x51a8,0x51ad,0x51b0,0x51b8,0x51ba,0x51ba,0x51bc,0x51bf,0x51c2,0x51c6,0x51c8,0x51cd,0x51cf,0x51cf,0x51d1,0x51d6,0x51d8,0x51d8,0x51db,0x51e2,0x51e5,0x51e7,0x51e9,0x51ea,0x51ec,0x51ee,0x51f0,0x51fa,0x51fd,0x51fe,0x5200,0x5208,0x520a,0x520b,0x520e,0x520e,0x5211,0x5218,0x521d,0x521d,0x5222,0x5222,0x5224,0x522b,0x522e,0x522e,0x5230,0x5233,0x5235,0x523c,0x5243,0x5245,0x5247,0x5247,0x5249,0x524d,0x524f,0x524f,0x5254,0x5258,0x525a,0x5261,0x5263,0x5266,0x5269,0x526a,0x526c,0x526c,0x526e,0x5275,0x5277,0x5279,0x527d,0x527d,0x527f,0x5280,0x5282,0x5285,0x5287,0x528a,0x528c,0x528d,0x5291,0x5298,0x529a,0x529c,0x529f,0x52a0,0x52a3,0x52a7,0x52a9,0x52ad,0x52af,0x52b1,0x52b4,0x52be,0x52c0,0x52c1,0x52c3,0x52ca,0x52cc,0x52cd,0x52cf,0x52d2,0x52d4,0x52d9,0x52db,0x52ea,0x52ec,0x52ec,0x52f0,0x52fb,0x52fe,0x5303,0x5305,0x5308,0x530a,0x530d,0x530f,0x5311,0x5313,0x5313,0x5315,0x5321,0x5323,0x5325,0x5327,0x532d,0x532f,0x5333,0x5335,0x5335,0x5338,0x5343,0x5345,0x534d,0x5351,0x5354,0x5357,0x535c,0x535e,0x535e,0x5360,0x5361,0x5363,0x5367,0x5369,0x5369,0x536c,0x5375,0x5377,0x537b,0x537d,0x537f,0x5382,0x5384,0x5387,0x5389,0x538e,0x538e,0x5393,0x5394,0x5396,0x5396,0x5398,0x539a,0x539d,0x539d,0x539f,0x53a1,0x53a4,0x53a6,0x53a8,0x53ab,0x53ad,0x53b0,0x53b2,0x53b8,0x53ba,0x53bb,0x53bd,0x53bd,0x53c0,0x53c5,0x53c8,0x53cf,0x53d2,0x53d7,0x53d9,0x53db,0x53dd,0x53f8,0x53fa,0x53fa,0x5401,0x5404,0x5408,0x5413,0x541a,0x541b,0x541d,0x5421,0x5424,0x5424,0x5426,0x542f,0x5431,0x5431,0x5433,0x5436,0x5438,0x5439,0x543b,0x5440,0x5442,0x5444,0x5446,0x544a,0x544c,0x544f,0x5451,0x5451,0x5455,0x5455,0x545e,0x545f,0x5462,0x5462,0x5464,0x5464,0x5466,0x546e,0x5470,0x5471,0x5473,0x5477,0x547b,0x547d,0x547f,0x5481,0x5483,0x5486,0x5488,0x5492,0x5495,0x5496,0x549c,0x549c,0x549f,0x54a2,0x54a4,0x54af,0x54b1,0x54b3,0x54b7,0x54c4,0x54c6,0x54ca,0x54cd,0x54ce,0x54d8,0x54d8,0x54e0,0x54e2,0x54e5,0x54e6,0x54e8,0x54ea,0x54ec,0x54ef,0x54f1,0x54f3,0x54f6,0x54f6,0x54fa,0x54fa,0x54fc,0x5501,0x5504,0x5509,0x550c,0x5510,0x5514,0x5516,0x5527,0x5527,0x552a,0x552b,0x552e,0x552f,0x5531,0x5533,0x5535,0x5536,0x5538,0x5539,0x553b,0x553e,0x5540,0x5541,0x5544,0x5547,0x5549,0x554a,0x554c,0x554d,0x554f,0x5551,0x5553,0x5553,0x5556,0x5558,0x555a,0x555e,0x5560,0x5561,0x5563,0x5564,0x5566,0x5566,0x557b,0x5584,0x5586,0x558b,0x558e,0x558f,0x5591,0x5594,0x5597,0x559a,0x559c,0x559f,0x55a3,0x55a4,0x55a7,0x55ae,0x55b0,0x55b0,0x55b2,0x55b2,0x55b6,0x55b6,0x55bf,0x55bf,0x55c1,0x55c1,0x55c3,0x55c7,0x55c9,0x55c9,0x55cb,0x55cc,0x55ce,0x55ce,0x55d1,0x55d4,0x55d7,0x55d8,0x55da,0x55df,0x55e2,0x55e4,0x55e9,0x55e9,0x55ec,0x55ec,0x55ee,0x55ee,0x55f1,0x55f1,0x55f6,0x55f9,0x55fd,0x55ff,0x5605,0x560a,0x560d,0x5612,0x5614,0x5614,0x5616,0x5619,0x561b,0x561b,0x5620,0x5620,0x5628,0x5629,0x562c,0x562c,0x562f,0x5639,0x563b,0x563d,0x563f,0x5644,0x5646,0x5647,0x5649,0x5649,0x564b,0x5650,0x5653,0x5654,0x565b,0x565b,0x565e,0x565e,0x5660,0x5664,0x5666,0x5666,0x5668,0x566d,0x566f,0x566f,0x5671,0x5672,0x5674,0x5676,0x5678,0x5678,0x567a,0x567a,0x5680,0x5680,0x5684,0x5688,0x568a,0x568c,0x568f,0x568f,0x5694,0x5695,0x5699,0x569a,0x569d,0x56a0,0x56a2,0x56a2,0x56a5,0x56a9,0x56ab,0x56ae,0x56b1,0x56b4,0x56b6,0x56b7,0x56bc,0x56bc,0x56be,0x56be,0x56c0,0x56c3,0x56c5,0x56c5,0x56c8,0x56d1,0x56d3,0x56d3,0x56d7,0x56e1,0x56e3,0x56e8,0x56eb,0x56eb,0x56ed,0x56ee,0x56f0,0x56f3,0x56f6,0x56f7,0x56f9,0x56fa,0x56fd,0x56fd,0x56ff,0x5704,0x5707,0x570d,0x570f,0x570f,0x5711,0x5713,0x5715,0x5716,0x5718,0x5718,0x571a,0x571d,0x571f,0x572a,0x572c,0x5730,0x5733,0x5734,0x5737,0x5738,0x573b,0x573b,0x573d,0x5740,0x5742,0x5742,0x5745,0x5747,0x574a,0x574a,0x574c,0x5752,0x5759,0x5759,0x575f,0x575f,0x5761,0x5762,0x5764,0x576b,0x576d,0x5771,0x5773,0x5775,0x5777,0x5777,0x5779,0x577c,0x577e,0x577f,0x5781,0x5783,0x5788,0x5789,0x578b,0x578c,0x5793,0x5795,0x5797,0x5797,0x5799,0x579a,0x579c,0x57a4,0x57a7,0x57aa,0x57ac,0x57ac,0x57ae,0x57ae,0x57b0,0x57b0,0x57b3,0x57b3,0x57b8,0x57b8,0x57bd,0x57bd,0x57c0,0x57c0,0x57c3,0x57c3,0x57c6,0x57c8,0x57cb,0x57cc,0x57ce,0x57cf,0x57d2,0x57d7,0x57dc,0x57e1,0x57e3,0x57e4,0x57e6,0x57e7,0x57e9,0x57e9,0x57ed,0x57ed,0x57f0,0x57f0,0x57f4,0x5800,0x5802,0x5806,0x5808,0x580d,0x5815,0x5815,0x5819,0x5819,0x581b,0x581b,0x581d,0x5821,0x5824,0x5824,0x5826,0x5827,0x582a,0x582a,0x582d,0x582d,0x582f,0x5832,0x5834,0x5835,0x5839,0x583a,0x583d,0x583d,0x583f,0x5841,0x5849,0x584d,0x584f,0x5852,0x5854,0x5855,0x5857,0x585a,0x585e,0x585f,0x5861,0x5862,0x5864,0x5864,0x5867,0x5869,0x586b,0x586b,0x586d,0x586d,0x5870,0x5870,0x5872,0x5872,0x5875,0x5875,0x5878,0x5879,0x587c,0x587c,0x587e,0x5881,0x5883,0x5883,0x5885,0x5885,0x5887,0x588d,0x588f,0x5890,0x5893,0x5894,0x5896,0x5898,0x589c,0x58a2,0x58a6,0x58a6,0x58a8,0x58ab,0x58ae,0x58ae,0x58b1,0x58b3,0x58b8,0x58bc,0x58be,0x58be,0x58c1,0x58c5,0x58c7,0x58c8,0x58ca,0x58ca,0x58cc,0x58ce,0x58d0,0x58da,0x58dc,0x58e2,0x58e4,0x58e5,0x58e9,0x58e9,0x58eb,0x58ec,0x58ee,0x58f4,0x58f7,0x58f7,0x58f9,0x58fd,0x5902,0x5902,0x5905,0x5906,0x5909,0x590d,0x590f,0x5910,0x5912,0x5916,0x5918,0x591d,0x591f,0x591f,0x5921,0x5925,0x5927,0x5933,0x5935,0x5939,0x593d,0x593f,0x5943,0x5944,0x5946,0x5949,0x594e,0x5955,0x5957,0x595b,0x595d,0x5963,0x5965,0x5965,0x5967,0x596f,0x5972,0x5976,0x5978,0x5979,0x597b,0x597d,0x5981,0x5984,0x598a,0x598e,0x5992,0x5993,0x5995,0x5997,0x5999,0x5999,0x599b,0x599b,0x599d,0x599d,0x599f,0x599f,0x59a3,0x59a5,0x59a7,0x59a8,0x59ac,0x59b0,0x59b2,0x59b3,0x59b7,0x59b7,0x59b9,0x59bc,0x59be,0x59be,0x59c1,0x59c1,0x59c3,0x59c4,0x59c6,0x59c6,0x59c8,0x59cb,0x59cd,0x59cd,0x59d0,0x59d4,0x59d9,0x59da,0x59dc,0x59df,0x59e3,0x59e8,0x59ea,0x59ec,0x59ee,0x59ef,0x59f1,0x59f2,0x59f4,0x59f4,0x59f6,0x59f8,0x59fb,0x59fb,0x59ff,0x5a01,0x5a03,0x5a04,0x5a09,0x5a09,0x5a0c,0x5a0e,0x5a11,0x5a13,0x5a17,0x5a18,0x5a1a,0x5a1c,0x5a1e,0x5a20,0x5a23,0x5a25,0x5a27,0x5a2a,0x5a2d,0x5a2d,0x5a2f,0x5a30,0x5a35,0x5a36,0x5a3c,0x5a3c,0x5a40,0x5a41,0x5a44,0x5a49,0x5a4c,0x5a4c,0x5a50,0x5a50,0x5a55,0x5a55,0x5a5a,0x5a5a,0x5a5e,0x5a5e,0x5a62,0x5a63,0x5a65,0x5a67,0x5a6a,0x5a6a,0x5a6c,0x5a6d,0x5a77,0x5a77,0x5a7a,0x5a7b,0x5a7e,0x5a7f,0x5a84,0x5a84,0x5a8b,0x5a8b,0x5a90,0x5a90,0x5a92,0x5a93,0x5a96,0x5a96,0x5a99,0x5a9c,0x5a9e,0x5aa0,0x5aa2,0x5aa2,0x5aa7,0x5aa7,0x5aac,0x5aac,0x5ab1,0x5ab3,0x5ab5,0x5ab5,0x5ab8,0x5ab8,0x5aba,0x5abf,0x5ac1,0x5ac2,0x5ac4,0x5ac4,0x5ac6,0x5ac6,0x5ac8,0x5ac9,0x5acb,0x5acc,0x5acf,0x5ad0,0x5ad6,0x5ad7,0x5ada,0x5ada,0x5adc,0x5adc,0x5ae0,0x5ae1,0x5ae3,0x5ae3,0x5ae5,0x5ae6,0x5ae9,0x5aea,0x5aee,0x5aee,0x5af0,0x5af0,0x5af5,0x5af6,0x5afa,0x5afb,0x5afd,0x5afd,0x5b00,0x5b01,0x5b08,0x5b09,0x5b0b,0x5b0c,0x5b16,0x5b17,0x5b19,0x5b19,0x5b1b,0x5b1b,0x5b1d,0x5b1d,0x5b21,0x5b22,0x5b25,0x5b25,0x5b2a,0x5b2a,0x5b2c,0x5b2d,0x5b30,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b36,0x5b36,0x5b38,0x5b38,0x5b3e,0x5b3e,0x5b40,0x5b41,0x5b43,0x5b43,0x5b45,0x5b45,0x5b4b,0x5b4c,0x5b50,0x5b52,0x5b54,0x5b58,0x5b5a,0x5b5f,0x5b63,0x5b66,0x5b68,0x5b69,0x5b6b,0x5b6b,0x5b6e,0x5b71,0x5b73,0x5b73,0x5b75,0x5b76,0x5b78,0x5b78,0x5b7a,0x5b7a,0x5b7c,0x5b91,0x5b93,0x5b9d,0x5b9f,0x5b9f,0x5ba2,0x5ba6,0x5ba8,0x5ba9,0x5bac,0x5bba,0x5bbc,0x5bbc,0x5bbf,0x5bc7,0x5bc9,0x5bc9,0x5bcc,0x5bd0,0x5bd2,0x5bd4,0x5bd6,0x5bdb,0x5bdd,0x5be2,0x5be4,0x5be9,0x5beb,0x5bec,0x5bee,0x5bf1,0x5bf3,0x5bf6,0x5bf8,0x5bf8,0x5bfa,0x5bfa,0x5bfd,0x5bff,0x5c01,0x5c0f,0x5c11,0x5c14,0x5c16,0x5c17,0x5c19,0x5c1a,0x5c1e,0x5c20,0x5c22,0x5c24,0x5c26,0x5c26,0x5c28,0x5c2e,0x5c30,0x5c32,0x5c35,0x5c36,0x5c38,0x5c41,0x5c45,0x5c46,0x5c48,0x5c48,0x5c4a,0x5c4b,0x5c4d,0x5c51,0x5c53,0x5c53,0x5c55,0x5c55,0x5c59,0x5c5c,0x5c5e,0x5c65,0x5c67,0x5c69,0x5c6c,0x5c71,0x5c74,0x5c76,0x5c79,0x5c7d,0x5c87,0x5c88,0x5c8a,0x5c8a,0x5c8c,0x5c8c,0x5c8f,0x5c92,0x5c94,0x5c94,0x5c9d,0x5c9d,0x5c9f,0x5ca3,0x5ca6,0x5cad,0x5cb1,0x5cb8,0x5cba,0x5cbc,0x5cbe,0x5cbe,0x5cc5,0x5cc5,0x5cc7,0x5cc7,0x5cc9,0x5cc9,0x5ccb,0x5ccb,0x5cd0,0x5cd0,0x5cd2,0x5cd2,0x5cd7,0x5cd7,0x5cd9,0x5cd9,0x5cdd,0x5cdd,0x5ce0,0x5ce1,0x5ce6,0x5ce6,0x5ce8,0x5cea,0x5ced,0x5cf2,0x5cf4,0x5cf6,0x5cfa,0x5cfb,0x5cfd,0x5cfd,0x5d01,0x5d01,0x5d06,0x5d07,0x5d0b,0x5d0b,0x5d0d,0x5d0e,0x5d10,0x5d12,0x5d14,0x5d1b,0x5d1d,0x5d1d,0x5d1f,0x5d20,0x5d22,0x5d24,0x5d26,0x5d27,0x5d29,0x5d29,0x5d2b,0x5d2b,0x5d31,0x5d31,0x5d34,0x5d34,0x5d39,0x5d39,0x5d3d,0x5d3d,0x5d3f,0x5d3f,0x5d42,0x5d43,0x5d46,0x5d48,0x5d4a,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d53,0x5d55,0x5d55,0x5d59,0x5d59,0x5d5c,0x5d5c,0x5d5f,0x5d62,0x5d64,0x5d64,0x5d69,0x5d6a,0x5d6c,0x5d6d,0x5d6f,0x5d70,0x5d73,0x5d73,0x5d76,0x5d76,0x5d79,0x5d7a,0x5d7e,0x5d7f,0x5d81,0x5d84,0x5d87,0x5d88,0x5d8a,0x5d8c,0x5d90,0x5d90,0x5d92,0x5d95,0x5d97,0x5d97,0x5d99,0x5d99,0x5d9b,0x5d9b,0x5d9d,0x5d9d,0x5d9f,0x5da0,0x5da2,0x5da2,0x5da4,0x5da4,0x5da7,0x5da7,0x5dab,0x5dac,0x5dae,0x5dae,0x5db0,0x5db0,0x5db2,0x5db2,0x5db4,0x5db4,0x5db7,0x5dba,0x5dbc,0x5dbd,0x5dc3,0x5dc3,0x5dc7,0x5dc7,0x5dc9,0x5dc9,0x5dcb,0x5dce,0x5dd0,0x5dd3,0x5dd6,0x5dd9,0x5ddb,0x5ddb,0x5ddd,0x5dde,0x5de0,0x5de9,0x5deb,0x5deb,0x5dee,0x5dee,0x5df1,0x5df5,0x5df7,0x5df9,0x5dfb,0x5dfb,0x5dfd,0x5e00,0x5e02,0x5e03,0x5e06,0x5e07,0x5e0b,0x5e0d,0x5e11,0x5e12,0x5e14,0x5e16,0x5e18,0x5e1b,0x5e1d,0x5e1d,0x5e1f,0x5e20,0x5e25,0x5e25,0x5e28,0x5e28,0x5e2b,0x5e2b,0x5e2d,0x5e30,0x5e32,0x5e33,0x5e35,0x5e38,0x5e3d,0x5e3e,0x5e40,0x5e40,0x5e43,0x5e45,0x5e47,0x5e47,0x5e49,0x5e49,0x5e4b,0x5e4c,0x5e4e,0x5e4e,0x5e50,0x5e51,0x5e54,0x5e58,0x5e5b,0x5e5c,0x5e5e,0x5e5f,0x5e61,0x5e64,0x5e68,0x5e68,0x5e6a,0x5e6e,0x5e70,0x5e70,0x5e72,0x5e81,0x5e83,0x5e84,0x5e87,0x5e87,0x5e8a,0x5e8b,0x5e8e,0x5e8f,0x5e95,0x5e97,0x5e99,0x5e9a,0x5e9c,0x5e9c,0x5ea0,0x5ea0,0x5ea2,0x5ea2,0x5ea4,0x5ea8,0x5eaa,0x5ead,0x5eb1,0x5eb1,0x5eb3,0x5eb3,0x5eb5,0x5eb9,0x5ebd,0x5ebf,0x5ec1,0x5ec3,0x5ec6,0x5ec6,0x5ec8,0x5ecc,0x5ece,0x5ed6,0x5ed9,0x5ee3,0x5ee5,0x5ee5,0x5ee8,0x5ee9,0x5eeb,0x5eec,0x5ef0,0x5ef1,0x5ef3,0x5ef4,0x5ef6,0x5f04,0x5f06,0x5f11,0x5f13,0x5f19,0x5f1b,0x5f1f,0x5f21,0x5f29,0x5f2b,0x5f31,0x5f34,0x5f38,0x5f3a,0x5f41,0x5f44,0x5f45,0x5f47,0x5f48,0x5f4a,0x5f4a,0x5f4c,0x5f4e,0x5f50,0x5f51,0x5f53,0x5f54,0x5f56,0x5f59,0x5f5b,0x5f5d,0x5f60,0x5f67,0x5f69,0x5f6d,0x5f6f,0x5f75,0x5f77,0x5f7a,0x5f7c,0x5f85,0x5f87,0x5f8d,0x5f8f,0x5f93,0x5f96,0x5f99,0x5f9c,0x5f9e,0x5fa0,0x5fa2,0x5fa4,0x5fa4,0x5fa7,0x5fb1,0x5fb3,0x5fb5,0x5fb7,0x5fb9,0x5fbc,0x5fbd,0x5fc3,0x5fc5,0x5fc7,0x5fc9,0x5fcb,0x5fcd,0x5fd0,0x5fd4,0x5fd6,0x5fd9,0x5fdc,0x5fde,0x5fe0,0x5fe2,0x5fe4,0x5fe4,0x5fe8,0x5ff3,0x5ff5,0x5ff6,0x5ff8,0x5ff8,0x5ffa,0x5ffd,0x5fff,0x5fff,0x6007,0x6007,0x600a,0x600a,0x600d,0x6010,0x6012,0x601d,0x601f,0x6022,0x6024,0x602b,0x602d,0x602d,0x602f,0x602f,0x6031,0x6031,0x6033,0x6033,0x6035,0x6035,0x603a,0x603a,0x6040,0x6043,0x6046,0x604d,0x6050,0x6052,0x6054,0x6057,0x6059,0x605a,0x605d,0x605d,0x605f,0x6065,0x6067,0x606d,0x606f,0x6071,0x6075,0x6075,0x6077,0x6077,0x607e,0x607f,0x6081,0x6086,0x6088,0x608e,0x6091,0x6098,0x609a,0x609b,0x609d,0x60a0,0x60a2,0x60aa,0x60b0,0x60b8,0x60bb,0x60be,0x60c2,0x60c2,0x60c4,0x60cb,0x60ce,0x60cf,0x60d1,0x60d1,0x60d3,0x60d5,0x60d8,0x60e3,0x60e5,0x60e5,0x60e7,0x60e8,0x60ee,0x60ee,0x60f0,0x60fd,0x6100,0x6103,0x6106,0x610a,0x610c,0x6117,0x6119,0x611c,0x611e,0x6122,0x6127,0x6128,0x612a,0x612c,0x6130,0x6131,0x6134,0x6137,0x6139,0x613a,0x613c,0x613f,0x6141,0x6142,0x6144,0x614e,0x6153,0x6153,0x6155,0x6155,0x6158,0x615a,0x615d,0x6160,0x6162,0x6165,0x6167,0x6168,0x616b,0x616c,0x616e,0x6178,0x617b,0x6184,0x6187,0x6187,0x618a,0x618b,0x618d,0x618e,0x6190,0x6194,0x6196,0x619a,0x619c,0x619d,0x619f,0x61a0,0x61a4,0x61a5,0x61a7,0x61ae,0x61b2,0x61b2,0x61b6,0x61b6,0x61b8,0x61ba,0x61bc,0x61bc,0x61be,0x61be,0x61c0,0x61c3,0x61c6,0x61d0,0x61d5,0x61d5,0x61dc,0x61df,0x61e1,0x61e3,0x61e5,0x61e9,0x61ec,0x61ed,0x61ef,0x61ef,0x61f2,0x61f2,0x61f4,0x61f8,0x61fa,0x61fa,0x61fc,0x6201,0x6203,0x6204,0x6207,0x620a,0x620c,0x620e,0x6210,0x6216,0x621a,0x6223,0x6226,0x6227,0x6229,0x622b,0x622e,0x6234,0x6236,0x6236,0x6238,0x6239,0x623b,0x623b,0x623d,0x6244,0x6246,0x6249,0x624b,0x624e,0x6250,0x6256,0x6258,0x6258,0x625a,0x625c,0x625e,0x625e,0x6260,0x6261,0x6263,0x6264,0x6268,0x6268,0x626d,0x626f,0x6271,0x6271,0x6273,0x6273,0x6276,0x6276,0x6279,0x6280,0x6282,0x6285,0x6289,0x628a,0x628d,0x6299,0x629b,0x629c,0x629e,0x629e,0x62a6,0x62a6,0x62a8,0x62a8,0x62ab,0x62ac,0x62b1,0x62b1,0x62b3,0x62b3,0x62b5,0x62b7,0x62b9,0x62bf,0x62c2,0x62c2,0x62c4,0x62ca,0x62cc,0x62dd,0x62e0,0x62e1,0x62ea,0x62ea,0x62ec,0x62ef,0x62f1,0x62f7,0x62fc,0x62ff,0x6301,0x6304,0x6307,0x630d,0x6310,0x6311,0x6313,0x6313,0x6316,0x6316,0x6318,0x6319,0x631b,0x631b,0x631f,0x631f,0x6327,0x632b,0x632d,0x632d,0x632f,0x632f,0x6332,0x6332,0x6335,0x6336,0x6339,0x633f,0x6341,0x6344,0x6346,0x6346,0x6349,0x6350,0x6352,0x6355,0x6357,0x6359,0x635b,0x635c,0x6365,0x6369,0x636b,0x636e,0x6371,0x6372,0x6374,0x6378,0x637a,0x637d,0x637f,0x6380,0x6382,0x6384,0x6387,0x638a,0x638c,0x638c,0x638e,0x6390,0x6392,0x6392,0x6394,0x6396,0x6398,0x639b,0x639e,0x63af,0x63b2,0x63b2,0x63b4,0x63b5,0x63bb,0x63bb,0x63bd,0x63be,0x63c0,0x63c1,0x63c3,0x63c6,0x63c8,0x63c9,0x63ce,0x63d6,0x63da,0x63dc,0x63e0,0x63e1,0x63e3,0x63e3,0x63e5,0x63e5,0x63e9,0x63ee,0x63f2,0x63fa,0x6406,0x6406,0x6409,0x640a,0x640d,0x640d,0x640f,0x6410,0x6412,0x6414,0x6416,0x6418,0x641c,0x641c,0x641e,0x641e,0x6420,0x6420,0x6422,0x6422,0x6424,0x6426,0x6428,0x642a,0x642c,0x642d,0x642f,0x6430,0x6434,0x6436,0x643a,0x643a,0x643d,0x643f,0x6442,0x6442,0x644b,0x644b,0x644e,0x644f,0x6451,0x6454,0x6458,0x6458,0x645a,0x645d,0x645f,0x6461,0x6463,0x6463,0x6467,0x6467,0x6469,0x6469,0x646d,0x646d,0x646f,0x646f,0x6473,0x6474,0x6476,0x6476,0x6478,0x647b,0x647d,0x647d,0x6483,0x6483,0x6485,0x6485,0x6487,0x6488,0x648f,0x6493,0x6495,0x6495,0x6498,0x649b,0x649d,0x649f,0x64a1,0x64a1,0x64a3,0x64a6,0x64a8,0x64a9,0x64ab,0x64ae,0x64b0,0x64b0,0x64b2,0x64b3,0x64b9,0x64b9,0x64bb,0x64bf,0x64c1,0x64c2,0x64c4,0x64c5,0x64c7,0x64c7,0x64c9,0x64ce,0x64d0,0x64d2,0x64d4,0x64d5,0x64d7,0x64d8,0x64da,0x64da,0x64e0,0x64e7,0x64e9,0x64ea,0x64ec,0x64ed,0x64ef,0x64f2,0x64f4,0x64f7,0x64fa,0x64fb,0x64fd,0x6501,0x6504,0x6505,0x6508,0x650a,0x650f,0x650f,0x6513,0x6514,0x6516,0x6516,0x6518,0x6519,0x651b,0x651f,0x6522,0x6524,0x6526,0x6526,0x6529,0x652c,0x652e,0x652f,0x6531,0x6532,0x6534,0x653f,0x6543,0x6545,0x6547,0x6549,0x654d,0x6552,0x6554,0x6559,0x655d,0x6560,0x6562,0x6563,0x6566,0x6567,0x656b,0x656c,0x6570,0x6570,0x6572,0x6572,0x6574,0x6575,0x6577,0x6578,0x657a,0x657a,0x657d,0x657d,0x6581,0x6585,0x6587,0x658a,0x658c,0x658c,0x658e,0x658e,0x6590,0x6592,0x6595,0x6595,0x6597,0x6599,0x659b,0x659d,0x659f,0x65a1,0x65a3,0x65a7,0x65ab,0x65b0,0x65b2,0x65b5,0x65b7,0x65b9,0x65bc,0x65bf,0x65c1,0x65c6,0x65c8,0x65c9,0x65cb,0x65cc,0x65ce,0x65d0,0x65d2,0x65d2,0x65d4,0x65d4,0x65d6,0x65d9,0x65db,0x65db,0x65df,0x65e3,0x65e5,0x65e9,0x65ec,0x65ed,0x65f0,0x65f2,0x65f4,0x65f5,0x65f9,0x65fc,0x65fe,0x6600,0x6602,0x6604,0x6606,0x660a,0x660c,0x660f,0x6611,0x6616,0x661c,0x6631,0x6633,0x6637,0x6639,0x663c,0x663f,0x6646,0x6648,0x664c,0x664e,0x664f,0x6651,0x6652,0x6657,0x6670,0x6673,0x667c,0x667e,0x6681,0x6683,0x6684,0x6687,0x6689,0x668b,0x668e,0x6690,0x6692,0x6696,0x669d,0x669f,0x66a0,0x66a2,0x66a2,0x66a4,0x66a4,0x66a6,0x66a6,0x66ab,0x66ab,0x66ad,0x66ae,0x66b1,0x66b5,0x66b8,0x66b9,0x66bb,0x66bc,0x66be,0x66c4,0x66c6,0x66c9,0x66cc,0x66cc,0x66ce,0x66cf,0x66d4,0x66d4,0x66d6,0x66d6,0x66d9,0x66dd,0x66df,0x66e0,0x66e6,0x66e6,0x66e8,0x66e9,0x66eb,0x66ec,0x66ee,0x66ee,0x66f0,0x66f0,0x66f2,0x66f5,0x66f7,0x6701,0x6703,0x6703,0x6705,0x6705,0x6707,0x6709,0x670b,0x6710,0x6712,0x6717,0x6719,0x6719,0x671b,0x6720,0x6722,0x6722,0x6725,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6738,0x673a,0x673a,0x673d,0x673f,0x6741,0x6741,0x6743,0x6743,0x6745,0x6749,0x674c,0x6751,0x6753,0x6756,0x6759,0x6759,0x675c,0x6766,0x676a,0x676a,0x676c,0x6777,0x677b,0x677c,0x677e,0x6781,0x6784,0x6785,0x6787,0x6787,0x6789,0x6789,0x678b,0x678c,0x678e,0x6793,0x6795,0x679d,0x67a0,0x67a2,0x67a4,0x67a4,0x67a6,0x67a6,0x67a9,0x67a9,0x67af,0x67b9,0x67bb,0x67be,0x67c0,0x67c6,0x67c8,0x67ca,0x67ce,0x67d4,0x67d7,0x67de,0x67e1,0x67e2,0x67e4,0x67e4,0x67e6,0x67e7,0x67e9,0x67e9,0x67ec,0x67ec,0x67ee,0x67f7,0x67f9,0x67fc,0x67fe,0x67ff,0x6801,0x6805,0x6810,0x6810,0x6813,0x6814,0x6816,0x6819,0x681d,0x681f,0x6821,0x6822,0x6827,0x682d,0x682f,0x6834,0x6838,0x6839,0x683b,0x6846,0x6848,0x684a,0x684c,0x684e,0x6850,0x6855,0x6857,0x6859,0x685b,0x685d,0x685f,0x685f,0x6863,0x6863,0x6867,0x6867,0x686b,0x686b,0x686e,0x6872,0x6874,0x6877,0x6879,0x687c,0x687e,0x687f,0x6881,0x6886,0x6888,0x6888,0x688d,0x6890,0x6893,0x6894,0x6896,0x689d,0x689f,0x68a3,0x68a5,0x68ab,0x68ad,0x68b6,0x68b9,0x68bc,0x68c3,0x68c6,0x68c8,0x68cd,0x68cf,0x68da,0x68dc,0x68dd,0x68df,0x68e1,0x68e3,0x68e5,0x68e7,0x68e8,0x68ea,0x68f2,0x68f5,0x68f7,0x68f9,0x68fd,0x6900,0x6901,0x6903,0x6913,0x6916,0x6917,0x6919,0x691c,0x6921,0x6923,0x6925,0x6926,0x6928,0x6928,0x692a,0x692a,0x6930,0x6931,0x6933,0x6936,0x6938,0x6939,0x693b,0x693b,0x693d,0x693d,0x693f,0x693f,0x6942,0x6942,0x6945,0x6946,0x6949,0x694a,0x694e,0x694e,0x6953,0x6955,0x6957,0x6957,0x6959,0x695e,0x6960,0x6966,0x6968,0x6975,0x6977,0x6982,0x6986,0x6986,0x698a,0x698a,0x698d,0x698e,0x6991,0x6992,0x6994,0x6996,0x6998,0x6998,0x699b,0x699c,0x69a0,0x69a1,0x69a5,0x69a8,0x69ab,0x69ab,0x69ad,0x69b2,0x69b4,0x69b4,0x69b7,0x69b8,0x69ba,0x69bc,0x69be,0x69c1,0x69c3,0x69c3,0x69c5,0x69c5,0x69c7,0x69c8,0x69ca,0x69d1,0x69d3,0x69d3,0x69d6,0x69d9,0x69dd,0x69de,0x69e2,0x69e3,0x69e5,0x69e5,0x69e7,0x69eb,0x69ed,0x69ef,0x69f1,0x69f6,0x69f9,0x69f9,0x69fb,0x69fb,0x69fd,0x6a03,0x6a05,0x6a05,0x6a0a,0x6a0c,0x6a0f,0x6a0f,0x6a11,0x6a15,0x6a17,0x6a17,0x6a19,0x6a1b,0x6a1d,0x6a24,0x6a28,0x6a2b,0x6a2e,0x6a2e,0x6a30,0x6a30,0x6a32,0x6a3b,0x6a3d,0x6a3f,0x6a44,0x6a4b,0x6a4e,0x6a4e,0x6a50,0x6a52,0x6a54,0x6a56,0x6a58,0x6a59,0x6a5b,0x6a5b,0x6a5f,0x6a5f,0x6a61,0x6a62,0x6a64,0x6a64,0x6a66,0x6a67,0x6a6a,0x6a6b,0x6a71,0x6a73,0x6a78,0x6a78,0x6a7a,0x6a7a,0x6a7e,0x6a81,0x6a83,0x6a84,0x6a86,0x6a87,0x6a89,0x6a89,0x6a8b,0x6a8b,0x6a8d,0x6a8e,0x6a90,0x6a91,0x6a94,0x6a94,0x6a97,0x6a97,0x6a9b,0x6aa3,0x6aa5,0x6aa5,0x6aaa,0x6aac,0x6aae,0x6ab1,0x6ab3,0x6ab4,0x6ab8,0x6ab8,0x6abb,0x6abb,0x6abd,0x6abf,0x6ac1,0x6ac3,0x6ac6,0x6ac6,0x6ac8,0x6ac9,0x6acc,0x6acc,0x6ad0,0x6ad1,0x6ad3,0x6ad6,0x6ada,0x6adf,0x6ae2,0x6ae2,0x6ae4,0x6ae4,0x6ae7,0x6ae8,0x6aea,0x6aea,0x6aec,0x6aec,0x6af0,0x6af3,0x6af8,0x6af8,0x6afa,0x6afd,0x6b02,0x6b07,0x6b09,0x6b0b,0x6b0f,0x6b12,0x6b16,0x6b17,0x6b1b,0x6b1b,0x6b1d,0x6b21,0x6b23,0x6b24,0x6b27,0x6b28,0x6b2b,0x6b2c,0x6b2f,0x6b2f,0x6b32,0x6b32,0x6b35,0x6b3b,0x6b3d,0x6b3f,0x6b43,0x6b43,0x6b46,0x6b47,0x6b49,0x6b4a,0x6b4c,0x6b4e,0x6b50,0x6b50,0x6b52,0x6b54,0x6b56,0x6b56,0x6b58,0x6b59,0x6b5b,0x6b5b,0x6b5d,0x6b5d,0x6b5f,0x6b67,0x6b69,0x6b6c,0x6b6e,0x6b70,0x6b72,0x6b75,0x6b77,0x6b7b,0x6b7d,0x6b86,0x6b89,0x6b8b,0x6b8d,0x6b8d,0x6b95,0x6b98,0x6b9b,0x6b9b,0x6b9e,0x6ba0,0x6ba2,0x6ba4,0x6ba8,0x6bb5,0x6bb7,0x6bc0,0x6bc3,0x6bc9,0x6bcb,0x6bcf,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdb,0x6bdf,0x6bdf,0x6be1,0x6be1,0x6be3,0x6be3,0x6be6,0x6be7,0x6beb,0x6bec,0x6bee,0x6bef,0x6bf1,0x6bf1,0x6bf3,0x6bf3,0x6bf7,0x6bf7,0x6bf9,0x6bf9,0x6bff,0x6bff,0x6c02,0x6c02,0x6c04,0x6c05,0x6c08,0x6c0a,0x6c0d,0x6c14,0x6c17,0x6c17,0x6c19,0x6c19,0x6c1b,0x6c1b,0x6c1f,0x6c1f,0x6c23,0x6c24,0x6c26,0x6c28,0x6c2c,0x6c2c,0x6c2e,0x6c2e,0x6c33,0x6c38,0x6c3a,0x6c3b,0x6c3e,0x6c42,0x6c4a,0x6c4b,0x6c4d,0x6c50,0x6c52,0x6c52,0x6c54,0x6c55,0x6c57,0x6c57,0x6c59,0x6c60,0x6c62,0x6c62,0x6c67,0x6c68,0x6c6a,0x6c6b,0x6c6d,0x6c6d,0x6c6f,0x6c70,0x6c72,0x6c74,0x6c76,0x6c76,0x6c78,0x6c7b,0x6c7d,0x6c7e,0x6c81,0x6c89,0x6c8c,0x6c8d,0x6c90,0x6c90,0x6c92,0x6c9c,0x6c9f,0x6c9f,0x6ca1,0x6ca2,0x6caa,0x6cae,0x6cb0,0x6cb4,0x6cb8,0x6cbf,0x6cc1,0x6cc2,0x6cc4,0x6cc6,0x6cc9,0x6cca,0x6ccc,0x6ccd,0x6ccf,0x6cd7,0x6cd9,0x6cdd,0x6ce0,0x6ce3,0x6ce5,0x6ce5,0x6ce7,0x6cf4,0x6cfb,0x6cfb,0x6d00,0x6d01,0x6d04,0x6d04,0x6d07,0x6d07,0x6d0a,0x6d0c,0x6d0e,0x6d0f,0x6d11,0x6d13,0x6d17,0x6d17,0x6d19,0x6d1b,0x6d1e,0x6d1f,0x6d24,0x6d2b,0x6d2e,0x6d2f,0x6d31,0x6d36,0x6d38,0x6d39,0x6d3b,0x6d3f,0x6d41,0x6d41,0x6d44,0x6d45,0x6d57,0x6d5c,0x6d5e,0x6d61,0x6d63,0x6d67,0x6d69,0x6d6a,0x6d6c,0x6d6c,0x6d6e,0x6d70,0x6d74,0x6d74,0x6d77,0x6d79,0x6d7c,0x6d7c,0x6d80,0x6d82,0x6d85,0x6d85,0x6d87,0x6d8a,0x6d8c,0x6d8e,0x6d91,0x6d99,0x6d9b,0x6d9c,0x6daa,0x6dac,0x6dae,0x6daf,0x6db2,0x6db2,0x6db4,0x6db5,0x6db7,0x6db9,0x6dbc,0x6dbd,0x6dbf,0x6dc0,0x6dc2,0x6dc2,0x6dc4,0x6dc8,0x6dca,0x6dcc,0x6dce,0x6dd2,0x6dd5,0x6dd6,0x6dd8,0x6ddb,0x6ddd,0x6de2,0x6de4,0x6de6,0x6de8,0x6dec,0x6dee,0x6dfc,0x6e00,0x6e00,0x6e04,0x6e05,0x6e07,0x6e0b,0x6e13,0x6e13,0x6e15,0x6e15,0x6e17,0x6e17,0x6e19,0x6e1b,0x6e1d,0x6e27,0x6e29,0x6e29,0x6e2b,0x6e2f,0x6e32,0x6e32,0x6e34,0x6e34,0x6e36,0x6e36,0x6e38,0x6e3c,0x6e3e,0x6e3e,0x6e42,0x6e45,0x6e48,0x6e4f,0x6e51,0x6e54,0x6e56,0x6e58,0x6e5b,0x6e5f,0x6e62,0x6e63,0x6e67,0x6e68,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e72,0x6e73,0x6e76,0x6e76,0x6e7b,0x6e7b,0x6e7d,0x6e80,0x6e82,0x6e82,0x6e89,0x6e89,0x6e8c,0x6e8d,0x6e8f,0x6e90,0x6e93,0x6e93,0x6e96,0x6e96,0x6e98,0x6e99,0x6e9c,0x6e9d,0x6e9f,0x6ea0,0x6ea2,0x6ea2,0x6ea5,0x6ea5,0x6ea7,0x6ea7,0x6eaa,0x6eab,0x6ead,0x6eaf,0x6eb1,0x6eb4,0x6eb6,0x6eb7,0x6eba,0x6ebd,0x6ebf,0x6ec5,0x6ec7,0x6ecf,0x6ed1,0x6ed1,0x6ed3,0x6ed5,0x6ed9,0x6edb,0x6edd,0x6ede,0x6ee6,0x6ee6,0x6eeb,0x6eef,0x6ef2,0x6ef2,0x6ef4,0x6ef4,0x6ef7,0x6ef9,0x6efb,0x6efb,0x6efd,0x6eff,0x6f01,0x6f02,0x6f04,0x6f04,0x6f06,0x6f06,0x6f08,0x6f0a,0x6f0c,0x6f0d,0x6f0f,0x6f11,0x6f13,0x6f16,0x6f18,0x6f18,0x6f1a,0x6f1b,0x6f20,0x6f20,0x6f22,0x6f23,0x6f25,0x6f26,0x6f29,0x6f2d,0x6f2f,0x6f33,0x6f35,0x6f36,0x6f38,0x6f38,0x6f3b,0x6f3c,0x6f3e,0x6f3f,0x6f41,0x6f41,0x6f45,0x6f45,0x6f4f,0x6f4f,0x6f51,0x6f54,0x6f57,0x6f62,0x6f64,0x6f64,0x6f66,0x6f66,0x6f68,0x6f68,0x6f6c,0x6f70,0x6f74,0x6f74,0x6f78,0x6f78,0x6f7a,0x6f7a,0x6f7c,0x6f7e,0x6f80,0x6f84,0x6f86,0x6f88,0x6f8b,0x6f8e,0x6f90,0x6f94,0x6f96,0x6f98,0x6f9a,0x6f9a,0x6f9d,0x6f9d,0x6f9f,0x6fa1,0x6fa3,0x6fa8,0x6faa,0x6faa,0x6fae,0x6fb1,0x6fb3,0x6fb3,0x6fb5,0x6fb7,0x6fb9,0x6fb9,0x6fbc,0x6fbc,0x6fbe,0x6fbe,0x6fc0,0x6fc3,0x6fc5,0x6fca,0x6fd4,0x6fd5,0x6fd8,0x6fd8,0x6fda,0x6fdb,0x6fde,0x6fe1,0x6fe4,0x6fe4,0x6fe8,0x6fe9,0x6feb,0x6fec,0x6fee,0x6ff1,0x6ff3,0x6ff3,0x6ff5,0x6ff6,0x6ff9,0x6ffa,0x6ffc,0x6ffe,0x7000,0x7001,0x7005,0x7007,0x7009,0x700b,0x700d,0x700d,0x700f,0x700f,0x7011,0x7011,0x7015,0x7015,0x7017,0x7018,0x701a,0x701b,0x701d,0x7020,0x7023,0x7023,0x7026,0x7028,0x702c,0x702c,0x702f,0x7030,0x7032,0x7032,0x7034,0x7034,0x7037,0x7037,0x7039,0x703a,0x703c,0x703c,0x703e,0x703e,0x7043,0x7044,0x7047,0x704c,0x704e,0x704e,0x7051,0x7051,0x7054,0x7055,0x7058,0x7058,0x705d,0x705e,0x7063,0x7065,0x7069,0x7069,0x706b,0x706c,0x706e,0x7070,0x7075,0x7076,0x7078,0x7078,0x707c,0x707e,0x7081,0x7081,0x7085,0x7086,0x7089,0x708a,0x708e,0x708e,0x7092,0x7092,0x7094,0x7099,0x709b,0x709b,0x709f,0x709f,0x70a4,0x70a4,0x70ab,0x70b1,0x70b3,0x70b4,0x70b7,0x70bb,0x70c8,0x70c8,0x70ca,0x70cb,0x70cf,0x70cf,0x70d1,0x70d1,0x70d3,0x70d6,0x70d8,0x70d9,0x70dc,0x70dd,0x70df,0x70df,0x70e4,0x70e4,0x70ec,0x70ec,0x70f1,0x70f1,0x70f9,0x70fa,0x70fd,0x70fd,0x7103,0x7109,0x710b,0x710c,0x710f,0x710f,0x7114,0x7114,0x7119,0x711a,0x711c,0x711c,0x711e,0x711e,0x7120,0x7121,0x7126,0x7126,0x712b,0x712b,0x712d,0x7131,0x7136,0x7136,0x7138,0x7138,0x713c,0x713c,0x7141,0x7141,0x7145,0x7147,0x7149,0x714c,0x714e,0x714e,0x7150,0x7153,0x7155,0x7157,0x7159,0x715a,0x715c,0x715c,0x715e,0x715e,0x7160,0x7160,0x7162,0x7162,0x7164,0x7169,0x716c,0x716c,0x716e,0x716e,0x7179,0x7179,0x717d,0x717d,0x7180,0x7180,0x7184,0x7185,0x7187,0x7188,0x718a,0x718a,0x718c,0x718c,0x718f,0x718f,0x7192,0x7192,0x7194,0x7196,0x7199,0x719b,0x719f,0x71a0,0x71a2,0x71a2,0x71a8,0x71a8,0x71ac,0x71ac,0x71ae,0x71b3,0x71b9,0x71ba,0x71be,0x71c1,0x71c3,0x71c4,0x71c8,0x71c9,0x71cb,0x71cc,0x71ce,0x71ce,0x71d0,0x71d0,0x71d2,0x71d7,0x71d9,0x71da,0x71dc,0x71dc,0x71df,0x71e0,0x71e5,0x71e7,0x71ec,0x71ee,0x71f4,0x71f5,0x71f8,0x71f9,0x71fb,0x71fc,0x71fe,0x7200,0x7206,0x7209,0x720d,0x720d,0x7210,0x7210,0x7213,0x7213,0x7215,0x7215,0x7217,0x7217,0x721a,0x721b,0x721d,0x721d,0x721f,0x721f,0x7224,0x7224,0x7228,0x7228,0x722a,0x722d,0x722f,0x7230,0x7232,0x7232,0x7234,0x7236,0x7238,0x7243,0x7245,0x7248,0x724b,0x724c,0x724e,0x7250,0x7252,0x7253,0x7255,0x7263,0x7267,0x7269,0x726b,0x726b,0x726e,0x726f,0x7271,0x7272,0x7274,0x7274,0x7277,0x7279,0x727b,0x7282,0x7284,0x7284,0x7287,0x7287,0x7289,0x7289,0x728d,0x728e,0x7292,0x7293,0x7296,0x7296,0x729b,0x729b,0x72a0,0x72a0,0x72a2,0x72a2,0x72a7,0x72a8,0x72ac,0x72b2,0x72b4,0x72b4,0x72b6,0x72b6,0x72b9,0x72b9,0x72be,0x72be,0x72c0,0x72c4,0x72c6,0x72c7,0x72c9,0x72c9,0x72cc,0x72cc,0x72ce,0x72ce,0x72d0,0x72d0,0x72d2,0x72d2,0x72d5,0x72d9,0x72db,0x72db,0x72df,0x72e2,0x72e5,0x72e5,0x72e9,0x72e9,0x72ec,0x72ed,0x72f3,0x72f4,0x72f7,0x72fe,0x7302,0x7302,0x7304,0x7305,0x7307,0x7307,0x730a,0x730b,0x730d,0x730d,0x7312,0x7313,0x7316,0x7319,0x731b,0x731f,0x7322,0x7322,0x7324,0x7325,0x7327,0x732c,0x732e,0x732f,0x7331,0x7337,0x7339,0x733b,0x733d,0x733f,0x7343,0x7345,0x734d,0x7350,0x7352,0x7352,0x7356,0x7358,0x735d,0x7360,0x7363,0x7363,0x7366,0x736c,0x736e,0x7372,0x7375,0x7375,0x7377,0x737c,0x7380,0x7381,0x7383,0x7387,0x7389,0x738b,0x738e,0x738e,0x7390,0x7390,0x7393,0x7398,0x739c,0x739c,0x739e,0x73a0,0x73a2,0x73a2,0x73a5,0x73a6,0x73a8,0x73ab,0x73ad,0x73ad,0x73b2,0x73b3,0x73b5,0x73b5,0x73b7,0x73b7,0x73b9,0x73bd,0x73bf,0x73c0,0x73c2,0x73c2,0x73c5,0x73c6,0x73c8,0x73cf,0x73d2,0x73d3,0x73d6,0x73d6,0x73d9,0x73d9,0x73dd,0x73de,0x73e0,0x73e1,0x73e3,0x73e7,0x73e9,0x73ea,0x73ed,0x73ee,0x73f1,0x73f1,0x73f4,0x73f5,0x73f7,0x73fb,0x73fd,0x7401,0x7403,0x7407,0x7409,0x740a,0x7411,0x7411,0x7413,0x7413,0x741a,0x741b,0x7421,0x7422,0x7424,0x7426,0x7428,0x7436,0x7439,0x743a,0x743f,0x7441,0x7443,0x7444,0x7446,0x7447,0x744b,0x744b,0x744d,0x744d,0x7451,0x7453,0x7455,0x7455,0x7457,0x7457,0x7459,0x7460,0x7462,0x7464,0x7466,0x746b,0x746d,0x7473,0x7476,0x7476,0x747e,0x747e,0x7480,0x7481,0x7483,0x7483,0x7485,0x7489,0x748b,0x748b,0x748f,0x7492,0x7497,0x749a,0x749c,0x749c,0x749e,0x74a3,0x74a5,0x74ab,0x74ae,0x74b2,0x74b5,0x74b5,0x74b9,0x74bb,0x74bd,0x74bd,0x74bf,0x74bf,0x74c8,0x74ca,0x74cc,0x74cc,0x74cf,0x74d0,0x74d3,0x74d4,0x74d6,0x74d6,0x74d8,0x74d8,0x74da,0x74dc,0x74de,0x74e0,0x74e2,0x74e4,0x74e6,0x74eb,0x74ee,0x74f2,0x74f4,0x74f4,0x74f6,0x74f8,0x74fa,0x74fc,0x74ff,0x74ff,0x7501,0x7501,0x7503,0x7506,0x750c,0x750e,0x7511,0x7513,0x7515,0x7518,0x751a,0x751a,0x751c,0x751c,0x751e,0x752c,0x752f,0x7533,0x7536,0x7540,0x7543,0x7544,0x7546,0x7552,0x7554,0x7554,0x7557,0x7557,0x7559,0x7562,0x7564,0x7567,0x7569,0x756d,0x756f,0x757f,0x7581,0x7582,0x7585,0x7587,0x7589,0x758c,0x758e,0x7595,0x7599,0x759a,0x759c,0x759d,0x75a2,0x75a5,0x75ab,0x75ab,0x75b0,0x75b5,0x75b7,0x75ba,0x75bc,0x75c7,0x75ca,0x75ca,0x75cc,0x75cf,0x75d2,0x75d5,0x75d7,0x75d9,0x75db,0x75e4,0x75e7,0x75e7,0x75e9,0x75e9,0x75ec,0x75ec,0x75ee,0x75f4,0x75f9,0x75fa,0x75fc,0x75fc,0x75fe,0x7604,0x7607,0x760d,0x760f,0x760f,0x7612,0x7613,0x7615,0x7616,0x7618,0x7619,0x761b,0x7629,0x762d,0x762d,0x7630,0x7630,0x7632,0x7635,0x7638,0x763c,0x7640,0x764c,0x764e,0x764e,0x7652,0x7652,0x7655,0x7656,0x7658,0x7659,0x765c,0x765c,0x765f,0x765f,0x7661,0x7662,0x7664,0x7665,0x7667,0x766a,0x766c,0x7672,0x7674,0x7674,0x7676,0x7676,0x7678,0x7678,0x767a,0x767e,0x7680,0x7688,0x768b,0x768e,0x7690,0x7690,0x7693,0x7693,0x7695,0x7696,0x7699,0x76a8,0x76aa,0x76aa,0x76ad,0x76b0,0x76b4,0x76b4,0x76b6,0x76ba,0x76bd,0x76bd,0x76bf,0x76bf,0x76c1,0x76c3,0x76c5,0x76c6,0x76c8,0x76ce,0x76d2,0x76d2,0x76d4,0x76d4,0x76d6,0x76d7,0x76d9,0x76d9,0x76db,0x76dc,0x76de,0x76e1,0x76e3,0x76e8,0x76ea,0x76ec,0x76ee,0x76ee,0x76f0,0x76f2,0x76f4,0x76f4,0x76f6,0x76f6,0x76f8,0x76f9,0x76fb,0x76fc,0x76fe,0x76fe,0x7700,0x7701,0x7704,0x7704,0x7706,0x770c,0x770e,0x770e,0x7712,0x7712,0x7714,0x7715,0x7717,0x7717,0x7719,0x771c,0x771e,0x7720,0x7722,0x7722,0x7724,0x7726,0x7728,0x7729,0x772d,0x772f,0x7734,0x773a,0x773c,0x773e,0x7740,0x7740,0x7742,0x7742,0x7745,0x7747,0x774a,0x774a,0x774d,0x774f,0x7752,0x7752,0x7756,0x7758,0x775a,0x775c,0x775e,0x7768,0x776a,0x776c,0x7770,0x7770,0x7772,0x7774,0x7779,0x777a,0x777c,0x7780,0x7784,0x7784,0x778b,0x778e,0x7791,0x7791,0x7794,0x7796,0x779a,0x779a,0x779e,0x77a0,0x77a2,0x77a2,0x77a4,0x77a5,0x77a7,0x77a7,0x77a9,0x77aa,0x77ac,0x77b1,0x77b3,0x77b3,0x77b5,0x77b7,0x77b9,0x77b9,0x77bb,0x77bf,0x77c3,0x77c3,0x77c7,0x77c7,0x77c9,0x77c9,0x77cd,0x77cd,0x77d1,0x77d2,0x77d5,0x77d5,0x77d7,0x77d7,0x77d9,0x77dc,0x77de,0x77e0,0x77e2,0x77e7,0x77e9,0x77ea,0x77ec,0x77f1,0x77f3,0x77f4,0x77f8,0x77f8,0x77fb,0x77fc,0x7802,0x7802,0x7805,0x7806,0x7809,0x7809,0x780c,0x780e,0x7811,0x7812,0x7814,0x7815,0x7819,0x7819,0x781d,0x781d,0x7820,0x7823,0x7825,0x7827,0x782c,0x782e,0x7830,0x7830,0x7832,0x7832,0x7834,0x7835,0x7837,0x7837,0x783a,0x783a,0x783f,0x783f,0x7843,0x7845,0x7847,0x7848,0x784c,0x784c,0x784e,0x784f,0x7851,0x7852,0x785c,0x785e,0x7860,0x7861,0x7863,0x7864,0x7868,0x7868,0x786a,0x786c,0x786e,0x786f,0x7872,0x7872,0x7874,0x7874,0x787a,0x787a,0x787c,0x787c,0x787e,0x787e,0x7881,0x7881,0x7886,0x7887,0x788a,0x788a,0x788c,0x788f,0x7891,0x7891,0x7893,0x7895,0x7897,0x7898,0x789a,0x789a,0x789d,0x789f,0x78a1,0x78a1,0x78a3,0x78a4,0x78a7,0x78aa,0x78ac,0x78ad,0x78af,0x78b3,0x78b5,0x78b5,0x78ba,0x78bf,0x78c1,0x78c1,0x78c5,0x78cc,0x78ce,0x78ce,0x78d0,0x78d6,0x78da,0x78db,0x78df,0x78e1,0x78e4,0x78e4,0x78e6,0x78e8,0x78ea,0x78ea,0x78ec,0x78ec,0x78ef,0x78ef,0x78f2,0x78f4,0x78f6,0x78f7,0x78f9,0x78fb,0x78fd,0x7901,0x7906,0x7907,0x790c,0x790c,0x790e,0x790e,0x7910,0x7912,0x7919,0x791c,0x791e,0x7920,0x7925,0x792e,0x7930,0x7931,0x7934,0x7935,0x793a,0x7942,0x7944,0x794b,0x794f,0x7951,0x7953,0x7958,0x795a,0x7960,0x7962,0x7962,0x7965,0x7965,0x7967,0x7969,0x796b,0x796b,0x796d,0x796d,0x7972,0x7972,0x7977,0x7977,0x7979,0x797c,0x797e,0x7981,0x7984,0x7985,0x798a,0x798f,0x7991,0x7991,0x7993,0x7996,0x7998,0x7998,0x799b,0x799d,0x79a1,0x79a1,0x79a6,0x79ab,0x79ae,0x79b1,0x79b3,0x79b4,0x79b8,0x79bb,0x79bd,0x79c2,0x79c4,0x79c4,0x79c7,0x79cd,0x79cf,0x79cf,0x79d1,0x79d2,0x79d4,0x79d6,0x79d8,0x79d8,0x79da,0x79da,0x79dd,0x79e7,0x79e9,0x79ed,0x79f0,0x79f1,0x79f8,0x79f8,0x79fb,0x79fc,0x7a00,0x7a00,0x7a02,0x7a03,0x7a05,0x7a05,0x7a07,0x7a0e,0x7a11,0x7a11,0x7a14,0x7a15,0x7a17,0x7a1c,0x7a1e,0x7a21,0x7a27,0x7a27,0x7a2b,0x7a2b,0x7a2d,0x7a32,0x7a34,0x7a35,0x7a37,0x7a40,0x7a42,0x7a49,0x7a4c,0x7a50,0x7a55,0x7a57,0x7a59,0x7a59,0x7a5c,0x7a5d,0x7a5f,0x7a63,0x7a65,0x7a65,0x7a67,0x7a67,0x7a69,0x7a6b,0x7a6d,0x7a6d,0x7a70,0x7a70,0x7a74,0x7a76,0x7a78,0x7a7a,0x7a7d,0x7a86,0x7a88,0x7a88,0x7a8a,0x7a8b,0x7a90,0x7a98,0x7a9e,0x7aa0,0x7aa3,0x7aa3,0x7aa9,0x7aaa,0x7aac,0x7aac,0x7aae,0x7ab0,0x7ab3,0x7ab3,0x7ab5,0x7ab6,0x7ab9,0x7abf,0x7ac3,0x7acf,0x7ad1,0x7ad3,0x7ad5,0x7ad5,0x7ad9,0x7add,0x7adf,0x7ae3,0x7ae5,0x7aed,0x7aef,0x7af1,0x7af4,0x7af4,0x7af6,0x7af6,0x7af8,0x7afb,0x7afd,0x7aff,0x7b02,0x7b02,0x7b04,0x7b04,0x7b06,0x7b08,0x7b0a,0x7b0b,0x7b0f,0x7b0f,0x7b11,0x7b12,0x7b14,0x7b14,0x7b18,0x7b19,0x7b1b,0x7b1b,0x7b1e,0x7b20,0x7b23,0x7b23,0x7b25,0x7b31,0x7b33,0x7b36,0x7b39,0x7b39,0x7b3b,0x7b3b,0x7b3d,0x7b3d,0x7b3f,0x7b41,0x7b45,0x7b49,0x7b4b,0x7b56,0x7b5d,0x7b5d,0x7b60,0x7b60,0x7b64,0x7b67,0x7b69,0x7b6a,0x7b6c,0x7b75,0x7b77,0x7b77,0x7b79,0x7b7a,0x7b7f,0x7b7f,0x7b84,0x7b84,0x7b86,0x7b87,0x7b89,0x7b89,0x7b8b,0x7b8b,0x7b8d,0x7b92,0x7b94,0x7ba1,0x7ba5,0x7ba5,0x7baa,0x7baa,0x7bac,0x7bad,0x7baf,0x7bb2,0x7bb4,0x7bb6,0x7bb8,0x7bb8,0x7bba,0x7bbd,0x7bc0,0x7bc2,0x7bc4,0x7bcc,0x7bcf,0x7bcf,0x7bd4,0x7bd4,0x7bd6,0x7bd7,0x7bd9,0x7bdb,0x7bdd,0x7bdd,0x7be0,0x7be0,0x7be4,0x7be6,0x7be8,0x7bea,0x7bed,0x7bed,0x7bf0,0x7bf0,0x7bf2,0x7bfa,0x7bfc,0x7bfc,0x7bfe,0x7bfe,0x7c00,0x7c04,0x7c06,0x7c07,0x7c09,0x7c09,0x7c0b,0x7c0f,0x7c11,0x7c14,0x7c17,0x7c17,0x7c19,0x7c19,0x7c1b,0x7c1b,0x7c1e,0x7c21,0x7c23,0x7c23,0x7c25,0x7c28,0x7c2a,0x7c2c,0x7c2f,0x7c2f,0x7c31,0x7c31,0x7c33,0x7c34,0x7c36,0x7c3a,0x7c3d,0x7c40,0x7c42,0x7c43,0x7c45,0x7c46,0x7c4a,0x7c4a,0x7c4c,0x7c4d,0x7c4f,0x7c61,0x7c63,0x7c65,0x7c67,0x7c67,0x7c69,0x7c69,0x7c6c,0x7c70,0x7c72,0x7c73,0x7c75,0x7c75,0x7c79,0x7c79,0x7c7b,0x7c7e,0x7c81,0x7c83,0x7c86,0x7c87,0x7c89,0x7c89,0x7c8b,0x7c8b,0x7c8d,0x7c8d,0x7c8f,0x7c90,0x7c92,0x7c92,0x7c94,0x7c95,0x7c97,0x7c98,0x7c9b,0x7c9b,0x7c9e,0x7ca2,0x7ca4,0x7ca8,0x7cab,0x7cab,0x7cad,0x7cae,0x7cb0,0x7cb3,0x7cb6,0x7cb7,0x7cb9,0x7cc0,0x7cc2,0x7cc2,0x7cc4,0x7cc5,0x7cc7,0x7cca,0x7ccd,0x7ccf,0x7cd2,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce6,0x7ce7,0x7ce9,0x7ce9,0x7ceb,0x7ceb,0x7cef,0x7cef,0x7cf2,0x7cf2,0x7cf4,0x7cf6,0x7cf8,0x7cfb,0x7cfe,0x7cfe,0x7d00,0x7d00,0x7d02,0x7d0b,0x7d0d,0x7d0d,0x7d0f,0x7d1e,0x7d20,0x7d23,0x7d26,0x7d26,0x7d2a,0x7d33,0x7d35,0x7d35,0x7d39,0x7d3a,0x7d3c,0x7d48,0x7d4b,0x7d51,0x7d53,0x7d53,0x7d55,0x7d57,0x7d59,0x7d5e,0x7d61,0x7d63,0x7d65,0x7d68,0x7d6a,0x7d6a,0x7d6e,0x7d6e,0x7d70,0x7d73,0x7d75,0x7d76,0x7d78,0x7d7b,0x7d7d,0x7d7d,0x7d7f,0x7d7f,0x7d81,0x7d83,0x7d85,0x7d86,0x7d88,0x7d89,0x7d8b,0x7d8d,0x7d8f,0x7d8f,0x7d91,0x7d91,0x7d93,0x7d93,0x7d96,0x7d97,0x7d99,0x7da0,0x7da2,0x7da3,0x7da6,0x7da7,0x7daa,0x7dbb,0x7dbd,0x7dc0,0x7dc2,0x7dc7,0x7dca,0x7dd2,0x7dd5,0x7dda,0x7ddc,0x7dde,0x7de0,0x7de6,0x7de8,0x7ded,0x7def,0x7def,0x7df1,0x7df2,0x7df4,0x7df6,0x7df9,0x7dfb,0x7e00,0x7e01,0x7e04,0x7e05,0x7e08,0x7e0b,0x7e10,0x7e12,0x7e15,0x7e15,0x7e17,0x7e17,0x7e1b,0x7e23,0x7e26,0x7e28,0x7e2b,0x7e2f,0x7e31,0x7e33,0x7e35,0x7e37,0x7e39,0x7e3b,0x7e3d,0x7e3f,0x7e41,0x7e41,0x7e43,0x7e48,0x7e4a,0x7e4b,0x7e4d,0x7e4e,0x7e50,0x7e50,0x7e52,0x7e52,0x7e54,0x7e56,0x7e58,0x7e5a,0x7e5d,0x7e5f,0x7e61,0x7e62,0x7e65,0x7e67,0x7e69,0x7e6b,0x7e6d,0x7e70,0x7e73,0x7e73,0x7e75,0x7e75,0x7e78,0x7e79,0x7e7b,0x7e7f,0x7e81,0x7e83,0x7e86,0x7e8a,0x7e8c,0x7e96,0x7e98,0x7e98,0x7e9a,0x7e9f,0x7f36,0x7f36,0x7f38,0x7f38,0x7f3a,0x7f3f,0x7f43,0x7f45,0x7f47,0x7f47,0x7f4c,0x7f55,0x7f58,0x7f58,0x7f5b,0x7f5d,0x7f5f,0x7f61,0x7f63,0x7f6b,0x7f6d,0x7f6e,0x7f70,0x7f72,0x7f75,0x7f75,0x7f77,0x7f79,0x7f7d,0x7f80,0x7f82,0x7f83,0x7f85,0x7f88,0x7f8a,0x7f91,0x7f94,0x7f94,0x7f96,0x7f97,0x7f9a,0x7f9a,0x7f9c,0x7f9e,0x7fa1,0x7fa4,0x7fa6,0x7fa6,0x7fa8,0x7faa,0x7fad,0x7faf,0x7fb2,0x7fb2,0x7fb4,0x7fb4,0x7fb6,0x7fb6,0x7fb8,0x7fb9,0x7fbc,0x7fbd,0x7fbf,0x7fc1,0x7fc3,0x7fc3,0x7fc5,0x7fc6,0x7fc8,0x7fc8,0x7fca,0x7fca,0x7fcc,0x7fcc,0x7fce,0x7fcf,0x7fd2,0x7fd2,0x7fd4,0x7fd5,0x7fdb,0x7fdb,0x7fdf,0x7fe1,0x7fe3,0x7fe3,0x7fe5,0x7fe6,0x7fe8,0x7fe9,0x7feb,0x7fec,0x7fee,0x7ff0,0x7ff2,0x7ff3,0x7ff9,0x8008,0x800a,0x8019,0x801c,0x8021,0x8024,0x8024,0x8026,0x8026,0x8028,0x8028,0x802c,0x802c,0x802e,0x802e,0x8030,0x8030,0x8033,0x8037,0x8039,0x8040,0x8043,0x8044,0x8046,0x8046,0x804a,0x804a,0x8052,0x8052,0x8056,0x8056,0x8058,0x8058,0x805a,0x805a,0x805e,0x8062,0x8064,0x8064,0x8066,0x8066,0x8068,0x8068,0x806d,0x806d,0x806f,0x8077,0x8079,0x8079,0x807b,0x807b,0x807d,0x8081,0x8084,0x8089,0x808b,0x808c,0x808e,0x808e,0x8093,0x8093,0x8096,0x8096,0x8098,0x809e,0x80a1,0x80a2,0x80a4,0x80a7,0x80a9,0x80ad,0x80af,0x80af,0x80b1,0x80b2,0x80b4,0x80b4,0x80b8,0x80ba,0x80c3,0x80c6,0x80c8,0x80c8,0x80ca,0x80ca,0x80cc,0x80cf,0x80d2,0x80d2,0x80d4,0x80db,0x80dd,0x80de,0x80e0,0x80e1,0x80e4,0x80e6,0x80ed,0x80fe,0x8101,0x8103,0x8105,0x810b,0x810d,0x810d,0x8116,0x8118,0x811a,0x811c,0x811e,0x811e,0x8120,0x8120,0x8123,0x8124,0x8127,0x8127,0x8129,0x8129,0x812b,0x812c,0x812f,0x8131,0x8133,0x8133,0x8135,0x8135,0x8139,0x813a,0x813c,0x813e,0x8141,0x8141,0x8145,0x8147,0x814a,0x814c,0x814e,0x814e,0x8150,0x8155,0x8157,0x8157,0x815f,0x8161,0x8165,0x8169,0x816b,0x816b,0x816d,0x8171,0x8173,0x8174,0x8177,0x817a,0x817f,0x8186,0x8188,0x8188,0x818a,0x818b,0x818e,0x8190,0x8193,0x8193,0x8195,0x8196,0x8198,0x8198,0x819a,0x819e,0x81a0,0x81a0,0x81a2,0x81a4,0x81a8,0x81a9,0x81ae,0x81ae,0x81b0,0x81b0,0x81b2,0x81b5,0x81b8,0x81b8,0x81ba,0x81bb,0x81bd,0x81c3,0x81c5,0x81c6,0x81c8,0x81cb,0x81cd,0x81cf,0x81d1,0x81d1,0x81d3,0x81d3,0x81d5,0x81db,0x81dd,0x81e1,0x81e3,0x81e5,0x81e7,0x81e8,0x81ea,0x81ed,0x81ef,0x81f6,0x81f8,0x8205,0x8207,0x8210,0x8212,0x8214,0x8216,0x821f,0x8221,0x8222,0x8228,0x822c,0x822e,0x822e,0x8232,0x823a,0x823c,0x823c,0x8240,0x8240,0x8243,0x8247,0x8249,0x8249,0x824b,0x824b,0x824e,0x824f,0x8251,0x8251,0x8256,0x825a,0x825c,0x825d,0x825f,0x8260,0x8262,0x8264,0x8266,0x8268,0x826a,0x826b,0x826d,0x826f,0x8271,0x8272,0x8274,0x8274,0x8276,0x8279,0x827b,0x827b,0x827d,0x8281,0x8283,0x8284,0x8287,0x8287,0x8289,0x828b,0x828d,0x828e,0x8291,0x8294,0x8296,0x8296,0x8298,0x829b,0x829d,0x829d,0x829f,0x82a1,0x82a3,0x82b4,0x82b7,0x82bf,0x82c5,0x82c6,0x82d0,0x82d5,0x82d7,0x82d7,0x82d9,0x82dc,0x82de,0x82e8,0x82ea,0x82eb,0x82ed,0x82ed,0x82ef,0x82ef,0x82f1,0x82f1,0x82f3,0x82f4,0x82f6,0x82f7,0x82f9,0x82fb,0x82fd,0x82fe,0x8300,0x830c,0x830e,0x830e,0x8316,0x8318,0x831b,0x831f,0x8321,0x8323,0x8328,0x8328,0x832b,0x833a,0x833c,0x833d,0x8340,0x8340,0x8342,0x8347,0x8349,0x834a,0x834d,0x8358,0x835a,0x835a,0x8362,0x8363,0x8370,0x8370,0x8373,0x8373,0x8375,0x8375,0x8377,0x8378,0x837b,0x837d,0x837f,0x8380,0x8382,0x8382,0x8384,0x8387,0x8389,0x838a,0x838d,0x838e,0x8392,0x8396,0x8398,0x83a0,0x83a2,0x83a2,0x83a6,0x83ad,0x83b1,0x83b1,0x83b5,0x83b5,0x83bd,0x83c1,0x83c5,0x83c5,0x83c7,0x83c7,0x83c9,0x83ca,0x83cc,0x83cc,0x83ce,0x83d1,0x83d3,0x83d4,0x83d6,0x83d6,0x83d8,0x83d8,0x83dc,0x83dd,0x83df,0x83e1,0x83e5,0x83e5,0x83e8,0x83eb,0x83ef,0x83f2,0x83f4,0x83f4,0x83f6,0x83f9,0x83fb,0x83fd,0x8401,0x8401,0x8403,0x8404,0x8406,0x8407,0x840a,0x840f,0x8411,0x8411,0x8413,0x8413,0x8415,0x8415,0x8417,0x8417,0x8419,0x8419,0x8420,0x8420,0x8422,0x8422,0x8429,0x842a,0x842c,0x842c,0x842f,0x842f,0x8431,0x8431,0x8435,0x8435,0x8438,0x8439,0x843c,0x843d,0x8445,0x844a,0x844d,0x844f,0x8451,0x8452,0x8456,0x845c,0x845f,0x8467,0x8469,0x8471,0x8473,0x847a,0x847c,0x847d,0x8481,0x8482,0x8484,0x8485,0x848b,0x848b,0x8490,0x8490,0x8492,0x8495,0x8497,0x8497,0x8499,0x8499,0x849c,0x849c,0x849e,0x849f,0x84a1,0x84a1,0x84a6,0x84a6,0x84a8,0x84aa,0x84ad,0x84ad,0x84af,0x84af,0x84b1,0x84b2,0x84b4,0x84b4,0x84b8,0x84c2,0x84c4,0x84c4,0x84c6,0x84d1,0x84d3,0x84d3,0x84d6,0x84d6,0x84d9,0x84da,0x84dc,0x84dc,0x84e7,0x84e7,0x84ea,0x84ea,0x84ec,0x84ec,0x84ee,0x84f2,0x84f4,0x84f4,0x84f7,0x84f7,0x84fa,0x84fd,0x84ff,0x8500,0x8502,0x8503,0x8506,0x8507,0x850c,0x850c,0x850e,0x850e,0x8510,0x8511,0x8513,0x8515,0x8517,0x8518,0x851a,0x851c,0x851e,0x851f,0x8521,0x8527,0x852a,0x852d,0x852f,0x852f,0x8532,0x8536,0x853d,0x8541,0x8543,0x8543,0x8546,0x8546,0x8548,0x854b,0x854e,0x8553,0x8555,0x855a,0x855c,0x8564,0x8568,0x856b,0x856d,0x856d,0x856f,0x856f,0x8577,0x8577,0x8579,0x857b,0x857d,0x8581,0x8584,0x858c,0x858f,0x8591,0x8593,0x8594,0x8597,0x8599,0x859b,0x859d,0x859f,0x85a0,0x85a2,0x85a2,0x85a4,0x85b0,0x85b4,0x85b4,0x85b6,0x85ba,0x85bc,0x85bf,0x85c1,0x85c2,0x85c7,0x85c7,0x85c9,0x85cb,0x85cd,0x85d0,0x85d5,0x85d5,0x85d8,0x85da,0x85dc,0x85dd,0x85df,0x85e1,0x85e4,0x85e6,0x85e8,0x85ea,0x85ed,0x85ed,0x85f3,0x85f4,0x85f6,0x85f7,0x85f9,0x85fc,0x85fe,0x8600,0x8602,0x8602,0x8604,0x8607,0x860a,0x860b,0x860d,0x860e,0x8610,0x8613,0x8616,0x861b,0x861e,0x861e,0x8621,0x8622,0x8624,0x8624,0x8627,0x8627,0x8629,0x8629,0x862d,0x862d,0x862f,0x8630,0x8636,0x8636,0x8638,0x863a,0x863c,0x863d,0x863f,0x8642,0x8646,0x8646,0x864d,0x864e,0x8650,0x8650,0x8652,0x8664,0x8667,0x8667,0x8669,0x8669,0x866b,0x866c,0x866f,0x866f,0x8671,0x8671,0x8675,0x8677,0x8679,0x867b,0x867d,0x867d,0x8687,0x868d,0x8691,0x8691,0x8693,0x8693,0x8695,0x8696,0x8698,0x8698,0x869a,0x869a,0x869c,0x869d,0x86a1,0x86a1,0x86a3,0x86a4,0x86a6,0x86ab,0x86ad,0x86ad,0x86af,0x86b1,0x86b3,0x86b9,0x86bf,0x86c1,0x86c3,0x86c7,0x86c9,0x86c9,0x86cb,0x86cb,0x86cd,0x86ce,0x86d1,0x86d2,0x86d4,0x86d5,0x86d7,0x86d7,0x86d9,0x86dc,0x86de,0x86e0,0x86e3,0x86e7,0x86e9,0x86e9,0x86ec,0x86ef,0x86f8,0x86fe,0x8700,0x8700,0x8702,0x870b,0x870d,0x8714,0x8718,0x871a,0x871c,0x871c,0x871e,0x871f,0x8721,0x8723,0x8725,0x8725,0x8728,0x8729,0x872e,0x872f,0x8731,0x8732,0x8734,0x8734,0x8737,0x8737,0x8739,0x8740,0x8743,0x8743,0x8745,0x8745,0x8749,0x8749,0x874b,0x874e,0x8751,0x8751,0x8753,0x8753,0x8755,0x8755,0x8757,0x8759,0x875d,0x875d,0x875f,0x8761,0x8763,0x8766,0x8768,0x8768,0x876a,0x876a,0x876e,0x876f,0x8771,0x8772,0x8774,0x8774,0x8776,0x8776,0x8778,0x8778,0x877b,0x877c,0x877f,0x877f,0x8782,0x8789,0x878b,0x878e,0x8790,0x8790,0x8793,0x8793,0x8795,0x8795,0x8797,0x8799,0x879e,0x87a0,0x87a2,0x87a3,0x87a7,0x87a7,0x87ab,0x87af,0x87b1,0x87b1,0x87b3,0x87b3,0x87b5,0x87b5,0x87ba,0x87bb,0x87bd,0x87c1,0x87c4,0x87c4,0x87c6,0x87cb,0x87ce,0x87ce,0x87d0,0x87d0,0x87d2,0x87d2,0x87d5,0x87d6,0x87d9,0x87da,0x87dc,0x87dc,0x87df,0x87e0,0x87e2,0x87e6,0x87ea,0x87ed,0x87ef,0x87ef,0x87f1,0x87f3,0x87f5,0x87fb,0x87fe,0x87ff,0x8801,0x8801,0x8803,0x8803,0x8805,0x8807,0x8809,0x880b,0x880d,0x8816,0x8818,0x881c,0x881e,0x881f,0x8821,0x8823,0x8827,0x8828,0x882d,0x882e,0x8830,0x8832,0x8835,0x8836,0x8839,0x883c,0x8840,0x8846,0x8848,0x884e,0x8851,0x8853,0x8855,0x8864,0x8868,0x8869,0x886b,0x886b,0x886e,0x8872,0x8875,0x8875,0x8877,0x8877,0x8879,0x8879,0x887b,0x887b,0x887d,0x8882,0x8888,0x8888,0x888b,0x888b,0x888d,0x888d,0x8892,0x8892,0x8896,0x889c,0x889e,0x88a0,0x88a2,0x88a2,0x88a4,0x88a4,0x88a8,0x88a8,0x88aa,0x88ab,0x88ae,0x88ae,0x88b0,0x88b1,0x88b4,0x88b5,0x88b7,0x88b7,0x88ba,0x88ba,0x88bc,0x88c6,0x88ca,0x88cf,0x88d1,0x88d5,0x88d8,0x88d9,0x88db,0x88e1,0x88e7,0x88e8,0x88ef,0x88f5,0x88f7,0x88f9,0x88fc,0x88fe,0x8901,0x8902,0x8904,0x8904,0x8906,0x8907,0x890a,0x890a,0x890c,0x8910,0x8912,0x8913,0x8915,0x8916,0x8918,0x891a,0x891c,0x891e,0x8920,0x8920,0x8925,0x8928,0x892a,0x892b,0x8930,0x8932,0x8935,0x893b,0x893e,0x893e,0x8940,0x8946,0x8949,0x8949,0x894c,0x894d,0x894f,0x894f,0x8952,0x8952,0x8956,0x8957,0x895a,0x895c,0x895e,0x8964,0x8966,0x8966,0x896a,0x896b,0x896d,0x8970,0x8972,0x8975,0x8977,0x8977,0x897a,0x8981,0x8983,0x8983,0x8986,0x898b,0x898d,0x898d,0x898f,0x8990,0x8993,0x8998,0x899a,0x899c,0x899f,0x89a1,0x89a5,0x89a7,0x89a9,0x89aa,0x89ac,0x89ac,0x89af,0x89b0,0x89b2,0x89b7,0x89ba,0x89ba,0x89bc,0x89bd,0x89bf,0x89c1,0x89d2,0x89d2,0x89d4,0x89d8,0x89da,0x89da,0x89dc,0x89dd,0x89e3,0x89e3,0x89e5,0x89e7,0x89e9,0x89e9,0x89eb,0x89eb,0x89ed,0x89ed,0x89f1,0x89f1,0x89f3,0x89f4,0x89f6,0x89f6,0x89f8,0x89f9,0x89fd,0x89fd,0x89ff,0x8a05,0x8a07,0x8a08,0x8a0a,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a18,0x8a1b,0x8a1b,0x8a1d,0x8a26,0x8a2a,0x8a2d,0x8a2f,0x8a2f,0x8a31,0x8a31,0x8a33,0x8a37,0x8a3a,0x8a3e,0x8a40,0x8a41,0x8a43,0x8a43,0x8a45,0x8a49,0x8a4d,0x8a4e,0x8a50,0x8a58,0x8a5b,0x8a5e,0x8a60,0x8a63,0x8a65,0x8a67,0x8a69,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a73,0x8a75,0x8a77,0x8a79,0x8a7c,0x8a7e,0x8a80,0x8a82,0x8a87,0x8a89,0x8a89,0x8a8b,0x8a8d,0x8a8f,0x8a93,0x8a95,0x8a9a,0x8a9e,0x8aa1,0x8aa3,0x8aaa,0x8aac,0x8ab0,0x8ab2,0x8ab3,0x8ab6,0x8ab7,0x8ab9,0x8ab9,0x8abb,0x8abc,0x8abe,0x8abf,0x8ac2,0x8ac4,0x8ac6,0x8acd,0x8acf,0x8ad7,0x8ada,0x8ae2,0x8ae4,0x8ae4,0x8ae6,0x8ae7,0x8aeb,0x8aee,0x8af0,0x8af1,0x8af3,0x8af8,0x8afa,0x8afa,0x8afc,0x8afc,0x8afe,0x8b02,0x8b04,0x8b07,0x8b0a,0x8b11,0x8b14,0x8b14,0x8b16,0x8b17,0x8b19,0x8b21,0x8b26,0x8b26,0x8b28,0x8b28,0x8b2b,0x8b2d,0x8b30,0x8b30,0x8b33,0x8b33,0x8b37,0x8b37,0x8b39,0x8b39,0x8b3c,0x8b3c,0x8b3e,0x8b3e,0x8b41,0x8b46,0x8b48,0x8b49,0x8b4c,0x8b4f,0x8b51,0x8b54,0x8b56,0x8b56,0x8b58,0x8b5c,0x8b5e,0x8b5f,0x8b63,0x8b63,0x8b66,0x8b66,0x8b69,0x8b69,0x8b6b,0x8b6d,0x8b6f,0x8b72,0x8b74,0x8b74,0x8b76,0x8b79,0x8b7c,0x8b81,0x8b83,0x8b85,0x8b8a,0x8b90,0x8b92,0x8b96,0x8b99,0x8b9a,0x8b9c,0x8ba0,0x8c37,0x8c3a,0x8c3d,0x8c3f,0x8c41,0x8c41,0x8c45,0x8c4c,0x8c4e,0x8c51,0x8c53,0x8c55,0x8c57,0x8c5b,0x8c5d,0x8c5d,0x8c61,0x8c64,0x8c66,0x8c66,0x8c68,0x8c6d,0x8c73,0x8c73,0x8c75,0x8c76,0x8c78,0x8c7c,0x8c7e,0x8c7e,0x8c82,0x8c82,0x8c85,0x8c87,0x8c89,0x8c8e,0x8c90,0x8c90,0x8c92,0x8c94,0x8c98,0x8c99,0x8c9b,0x8ca2,0x8ca4,0x8ca4,0x8ca7,0x8cb0,0x8cb2,0x8cb4,0x8cb6,0x8cbd,0x8cbf,0x8ccb,0x8ccd,0x8ccf,0x8cd1,0x8cd3,0x8cd5,0x8cd6,0x8cd9,0x8cde,0x8ce0,0x8ce4,0x8ce6,0x8ce6,0x8ce8,0x8ce8,0x8cea,0x8cea,0x8cec,0x8ced,0x8cef,0x8cf2,0x8cf4,0x8cf5,0x8cf7,0x8cf8,0x8cfa,0x8cff,0x8d01,0x8d01,0x8d03,0x8d05,0x8d07,0x8d0b,0x8d0d,0x8d10,0x8d12,0x8d14,0x8d16,0x8d17,0x8d1b,0x8d1d,0x8d64,0x8d67,0x8d69,0x8d69,0x8d6b,0x8d6e,0x8d70,0x8d71,0x8d73,0x8d74,0x8d76,0x8d77,0x8d7f,0x8d7f,0x8d81,0x8d82,0x8d84,0x8d85,0x8d88,0x8d88,0x8d8a,0x8d8a,0x8d8d,0x8d8d,0x8d90,0x8d91,0x8d95,0x8d95,0x8d99,0x8d99,0x8d9e,0x8da0,0x8da3,0x8da3,0x8da6,0x8da6,0x8da8,0x8da8,0x8dab,0x8dac,0x8daf,0x8daf,0x8db2,0x8db3,0x8db5,0x8db5,0x8db7,0x8db7,0x8db9,0x8dbc,0x8dbe,0x8dbe,0x8dc0,0x8dc0,0x8dc2,0x8dc2,0x8dc5,0x8dc8,0x8dca,0x8dcc,0x8dce,0x8dcf,0x8dd1,0x8dd1,0x8dd4,0x8dd7,0x8dd9,0x8ddb,0x8ddd,0x8ddd,0x8ddf,0x8ddf,0x8de1,0x8de1,0x8de3,0x8de5,0x8de7,0x8de8,0x8dea,0x8dec,0x8def,0x8df5,0x8dfc,0x8dfd,0x8dff,0x8dff,0x8e01,0x8e01,0x8e04,0x8e06,0x8e08,0x8e0c,0x8e0f,0x8e11,0x8e14,0x8e14,0x8e16,0x8e16,0x8e1d,0x8e23,0x8e26,0x8e27,0x8e2a,0x8e2a,0x8e30,0x8e31,0x8e33,0x8e39,0x8e3d,0x8e3d,0x8e40,0x8e42,0x8e44,0x8e44,0x8e47,0x8e50,0x8e54,0x8e55,0x8e59,0x8e59,0x8e5b,0x8e64,0x8e69,0x8e69,0x8e6c,0x8e6d,0x8e6f,0x8e72,0x8e74,0x8e77,0x8e79,0x8e7c,0x8e81,0x8e85,0x8e87,0x8e87,0x8e89,0x8e8b,0x8e8d,0x8e8d,0x8e90,0x8e95,0x8e98,0x8e9b,0x8e9d,0x8e9e,0x8ea1,0x8ea2,0x8ea7,0x8ea7,0x8ea9,0x8eb1,0x8eb3,0x8eb3,0x8eb5,0x8eb6,0x8eba,0x8ebb,0x8ebe,0x8ebe,0x8ec0,0x8ec1,0x8ec3,0x8ec8,0x8eca,0x8ecd,0x8ecf,0x8ecf,0x8ed1,0x8ed2,0x8ed4,0x8ed4,0x8edb,0x8edc,0x8edf,0x8edf,0x8ee2,0x8ee3,0x8ee8,0x8ee8,0x8eeb,0x8eeb,0x8eed,0x8eee,0x8ef0,0x8ef1,0x8ef7,0x8efe,0x8f00,0x8f00,0x8f02,0x8f03,0x8f05,0x8f05,0x8f07,0x8f0a,0x8f0c,0x8f0c,0x8f0f,0x8f10,0x8f12,0x8f19,0x8f1b,0x8f21,0x8f23,0x8f23,0x8f25,0x8f2f,0x8f33,0x8f3b,0x8f3e,0x8f47,0x8f49,0x8f4a,0x8f4c,0x8f4f,0x8f51,0x8f55,0x8f57,0x8f58,0x8f5c,0x8f5f,0x8f61,0x8f66,0x8f9b,0x8fa8,0x8fad,0x8fb2,0x8fb4,0x8fb8,0x8fba,0x8fbc,0x8fbe,0x8fc2,0x8fc4,0x8fc6,0x8fc8,0x8fc8,0x8fca,0x8fcb,0x8fcd,0x8fce,0x8fd0,0x8fd5,0x8fda,0x8fda,0x8fe0,0x8fe0,0x8fe2,0x8fe6,0x8fe8,0x8feb,0x8fed,0x8ff1,0x8ff4,0x8ffb,0x8ffd,0x8ffe,0x9000,0x9006,0x9008,0x9008,0x900b,0x9011,0x9013,0x901b,0x901d,0x9023,0x9027,0x902a,0x902c,0x902f,0x9031,0x9039,0x903c,0x903c,0x903e,0x903f,0x9041,0x9045,0x9047,0x9047,0x9049,0x9056,0x9058,0x9059,0x905b,0x905e,0x9060,0x9063,0x9065,0x9069,0x906c,0x9070,0x9072,0x9072,0x9074,0x907a,0x907c,0x907d,0x907f,0x9085,0x9087,0x908c,0x908e,0x9091,0x9095,0x9095,0x9097,0x9099,0x909b,0x909b,0x90a0,0x90a3,0x90a5,0x90a6,0x90a8,0x90a8,0x90aa,0x90aa,0x90af,0x90b6,0x90b8,0x90b8,0x90bd,0x90be,0x90c1,0x90c1,0x90c3,0x90c5,0x90c7,0x90ca,0x90cc,0x90cc,0x90ce,0x90ce,0x90d2,0x90d2,0x90d5,0x90d5,0x90d7,0x90d9,0x90db,0x90df,0x90e1,0x90e2,0x90e4,0x90e5,0x90e8,0x90e8,0x90eb,0x90eb,0x90ed,0x90ed,0x90ef,0x90f0,0x90f2,0x90f2,0x90f4,0x90f7,0x90fd,0x9100,0x9102,0x9102,0x9104,0x9106,0x9108,0x9108,0x910d,0x910d,0x9110,0x9110,0x9112,0x9112,0x9114,0x911a,0x911c,0x911c,0x911e,0x911e,0x9120,0x9120,0x9122,0x9123,0x9125,0x9125,0x9127,0x9127,0x9129,0x9129,0x912d,0x9132,0x9134,0x9134,0x9136,0x9137,0x9139,0x913a,0x913c,0x913d,0x9143,0x9143,0x9146,0x914f,0x9152,0x9154,0x9156,0x915b,0x9161,0x9165,0x9167,0x9167,0x9169,0x916a,0x916c,0x916d,0x9172,0x9175,0x9177,0x917b,0x9181,0x9183,0x9185,0x9187,0x9189,0x918b,0x918d,0x918e,0x9190,0x9195,0x9197,0x9198,0x919c,0x919c,0x919e,0x919e,0x91a1,0x91a2,0x91a4,0x91a4,0x91a6,0x91a6,0x91a8,0x91a8,0x91aa,0x91b6,0x91b8,0x91b8,0x91ba,0x91bd,0x91bf,0x91c9,0x91cb,0x91d1,0x91d3,0x91d4,0x91d6,0x91df,0x91e1,0x91e1,0x91e3,0x91e7,0x91e9,0x91ea,0x91ec,0x91f1,0x91f5,0x91f7,0x91f9,0x91f9,0x91fb,0x91fd,0x91ff,0x9201,0x9204,0x9207,0x9209,0x920a,0x920c,0x920e,0x9210,0x9218,0x921c,0x921e,0x9223,0x9226,0x9228,0x9229,0x922c,0x922c,0x922e,0x9230,0x9233,0x923a,0x923c,0x923c,0x923e,0x9240,0x9242,0x924b,0x924d,0x9251,0x9256,0x925e,0x9260,0x9262,0x9264,0x9269,0x926e,0x9271,0x9275,0x9279,0x927b,0x9280,0x9283,0x9283,0x9285,0x9285,0x9288,0x928a,0x928d,0x928e,0x9291,0x9293,0x9295,0x929c,0x929f,0x92a0,0x92a4,0x92a5,0x92a7,0x92a8,0x92ab,0x92ab,0x92ad,0x92ad,0x92af,0x92af,0x92b2,0x92b3,0x92b6,0x92bd,0x92bf,0x92c3,0x92c5,0x92c8,0x92cb,0x92d0,0x92d2,0x92d3,0x92d5,0x92d5,0x92d7,0x92d9,0x92dc,0x92dd,0x92df,0x92e1,0x92e3,0x92e5,0x92e7,0x92ea,0x92ec,0x92ee,0x92f0,0x92f0,0x92f2,0x92f3,0x92f7,0x92fc,0x92ff,0x9300,0x9302,0x9302,0x9304,0x9304,0x9306,0x9306,0x9308,0x9308,0x930d,0x930d,0x930f,0x9311,0x9314,0x9315,0x9318,0x931a,0x931c,0x932c,0x932e,0x932f,0x9332,0x9337,0x933a,0x933b,0x9344,0x9344,0x9347,0x934b,0x934d,0x934d,0x9350,0x9352,0x9354,0x9358,0x935a,0x935c,0x935e,0x935e,0x9360,0x9360,0x9364,0x9365,0x9367,0x9367,0x9369,0x9371,0x9373,0x9376,0x937a,0x937a,0x937c,0x9382,0x9388,0x9388,0x938a,0x938d,0x938f,0x938f,0x9392,0x9392,0x9394,0x9398,0x939a,0x939b,0x939e,0x939e,0x93a1,0x93a1,0x93a3,0x93a4,0x93a6,0x93a9,0x93ab,0x93ae,0x93b0,0x93b0,0x93b4,0x93b6,0x93b9,0x93bb,0x93c1,0x93c1,0x93c3,0x93cd,0x93d0,0x93d1,0x93d3,0x93d3,0x93d6,0x93d9,0x93dc,0x93df,0x93e1,0x93e2,0x93e4,0x93e8,0x93f1,0x93f1,0x93f5,0x93f5,0x93f7,0x93fb,0x93fd,0x93fd,0x9401,0x9404,0x9407,0x9409,0x940d,0x9410,0x9413,0x941a,0x941f,0x941f,0x9421,0x9421,0x942b,0x942b,0x942e,0x942f,0x9431,0x9436,0x9438,0x9438,0x943a,0x943b,0x943d,0x943d,0x943f,0x943f,0x9441,0x9441,0x9443,0x9445,0x9448,0x9448,0x944a,0x944a,0x944c,0x944c,0x9451,0x9453,0x9455,0x9455,0x9459,0x945c,0x945e,0x9463,0x9468,0x9468,0x946a,0x946b,0x946d,0x9472,0x9475,0x9475,0x9477,0x9477,0x947c,0x947f,0x9481,0x9481,0x9483,0x9485,0x9577,0x9579,0x957e,0x9580,0x9582,0x9584,0x9586,0x958f,0x9591,0x9594,0x9596,0x9596,0x9598,0x9599,0x959d,0x95a9,0x95ab,0x95ad,0x95b1,0x95b2,0x95b4,0x95b4,0x95b6,0x95b6,0x95b9,0x95bf,0x95c3,0x95c3,0x95c6,0x95cd,0x95d0,0x95d6,0x95d8,0x95da,0x95dc,0x95e2,0x95e4,0x95e6,0x95e8,0x95e8,0x961c,0x961e,0x9621,0x9622,0x9624,0x9626,0x9628,0x9628,0x962a,0x962a,0x962c,0x962c,0x962e,0x962f,0x9631,0x9634,0x9637,0x963d,0x963f,0x9642,0x9644,0x9644,0x964b,0x964d,0x964f,0x9650,0x9652,0x9652,0x9654,0x9654,0x9656,0x9658,0x965b,0x965f,0x9661,0x9666,0x966a,0x966a,0x966c,0x966c,0x966e,0x966e,0x9670,0x9670,0x9672,0x9678,0x967a,0x967f,0x9681,0x9686,0x9688,0x968b,0x968d,0x968f,0x9691,0x9691,0x9694,0x969d,0x969f,0x96a0,0x96a3,0x96aa,0x96ae,0x96b4,0x96b6,0x96bd,0x96c0,0x96c1,0x96c4,0x96c7,0x96c9,0x96ce,0x96d1,0x96d2,0x96d5,0x96d6,0x96d8,0x96df,0x96e2,0x96e3,0x96e8,0x96eb,0x96ef,0x96f2,0x96f6,0x96f7,0x96f9,0x96fb,0x9700,0x9700,0x9702,0x970a,0x970d,0x970f,0x9711,0x9711,0x9713,0x9714,0x9716,0x9716,0x9719,0x971e,0x9721,0x9724,0x9727,0x9728,0x972a,0x972a,0x9730,0x9733,0x9736,0x9736,0x9738,0x9739,0x973b,0x973b,0x973d,0x973e,0x9741,0x9744,0x9746,0x974a,0x974d,0x974f,0x9751,0x9752,0x9755,0x975c,0x975e,0x975e,0x9760,0x9764,0x9766,0x976b,0x976d,0x976e,0x9771,0x9771,0x9773,0x9774,0x9776,0x977d,0x977f,0x9781,0x9784,0x9786,0x9789,0x9789,0x978b,0x978b,0x978d,0x978d,0x978f,0x9790,0x9795,0x979a,0x979c,0x979c,0x979e,0x97a0,0x97a2,0x97a3,0x97a6,0x97a6,0x97a8,0x97a8,0x97ab,0x97ae,0x97b1,0x97b6,0x97b8,0x97ba,0x97bc,0x97bc,0x97be,0x97bf,0x97c1,0x97c1,0x97c3,0x97ce,0x97d0,0x97d1,0x97d3,0x97d4,0x97d7,0x97d9,0x97db,0x97de,0x97e0,0x97e1,0x97e4,0x97e4,0x97e6,0x97e6,0x97ed,0x97ef,0x97f1,0x97f8,0x97fa,0x97fb,0x97ff,0x97ff,0x9801,0x9808,0x980a,0x980a,0x980c,0x9814,0x9816,0x981a,0x981c,0x981c,0x981e,0x981e,0x9820,0x9821,0x9823,0x9826,0x982b,0x9830,0x9832,0x9835,0x9837,0x9839,0x983b,0x983e,0x9844,0x9844,0x9846,0x9847,0x984a,0x984f,0x9851,0x985b,0x985e,0x985e,0x9862,0x9863,0x9865,0x9867,0x986a,0x986c,0x986f,0x9871,0x9873,0x9875,0x98a8,0x98a8,0x98aa,0x98ab,0x98ad,0x98b1,0x98b4,0x98b4,0x98b6,0x98b8,0x98ba,0x98bc,0x98bf,0x98bf,0x98c2,0x98c8,0x98cb,0x98cc,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e3,0x98e5,0x98e7,0x98e9,0x98eb,0x98ed,0x98f4,0x98f6,0x98f6,0x98fc,0x98fe,0x9902,0x9903,0x9905,0x9905,0x9907,0x990a,0x990c,0x990c,0x9910,0x9918,0x991a,0x9922,0x9924,0x9924,0x9926,0x9928,0x992b,0x992c,0x992e,0x992e,0x9931,0x9935,0x9939,0x993e,0x9940,0x9942,0x9945,0x9949,0x994b,0x994e,0x9950,0x9952,0x9954,0x9955,0x9957,0x9959,0x995b,0x995c,0x995e,0x9960,0x9963,0x9963,0x9996,0x9999,0x999b,0x999b,0x999d,0x999f,0x99a3,0x99a3,0x99a5,0x99a6,0x99a8,0x99a8,0x99ac,0x99ae,0x99b0,0x99b5,0x99b9,0x99ba,0x99bc,0x99bd,0x99bf,0x99bf,0x99c1,0x99c1,0x99c3,0x99c6,0x99c8,0x99c9,0x99d0,0x99d5,0x99d8,0x99df,0x99e1,0x99e2,0x99e7,0x99e7,0x99ea,0x99ee,0x99f0,0x99f2,0x99f4,0x99f5,0x99f8,0x99f9,0x99fb,0x99ff,0x9a01,0x9a05,0x9a08,0x9a08,0x9a0a,0x9a0c,0x9a0e,0x9a13,0x9a16,0x9a16,0x9a19,0x9a1a,0x9a1e,0x9a1e,0x9a20,0x9a20,0x9a22,0x9a24,0x9a27,0x9a28,0x9a2b,0x9a2b,0x9a2d,0x9a2e,0x9a30,0x9a31,0x9a33,0x9a33,0x9a35,0x9a38,0x9a3e,0x9a3e,0x9a40,0x9a45,0x9a47,0x9a47,0x9a4a,0x9a4e,0x9a51,0x9a52,0x9a54,0x9a58,0x9a5a,0x9a5b,0x9a5d,0x9a5d,0x9a5f,0x9a5f,0x9a62,0x9a62,0x9a64,0x9a65,0x9a69,0x9a6c,0x9aa8,0x9aa8,0x9aaa,0x9aaa,0x9aac,0x9ab0,0x9ab2,0x9ab2,0x9ab4,0x9ab9,0x9abb,0x9ac1,0x9ac3,0x9ac4,0x9ac6,0x9ac6,0x9ac8,0x9ac8,0x9ace,0x9ad9,0x9adb,0x9adc,0x9ade,0x9ae0,0x9ae2,0x9ae7,0x9ae9,0x9aef,0x9af1,0x9af5,0x9af7,0x9af7,0x9af9,0x9afb,0x9afd,0x9afd,0x9aff,0x9b06,0x9b08,0x9b09,0x9b0b,0x9b0e,0x9b10,0x9b10,0x9b12,0x9b12,0x9b16,0x9b16,0x9b18,0x9b1d,0x9b1f,0x9b20,0x9b22,0x9b23,0x9b25,0x9b2f,0x9b31,0x9b35,0x9b37,0x9b37,0x9b39,0x9b3d,0x9b41,0x9b45,0x9b48,0x9b48,0x9b4b,0x9b4f,0x9b51,0x9b51,0x9b54,0x9b58,0x9b5a,0x9b5b,0x9b5e,0x9b5e,0x9b61,0x9b61,0x9b63,0x9b63,0x9b65,0x9b66,0x9b68,0x9b68,0x9b6a,0x9b6f,0x9b72,0x9b79,0x9b7f,0x9b80,0x9b83,0x9b87,0x9b89,0x9b8b,0x9b8d,0x9b94,0x9b96,0x9b97,0x9b9a,0x9b9a,0x9b9d,0x9ba0,0x9ba6,0x9bae,0x9bb0,0x9bb2,0x9bb4,0x9bb4,0x9bb7,0x9bb9,0x9bbb,0x9bbc,0x9bbe,0x9bc1,0x9bc6,0x9bca,0x9bce,0x9bd2,0x9bd4,0x9bd4,0x9bd6,0x9bd8,0x9bdb,0x9bdb,0x9bdd,0x9bdd,0x9bdf,0x9bdf,0x9be1,0x9be5,0x9be7,0x9be8,0x9bea,0x9beb,0x9bee,0x9bf3,0x9bf5,0x9bf5,0x9bf7,0x9bfa,0x9bfd,0x9bfd,0x9bff,0x9c00,0x9c02,0x9c02,0x9c04,0x9c04,0x9c06,0x9c06,0x9c08,0x9c0d,0x9c0f,0x9c16,0x9c18,0x9c1e,0x9c21,0x9c2a,0x9c2d,0x9c32,0x9c35,0x9c37,0x9c39,0x9c3b,0x9c3d,0x9c3e,0x9c41,0x9c41,0x9c43,0x9c4a,0x9c4e,0x9c50,0x9c52,0x9c54,0x9c56,0x9c58,0x9c5a,0x9c61,0x9c63,0x9c63,0x9c65,0x9c65,0x9c67,0x9c6b,0x9c6d,0x9c6e,0x9c70,0x9c70,0x9c72,0x9c72,0x9c75,0x9c78,0x9c7a,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9ce9,0x9ceb,0x9cec,0x9cf0,0x9cf0,0x9cf2,0x9cf4,0x9cf6,0x9cf7,0x9cf9,0x9cf9,0x9d02,0x9d03,0x9d06,0x9d09,0x9d0b,0x9d0b,0x9d0e,0x9d0e,0x9d11,0x9d12,0x9d15,0x9d15,0x9d17,0x9d18,0x9d1b,0x9d1f,0x9d23,0x9d23,0x9d26,0x9d26,0x9d28,0x9d28,0x9d2a,0x9d2c,0x9d2f,0x9d30,0x9d32,0x9d34,0x9d3a,0x9d3f,0x9d41,0x9d48,0x9d4a,0x9d4a,0x9d50,0x9d54,0x9d59,0x9d59,0x9d5c,0x9d65,0x9d69,0x9d6c,0x9d6f,0x9d70,0x9d72,0x9d73,0x9d76,0x9d77,0x9d7a,0x9d7c,0x9d7e,0x9d7e,0x9d83,0x9d84,0x9d86,0x9d87,0x9d89,0x9d8a,0x9d8d,0x9d8f,0x9d92,0x9d93,0x9d95,0x9d9a,0x9da1,0x9da1,0x9da4,0x9da4,0x9da9,0x9dac,0x9dae,0x9daf,0x9db1,0x9db2,0x9db4,0x9db5,0x9db8,0x9dbd,0x9dbf,0x9dc4,0x9dc6,0x9dc7,0x9dc9,0x9dca,0x9dcf,0x9dcf,0x9dd3,0x9dd7,0x9dd9,0x9dda,0x9dde,0x9de0,0x9de3,0x9de3,0x9de5,0x9de7,0x9de9,0x9de9,0x9deb,0x9deb,0x9ded,0x9df0,0x9df2,0x9df4,0x9df8,0x9dfa,0x9dfd,0x9dfe,0x9e02,0x9e02,0x9e07,0x9e07,0x9e0a,0x9e0a,0x9e0d,0x9e0e,0x9e10,0x9e12,0x9e15,0x9e16,0x9e19,0x9e1f,0x9e75,0x9e75,0x9e78,0x9e7d,0x9e7f,0x9e85,0x9e87,0x9e88,0x9e8b,0x9e8c,0x9e8e,0x9e8f,0x9e91,0x9e93,0x9e95,0x9e98,0x9e9b,0x9e9b,0x9e9d,0x9e9f,0x9ea4,0x9ea6,0x9ea8,0x9eaa,0x9eac,0x9eb0,0x9eb3,0x9eb5,0x9eb8,0x9ebf,0x9ec3,0x9ec4,0x9ec6,0x9ec6,0x9ec8,0x9ec8,0x9ecb,0x9ed2,0x9ed4,0x9ed5,0x9ed8,0x9ed9,0x9edb,0x9ee0,0x9ee4,0x9ee5,0x9ee7,0x9ee8,0x9eec,0x9ef2,0x9ef4,0x9ef9,0x9efb,0x9eff,0x9f02,0x9f03,0x9f07,0x9f09,0x9f0e,0x9f17,0x9f19,0x9f1b,0x9f1f,0x9f22,0x9f26,0x9f26,0x9f2a,0x9f2c,0x9f2f,0x9f2f,0x9f31,0x9f32,0x9f34,0x9f34,0x9f37,0x9f37,0x9f39,0x9f3f,0x9f41,0x9f41,0x9f43,0x9f47,0x9f4a,0x9f4b,0x9f4e,0x9f50,0x9f52,0x9f58,0x9f5a,0x9f5a,0x9f5d,0x9f63,0x9f66,0x9f6a,0x9f6c,0x9f73,0x9f75,0x9f77,0x9f7a,0x9f7a,0x9f7d,0x9f7d,0x9f7f,0x9f7f,0x9f8d,0x9f8d,0x9f8f,0x9f92,0x9f94,0x9f97,0x9f99,0x9f99,0x9f9c,0x9fa3,0x9fa5,0x9fa5,0x9fb4,0x9fb4,0x9fbc,0x9fc2,0x9fc4,0x9fc4,0x9fc6,0x9fc6,0x9fcc,0x9fcc,0xf900,0xf959,0xf95b,0xf9f2,0xf9f4,0xfa0b,0xfa0e,0xfa6d,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x2000b,0x2000b,0x20089,0x2008a,0x200a2,0x200a2,0x200a4,0x200a4,0x200b0,0x200b0,0x200f5,0x200f5,0x20158,0x20158,0x201a2,0x201a2,0x20213,0x20213,0x2032b,0x2032b,0x20371,0x20371,0x20381,0x20381,0x203f9,0x203f9,0x2044a,0x2044a,0x20509,0x20509,0x2053f,0x2053f,0x205b1,0x205b1,0x205d6,0x205d6,0x20611,0x20611,0x20628,0x20628,0x206ec,0x206ec,0x2074f,0x2074f,0x207c8,0x207c8,0x20807,0x20807,0x2083a,0x2083a,0x208b9,0x208b9,0x2090e,0x2090e,0x2097c,0x2097c,0x20984,0x20984,0x2099d,0x2099d,0x20a64,0x20a64,0x20ad3,0x20ad3,0x20b1d,0x20b1d,0x20b9f,0x20b9f,0x20bb7,0x20bb7,0x20d45,0x20d45,0x20d58,0x20d58,0x20de1,0x20de1,0x20e64,0x20e64,0x20e6d,0x20e6d,0x20e95,0x20e95,0x20f5f,0x20f5f,0x21201,0x21201,0x2123d,0x2123d,0x21255,0x21255,0x21274,0x21274,0x2127b,0x2127b,0x212d7,0x212d7,0x212e4,0x212e4,0x212fd,0x212fd,0x2131b,0x2131b,0x21336,0x21336,0x21344,0x21344,0x213c4,0x213c4,0x2146d,0x2146e,0x215d7,0x215d7,0x21647,0x21647,0x216b4,0x216b4,0x21706,0x21706,0x21742,0x21742,0x218bd,0x218bd,0x219c3,0x219c3,0x21a1a,0x21a1a,0x21c56,0x21c56,0x21d2d,0x21d2d,0x21d45,0x21d45,0x21d62,0x21d62,0x21d78,0x21d78,0x21d92,0x21d92,0x21d9c,0x21d9c,0x21da1,0x21da1,0x21db7,0x21db7,0x21de0,0x21de0,0x21e33,0x21e34,0x21f1e,0x21f1e,0x21f76,0x21f76,0x21ffa,0x21ffa,0x2217b,0x2217b,0x22218,0x22218,0x2231e,0x2231e,0x223ad,0x223ad,0x22609,0x22609,0x226f3,0x226f3,0x2285b,0x2285b,0x228ab,0x228ab,0x2298f,0x2298f,0x22ab8,0x22ab8,0x22b46,0x22b46,0x22b4f,0x22b50,0x22ba6,0x22ba6,0x22c1d,0x22c1d,0x22c24,0x22c24,0x22de1,0x22de1,0x22e42,0x22e42,0x22feb,0x22feb,0x231b6,0x231b6,0x231c3,0x231c4,0x231f5,0x231f5,0x23372,0x23372,0x233cc,0x233cc,0x233d0,0x233d0,0x233d2,0x233d3,0x233d5,0x233d5,0x233da,0x233da,0x233df,0x233df,0x233e4,0x233e4,0x233fe,0x233fe,0x2344a,0x2344b,0x23451,0x23451,0x23465,0x23465,0x234e4,0x234e4,0x2355a,0x2355a,0x23594,0x23594,0x235c4,0x235c4,0x23638,0x2363a,0x23647,0x23647,0x2370c,0x2370c,0x2371c,0x2371c,0x2373f,0x2373f,0x23763,0x23764,0x237e7,0x237e7,0x237f1,0x237f1,0x237ff,0x237ff,0x23824,0x23824,0x2383d,0x2383d,0x23a98,0x23a98,0x23c7f,0x23c7f,0x23cbe,0x23cbe,0x23cfe,0x23cfe,0x23d00,0x23d00,0x23d0e,0x23d0e,0x23d40,0x23d40,0x23dd3,0x23dd3,0x23df9,0x23dfa,0x23f7e,0x23f7e,0x2404b,0x2404b,0x24096,0x24096,0x24103,0x24103,0x241c6,0x241c6,0x241fe,0x241fe,0x242ee,0x242ee,0x243bc,0x243bc,0x243d0,0x243d0,0x24629,0x24629,0x246a5,0x246a5,0x247f1,0x247f1,0x24896,0x24896,0x248e9,0x248e9,0x24a4d,0x24a4d,0x24b56,0x24b56,0x24b6f,0x24b6f,0x24c16,0x24c16,0x24d14,0x24d14,0x24e04,0x24e04,0x24e0e,0x24e0e,0x24e37,0x24e37,0x24e6a,0x24e6a,0x24e8b,0x24e8b,0x24ff2,0x24ff2,0x2504a,0x2504a,0x25055,0x25055,0x25122,0x25122,0x251a9,0x251a9,0x251cd,0x251cd,0x251e5,0x251e5,0x2521e,0x2521e,0x2524c,0x2524c,0x2542e,0x2542e,0x2548e,0x2548e,0x254d9,0x254d9,0x2550e,0x2550e,0x255a7,0x255a7,0x2567f,0x2567f,0x25771,0x25771,0x257a9,0x257a9,0x257b4,0x257b4,0x25874,0x25874,0x259c4,0x259c4,0x259cc,0x259cc,0x259d4,0x259d4,0x25ad7,0x25ad7,0x25ae3,0x25ae4,0x25af1,0x25af1,0x25bb2,0x25bb2,0x25c4b,0x25c4b,0x25c64,0x25c64,0x25da1,0x25da1,0x25e2e,0x25e2e,0x25e56,0x25e56,0x25e62,0x25e62,0x25e65,0x25e65,0x25ec2,0x25ec2,0x25ed8,0x25ed8,0x25ee8,0x25ee8,0x25f23,0x25f23,0x25f5c,0x25f5c,0x25fd4,0x25fd4,0x25fe0,0x25fe0,0x25ffb,0x25ffb,0x2600c,0x2600c,0x26017,0x26017,0x26060,0x26060,0x260ed,0x260ed,0x26222,0x26222,0x2626a,0x2626a,0x26270,0x26270,0x26286,0x26286,0x2634c,0x2634c,0x26402,0x26402,0x2667e,0x2667e,0x266b0,0x266b0,0x2671d,0x2671d,0x268dd,0x268dd,0x268ea,0x268ea,0x26951,0x26951,0x2696f,0x2696f,0x26999,0x26999,0x269dd,0x269dd,0x26a1e,0x26a1e,0x26a58,0x26a58,0x26a8c,0x26a8c,0x26ab7,0x26ab7,0x26aff,0x26aff,0x26c29,0x26c29,0x26c73,0x26c73,0x26c9e,0x26c9e,0x26cdd,0x26cdd,0x26e40,0x26e40,0x26e65,0x26e65,0x26f94,0x26f94,0x26ff6,0x26ff8,0x270f4,0x270f4,0x2710d,0x2710d,0x27139,0x27139,0x273da,0x273db,0x273fe,0x273fe,0x27410,0x27410,0x27449,0x27449,0x27614,0x27615,0x27631,0x27631,0x27684,0x27684,0x27693,0x27693,0x2770e,0x2770e,0x27723,0x27723,0x27752,0x27752,0x278b2,0x278b2,0x27985,0x27985,0x279b4,0x279b4,0x27a84,0x27a84,0x27bb3,0x27bb3,0x27bbe,0x27bbe,0x27bc7,0x27bc7,0x27c3c,0x27c3c,0x27cb8,0x27cb8,0x27d73,0x27d73,0x27da0,0x27da0,0x27e10,0x27e10,0x27eaf,0x27eaf,0x27fb7,0x27fb7,0x2808a,0x2808a,0x280bb,0x280bb,0x28277,0x28277,0x28282,0x28282,0x282f3,0x282f3,0x283cd,0x283cd,0x2840c,0x2840c,0x28455,0x28455,0x284dc,0x284dc,0x2856b,0x2856b,0x285c8,0x285c9,0x286d7,0x286d7,0x286fa,0x286fa,0x28946,0x28946,0x28949,0x28949,0x2896b,0x2896b,0x28987,0x28988,0x289ba,0x289bb,0x28a1e,0x28a1e,0x28a29,0x28a29,0x28a43,0x28a43,0x28a71,0x28a71,0x28a99,0x28a99,0x28acd,0x28acd,0x28add,0x28add,0x28ae4,0x28ae4,0x28bc1,0x28bc1,0x28bef,0x28bef,0x28cdd,0x28cdd,0x28d10,0x28d10,0x28d71,0x28d71,0x28dfb,0x28dfb,0x28e0f,0x28e0f,0x28e17,0x28e17,0x28e1f,0x28e1f,0x28e36,0x28e36,0x28e89,0x28e89,0x28eeb,0x28eeb,0x28ef6,0x28ef6,0x28f32,0x28f32,0x28ff8,0x28ff8,0x292a0,0x292a0,0x292b1,0x292b1,0x29490,0x29490,0x295cf,0x295cf,0x2967f,0x2967f,0x296f0,0x296f0,0x29719,0x29719,0x29750,0x29750,0x29810,0x29810,0x298c6,0x298c6,0x29a72,0x29a72,0x29d4b,0x29d4b,0x29ddb,0x29ddb,0x29e15,0x29e15,0x29e3d,0x29e3d,0x29e49,0x29e49,0x29e8a,0x29e8a,0x29ec4,0x29ec4,0x29edb,0x29edb,0x29ee9,0x29ee9,0x29fce,0x29fce,0x29fd7,0x29fd7,0x2a01a,0x2a01a,0x2a02f,0x2a02f,0x2a082,0x2a082,0x2a0f9,0x2a0f9,0x2a190,0x2a190,0x2a2b2,0x2a2b2,0x2a38c,0x2a38c,0x2a437,0x2a437,0x2a5f1,0x2a5f1,0x2a602,0x2a602,0x2a61a,0x2a61a,0x2a6b2,0x2a6b2,0x2a9e6,0x2a9e6,0x2b746,0x2b746,0x2b751,0x2b751,0x2b753,0x2b753,0x2b75a,0x2b75a,0x2b75c,0x2b75c,0x2b765,0x2b765,0x2b776,0x2b777,0x2b77c,0x2b77c,0x2b782,0x2b782,0x2b789,0x2b789,0x2b78b,0x2b78b,0x2b78e,0x2b78e,0x2b794,0x2b794,0x2b7ac,0x2b7ac,0x2b7af,0x2b7af,0x2b7bd,0x2b7bd,0x2b7c9,0x2b7c9,0x2b7cf,0x2b7cf,0x2b7d2,0x2b7d2,0x2b7d8,0x2b7d8,0x2b7f0,0x2b7f0,0x2b80d,0x2b80d,0x2b817,0x2b817,0x2b81a,0x2b81a,0x2d544,0x2d544,0x2e278,0x2e278,0x2e569,0x2e569,0x2e6ea,0x2e6ea,0x2f804,0x2f804,0x2f80f,0x2f80f,0x2f815,0x2f815,0x2f818,0x2f818,0x2f81a,0x2f81a,0x2f822,0x2f822,0x2f828,0x2f828,0x2f82c,0x2f82c,0x2f833,0x2f833,0x2f83f,0x2f83f,0x2f846,0x2f846,0x2f852,0x2f852,0x2f862,0x2f862,0x2f86d,0x2f86d,0x2f873,0x2f873,0x2f877,0x2f877,0x2f884,0x2f884,0x2f899,0x2f89a,0x2f8a6,0x2f8a6,0x2f8ac,0x2f8ac,0x2f8b2,0x2f8b2,0x2f8b6,0x2f8b6,0x2f8d3,0x2f8d3,0x2f8db,0x2f8dc,0x2f8e1,0x2f8e1,0x2f8e5,0x2f8e5,0x2f8ea,0x2f8ea,0x2f8ed,0x2f8ed,0x2f8fc,0x2f8fc,0x2f903,0x2f903,0x2f90b,0x2f90b,0x2f90f,0x2f90f,0x2f91a,0x2f91a,0x2f920,0x2f921,0x2f945,0x2f945,0x2f947,0x2f947,0x2f96c,0x2f96c,0x2f995,0x2f995,0x2f9d0,0x2f9d0,0x2f9de,0x2f9df,0x2f9f4,0x2f9f4,0x30ede,0x30ede,0x3106c,0x3106c,]), - NotoFont.fromFlatRanges('Noto Sans Javanese', 'http://fonts.gstatic.com/s/notosansjavanese/v15/2V0AKJkDAIA6Hp4zoSScDjV0Y-eoHAHJ8r88Rp29eA.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa980,0xa9cd,0xa9cf,0xa9d9,0xa9de,0xa9df,]), - NotoFont.fromFlatRanges('Noto Sans KR', 'http://fonts.gstatic.com/s/notosanskr/v27/PbykFmXiEBPT4ITbgNA5Cgm20HTs4JMMuA.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1100,0x11ff,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x349a,0x349a,0x34d7,0x34d7,0x3515,0x3515,0x3521,0x3521,0x353e,0x353e,0x35ff,0x35ff,0x366f,0x366f,0x36c3,0x36c5,0x36e6,0x36e6,0x3723,0x3723,0x372f,0x372f,0x373a,0x373a,0x37bc,0x37bc,0x380c,0x380c,0x3818,0x3818,0x3883,0x3883,0x38ba,0x38ba,0x38e7,0x38e7,0x38fd,0x38fd,0x3960,0x3960,0x3965,0x3965,0x3983,0x3983,0x3990,0x3990,0x39a5,0x39a5,0x39b6,0x39b6,0x3a39,0x3a39,0x3aa4,0x3aa4,0x3adc,0x3adc,0x3af6,0x3af6,0x3b03,0x3b03,0x3b23,0x3b23,0x3b79,0x3b79,0x3bf3,0x3bf3,0x3c14,0x3c14,0x3c24,0x3c24,0x3c2d,0x3c2d,0x3cbd,0x3cbe,0x3cfc,0x3cfc,0x3d17,0x3d17,0x3d5f,0x3d5f,0x3dbc,0x3dbc,0x3dc2,0x3dc2,0x3ec4,0x3ec4,0x3eed,0x3eed,0x3efd,0x3efd,0x3f04,0x3f04,0x402f,0x402f,0x4034,0x4034,0x4062,0x4062,0x40a9,0x40a9,0x40c9,0x40c9,0x4137,0x4137,0x41ac,0x41ac,0x4259,0x4259,0x43bb,0x43bb,0x43c7,0x43c7,0x43e7,0x43e7,0x43ea,0x43ea,0x4450,0x4450,0x4512,0x4512,0x45f2,0x45f2,0x4618,0x4618,0x46b7,0x46b7,0x46be,0x46be,0x46d4,0x46d4,0x46d8,0x46d8,0x46dd,0x46dd,0x472d,0x472d,0x476c,0x476c,0x477d,0x477d,0x479f,0x479f,0x4863,0x4863,0x4883,0x4883,0x4896,0x4896,0x48a6,0x48a6,0x4925,0x4925,0x499e,0x499e,0x49a5,0x49a5,0x49cb,0x49cb,0x4a12,0x4a12,0x4a2d,0x4a2d,0x4ab8,0x4ab8,0x4adf,0x4adf,0x4ae8,0x4ae8,0x4afb,0x4afb,0x4b53,0x4b53,0x4b71,0x4b71,0x4cdf,0x4ce0,0x4d1b,0x4d1b,0x4e00,0x4e01,0x4e03,0x4e03,0x4e07,0x4e0b,0x4e0d,0x4e0e,0x4e11,0x4e11,0x4e14,0x4e16,0x4e18,0x4e19,0x4e1e,0x4e1f,0x4e24,0x4e24,0x4e26,0x4e26,0x4e28,0x4e28,0x4e2b,0x4e2d,0x4e30,0x4e32,0x4e36,0x4e36,0x4e38,0x4e39,0x4e3b,0x4e3b,0x4e3f,0x4e3f,0x4e42,0x4e43,0x4e45,0x4e45,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e56,0x4e5b,0x4e5d,0x4e5f,0x4e67,0x4e67,0x4e6b,0x4e6d,0x4e71,0x4e71,0x4e73,0x4e73,0x4e76,0x4e77,0x4e7a,0x4e7c,0x4e7e,0x4e7e,0x4e80,0x4e80,0x4e82,0x4e82,0x4e85,0x4e86,0x4e88,0x4e89,0x4e8b,0x4e8c,0x4e8e,0x4e92,0x4e94,0x4e95,0x4e98,0x4e99,0x4e9b,0x4e9c,0x4e9e,0x4ea2,0x4ea4,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eae,0x4eb0,0x4eb0,0x4eb3,0x4eb4,0x4eb6,0x4eb6,0x4eb9,0x4ebb,0x4ec0,0x4ec1,0x4ec4,0x4ec4,0x4ec6,0x4ec7,0x4eca,0x4ecb,0x4ecd,0x4ecd,0x4ed4,0x4ed9,0x4edd,0x4edf,0x4ee1,0x4ee1,0x4ee3,0x4ee5,0x4eee,0x4eee,0x4ef0,0x4ef0,0x4ef2,0x4ef3,0x4ef5,0x4ef7,0x4efb,0x4efb,0x4efd,0x4efd,0x4eff,0x4f01,0x4f09,0x4f0b,0x4f0d,0x4f11,0x4f1a,0x4f1a,0x4f1d,0x4f1d,0x4f2f,0x4f30,0x4f34,0x4f34,0x4f36,0x4f36,0x4f38,0x4f38,0x4f3a,0x4f3a,0x4f3c,0x4f3e,0x4f42,0x4f43,0x4f46,0x4f49,0x4f4b,0x4f4b,0x4f4d,0x4f51,0x4f53,0x4f57,0x4f59,0x4f5f,0x4f69,0x4f6a,0x4f6f,0x4f70,0x4f73,0x4f74,0x4f76,0x4f76,0x4f78,0x4f81,0x4f83,0x4f84,0x4f86,0x4f86,0x4f88,0x4f8b,0x4f8d,0x4f92,0x4f94,0x4f94,0x4f96,0x4f98,0x4f9a,0x4f9d,0x4fae,0x4faf,0x4fb2,0x4fb2,0x4fb5,0x4fb6,0x4fb9,0x4fb9,0x4fbb,0x4fbb,0x4fbf,0x4fbf,0x4fc1,0x4fc5,0x4fc9,0x4fca,0x4fcc,0x4fd4,0x4fd7,0x4fdb,0x4fdd,0x4fe1,0x4fe3,0x4fe3,0x4fee,0x4ff1,0x4ff3,0x4ff6,0x4ff8,0x4ff8,0x4ffa,0x4ffa,0x4ffe,0x4ffe,0x5000,0x5000,0x5002,0x5002,0x5005,0x5007,0x5009,0x5009,0x500b,0x500b,0x500d,0x500d,0x500f,0x500f,0x5011,0x5014,0x5016,0x5016,0x5018,0x501a,0x501c,0x501c,0x501e,0x501f,0x5021,0x502e,0x5030,0x5030,0x503b,0x503b,0x5043,0x5044,0x5047,0x504a,0x504e,0x504f,0x5053,0x5053,0x5055,0x5056,0x5058,0x505a,0x505c,0x505c,0x5060,0x5060,0x5062,0x5062,0x5065,0x5066,0x506a,0x506a,0x5070,0x5070,0x5072,0x5072,0x5074,0x5076,0x5078,0x5078,0x5080,0x5080,0x5083,0x5083,0x5085,0x5085,0x508b,0x508b,0x508d,0x508d,0x5091,0x5092,0x5094,0x5094,0x5096,0x5096,0x5098,0x509b,0x509d,0x509e,0x50a2,0x50a2,0x50ac,0x50ae,0x50b2,0x50b5,0x50b7,0x50b7,0x50bd,0x50bf,0x50c2,0x50c2,0x50c4,0x50c5,0x50c9,0x50ca,0x50cf,0x50cf,0x50d1,0x50d1,0x50d4,0x50d6,0x50da,0x50db,0x50de,0x50de,0x50e2,0x50e2,0x50e5,0x50e7,0x50e9,0x50e9,0x50ec,0x50ee,0x50f5,0x50f5,0x50f9,0x50f9,0x50fb,0x50fb,0x50fe,0x5104,0x5106,0x5107,0x5109,0x5109,0x510b,0x510c,0x5110,0x5110,0x5112,0x5115,0x5117,0x5118,0x511a,0x511c,0x511f,0x511f,0x5121,0x5122,0x5124,0x5125,0x5127,0x5127,0x512a,0x512b,0x5131,0x5133,0x5135,0x5135,0x5137,0x513c,0x513f,0x5141,0x5143,0x5149,0x514b,0x514e,0x5150,0x5150,0x5152,0x5152,0x5154,0x5157,0x515a,0x515a,0x515c,0x515c,0x5162,0x5162,0x5165,0x5165,0x5167,0x516e,0x5171,0x5171,0x5175,0x5178,0x517c,0x517c,0x5180,0x5180,0x5182,0x5182,0x5186,0x5186,0x5189,0x518a,0x518c,0x518d,0x518f,0x518f,0x5191,0x5193,0x5195,0x5199,0x519e,0x519e,0x51a0,0x51a0,0x51a2,0x51a5,0x51aa,0x51ac,0x51b0,0x51b2,0x51b6,0x51b7,0x51bd,0x51be,0x51c4,0x51c6,0x51c9,0x51cd,0x51d2,0x51d2,0x51d4,0x51d4,0x51d6,0x51d6,0x51db,0x51de,0x51e0,0x51e1,0x51e9,0x51e9,0x51ed,0x51ed,0x51f0,0x51f1,0x51f3,0x51f6,0x51f8,0x51fa,0x51fd,0x51fd,0x5200,0x5203,0x5206,0x5208,0x520a,0x520a,0x520e,0x520e,0x5211,0x5211,0x5213,0x5213,0x5216,0x5217,0x521d,0x521d,0x5224,0x5227,0x5229,0x522a,0x522e,0x522e,0x5230,0x5233,0x5236,0x523b,0x5243,0x5244,0x5246,0x5247,0x5249,0x524d,0x5254,0x5257,0x525a,0x525b,0x525d,0x525f,0x5261,0x5261,0x5269,0x526a,0x526f,0x526f,0x5272,0x5272,0x5274,0x5275,0x5277,0x5277,0x527a,0x527a,0x527d,0x527d,0x527f,0x527f,0x5282,0x5283,0x5287,0x5289,0x528d,0x528d,0x5291,0x5293,0x5297,0x5298,0x529b,0x529b,0x529f,0x52a0,0x52a3,0x52a4,0x52a7,0x52a7,0x52a9,0x52ae,0x52b9,0x52b9,0x52be,0x52be,0x52c1,0x52c1,0x52c3,0x52c3,0x52c5,0x52c5,0x52c7,0x52c7,0x52c9,0x52c9,0x52cc,0x52cd,0x52d2,0x52d2,0x52d5,0x52d6,0x52d8,0x52d9,0x52db,0x52db,0x52dd,0x52e4,0x52e6,0x52e6,0x52ed,0x52ed,0x52f2,0x52f3,0x52f5,0x52f5,0x52f8,0x52fb,0x52fe,0x5303,0x5305,0x5305,0x5308,0x5308,0x530a,0x530a,0x530c,0x530d,0x530f,0x5310,0x5315,0x5317,0x5319,0x531a,0x5320,0x5321,0x5323,0x5323,0x5327,0x5327,0x532a,0x532a,0x532f,0x532f,0x5331,0x5331,0x5336,0x5336,0x5338,0x533b,0x533d,0x5341,0x5343,0x5345,0x5347,0x534a,0x534d,0x534d,0x5351,0x5354,0x5357,0x5357,0x535a,0x535a,0x535c,0x535c,0x535e,0x535e,0x5360,0x5361,0x5364,0x5364,0x5366,0x5366,0x5368,0x5369,0x536c,0x536c,0x536e,0x5375,0x5377,0x537b,0x537d,0x537f,0x5382,0x5382,0x5384,0x5384,0x538e,0x538e,0x5393,0x5393,0x5396,0x5396,0x5398,0x5398,0x539a,0x539a,0x539d,0x539d,0x539f,0x53a0,0x53a5,0x53a6,0x53aa,0x53aa,0x53ad,0x53ae,0x53b2,0x53b3,0x53b6,0x53b6,0x53b9,0x53b9,0x53bb,0x53bb,0x53c2,0x53c3,0x53c5,0x53c5,0x53c8,0x53cd,0x53d4,0x53d4,0x53d6,0x53d7,0x53d9,0x53d9,0x53db,0x53db,0x53df,0x53df,0x53e1,0x53e6,0x53e8,0x53f8,0x5401,0x5401,0x5403,0x5404,0x5408,0x5411,0x541b,0x541b,0x541d,0x541d,0x541f,0x5420,0x5426,0x5426,0x5429,0x5429,0x542b,0x542c,0x542e,0x542e,0x5431,0x5431,0x5433,0x5433,0x5436,0x5436,0x5438,0x5439,0x543b,0x543e,0x5440,0x5440,0x5442,0x5442,0x5446,0x5446,0x5448,0x5448,0x544a,0x544a,0x544e,0x544e,0x5451,0x5451,0x545d,0x545d,0x545f,0x545f,0x5462,0x5462,0x5464,0x5464,0x5466,0x5466,0x5468,0x5468,0x546a,0x546b,0x5470,0x5471,0x5473,0x5473,0x5475,0x5476,0x547b,0x547d,0x547f,0x5480,0x5484,0x5484,0x5486,0x5487,0x548b,0x5490,0x5496,0x5496,0x54a0,0x54a0,0x54a2,0x54a2,0x54a4,0x54a5,0x54a8,0x54a8,0x54ab,0x54ac,0x54af,0x54af,0x54b2,0x54b3,0x54b8,0x54b8,0x54bb,0x54bd,0x54bf,0x54c4,0x54c6,0x54c9,0x54e1,0x54e1,0x54e5,0x54e6,0x54e8,0x54e9,0x54ed,0x54ee,0x54f1,0x54f2,0x54fa,0x54fa,0x54fd,0x54fd,0x54ff,0x54ff,0x5504,0x5504,0x5506,0x5507,0x5509,0x5509,0x550e,0x5510,0x5514,0x5514,0x551c,0x551c,0x552b,0x552b,0x552e,0x552f,0x5531,0x5531,0x5533,0x5533,0x5535,0x5535,0x5539,0x5539,0x553c,0x553c,0x553e,0x553e,0x5540,0x5540,0x5542,0x5542,0x5544,0x5544,0x5546,0x5546,0x554a,0x554a,0x554f,0x554f,0x5553,0x5553,0x5556,0x5557,0x555c,0x555c,0x555e,0x555e,0x5563,0x5563,0x557b,0x5581,0x5583,0x5584,0x5586,0x5587,0x5589,0x558b,0x5591,0x5591,0x5593,0x5594,0x5598,0x559a,0x559c,0x559f,0x55a3,0x55a4,0x55a7,0x55ac,0x55ae,0x55ae,0x55b0,0x55b0,0x55c3,0x55c3,0x55c5,0x55c5,0x55c7,0x55c7,0x55c9,0x55c9,0x55d1,0x55d1,0x55d4,0x55d4,0x55da,0x55dc,0x55df,0x55e0,0x55e2,0x55e4,0x55f7,0x55f7,0x55fd,0x55ff,0x5604,0x5604,0x5606,0x5606,0x5608,0x5609,0x560c,0x5610,0x5612,0x5612,0x5614,0x5614,0x5616,0x5617,0x5629,0x5629,0x562c,0x562c,0x562f,0x562f,0x5632,0x5632,0x5634,0x5634,0x5636,0x5639,0x563b,0x563b,0x563f,0x563f,0x5641,0x5642,0x5649,0x5649,0x564b,0x564b,0x564d,0x564f,0x5653,0x5653,0x5664,0x5665,0x5668,0x566d,0x566f,0x566f,0x5672,0x5672,0x5674,0x5674,0x5676,0x5676,0x5678,0x5678,0x567a,0x567a,0x5680,0x5680,0x5684,0x5684,0x5686,0x5687,0x568f,0x568f,0x5699,0x569a,0x56a5,0x56a5,0x56a7,0x56a7,0x56ac,0x56ac,0x56ae,0x56ae,0x56b3,0x56b4,0x56b6,0x56b6,0x56bc,0x56bc,0x56c0,0x56c3,0x56c8,0x56ca,0x56cd,0x56cd,0x56d1,0x56d1,0x56d7,0x56d7,0x56da,0x56db,0x56de,0x56e0,0x56e3,0x56e3,0x56e6,0x56e7,0x56eb,0x56eb,0x56ed,0x56ee,0x56f0,0x56f0,0x56f3,0x56f3,0x56f7,0x56f7,0x56f9,0x56fa,0x56fd,0x56fd,0x56ff,0x56ff,0x5701,0x5704,0x5707,0x570b,0x570d,0x570d,0x5712,0x5713,0x5716,0x5716,0x5718,0x5718,0x571c,0x571c,0x571f,0x571f,0x5725,0x5725,0x5728,0x572a,0x572c,0x572e,0x5730,0x5730,0x573b,0x573b,0x573e,0x573e,0x5740,0x5742,0x5747,0x5747,0x574a,0x574a,0x574c,0x5751,0x5761,0x5761,0x5764,0x5764,0x5766,0x576a,0x576e,0x5771,0x5773,0x5773,0x5775,0x5775,0x5777,0x5778,0x577b,0x577c,0x5782,0x5782,0x5788,0x5788,0x578b,0x578c,0x5793,0x5793,0x5795,0x5795,0x579e,0x579e,0x57a0,0x57a0,0x57a2,0x57a4,0x57b8,0x57b8,0x57bd,0x57bd,0x57c3,0x57c3,0x57c6,0x57c9,0x57cb,0x57cb,0x57ce,0x57cf,0x57d1,0x57d2,0x57dc,0x57dc,0x57df,0x57e0,0x57e4,0x57e4,0x57e9,0x57e9,0x57ed,0x57ee,0x57f0,0x57f0,0x57f3,0x57f4,0x57f6,0x57f7,0x57f9,0x57fd,0x5800,0x5800,0x5802,0x5806,0x5808,0x580b,0x5817,0x5817,0x5819,0x5819,0x581d,0x581e,0x5820,0x5821,0x5823,0x5824,0x5826,0x5827,0x582a,0x582a,0x582d,0x582d,0x582f,0x5831,0x5834,0x5835,0x583a,0x583a,0x5840,0x5840,0x5849,0x584d,0x584f,0x5852,0x5854,0x5854,0x5857,0x585a,0x585e,0x585e,0x5861,0x5862,0x5864,0x5864,0x5869,0x5869,0x5875,0x5875,0x5879,0x5879,0x587c,0x587e,0x5880,0x5881,0x5883,0x5883,0x5885,0x5885,0x5889,0x588a,0x588c,0x588d,0x5890,0x5890,0x5893,0x5893,0x589c,0x589f,0x58a1,0x58a1,0x58a3,0x58a3,0x58a8,0x58a9,0x58ab,0x58ab,0x58ae,0x58ae,0x58b0,0x58b1,0x58b3,0x58b3,0x58ba,0x58bb,0x58be,0x58be,0x58c1,0x58c1,0x58c3,0x58c3,0x58c5,0x58c5,0x58c7,0x58c7,0x58ce,0x58ce,0x58d1,0x58d1,0x58d3,0x58d5,0x58d8,0x58da,0x58dc,0x58df,0x58e1,0x58e1,0x58e4,0x58e4,0x58eb,0x58ec,0x58ee,0x58f0,0x58f2,0x58f2,0x58f9,0x58fb,0x58fd,0x58fd,0x5902,0x5902,0x5906,0x5906,0x5908,0x5908,0x590a,0x590a,0x590f,0x5910,0x5914,0x5916,0x5919,0x591c,0x5922,0x5922,0x5924,0x5925,0x5927,0x5927,0x5929,0x592f,0x5931,0x5932,0x5937,0x5938,0x593d,0x593e,0x5944,0x5944,0x5947,0x5949,0x594c,0x594c,0x594e,0x5951,0x5953,0x5955,0x5957,0x5958,0x595a,0x595a,0x595c,0x595c,0x5960,0x5960,0x5962,0x5962,0x5967,0x5967,0x5969,0x596e,0x5972,0x5974,0x5976,0x5976,0x5978,0x5978,0x597d,0x597d,0x5982,0x5984,0x598a,0x598a,0x598c,0x598d,0x5991,0x5993,0x5996,0x5997,0x5999,0x5999,0x599d,0x599d,0x59a3,0x59a5,0x59a7,0x59a8,0x59ac,0x59ac,0x59af,0x59af,0x59b2,0x59b2,0x59b5,0x59b6,0x59b8,0x59b9,0x59bb,0x59bb,0x59be,0x59bf,0x59c1,0x59c1,0x59c3,0x59c3,0x59c6,0x59c6,0x59c8,0x59cb,0x59cd,0x59cd,0x59d0,0x59d4,0x59d9,0x59da,0x59dc,0x59de,0x59e2,0x59e6,0x59e8,0x59e8,0x59ea,0x59ec,0x59ee,0x59ee,0x59f0,0x59f0,0x59f2,0x59f2,0x59f7,0x59fc,0x59ff,0x59ff,0x5a01,0x5a01,0x5a03,0x5a03,0x5a09,0x5a0a,0x5a0d,0x5a0d,0x5a11,0x5a11,0x5a13,0x5a13,0x5a18,0x5a19,0x5a1b,0x5a1c,0x5a1f,0x5a20,0x5a23,0x5a23,0x5a25,0x5a25,0x5a27,0x5a27,0x5a29,0x5a29,0x5a2b,0x5a2b,0x5a2d,0x5a2d,0x5a35,0x5a36,0x5a3c,0x5a3c,0x5a3f,0x5a41,0x5a46,0x5a47,0x5a49,0x5a49,0x5a4b,0x5a4c,0x5a50,0x5a51,0x5a5a,0x5a5a,0x5a60,0x5a60,0x5a62,0x5a63,0x5a66,0x5a67,0x5a69,0x5a6a,0x5a6d,0x5a6d,0x5a72,0x5a72,0x5a77,0x5a77,0x5a7f,0x5a7f,0x5a84,0x5a84,0x5a8d,0x5a8d,0x5a90,0x5a90,0x5a92,0x5a93,0x5a95,0x5a95,0x5a9a,0x5a9b,0x5a9e,0x5a9f,0x5aa2,0x5aa2,0x5aa4,0x5aa4,0x5aa7,0x5aa7,0x5aaa,0x5aaa,0x5ab3,0x5ab3,0x5ab5,0x5ab5,0x5aba,0x5abf,0x5ac1,0x5ac2,0x5ac4,0x5ac4,0x5ac8,0x5ac9,0x5acb,0x5acc,0x5ad5,0x5ad7,0x5ad9,0x5adb,0x5add,0x5add,0x5ae0,0x5ae6,0x5ae9,0x5ae9,0x5aeb,0x5aeb,0x5aed,0x5aef,0x5af6,0x5af6,0x5afa,0x5afb,0x5afd,0x5afd,0x5b00,0x5b00,0x5b05,0x5b05,0x5b08,0x5b09,0x5b0b,0x5b0c,0x5b16,0x5b16,0x5b19,0x5b19,0x5b1b,0x5b1b,0x5b25,0x5b25,0x5b28,0x5b28,0x5b2a,0x5b2a,0x5b2d,0x5b2d,0x5b30,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b3e,0x5b40,0x5b43,0x5b43,0x5b45,0x5b45,0x5b4c,0x5b4c,0x5b50,0x5b51,0x5b54,0x5b58,0x5b5a,0x5b5d,0x5b5f,0x5b5f,0x5b61,0x5b61,0x5b63,0x5b66,0x5b69,0x5b69,0x5b6b,0x5b6b,0x5b70,0x5b71,0x5b75,0x5b76,0x5b78,0x5b78,0x5b7a,0x5b7a,0x5b7c,0x5b7c,0x5b7f,0x5b82,0x5b85,0x5b85,0x5b87,0x5b8c,0x5b8f,0x5b8f,0x5b93,0x5b93,0x5b95,0x5b9d,0x5b9f,0x5b9f,0x5ba2,0x5ba6,0x5bac,0x5bac,0x5bae,0x5bae,0x5bb0,0x5bb0,0x5bb3,0x5bb6,0x5bb8,0x5bb9,0x5bbf,0x5bc0,0x5bc2,0x5bc7,0x5bcc,0x5bcc,0x5bd0,0x5bd0,0x5bd2,0x5bd4,0x5bd6,0x5bd8,0x5bdb,0x5bdb,0x5bde,0x5bdf,0x5be1,0x5be2,0x5be4,0x5be9,0x5beb,0x5bf0,0x5bf5,0x5bf6,0x5bf8,0x5bfa,0x5bff,0x5bff,0x5c01,0x5c01,0x5c04,0x5c0f,0x5c11,0x5c11,0x5c14,0x5c14,0x5c16,0x5c16,0x5c19,0x5c19,0x5c1f,0x5c20,0x5c22,0x5c24,0x5c28,0x5c28,0x5c2b,0x5c2b,0x5c31,0x5c31,0x5c38,0x5c41,0x5c45,0x5c48,0x5c4b,0x5c4b,0x5c4d,0x5c4e,0x5c50,0x5c51,0x5c55,0x5c55,0x5c5b,0x5c5b,0x5c60,0x5c60,0x5c62,0x5c62,0x5c64,0x5c65,0x5c68,0x5c68,0x5c6c,0x5c6c,0x5c6f,0x5c6f,0x5c71,0x5c71,0x5c73,0x5c73,0x5c79,0x5c7a,0x5c88,0x5c88,0x5c8a,0x5c8a,0x5c8c,0x5c8c,0x5c8f,0x5c92,0x5c94,0x5c94,0x5c9d,0x5c9d,0x5ca1,0x5ca1,0x5ca3,0x5ca3,0x5ca5,0x5cad,0x5cb1,0x5cb1,0x5cb3,0x5cb3,0x5cb5,0x5cb5,0x5cb7,0x5cb8,0x5cba,0x5cba,0x5cbe,0x5cbe,0x5cc0,0x5cc0,0x5ccb,0x5ccb,0x5cd2,0x5cd2,0x5cd9,0x5cd9,0x5ce0,0x5ce0,0x5ce8,0x5ce9,0x5ced,0x5ced,0x5cef,0x5cf1,0x5cf4,0x5cf4,0x5cf6,0x5cf6,0x5cfb,0x5cfb,0x5cfd,0x5cfd,0x5d06,0x5d07,0x5d0d,0x5d0e,0x5d10,0x5d11,0x5d14,0x5d19,0x5d1b,0x5d1b,0x5d1f,0x5d1f,0x5d22,0x5d22,0x5d24,0x5d24,0x5d26,0x5d27,0x5d29,0x5d29,0x5d34,0x5d34,0x5d3d,0x5d3d,0x5d41,0x5d42,0x5d44,0x5d44,0x5d4b,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d50,0x5d53,0x5d54,0x5d69,0x5d69,0x5d6c,0x5d6c,0x5d6f,0x5d6f,0x5d71,0x5d71,0x5d81,0x5d82,0x5d84,0x5d84,0x5d86,0x5d87,0x5d8b,0x5d8b,0x5d92,0x5d92,0x5d94,0x5d95,0x5d99,0x5d99,0x5d9d,0x5d9d,0x5da0,0x5da0,0x5da2,0x5da2,0x5da7,0x5da7,0x5daa,0x5dab,0x5dae,0x5dae,0x5db0,0x5db0,0x5db7,0x5db8,0x5dba,0x5dba,0x5dbc,0x5dbe,0x5dc9,0x5dc9,0x5dcb,0x5dcb,0x5dcd,0x5dcd,0x5dd1,0x5dd3,0x5dd6,0x5dd6,0x5dda,0x5ddb,0x5ddd,0x5dde,0x5de0,0x5de2,0x5de5,0x5de8,0x5deb,0x5deb,0x5dee,0x5dee,0x5df1,0x5df5,0x5df7,0x5df9,0x5dfb,0x5dfb,0x5dfd,0x5dfe,0x5e02,0x5e03,0x5e06,0x5e06,0x5e09,0x5e09,0x5e0c,0x5e0c,0x5e11,0x5e11,0x5e15,0x5e16,0x5e19,0x5e1b,0x5e1d,0x5e1d,0x5e20,0x5e20,0x5e25,0x5e25,0x5e28,0x5e28,0x5e2b,0x5e2b,0x5e2d,0x5e2d,0x5e33,0x5e33,0x5e36,0x5e38,0x5e3d,0x5e3d,0x5e3f,0x5e40,0x5e43,0x5e45,0x5e47,0x5e47,0x5e4c,0x5e4c,0x5e4e,0x5e4e,0x5e54,0x5e55,0x5e58,0x5e58,0x5e5e,0x5e5f,0x5e61,0x5e63,0x5e68,0x5e68,0x5e6a,0x5e6c,0x5e70,0x5e74,0x5e76,0x5e80,0x5e83,0x5e84,0x5e87,0x5e87,0x5e8a,0x5e8b,0x5e8f,0x5e8f,0x5e95,0x5e97,0x5e9a,0x5e9a,0x5e9c,0x5e9c,0x5ea0,0x5ea0,0x5ea5,0x5ea8,0x5eab,0x5eab,0x5ead,0x5ead,0x5eb3,0x5eb3,0x5eb5,0x5eb8,0x5ebd,0x5ebe,0x5ec1,0x5ec2,0x5ec8,0x5ecb,0x5ecf,0x5ed1,0x5ed3,0x5ed3,0x5ed5,0x5ed6,0x5ed9,0x5edb,0x5edd,0x5ee3,0x5ee5,0x5ee5,0x5ee7,0x5ee9,0x5eec,0x5eec,0x5ef1,0x5ef1,0x5ef3,0x5ef4,0x5ef6,0x5ef7,0x5efa,0x5efb,0x5efe,0x5eff,0x5f01,0x5f01,0x5f03,0x5f04,0x5f07,0x5f08,0x5f0a,0x5f0b,0x5f0f,0x5f0f,0x5f11,0x5f15,0x5f17,0x5f18,0x5f1b,0x5f1b,0x5f1f,0x5f1f,0x5f22,0x5f22,0x5f25,0x5f27,0x5f29,0x5f29,0x5f2d,0x5f2d,0x5f31,0x5f31,0x5f34,0x5f35,0x5f37,0x5f37,0x5f3a,0x5f3a,0x5f3c,0x5f3c,0x5f3e,0x5f3e,0x5f40,0x5f40,0x5f46,0x5f46,0x5f48,0x5f48,0x5f4a,0x5f4a,0x5f4c,0x5f4c,0x5f4e,0x5f4e,0x5f50,0x5f51,0x5f53,0x5f54,0x5f56,0x5f59,0x5f5b,0x5f5b,0x5f5d,0x5f5d,0x5f61,0x5f62,0x5f64,0x5f67,0x5f69,0x5f6d,0x5f70,0x5f71,0x5f73,0x5f73,0x5f77,0x5f77,0x5f79,0x5f79,0x5f7c,0x5f7c,0x5f7f,0x5f82,0x5f85,0x5f85,0x5f87,0x5f8c,0x5f90,0x5f92,0x5f97,0x5f99,0x5f9c,0x5f9c,0x5f9e,0x5f9e,0x5fa0,0x5fa1,0x5fa3,0x5fa3,0x5fa7,0x5faa,0x5fac,0x5faf,0x5fb3,0x5fb3,0x5fb5,0x5fb5,0x5fb7,0x5fb7,0x5fb9,0x5fb9,0x5fbc,0x5fbd,0x5fc3,0x5fc5,0x5fc8,0x5fc9,0x5fcc,0x5fce,0x5fd0,0x5fd0,0x5fd2,0x5fd3,0x5fd5,0x5fd9,0x5fdc,0x5fe1,0x5fe4,0x5fe4,0x5fe8,0x5fe8,0x5feb,0x5feb,0x5fed,0x5fef,0x5ff1,0x5ff1,0x5ff5,0x5ff5,0x5ff8,0x5ff8,0x5ffb,0x5ffd,0x5fff,0x5fff,0x600a,0x600a,0x600d,0x600d,0x600f,0x600f,0x6012,0x6012,0x6014,0x6017,0x6019,0x6019,0x601b,0x601d,0x6020,0x6021,0x6025,0x602a,0x602f,0x6030,0x6033,0x6033,0x6041,0x6043,0x6046,0x6048,0x604a,0x604b,0x604d,0x604d,0x6050,0x6050,0x6052,0x6052,0x6055,0x6055,0x6059,0x605a,0x605d,0x605d,0x605f,0x6060,0x6062,0x6065,0x6068,0x606d,0x606f,0x6070,0x6075,0x6075,0x6081,0x6081,0x6083,0x6086,0x6089,0x608d,0x608f,0x608f,0x6092,0x6092,0x6094,0x6097,0x609a,0x609b,0x609f,0x60a0,0x60a2,0x60a4,0x60a7,0x60a7,0x60aa,0x60aa,0x60b0,0x60b6,0x60b8,0x60b8,0x60bb,0x60be,0x60c4,0x60c7,0x60c9,0x60c9,0x60cb,0x60cb,0x60cf,0x60cf,0x60d1,0x60d1,0x60d3,0x60d3,0x60d5,0x60d5,0x60d7,0x60e2,0x60f0,0x60f4,0x60f6,0x60fc,0x6100,0x6101,0x6103,0x6103,0x6106,0x6106,0x6108,0x6109,0x610d,0x610f,0x6114,0x6115,0x611a,0x611c,0x611e,0x611f,0x6122,0x6122,0x6127,0x6128,0x612b,0x612d,0x6130,0x6130,0x6134,0x6134,0x6137,0x6137,0x613c,0x613c,0x613e,0x613f,0x6142,0x6142,0x6144,0x6144,0x6146,0x6148,0x614a,0x614d,0x614f,0x614f,0x6152,0x6155,0x6158,0x615a,0x615c,0x615d,0x615f,0x6164,0x6167,0x6168,0x616a,0x616b,0x616e,0x616e,0x6170,0x6171,0x6173,0x6177,0x617a,0x617a,0x617c,0x617e,0x6181,0x6183,0x618a,0x618a,0x618d,0x618e,0x6190,0x6194,0x6196,0x6196,0x6198,0x619a,0x61a4,0x61a4,0x61a7,0x61a9,0x61ab,0x61ac,0x61ae,0x61af,0x61b2,0x61b2,0x61b6,0x61b6,0x61b8,0x61b8,0x61ba,0x61be,0x61c3,0x61c3,0x61c6,0x61cc,0x61cf,0x61cf,0x61d5,0x61d5,0x61d7,0x61d7,0x61de,0x61df,0x61e3,0x61e3,0x61e6,0x61e6,0x61f2,0x61f2,0x61f6,0x61f8,0x61fa,0x61fa,0x61fc,0x6200,0x6207,0x6208,0x620a,0x620a,0x620c,0x620e,0x6210,0x6212,0x6214,0x6216,0x6218,0x6218,0x621a,0x621a,0x621e,0x621f,0x6221,0x6222,0x6226,0x6227,0x6229,0x622a,0x622d,0x622e,0x6230,0x6236,0x6239,0x6239,0x623e,0x6241,0x6243,0x6243,0x6247,0x624e,0x6251,0x6253,0x6257,0x6258,0x625b,0x625c,0x625e,0x625e,0x6263,0x6263,0x6268,0x6268,0x626e,0x626e,0x6271,0x6271,0x6273,0x6273,0x6276,0x6276,0x6279,0x627a,0x627c,0x627c,0x627e,0x6280,0x6283,0x6284,0x6286,0x6286,0x6289,0x628a,0x628f,0x628f,0x6291,0x6292,0x6294,0x6298,0x629b,0x629b,0x62a6,0x62a6,0x62a8,0x62a8,0x62ab,0x62ac,0x62ae,0x62ae,0x62b1,0x62b2,0x62b5,0x62b5,0x62b9,0x62b9,0x62bc,0x62bd,0x62c2,0x62c2,0x62c4,0x62cd,0x62cf,0x62d9,0x62db,0x62dc,0x62e1,0x62e1,0x62ec,0x62ef,0x62f1,0x62f1,0x62f3,0x62f3,0x62f5,0x62f7,0x62fd,0x62ff,0x6301,0x6302,0x6307,0x6307,0x6309,0x6309,0x630c,0x630c,0x6310,0x6312,0x6328,0x6328,0x632a,0x632b,0x632f,0x632f,0x6339,0x633b,0x633d,0x633e,0x6342,0x6344,0x6346,0x6346,0x6349,0x6349,0x634c,0x6350,0x6353,0x6353,0x6355,0x6355,0x6357,0x6357,0x635a,0x635a,0x6367,0x6369,0x636b,0x636b,0x636e,0x636e,0x6371,0x6372,0x6376,0x6377,0x637a,0x637b,0x637f,0x6380,0x6383,0x6384,0x6387,0x638a,0x638c,0x638c,0x638e,0x638f,0x6392,0x6392,0x6396,0x6396,0x6398,0x6398,0x639b,0x639c,0x639f,0x63a2,0x63a5,0x63a5,0x63a7,0x63aa,0x63ac,0x63ac,0x63be,0x63be,0x63c0,0x63c0,0x63c3,0x63c4,0x63c6,0x63c6,0x63c9,0x63c9,0x63cf,0x63d0,0x63d2,0x63d2,0x63d6,0x63d6,0x63da,0x63db,0x63df,0x63e1,0x63e3,0x63e3,0x63e9,0x63e9,0x63eb,0x63eb,0x63ed,0x63ee,0x63f2,0x63f2,0x63f4,0x63f7,0x6406,0x6406,0x6409,0x6409,0x640d,0x640d,0x640f,0x640f,0x6412,0x6412,0x6414,0x6414,0x6416,0x6418,0x641c,0x641c,0x6420,0x6420,0x6422,0x6422,0x6424,0x6425,0x6428,0x6428,0x642a,0x642d,0x642f,0x6430,0x6434,0x6434,0x6436,0x6436,0x643a,0x643a,0x643e,0x643e,0x6458,0x6458,0x645b,0x645b,0x645e,0x645e,0x6460,0x6460,0x6467,0x6467,0x6469,0x6469,0x646d,0x646d,0x646f,0x646f,0x6473,0x6473,0x6478,0x647b,0x647d,0x647d,0x6485,0x6485,0x6488,0x6488,0x6490,0x6493,0x6495,0x6495,0x6499,0x649b,0x649d,0x649f,0x64a4,0x64a5,0x64a9,0x64a9,0x64ab,0x64ab,0x64ad,0x64ae,0x64b0,0x64b0,0x64b2,0x64b2,0x64bb,0x64bc,0x64be,0x64bf,0x64c1,0x64c1,0x64c4,0x64c5,0x64c7,0x64c7,0x64c9,0x64ca,0x64cd,0x64ce,0x64d0,0x64d0,0x64d2,0x64d2,0x64d4,0x64d5,0x64d7,0x64d8,0x64da,0x64da,0x64e0,0x64e3,0x64e5,0x64e7,0x64ec,0x64ed,0x64ef,0x64ef,0x64f1,0x64f2,0x64f4,0x64f4,0x64fa,0x64fa,0x64fe,0x64fe,0x6500,0x6500,0x6502,0x6502,0x6504,0x6504,0x6507,0x6507,0x650a,0x650a,0x650f,0x650f,0x6514,0x6514,0x6518,0x6519,0x651d,0x651d,0x6522,0x6524,0x652a,0x652c,0x652f,0x652f,0x6532,0x6532,0x6534,0x6539,0x653b,0x653b,0x653d,0x653f,0x6543,0x6543,0x6545,0x6545,0x6548,0x6549,0x654d,0x654f,0x6551,0x6552,0x6554,0x6559,0x655d,0x655e,0x6562,0x6563,0x6566,0x6566,0x656c,0x656d,0x6572,0x6572,0x6574,0x6575,0x6577,0x6578,0x657e,0x657e,0x6581,0x6583,0x6585,0x6585,0x6587,0x6587,0x6589,0x6589,0x658c,0x658c,0x6590,0x6591,0x6597,0x6597,0x6599,0x6599,0x659b,0x659d,0x659f,0x659f,0x65a1,0x65a1,0x65a4,0x65a5,0x65a7,0x65a7,0x65ab,0x65ad,0x65af,0x65b2,0x65b7,0x65b7,0x65b9,0x65b9,0x65bc,0x65bd,0x65bf,0x65bf,0x65c1,0x65c6,0x65ca,0x65cc,0x65cf,0x65cf,0x65d2,0x65d2,0x65d7,0x65d7,0x65e0,0x65e1,0x65e3,0x65e3,0x65e5,0x65e6,0x65e8,0x65e9,0x65ec,0x65ed,0x65f1,0x65f2,0x65f4,0x65f4,0x65fa,0x65fd,0x65ff,0x6600,0x6602,0x6603,0x6606,0x6607,0x6609,0x660a,0x660c,0x6611,0x6613,0x6615,0x661b,0x661c,0x661e,0x6621,0x6623,0x6625,0x6627,0x6628,0x662b,0x662b,0x662d,0x662d,0x662f,0x6631,0x6634,0x6637,0x663a,0x663b,0x6641,0x6644,0x6648,0x6649,0x664b,0x664c,0x664e,0x6651,0x6659,0x665b,0x665d,0x6662,0x6664,0x6669,0x666b,0x6670,0x6673,0x6674,0x6676,0x667b,0x667d,0x667d,0x667f,0x667f,0x6684,0x6684,0x6687,0x6689,0x668b,0x668c,0x668e,0x668e,0x6690,0x6691,0x6696,0x6698,0x669a,0x669a,0x669d,0x669e,0x66a0,0x66a0,0x66a2,0x66a3,0x66ab,0x66ac,0x66ae,0x66ae,0x66b1,0x66b5,0x66b8,0x66bb,0x66be,0x66c1,0x66c4,0x66c9,0x66d3,0x66d4,0x66d6,0x66d6,0x66d8,0x66de,0x66e0,0x66e0,0x66e3,0x66e3,0x66e6,0x66e6,0x66e8,0x66ea,0x66ec,0x66ec,0x66ee,0x66f0,0x66f2,0x66f4,0x66f7,0x66fa,0x66fc,0x66fc,0x66fe,0x6700,0x6703,0x6705,0x6708,0x670d,0x6710,0x6710,0x6714,0x6715,0x6717,0x6717,0x671b,0x671b,0x671d,0x6720,0x6722,0x6723,0x6726,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6734,0x6736,0x6736,0x673a,0x673a,0x673d,0x673e,0x6745,0x6746,0x6749,0x6749,0x674b,0x674c,0x674e,0x6751,0x6753,0x6753,0x6756,0x6756,0x675c,0x6760,0x6765,0x6765,0x676a,0x676a,0x676c,0x676d,0x676f,0x6773,0x6775,0x6775,0x6777,0x6777,0x677b,0x677c,0x677e,0x677f,0x6783,0x6783,0x6787,0x6787,0x6789,0x6789,0x678b,0x678c,0x678f,0x6790,0x6792,0x6793,0x6795,0x6795,0x6797,0x679a,0x679c,0x679d,0x67af,0x67b0,0x67b2,0x67b3,0x67b6,0x67b8,0x67be,0x67be,0x67c1,0x67c1,0x67c4,0x67c5,0x67ca,0x67ca,0x67cf,0x67d4,0x67d6,0x67da,0x67dd,0x67df,0x67e2,0x67e2,0x67e9,0x67e9,0x67ec,0x67ec,0x67ef,0x67f1,0x67f3,0x67f6,0x67f9,0x67f9,0x67fb,0x67fb,0x67fe,0x67ff,0x6803,0x6804,0x6810,0x6810,0x6812,0x6813,0x6816,0x6817,0x681d,0x681e,0x6821,0x6822,0x682a,0x682a,0x682e,0x682f,0x6831,0x6832,0x6834,0x6834,0x6838,0x6839,0x683b,0x683d,0x6840,0x6844,0x6846,0x6846,0x6848,0x6849,0x684e,0x684e,0x6850,0x6851,0x6853,0x6854,0x686d,0x686d,0x686f,0x686f,0x6874,0x6874,0x6876,0x6877,0x687e,0x687f,0x6881,0x6881,0x6883,0x6883,0x6885,0x6886,0x688f,0x688f,0x6893,0x6894,0x6897,0x6897,0x689b,0x689b,0x689d,0x689d,0x689f,0x68a3,0x68a7,0x68a8,0x68ad,0x68ad,0x68af,0x68b1,0x68b3,0x68b3,0x68b5,0x68b6,0x68c4,0x68c5,0x68c9,0x68cd,0x68d0,0x68d0,0x68d2,0x68d2,0x68d5,0x68d8,0x68da,0x68da,0x68df,0x68e0,0x68e3,0x68e3,0x68e7,0x68e8,0x68ec,0x68ec,0x68ee,0x68ee,0x68f2,0x68f2,0x68f9,0x68fd,0x6900,0x6901,0x6904,0x6906,0x690b,0x690b,0x690d,0x690f,0x6911,0x6912,0x6919,0x6919,0x691c,0x691c,0x6927,0x6927,0x6930,0x6930,0x6934,0x6934,0x6936,0x6936,0x6939,0x6939,0x693d,0x693d,0x693f,0x693f,0x6942,0x6942,0x694a,0x694a,0x694f,0x694f,0x6953,0x6955,0x6957,0x6957,0x6959,0x695a,0x695d,0x695e,0x6960,0x6963,0x6965,0x6965,0x6968,0x6968,0x696a,0x696f,0x6973,0x6973,0x6975,0x6975,0x6977,0x6979,0x697b,0x697b,0x697d,0x697d,0x698e,0x698e,0x6991,0x6991,0x6994,0x6995,0x6998,0x6998,0x699b,0x699c,0x699f,0x699f,0x69a4,0x69a7,0x69ad,0x69ae,0x69b0,0x69b2,0x69b4,0x69b4,0x69b7,0x69b7,0x69ba,0x69bc,0x69be,0x69c1,0x69c3,0x69c3,0x69c7,0x69c7,0x69ca,0x69d0,0x69d3,0x69d3,0x69d6,0x69d6,0x69e2,0x69e2,0x69e5,0x69ea,0x69ed,0x69ed,0x69f2,0x69f2,0x69f9,0x69f9,0x69fb,0x69fb,0x69fd,0x69fd,0x69ff,0x6a00,0x6a02,0x6a02,0x6a05,0x6a05,0x6a0a,0x6a0b,0x6a11,0x6a14,0x6a17,0x6a17,0x6a19,0x6a19,0x6a1b,0x6a1b,0x6a1e,0x6a1f,0x6a21,0x6a21,0x6a23,0x6a23,0x6a29,0x6a29,0x6a2b,0x6a2b,0x6a35,0x6a35,0x6a38,0x6a3b,0x6a3d,0x6a3d,0x6a43,0x6a45,0x6a47,0x6a4d,0x6a50,0x6a50,0x6a52,0x6a53,0x6a58,0x6a5a,0x6a5f,0x6a5f,0x6a61,0x6a62,0x6a64,0x6a64,0x6a66,0x6a66,0x6a6b,0x6a6b,0x6a72,0x6a72,0x6a75,0x6a75,0x6a7f,0x6a80,0x6a83,0x6a84,0x6a89,0x6a89,0x6a8d,0x6a8e,0x6a90,0x6a90,0x6a94,0x6a94,0x6a97,0x6a97,0x6a9c,0x6a9d,0x6a9f,0x6aa0,0x6aa2,0x6aa3,0x6aae,0x6aae,0x6ab3,0x6ab3,0x6ab6,0x6ab6,0x6abb,0x6abc,0x6abf,0x6abf,0x6ac2,0x6ac3,0x6ad3,0x6ad3,0x6ada,0x6adf,0x6ae8,0x6ae8,0x6aea,0x6aea,0x6aec,0x6aec,0x6af6,0x6af6,0x6afb,0x6afc,0x6b02,0x6b04,0x6b0a,0x6b0a,0x6b0c,0x6b0c,0x6b11,0x6b12,0x6b16,0x6b16,0x6b1e,0x6b1e,0x6b20,0x6b21,0x6b23,0x6b23,0x6b2c,0x6b2c,0x6b32,0x6b32,0x6b37,0x6b3b,0x6b3d,0x6b3f,0x6b43,0x6b43,0x6b46,0x6b47,0x6b49,0x6b4a,0x6b4c,0x6b4c,0x6b4e,0x6b4e,0x6b50,0x6b50,0x6b54,0x6b54,0x6b59,0x6b5b,0x6b5f,0x6b67,0x6b69,0x6b6a,0x6b6f,0x6b6f,0x6b72,0x6b72,0x6b77,0x6b7b,0x6b7f,0x6b80,0x6b82,0x6b84,0x6b86,0x6b86,0x6b89,0x6b8a,0x6b8d,0x6b8d,0x6b91,0x6b91,0x6b96,0x6b96,0x6b98,0x6b98,0x6b9e,0x6b9e,0x6ba2,0x6ba2,0x6ba4,0x6ba4,0x6bab,0x6bab,0x6bad,0x6baf,0x6bb2,0x6bb3,0x6bb5,0x6bb5,0x6bb7,0x6bb7,0x6bba,0x6bba,0x6bbc,0x6bbd,0x6bbf,0x6bc1,0x6bc4,0x6bc6,0x6bcb,0x6bcb,0x6bcd,0x6bcd,0x6bcf,0x6bcf,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdb,0x6beb,0x6bec,0x6bef,0x6bef,0x6bf3,0x6bf3,0x6bf8,0x6bf8,0x6bff,0x6bff,0x6c05,0x6c05,0x6c08,0x6c08,0x6c0f,0x6c11,0x6c13,0x6c14,0x6c17,0x6c17,0x6c1b,0x6c1b,0x6c23,0x6c24,0x6c33,0x6c38,0x6c3e,0x6c43,0x6c4b,0x6c4b,0x6c4e,0x6c50,0x6c52,0x6c55,0x6c57,0x6c57,0x6c59,0x6c60,0x6c66,0x6c66,0x6c68,0x6c6a,0x6c6d,0x6c6d,0x6c70,0x6c70,0x6c72,0x6c72,0x6c74,0x6c74,0x6c76,0x6c76,0x6c7a,0x6c7a,0x6c7d,0x6c7e,0x6c81,0x6c89,0x6c8c,0x6c8d,0x6c90,0x6c90,0x6c92,0x6c96,0x6c98,0x6c9b,0x6ca2,0x6ca2,0x6cab,0x6cac,0x6cae,0x6cae,0x6cb0,0x6cb1,0x6cb3,0x6cb3,0x6cb6,0x6cb6,0x6cb8,0x6cb9,0x6cbb,0x6cbf,0x6cc1,0x6cc2,0x6cc4,0x6cc6,0x6cc9,0x6cca,0x6ccc,0x6ccc,0x6cd0,0x6cd1,0x6cd3,0x6cd5,0x6cd7,0x6cd7,0x6cd9,0x6cdd,0x6ce0,0x6ce3,0x6ce5,0x6ce5,0x6ce8,0x6ce8,0x6ceb,0x6ceb,0x6cee,0x6cf1,0x6cf3,0x6cf3,0x6cff,0x6cff,0x6d04,0x6d04,0x6d07,0x6d07,0x6d0a,0x6d0c,0x6d11,0x6d12,0x6d14,0x6d14,0x6d17,0x6d17,0x6d19,0x6d19,0x6d1b,0x6d1b,0x6d1e,0x6d1f,0x6d23,0x6d23,0x6d25,0x6d25,0x6d27,0x6d2c,0x6d2e,0x6d2e,0x6d32,0x6d32,0x6d35,0x6d36,0x6d38,0x6d3e,0x6d41,0x6d41,0x6d59,0x6d5a,0x6d5c,0x6d5c,0x6d61,0x6d61,0x6d63,0x6d67,0x6d69,0x6d6a,0x6d6c,0x6d6c,0x6d6e,0x6d6f,0x6d72,0x6d72,0x6d74,0x6d74,0x6d77,0x6d79,0x6d7f,0x6d7f,0x6d82,0x6d82,0x6d85,0x6d85,0x6d87,0x6d89,0x6d8c,0x6d8f,0x6d91,0x6d91,0x6d93,0x6d97,0x6daa,0x6dac,0x6daf,0x6daf,0x6db2,0x6db2,0x6db4,0x6db5,0x6db7,0x6db8,0x6dbc,0x6dbc,0x6dbf,0x6dc0,0x6dc3,0x6dc8,0x6dcb,0x6dcc,0x6dcf,0x6dd2,0x6dd6,0x6dd6,0x6dd8,0x6dda,0x6ddd,0x6dde,0x6de0,0x6de6,0x6de8,0x6de8,0x6dea,0x6dec,0x6dee,0x6dee,0x6df1,0x6df1,0x6df3,0x6df3,0x6df5,0x6dfc,0x6e05,0x6e05,0x6e08,0x6e08,0x6e0a,0x6e0a,0x6e17,0x6e17,0x6e19,0x6e1b,0x6e1d,0x6e1d,0x6e1f,0x6e26,0x6e28,0x6e28,0x6e2b,0x6e2d,0x6e2f,0x6e2f,0x6e32,0x6e32,0x6e34,0x6e34,0x6e36,0x6e38,0x6e3a,0x6e3a,0x6e3c,0x6e3e,0x6e40,0x6e40,0x6e43,0x6e45,0x6e4a,0x6e4a,0x6e4d,0x6e4e,0x6e51,0x6e51,0x6e53,0x6e56,0x6e58,0x6e58,0x6e5b,0x6e5c,0x6e5e,0x6e5f,0x6e63,0x6e63,0x6e67,0x6e67,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e72,0x6e73,0x6e75,0x6e75,0x6e7a,0x6e7a,0x6e8f,0x6e90,0x6e95,0x6e96,0x6e98,0x6e98,0x6e9c,0x6e9d,0x6e9f,0x6e9f,0x6ea2,0x6ea2,0x6ea5,0x6ea5,0x6ea7,0x6ea8,0x6eaa,0x6eab,0x6eaf,0x6eaf,0x6eb1,0x6eb2,0x6eb5,0x6eb7,0x6eba,0x6eba,0x6ebd,0x6ebd,0x6ec2,0x6ec5,0x6ec8,0x6ec9,0x6ecb,0x6ecc,0x6ece,0x6ece,0x6ed1,0x6ed1,0x6ed3,0x6ed5,0x6ed9,0x6ed9,0x6eec,0x6eed,0x6eef,0x6eef,0x6ef2,0x6ef2,0x6ef4,0x6ef5,0x6ef7,0x6ef8,0x6efc,0x6efc,0x6efe,0x6eff,0x6f01,0x6f02,0x6f04,0x6f04,0x6f06,0x6f06,0x6f09,0x6f09,0x6f0c,0x6f0c,0x6f0f,0x6f0f,0x6f11,0x6f11,0x6f13,0x6f15,0x6f19,0x6f1a,0x6f20,0x6f20,0x6f22,0x6f24,0x6f26,0x6f28,0x6f2a,0x6f2d,0x6f30,0x6f33,0x6f38,0x6f38,0x6f3c,0x6f3c,0x6f3e,0x6f3f,0x6f41,0x6f41,0x6f4f,0x6f4f,0x6f51,0x6f52,0x6f54,0x6f54,0x6f57,0x6f5f,0x6f61,0x6f64,0x6f66,0x6f66,0x6f6d,0x6f71,0x6f74,0x6f74,0x6f78,0x6f78,0x6f7a,0x6f7a,0x6f7c,0x6f7e,0x6f81,0x6f82,0x6f84,0x6f84,0x6f86,0x6f89,0x6f8b,0x6f8e,0x6f90,0x6f90,0x6f92,0x6f92,0x6f94,0x6f98,0x6f9f,0x6f9f,0x6fa1,0x6fa1,0x6fa3,0x6fa5,0x6fa7,0x6fa8,0x6faa,0x6faa,0x6fae,0x6faf,0x6fb1,0x6fb1,0x6fb3,0x6fb3,0x6fb6,0x6fb6,0x6fb9,0x6fb9,0x6fbe,0x6fbe,0x6fc0,0x6fc3,0x6fc6,0x6fc7,0x6fc9,0x6fca,0x6fd4,0x6fd5,0x6fd8,0x6fd8,0x6fda,0x6fdb,0x6fde,0x6fe1,0x6fe4,0x6fe6,0x6fe9,0x6fe9,0x6feb,0x6fec,0x6fee,0x6fef,0x6ff1,0x6ff1,0x6ff3,0x6ff4,0x6ff6,0x6ff6,0x6ffa,0x6ffa,0x6ffe,0x6ffe,0x7001,0x7001,0x7005,0x7007,0x7009,0x7009,0x700b,0x700b,0x700f,0x700f,0x7011,0x7013,0x7015,0x7015,0x7018,0x7018,0x701a,0x701f,0x7023,0x7023,0x7026,0x7028,0x702f,0x7030,0x7032,0x7032,0x7037,0x7038,0x703c,0x703c,0x703e,0x703e,0x7044,0x7044,0x7046,0x7046,0x704c,0x704c,0x704e,0x704e,0x7050,0x7051,0x7053,0x7053,0x7058,0x7058,0x705d,0x705e,0x7063,0x7063,0x7066,0x7066,0x7069,0x7069,0x706b,0x706c,0x706f,0x7070,0x7078,0x7078,0x707c,0x707e,0x7081,0x7081,0x7085,0x7086,0x708a,0x708a,0x708e,0x708e,0x7092,0x7092,0x7095,0x7095,0x7098,0x709b,0x70a1,0x70a1,0x70a4,0x70a4,0x70a6,0x70a6,0x70ab,0x70b0,0x70b3,0x70b3,0x70b7,0x70ba,0x70c8,0x70c8,0x70ca,0x70cb,0x70cf,0x70cf,0x70d3,0x70d4,0x70d8,0x70d9,0x70dc,0x70dd,0x70df,0x70df,0x70ef,0x70ef,0x70f1,0x70f1,0x70f9,0x70fa,0x70fd,0x70fd,0x7103,0x7104,0x7106,0x7106,0x7109,0x7109,0x710c,0x710c,0x7119,0x711a,0x711c,0x711c,0x711e,0x711e,0x7120,0x7121,0x7126,0x7126,0x712d,0x7131,0x7136,0x7136,0x7143,0x7143,0x7146,0x7147,0x7149,0x714a,0x714c,0x714c,0x714e,0x714e,0x7150,0x7150,0x7152,0x7153,0x7155,0x7157,0x7159,0x7159,0x715c,0x715e,0x7162,0x7162,0x7164,0x7169,0x716c,0x716c,0x716e,0x716e,0x717d,0x717d,0x7180,0x7180,0x7184,0x7185,0x7187,0x718a,0x718f,0x718f,0x7192,0x7192,0x7194,0x7194,0x7199,0x7199,0x719b,0x719b,0x719f,0x71a2,0x71a4,0x71a4,0x71a8,0x71a9,0x71ac,0x71ac,0x71af,0x71af,0x71b1,0x71b2,0x71b9,0x71ba,0x71be,0x71be,0x71c1,0x71c1,0x71c3,0x71c3,0x71c8,0x71c9,0x71cb,0x71cb,0x71ce,0x71d0,0x71d2,0x71d2,0x71d4,0x71d6,0x71d9,0x71d9,0x71db,0x71db,0x71df,0x71e0,0x71e5,0x71e7,0x71ec,0x71ee,0x71f9,0x71f9,0x71fb,0x7201,0x7206,0x7207,0x720b,0x720d,0x7210,0x7210,0x7214,0x7214,0x7217,0x7217,0x721a,0x721b,0x721f,0x721f,0x7225,0x7225,0x7228,0x7228,0x722a,0x722a,0x722c,0x722d,0x7230,0x7230,0x7232,0x7232,0x7235,0x7236,0x7238,0x723b,0x723d,0x7240,0x7242,0x7242,0x7246,0x7248,0x724b,0x724c,0x7252,0x7254,0x7256,0x7256,0x7258,0x725b,0x725d,0x725d,0x725f,0x725f,0x7261,0x7263,0x7267,0x7267,0x7269,0x7269,0x726f,0x726f,0x7272,0x7272,0x7274,0x7274,0x7278,0x7279,0x727d,0x727d,0x7280,0x7282,0x7287,0x7287,0x728d,0x728d,0x7292,0x7292,0x7296,0x7296,0x72a2,0x72a2,0x72a7,0x72a7,0x72ac,0x72ad,0x72af,0x72af,0x72b3,0x72b5,0x72c0,0x72c0,0x72c2,0x72c2,0x72c4,0x72c4,0x72c9,0x72c9,0x72ce,0x72ce,0x72d0,0x72d0,0x72d2,0x72d2,0x72d7,0x72d7,0x72d9,0x72d9,0x72e1,0x72e2,0x72e5,0x72e5,0x72e8,0x72e9,0x72ec,0x72ec,0x72f4,0x72f4,0x72f7,0x72fd,0x7309,0x730a,0x7313,0x7313,0x7316,0x7319,0x731b,0x731d,0x7322,0x7322,0x7325,0x7325,0x7327,0x732b,0x7331,0x7331,0x7334,0x7334,0x7336,0x7337,0x733e,0x733f,0x7343,0x7345,0x734e,0x734e,0x7350,0x7350,0x7352,0x7352,0x7357,0x7358,0x735c,0x735c,0x7360,0x7360,0x7368,0x736c,0x736f,0x7370,0x7372,0x7372,0x7375,0x7375,0x7377,0x7378,0x737a,0x737c,0x7381,0x7381,0x7384,0x7384,0x7386,0x7389,0x738b,0x738b,0x738e,0x738e,0x7392,0x7392,0x7394,0x7398,0x739e,0x73a0,0x73a6,0x73a7,0x73a9,0x73ab,0x73ad,0x73ad,0x73b2,0x73b4,0x73b7,0x73b7,0x73b9,0x73b9,0x73bb,0x73bd,0x73bf,0x73c0,0x73c2,0x73c2,0x73c6,0x73c6,0x73c8,0x73ca,0x73cc,0x73cd,0x73cf,0x73cf,0x73d2,0x73d2,0x73d6,0x73d9,0x73dd,0x73de,0x73e0,0x73e0,0x73e2,0x73e6,0x73e9,0x73eb,0x73ed,0x73ee,0x73f5,0x73f5,0x73f7,0x73f9,0x73fd,0x73fe,0x7401,0x7401,0x7403,0x7407,0x7409,0x7409,0x7413,0x7413,0x7417,0x7418,0x741b,0x741b,0x741d,0x741d,0x741f,0x7422,0x7424,0x7426,0x7428,0x7428,0x742a,0x742c,0x742e,0x7436,0x7438,0x7438,0x743a,0x743a,0x743f,0x7446,0x7448,0x7449,0x744b,0x744c,0x744e,0x744e,0x7455,0x7455,0x7457,0x7457,0x7459,0x7460,0x7462,0x7465,0x7468,0x746a,0x746d,0x7473,0x747d,0x747e,0x7480,0x7480,0x7482,0x7487,0x7489,0x748c,0x7490,0x7490,0x7498,0x7498,0x749c,0x749f,0x74a1,0x74a1,0x74a3,0x74a3,0x74a5,0x74a5,0x74a7,0x74a8,0x74aa,0x74ab,0x74b0,0x74b2,0x74b5,0x74b6,0x74b8,0x74b9,0x74bc,0x74bd,0x74bf,0x74c0,0x74c6,0x74c6,0x74ca,0x74ca,0x74cd,0x74cd,0x74cf,0x74d0,0x74d3,0x74d4,0x74d8,0x74d8,0x74da,0x74dc,0x74e0,0x74e0,0x74e2,0x74e3,0x74e6,0x74e6,0x74e9,0x74e9,0x74ee,0x74ee,0x74f2,0x74f3,0x74f7,0x74f7,0x7501,0x7501,0x7503,0x7504,0x750c,0x750e,0x7511,0x7511,0x7513,0x7513,0x7515,0x7515,0x7518,0x7518,0x751a,0x751c,0x751e,0x751f,0x7522,0x7526,0x7528,0x7528,0x752b,0x752c,0x7530,0x7533,0x7537,0x7538,0x753a,0x753b,0x753f,0x753f,0x7543,0x7543,0x7547,0x7547,0x754a,0x754c,0x754e,0x754f,0x7551,0x7551,0x7553,0x7554,0x7559,0x755d,0x7560,0x7560,0x7562,0x7562,0x7564,0x7567,0x756a,0x756b,0x756f,0x7570,0x7575,0x7576,0x7578,0x7578,0x757a,0x757a,0x757f,0x757f,0x7586,0x7588,0x758a,0x758b,0x758e,0x758f,0x7591,0x7592,0x7594,0x7594,0x7599,0x759a,0x759d,0x759d,0x75a3,0x75a3,0x75a5,0x75a5,0x75a9,0x75a9,0x75ab,0x75ab,0x75b1,0x75b5,0x75b8,0x75b9,0x75bc,0x75be,0x75c0,0x75c0,0x75c2,0x75c3,0x75c5,0x75c5,0x75c7,0x75c7,0x75ca,0x75ca,0x75cd,0x75ce,0x75d2,0x75d5,0x75d8,0x75d9,0x75db,0x75db,0x75de,0x75de,0x75e2,0x75e4,0x75e7,0x75e7,0x75f0,0x75f0,0x75f2,0x75f4,0x75f9,0x75fa,0x75fc,0x75fc,0x75ff,0x7601,0x7607,0x7609,0x760b,0x760b,0x760d,0x760d,0x7610,0x7610,0x7615,0x7615,0x7619,0x7619,0x761f,0x7622,0x7624,0x7624,0x7626,0x7627,0x762f,0x7631,0x7633,0x7634,0x763b,0x763b,0x7642,0x7643,0x7646,0x7649,0x764c,0x764c,0x764e,0x764e,0x7652,0x7652,0x7655,0x7656,0x7658,0x7658,0x765c,0x765c,0x7661,0x7662,0x7664,0x7665,0x7667,0x7669,0x766c,0x7672,0x7676,0x7676,0x7678,0x7678,0x767a,0x767e,0x7680,0x7681,0x7683,0x7684,0x7686,0x7687,0x768b,0x768b,0x768e,0x768e,0x7690,0x7690,0x7692,0x7693,0x7696,0x7697,0x769a,0x769c,0x769e,0x769e,0x76a4,0x76a4,0x76ac,0x76ac,0x76ae,0x76ae,0x76b4,0x76b4,0x76b6,0x76b6,0x76b8,0x76b8,0x76ba,0x76ba,0x76bf,0x76bf,0x76c2,0x76c3,0x76c6,0x76c6,0x76c8,0x76c8,0x76ca,0x76ca,0x76cc,0x76ce,0x76d2,0x76d4,0x76d6,0x76d6,0x76d9,0x76d9,0x76db,0x76dc,0x76de,0x76df,0x76e1,0x76e1,0x76e3,0x76e5,0x76e7,0x76e7,0x76ea,0x76ea,0x76ec,0x76ec,0x76ee,0x76ee,0x76f1,0x76f2,0x76f4,0x76f4,0x76f8,0x76f9,0x76fb,0x76fc,0x76fe,0x7702,0x7704,0x7704,0x7707,0x770c,0x7710,0x7710,0x771a,0x771b,0x771e,0x7720,0x7725,0x7726,0x7728,0x7729,0x7734,0x7734,0x7737,0x773c,0x773e,0x773e,0x7740,0x7740,0x7743,0x7743,0x7746,0x7747,0x774d,0x774d,0x7752,0x7752,0x775a,0x775b,0x775f,0x7763,0x7765,0x7766,0x7768,0x7768,0x776b,0x776c,0x7777,0x7777,0x7779,0x7779,0x777d,0x777f,0x778b,0x778b,0x778d,0x778e,0x7791,0x7791,0x7796,0x7796,0x7799,0x7799,0x779e,0x779e,0x77a0,0x77a0,0x77a2,0x77a2,0x77a5,0x77a5,0x77aa,0x77aa,0x77ac,0x77ae,0x77b0,0x77b0,0x77b3,0x77b3,0x77b9,0x77b9,0x77bb,0x77bd,0x77bf,0x77bf,0x77c7,0x77c7,0x77c9,0x77c9,0x77cd,0x77cd,0x77d7,0x77d7,0x77d9,0x77dc,0x77de,0x77de,0x77e1,0x77e3,0x77e5,0x77e5,0x77e7,0x77e7,0x77e9,0x77e9,0x77ed,0x77f0,0x77f3,0x77f3,0x77f8,0x77f8,0x77fa,0x77fd,0x7802,0x7802,0x7807,0x7807,0x780c,0x780c,0x780f,0x780f,0x7811,0x7812,0x7814,0x7814,0x7822,0x7822,0x7825,0x7827,0x782c,0x782d,0x7830,0x7830,0x7832,0x7832,0x7834,0x7834,0x7843,0x7843,0x7845,0x7845,0x784f,0x784f,0x785c,0x785d,0x7860,0x7860,0x7867,0x7868,0x786a,0x786c,0x786e,0x786f,0x787c,0x787c,0x7881,0x7881,0x7884,0x7884,0x7887,0x7887,0x788c,0x788f,0x7891,0x7891,0x7893,0x7893,0x7897,0x7897,0x789f,0x789f,0x78a3,0x78a4,0x78a7,0x78a9,0x78ac,0x78ad,0x78ba,0x78bc,0x78be,0x78be,0x78c1,0x78c1,0x78c5,0x78c5,0x78c8,0x78c8,0x78ca,0x78cb,0x78ce,0x78d1,0x78d4,0x78d5,0x78da,0x78da,0x78e0,0x78e0,0x78e7,0x78e8,0x78ea,0x78ea,0x78ec,0x78ec,0x78ef,0x78ef,0x78f4,0x78f5,0x78f7,0x78f7,0x78fa,0x78fd,0x7901,0x7901,0x790c,0x790c,0x790e,0x790f,0x7911,0x7912,0x7916,0x7916,0x7919,0x7919,0x7927,0x7927,0x792a,0x792d,0x7931,0x7931,0x793a,0x793c,0x793e,0x793e,0x7940,0x7941,0x7944,0x794a,0x7950,0x7950,0x7953,0x7958,0x795a,0x7960,0x7962,0x7962,0x7965,0x7965,0x7967,0x7968,0x796d,0x796d,0x7979,0x797a,0x797c,0x797c,0x797f,0x7981,0x798a,0x798b,0x798d,0x798f,0x7991,0x7991,0x7994,0x7994,0x799b,0x799b,0x799d,0x799d,0x79a6,0x79a8,0x79aa,0x79ab,0x79ae,0x79ae,0x79b0,0x79b1,0x79b3,0x79b4,0x79b8,0x79c1,0x79c4,0x79c4,0x79c6,0x79c6,0x79c9,0x79cb,0x79d1,0x79d2,0x79d5,0x79d5,0x79d8,0x79d8,0x79de,0x79df,0x79e2,0x79e4,0x79e6,0x79e7,0x79e9,0x79ec,0x79f5,0x79f5,0x79f8,0x79f8,0x79fb,0x79fb,0x7a00,0x7a02,0x7a05,0x7a05,0x7a08,0x7a08,0x7a0a,0x7a0d,0x7a14,0x7a14,0x7a17,0x7a1a,0x7a1c,0x7a1c,0x7a1e,0x7a20,0x7a22,0x7a22,0x7a27,0x7a27,0x7a2e,0x7a2e,0x7a30,0x7a31,0x7a33,0x7a33,0x7a36,0x7a37,0x7a39,0x7a39,0x7a3b,0x7a3d,0x7a3f,0x7a40,0x7a42,0x7a42,0x7a45,0x7a46,0x7a49,0x7a49,0x7a4c,0x7a4e,0x7a57,0x7a57,0x7a60,0x7a62,0x7a66,0x7a66,0x7a69,0x7a69,0x7a6b,0x7a6b,0x7a70,0x7a70,0x7a74,0x7a76,0x7a79,0x7a7a,0x7a7d,0x7a86,0x7a88,0x7a88,0x7a8a,0x7a8a,0x7a92,0x7a93,0x7a95,0x7a99,0x7a9b,0x7a9b,0x7a9f,0x7aa0,0x7aa3,0x7aa3,0x7aa9,0x7aaa,0x7aac,0x7aac,0x7aae,0x7aaf,0x7ab3,0x7ab3,0x7ab6,0x7ab6,0x7ab9,0x7abb,0x7abe,0x7abf,0x7ac4,0x7ac5,0x7ac7,0x7ac8,0x7aca,0x7acb,0x7ad7,0x7ad7,0x7ad9,0x7ad9,0x7adc,0x7add,0x7adf,0x7ae0,0x7ae2,0x7ae3,0x7ae5,0x7ae6,0x7aea,0x7aea,0x7aed,0x7aed,0x7aef,0x7aef,0x7af4,0x7af4,0x7af6,0x7af6,0x7af8,0x7afa,0x7afd,0x7afd,0x7aff,0x7aff,0x7b06,0x7b06,0x7b08,0x7b08,0x7b0a,0x7b0a,0x7b0c,0x7b0c,0x7b0e,0x7b0f,0x7b11,0x7b12,0x7b18,0x7b19,0x7b1b,0x7b1b,0x7b1e,0x7b1e,0x7b20,0x7b20,0x7b25,0x7b28,0x7b2c,0x7b2d,0x7b2f,0x7b2f,0x7b33,0x7b33,0x7b35,0x7b35,0x7b39,0x7b39,0x7b45,0x7b46,0x7b48,0x7b49,0x7b4b,0x7b4d,0x7b4f,0x7b54,0x7b56,0x7b56,0x7b5f,0x7b60,0x7b65,0x7b67,0x7b69,0x7b69,0x7b6c,0x7b6c,0x7b6e,0x7b6e,0x7b71,0x7b71,0x7b73,0x7b73,0x7b75,0x7b75,0x7b7d,0x7b7d,0x7b87,0x7b87,0x7b8b,0x7b8b,0x7b8d,0x7b8f,0x7b92,0x7b92,0x7b94,0x7b95,0x7b97,0x7b97,0x7b99,0x7b9a,0x7b9c,0x7b9d,0x7ba0,0x7ba1,0x7bad,0x7bad,0x7bb1,0x7bb1,0x7bb4,0x7bb4,0x7bb8,0x7bb8,0x7bbe,0x7bbe,0x7bc0,0x7bc1,0x7bc4,0x7bc4,0x7bc6,0x7bc7,0x7bc9,0x7bcc,0x7bd2,0x7bd2,0x7bd4,0x7bd4,0x7bd9,0x7bd9,0x7bdb,0x7bdb,0x7bdd,0x7bdd,0x7be0,0x7be1,0x7be4,0x7be4,0x7be6,0x7be6,0x7be9,0x7bea,0x7bf3,0x7bf3,0x7bf7,0x7bf7,0x7bfe,0x7bfe,0x7c00,0x7c00,0x7c07,0x7c07,0x7c09,0x7c09,0x7c0b,0x7c0b,0x7c0f,0x7c0f,0x7c12,0x7c12,0x7c1e,0x7c21,0x7c27,0x7c27,0x7c2a,0x7c2b,0x7c37,0x7c38,0x7c3d,0x7c3f,0x7c43,0x7c43,0x7c4c,0x7c4d,0x7c50,0x7c50,0x7c52,0x7c52,0x7c54,0x7c54,0x7c5b,0x7c5c,0x7c5f,0x7c60,0x7c64,0x7c65,0x7c67,0x7c67,0x7c69,0x7c69,0x7c6c,0x7c6c,0x7c72,0x7c73,0x7c7e,0x7c7e,0x7c81,0x7c81,0x7c83,0x7c83,0x7c89,0x7c89,0x7c8d,0x7c8d,0x7c92,0x7c92,0x7c95,0x7c95,0x7c97,0x7c98,0x7c9f,0x7c9f,0x7ca2,0x7ca2,0x7ca4,0x7ca8,0x7cae,0x7cae,0x7cb1,0x7cb3,0x7cb9,0x7cb9,0x7cbc,0x7cbe,0x7cc5,0x7cc6,0x7cca,0x7cca,0x7cd5,0x7cd7,0x7cd9,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce5,0x7ce5,0x7ce7,0x7ce7,0x7cef,0x7cef,0x7cf1,0x7cf2,0x7cf4,0x7cf6,0x7cf8,0x7cfb,0x7cfe,0x7cfe,0x7d00,0x7d00,0x7d02,0x7d08,0x7d0a,0x7d0b,0x7d0d,0x7d0d,0x7d10,0x7d10,0x7d13,0x7d15,0x7d17,0x7d1c,0x7d20,0x7d22,0x7d2b,0x7d2c,0x7d2e,0x7d33,0x7d35,0x7d35,0x7d38,0x7d3a,0x7d41,0x7d46,0x7d49,0x7d49,0x7d4c,0x7d4d,0x7d50,0x7d51,0x7d55,0x7d56,0x7d59,0x7d59,0x7d5b,0x7d5c,0x7d5e,0x7d5e,0x7d61,0x7d63,0x7d66,0x7d66,0x7d68,0x7d6a,0x7d6e,0x7d6e,0x7d70,0x7d73,0x7d75,0x7d76,0x7d79,0x7d7a,0x7d7f,0x7d7f,0x7d83,0x7d83,0x7d86,0x7d86,0x7d8e,0x7d8f,0x7d93,0x7d93,0x7d98,0x7d98,0x7d9a,0x7d9a,0x7d9c,0x7d9c,0x7da0,0x7da0,0x7da2,0x7da3,0x7da5,0x7da7,0x7da9,0x7da9,0x7dab,0x7dae,0x7db0,0x7db2,0x7db4,0x7db5,0x7db8,0x7db8,0x7dba,0x7dbb,0x7dbd,0x7dbf,0x7dc4,0x7dc4,0x7dc7,0x7dc7,0x7dca,0x7dcd,0x7dcf,0x7dcf,0x7dd6,0x7dd8,0x7dda,0x7dda,0x7ddc,0x7dde,0x7de0,0x7de1,0x7de3,0x7de3,0x7de6,0x7de6,0x7de8,0x7de9,0x7dec,0x7dec,0x7def,0x7def,0x7df4,0x7df4,0x7df6,0x7df6,0x7df9,0x7df9,0x7dfb,0x7dfb,0x7e03,0x7e03,0x7e08,0x7e0b,0x7e10,0x7e11,0x7e15,0x7e15,0x7e17,0x7e18,0x7e1b,0x7e1b,0x7e1d,0x7e23,0x7e2b,0x7e2b,0x7e2e,0x7e2f,0x7e31,0x7e33,0x7e35,0x7e35,0x7e37,0x7e37,0x7e39,0x7e39,0x7e3b,0x7e3b,0x7e3d,0x7e3e,0x7e41,0x7e41,0x7e43,0x7e48,0x7e50,0x7e50,0x7e52,0x7e52,0x7e54,0x7e57,0x7e59,0x7e5a,0x7e5e,0x7e5e,0x7e61,0x7e62,0x7e69,0x7e6b,0x7e6d,0x7e6d,0x7e6f,0x7e70,0x7e76,0x7e76,0x7e79,0x7e79,0x7e7c,0x7e7e,0x7e81,0x7e82,0x7e87,0x7e88,0x7e8a,0x7e8a,0x7e8c,0x7e8d,0x7e8f,0x7e8f,0x7e93,0x7e94,0x7e96,0x7e96,0x7e98,0x7e98,0x7e9b,0x7e9c,0x7e9f,0x7e9f,0x7f36,0x7f38,0x7f3a,0x7f3a,0x7f3e,0x7f3f,0x7f43,0x7f45,0x7f47,0x7f47,0x7f4b,0x7f4e,0x7f50,0x7f55,0x7f58,0x7f58,0x7f5d,0x7f5d,0x7f5f,0x7f61,0x7f63,0x7f63,0x7f66,0x7f66,0x7f68,0x7f68,0x7f6a,0x7f6b,0x7f6e,0x7f6e,0x7f70,0x7f70,0x7f72,0x7f72,0x7f75,0x7f75,0x7f77,0x7f79,0x7f7c,0x7f7e,0x7f82,0x7f82,0x7f85,0x7f88,0x7f8a,0x7f8a,0x7f8c,0x7f8c,0x7f8e,0x7f8e,0x7f94,0x7f94,0x7f96,0x7f98,0x7f9a,0x7f9a,0x7f9d,0x7f9e,0x7fa1,0x7fa1,0x7fa4,0x7fa4,0x7fa8,0x7fa9,0x7fab,0x7fab,0x7faf,0x7faf,0x7fb2,0x7fb2,0x7fb6,0x7fb6,0x7fb8,0x7fb9,0x7fbd,0x7fbd,0x7fbf,0x7fbf,0x7fc1,0x7fc1,0x7fc5,0x7fc5,0x7fca,0x7fca,0x7fcc,0x7fcc,0x7fce,0x7fce,0x7fd2,0x7fd2,0x7fd4,0x7fd6,0x7fdb,0x7fdb,0x7fdf,0x7fe1,0x7fe3,0x7fe4,0x7fe6,0x7fe6,0x7fe9,0x7fe9,0x7feb,0x7fec,0x7fee,0x7fee,0x7ff0,0x7ff0,0x7ff3,0x7ff3,0x7ff9,0x7ffc,0x7ffe,0x7ffe,0x8000,0x8009,0x800c,0x800c,0x8010,0x8012,0x8014,0x8019,0x801e,0x801e,0x8021,0x8021,0x8026,0x8026,0x8028,0x8028,0x802c,0x802d,0x8030,0x8030,0x8033,0x8033,0x8036,0x8036,0x803d,0x803d,0x803f,0x803f,0x8043,0x8043,0x8046,0x8046,0x8048,0x8048,0x804a,0x804a,0x8052,0x8052,0x8055,0x8056,0x8058,0x8058,0x805a,0x805a,0x805e,0x805e,0x8061,0x8061,0x806f,0x8073,0x8075,0x8077,0x807d,0x8080,0x8084,0x8087,0x8089,0x8089,0x808b,0x808c,0x8093,0x8093,0x8096,0x8096,0x8098,0x8098,0x809a,0x809b,0x809d,0x809d,0x80a1,0x80a2,0x80a5,0x80a6,0x80a9,0x80ab,0x80ad,0x80ad,0x80af,0x80af,0x80b1,0x80b2,0x80b4,0x80b5,0x80ba,0x80ba,0x80c3,0x80c4,0x80c6,0x80c6,0x80ca,0x80ca,0x80cc,0x80cc,0x80ce,0x80ce,0x80d5,0x80d6,0x80d9,0x80dc,0x80de,0x80de,0x80e0,0x80e1,0x80e4,0x80e5,0x80ef,0x80ef,0x80f1,0x80f1,0x80f4,0x80f4,0x80f7,0x80f8,0x80fd,0x80fe,0x8102,0x8102,0x8105,0x810a,0x8116,0x8118,0x811a,0x811b,0x8123,0x8124,0x8127,0x8127,0x8129,0x8129,0x812b,0x812b,0x812f,0x8130,0x8139,0x813a,0x813e,0x813e,0x8141,0x8141,0x8146,0x8146,0x814a,0x814b,0x814e,0x814e,0x8150,0x8155,0x8160,0x8160,0x8164,0x8166,0x816b,0x816b,0x816d,0x816d,0x8170,0x8171,0x8174,0x8174,0x8176,0x817a,0x817f,0x8180,0x8182,0x8184,0x8186,0x8186,0x8188,0x8188,0x818a,0x818b,0x818f,0x818f,0x819a,0x819a,0x819c,0x819e,0x81a0,0x81a0,0x81a3,0x81a3,0x81a8,0x81a9,0x81b0,0x81b0,0x81b3,0x81b5,0x81b8,0x81ba,0x81bd,0x81c0,0x81c2,0x81c2,0x81c6,0x81c6,0x81ca,0x81ca,0x81cd,0x81cd,0x81cf,0x81cf,0x81d1,0x81d1,0x81d8,0x81da,0x81dd,0x81dd,0x81df,0x81e0,0x81e3,0x81e3,0x81e5,0x81e5,0x81e7,0x81e8,0x81ea,0x81ea,0x81ec,0x81ed,0x81f3,0x81f4,0x81f6,0x81f6,0x81fa,0x81fc,0x81fe,0x81fe,0x8201,0x8203,0x8205,0x8205,0x8207,0x8208,0x820a,0x820a,0x820c,0x820d,0x8210,0x8210,0x8212,0x8212,0x8216,0x8216,0x8218,0x8218,0x821b,0x821c,0x821e,0x821f,0x8221,0x8221,0x822a,0x822c,0x8233,0x8233,0x8235,0x8239,0x823d,0x823d,0x8240,0x8240,0x8245,0x8245,0x8247,0x8247,0x8251,0x8251,0x8258,0x825a,0x825f,0x825f,0x8264,0x8264,0x8266,0x8266,0x8268,0x8268,0x826a,0x826b,0x826e,0x826f,0x8271,0x8272,0x8274,0x8274,0x8276,0x8279,0x827d,0x827e,0x8283,0x8283,0x828a,0x828b,0x828d,0x828e,0x8290,0x8290,0x8292,0x8292,0x8294,0x8294,0x8298,0x829a,0x829d,0x829d,0x829f,0x829f,0x82a1,0x82a3,0x82a5,0x82b1,0x82b3,0x82b3,0x82b7,0x82b9,0x82bb,0x82bf,0x82c5,0x82c5,0x82d1,0x82d5,0x82d7,0x82d7,0x82db,0x82dc,0x82de,0x82e1,0x82e3,0x82e3,0x82e5,0x82e7,0x82e9,0x82e9,0x82eb,0x82eb,0x82f1,0x82f1,0x82f3,0x82f4,0x82f9,0x82fb,0x82fd,0x8305,0x8308,0x8309,0x8317,0x8317,0x831b,0x831d,0x8323,0x8325,0x8328,0x8328,0x832a,0x832b,0x832f,0x832f,0x8331,0x8336,0x8338,0x8339,0x833c,0x833c,0x8340,0x8340,0x8343,0x8343,0x8347,0x8347,0x8349,0x834a,0x834f,0x8352,0x8363,0x8363,0x8373,0x8373,0x8377,0x8377,0x837a,0x837b,0x8382,0x8382,0x8385,0x8385,0x8389,0x838a,0x838e,0x838e,0x8392,0x8393,0x8396,0x8396,0x8398,0x8398,0x839a,0x839b,0x839d,0x83a0,0x83a2,0x83a2,0x83a8,0x83ab,0x83bd,0x83c2,0x83c5,0x83c5,0x83c9,0x83ca,0x83cc,0x83cc,0x83d1,0x83d1,0x83d3,0x83d4,0x83d6,0x83d6,0x83d8,0x83d8,0x83dc,0x83dc,0x83df,0x83e1,0x83e9,0x83e9,0x83eb,0x83eb,0x83ef,0x83f2,0x83f4,0x83f4,0x83f6,0x83f6,0x83f9,0x83f9,0x83fb,0x83fb,0x83fd,0x83fd,0x8403,0x8404,0x8406,0x8407,0x840a,0x840e,0x8429,0x8429,0x842c,0x842c,0x8431,0x8431,0x8435,0x8435,0x8438,0x8439,0x843c,0x843d,0x8446,0x8446,0x8449,0x844a,0x8451,0x8451,0x8457,0x8457,0x845a,0x845b,0x8461,0x8461,0x8463,0x8463,0x8466,0x8466,0x8469,0x846d,0x846f,0x8471,0x8473,0x8473,0x8475,0x8475,0x8477,0x8477,0x847a,0x847a,0x8482,0x8482,0x8490,0x8491,0x8494,0x8494,0x8499,0x8499,0x849c,0x849c,0x849f,0x849f,0x84a1,0x84a1,0x84a8,0x84a8,0x84ad,0x84ad,0x84af,0x84af,0x84b2,0x84b2,0x84b4,0x84b4,0x84b8,0x84bd,0x84bf,0x84c2,0x84c4,0x84c4,0x84c6,0x84c6,0x84c9,0x84cb,0x84cd,0x84cd,0x84cf,0x84d1,0x84d3,0x84d3,0x84d6,0x84d6,0x84da,0x84da,0x84ec,0x84ef,0x84f1,0x84f1,0x84f4,0x84f4,0x84fa,0x84fa,0x84fc,0x84fd,0x8500,0x8500,0x8506,0x8506,0x850e,0x850e,0x8511,0x8511,0x8513,0x8515,0x8517,0x8518,0x851a,0x851a,0x851e,0x851f,0x8521,0x8521,0x8523,0x8523,0x8525,0x8526,0x852a,0x852a,0x852c,0x852d,0x852f,0x8530,0x853d,0x853d,0x853f,0x853f,0x8541,0x8541,0x8543,0x8543,0x8546,0x8546,0x8549,0x854b,0x854e,0x854e,0x8553,0x8553,0x8555,0x8559,0x855e,0x855e,0x8561,0x8561,0x8563,0x8564,0x8568,0x856b,0x856d,0x856d,0x8578,0x8578,0x857a,0x857a,0x857e,0x857e,0x8580,0x8580,0x8584,0x8584,0x8586,0x8587,0x8589,0x858a,0x858c,0x858c,0x858f,0x858f,0x8591,0x8591,0x8594,0x8594,0x8597,0x8597,0x8599,0x8599,0x859b,0x859b,0x859d,0x859d,0x85a4,0x85a6,0x85a8,0x85ab,0x85af,0x85b0,0x85ba,0x85ba,0x85c1,0x85c1,0x85c7,0x85c7,0x85c9,0x85c9,0x85cd,0x85d0,0x85d5,0x85d5,0x85dc,0x85dd,0x85e4,0x85e5,0x85e9,0x85ea,0x85f7,0x85f7,0x85f9,0x85fb,0x85fd,0x85fd,0x85ff,0x8600,0x8602,0x8602,0x8604,0x8604,0x8606,0x8607,0x860a,0x860b,0x8616,0x8618,0x861a,0x861a,0x861f,0x861f,0x8622,0x8622,0x8627,0x8627,0x8629,0x862a,0x862d,0x862d,0x862f,0x862f,0x863c,0x863c,0x863f,0x863f,0x8641,0x8641,0x864d,0x864e,0x8650,0x8650,0x8653,0x8655,0x865b,0x865c,0x865e,0x865f,0x8667,0x8667,0x866b,0x866c,0x866f,0x866f,0x8671,0x8671,0x8678,0x867b,0x868a,0x868d,0x8693,0x8693,0x8695,0x8695,0x86a3,0x86a4,0x86a8,0x86aa,0x86af,0x86b1,0x86b4,0x86b4,0x86c0,0x86c0,0x86c5,0x86c7,0x86c9,0x86c9,0x86cb,0x86cb,0x86d4,0x86d4,0x86d9,0x86d9,0x86db,0x86db,0x86de,0x86df,0x86e3,0x86e4,0x86e9,0x86e9,0x86ec,0x86ed,0x86f8,0x86f9,0x86fb,0x86fb,0x86fe,0x86fe,0x8700,0x8700,0x8702,0x8703,0x8706,0x8706,0x8708,0x870b,0x8711,0x8711,0x8718,0x8718,0x871a,0x871a,0x871c,0x871d,0x8721,0x8721,0x8725,0x8725,0x8728,0x8729,0x8734,0x8735,0x8737,0x8737,0x873a,0x873b,0x873f,0x8740,0x874c,0x874c,0x874e,0x874e,0x8755,0x8755,0x8757,0x8757,0x8759,0x8759,0x875f,0x8760,0x8764,0x8766,0x8768,0x8768,0x876e,0x876e,0x8774,0x8774,0x8776,0x8776,0x8778,0x8778,0x8782,0x8783,0x878c,0x878d,0x8798,0x8798,0x879e,0x879f,0x87a2,0x87a3,0x87ad,0x87ad,0x87b3,0x87b4,0x87ba,0x87bb,0x87bd,0x87bd,0x87c0,0x87c0,0x87c4,0x87c4,0x87c7,0x87c7,0x87ca,0x87cb,0x87d2,0x87d2,0x87da,0x87db,0x87e0,0x87e0,0x87e3,0x87e3,0x87ec,0x87ec,0x87ef,0x87ef,0x87f2,0x87f2,0x87f7,0x87f7,0x87f9,0x87f9,0x87fb,0x87fb,0x87fe,0x87fe,0x8805,0x8805,0x880d,0x880d,0x8811,0x8811,0x8815,0x8815,0x881f,0x881f,0x8821,0x8823,0x8831,0x8832,0x8836,0x8836,0x8839,0x8839,0x883b,0x883b,0x8840,0x8840,0x8844,0x8844,0x8846,0x8846,0x884a,0x884a,0x884c,0x884e,0x8852,0x8853,0x8857,0x8857,0x8859,0x8859,0x885b,0x885b,0x885d,0x885e,0x8861,0x8864,0x8868,0x8868,0x886b,0x886b,0x886e,0x886e,0x8870,0x8870,0x8872,0x8872,0x8877,0x8877,0x887d,0x887f,0x8881,0x8882,0x8888,0x8888,0x888b,0x888b,0x888d,0x888d,0x8892,0x8892,0x8896,0x8897,0x889b,0x889b,0x889d,0x889e,0x88a2,0x88a2,0x88aa,0x88ab,0x88b4,0x88b4,0x88c0,0x88c2,0x88c5,0x88c5,0x88ca,0x88ca,0x88cd,0x88cd,0x88cf,0x88cf,0x88d2,0x88d2,0x88d4,0x88d5,0x88d8,0x88d9,0x88dc,0x88dd,0x88df,0x88df,0x88e1,0x88e1,0x88e8,0x88e8,0x88ef,0x88ef,0x88f1,0x88f1,0x88f3,0x88f5,0x88f8,0x88f9,0x88fd,0x88fe,0x8904,0x8904,0x8907,0x8907,0x890a,0x890a,0x890c,0x890c,0x8910,0x8913,0x8915,0x8915,0x8918,0x891a,0x8925,0x8925,0x8927,0x8927,0x892a,0x892b,0x892f,0x8930,0x8936,0x8936,0x8938,0x8938,0x893a,0x893b,0x8941,0x8941,0x8944,0x8944,0x894d,0x894d,0x8952,0x8952,0x8956,0x8956,0x8958,0x8958,0x895c,0x895c,0x895e,0x8960,0x8964,0x8964,0x896a,0x896a,0x896d,0x896d,0x896f,0x896f,0x8972,0x8972,0x8974,0x8974,0x897e,0x8981,0x8983,0x8983,0x8986,0x8989,0x898b,0x898b,0x898f,0x898f,0x8993,0x8993,0x8996,0x8998,0x899a,0x899a,0x89a0,0x89a1,0x89a8,0x89aa,0x89ac,0x89ac,0x89af,0x89af,0x89b2,0x89b3,0x89b6,0x89b7,0x89ba,0x89ba,0x89bd,0x89bd,0x89bf,0x89c1,0x89d2,0x89d2,0x89d4,0x89d4,0x89d6,0x89d7,0x89da,0x89da,0x89dc,0x89dd,0x89e3,0x89e3,0x89e5,0x89e7,0x89f0,0x89f1,0x89f3,0x89f4,0x89f6,0x89f6,0x89f8,0x89f8,0x8a00,0x8a00,0x8a02,0x8a03,0x8a07,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a0e,0x8a10,0x8a18,0x8a1b,0x8a1b,0x8a1d,0x8a1d,0x8a1f,0x8a1f,0x8a22,0x8a23,0x8a25,0x8a25,0x8a2a,0x8a2a,0x8a2d,0x8a2d,0x8a31,0x8a31,0x8a33,0x8a34,0x8a36,0x8a36,0x8a3a,0x8a3c,0x8a3e,0x8a3e,0x8a41,0x8a41,0x8a46,0x8a46,0x8a4b,0x8a4b,0x8a50,0x8a51,0x8a54,0x8a58,0x8a5b,0x8a5b,0x8a5e,0x8a5e,0x8a60,0x8a63,0x8a66,0x8a66,0x8a69,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a73,0x8a75,0x8a75,0x8a79,0x8a79,0x8a7c,0x8a7c,0x8a7f,0x8a7f,0x8a82,0x8a82,0x8a84,0x8a87,0x8a8c,0x8a8d,0x8a91,0x8a91,0x8a93,0x8a93,0x8a95,0x8a95,0x8a98,0x8a98,0x8a9a,0x8a9a,0x8a9e,0x8a9e,0x8aa0,0x8aa8,0x8aaa,0x8aaa,0x8ab0,0x8ab0,0x8ab2,0x8ab2,0x8ab9,0x8ab9,0x8abc,0x8abc,0x8abe,0x8abf,0x8ac2,0x8ac2,0x8ac4,0x8ac4,0x8ac7,0x8ac7,0x8ac9,0x8ac9,0x8acb,0x8acb,0x8acd,0x8acd,0x8acf,0x8acf,0x8ad2,0x8ad2,0x8ad6,0x8ad7,0x8adb,0x8ae1,0x8ae4,0x8ae4,0x8ae6,0x8ae7,0x8aea,0x8aeb,0x8aed,0x8aee,0x8af0,0x8af4,0x8af6,0x8af8,0x8afa,0x8afa,0x8afc,0x8afc,0x8afe,0x8afe,0x8b00,0x8b02,0x8b04,0x8b04,0x8b07,0x8b07,0x8b0c,0x8b0c,0x8b0e,0x8b0e,0x8b10,0x8b11,0x8b14,0x8b14,0x8b16,0x8b17,0x8b19,0x8b1d,0x8b20,0x8b20,0x8b23,0x8b23,0x8b26,0x8b26,0x8b28,0x8b28,0x8b2b,0x8b2c,0x8b33,0x8b33,0x8b37,0x8b37,0x8b39,0x8b39,0x8b3c,0x8b3c,0x8b3e,0x8b3e,0x8b41,0x8b41,0x8b43,0x8b43,0x8b46,0x8b46,0x8b49,0x8b49,0x8b4c,0x8b4c,0x8b4e,0x8b4f,0x8b53,0x8b54,0x8b56,0x8b56,0x8b58,0x8b5a,0x8b5c,0x8b5c,0x8b5e,0x8b5f,0x8b66,0x8b66,0x8b6b,0x8b6c,0x8b6f,0x8b71,0x8b74,0x8b74,0x8b77,0x8b77,0x8b7d,0x8b7d,0x8b7f,0x8b80,0x8b83,0x8b83,0x8b89,0x8b8a,0x8b8c,0x8b8c,0x8b8e,0x8b8e,0x8b90,0x8b90,0x8b92,0x8b93,0x8b96,0x8b96,0x8b9a,0x8b9a,0x8b9c,0x8b9c,0x8b9e,0x8b9e,0x8ba0,0x8ba0,0x8c37,0x8c37,0x8c3f,0x8c3f,0x8c41,0x8c41,0x8c46,0x8c4a,0x8c4c,0x8c4c,0x8c4e,0x8c4e,0x8c50,0x8c50,0x8c55,0x8c56,0x8c5a,0x8c5a,0x8c61,0x8c62,0x8c68,0x8c68,0x8c6a,0x8c6c,0x8c73,0x8c73,0x8c78,0x8c7a,0x8c82,0x8c83,0x8c8a,0x8c8a,0x8c8c,0x8c8d,0x8c93,0x8c94,0x8c98,0x8c98,0x8c9d,0x8ca2,0x8ca7,0x8cac,0x8caf,0x8cb0,0x8cb2,0x8cb4,0x8cb6,0x8cbd,0x8cbf,0x8cc4,0x8cc6,0x8cc8,0x8cca,0x8cca,0x8cd1,0x8cd1,0x8cd3,0x8cd3,0x8cd9,0x8cdc,0x8cde,0x8cde,0x8ce0,0x8ce6,0x8cea,0x8cea,0x8cec,0x8ced,0x8cf0,0x8cf1,0x8cf3,0x8cf4,0x8cfb,0x8cfd,0x8d04,0x8d05,0x8d07,0x8d08,0x8d0a,0x8d0b,0x8d0d,0x8d0d,0x8d0f,0x8d10,0x8d13,0x8d14,0x8d16,0x8d16,0x8d1b,0x8d1b,0x8d1d,0x8d1d,0x8d64,0x8d64,0x8d66,0x8d67,0x8d6b,0x8d6b,0x8d6d,0x8d6e,0x8d70,0x8d70,0x8d73,0x8d74,0x8d76,0x8d77,0x8d81,0x8d81,0x8d85,0x8d85,0x8d8a,0x8d8a,0x8d8e,0x8d8e,0x8d90,0x8d90,0x8d99,0x8d99,0x8da0,0x8da0,0x8da3,0x8da3,0x8da8,0x8da8,0x8dab,0x8dab,0x8db2,0x8db3,0x8dba,0x8dba,0x8dbe,0x8dbe,0x8dc2,0x8dc2,0x8dc6,0x8dc6,0x8dcb,0x8dcc,0x8dce,0x8dcf,0x8dd5,0x8dd7,0x8ddb,0x8ddb,0x8ddd,0x8ddd,0x8ddf,0x8ddf,0x8de1,0x8de1,0x8de3,0x8de3,0x8de8,0x8de8,0x8dea,0x8ded,0x8def,0x8def,0x8df1,0x8df1,0x8df3,0x8df3,0x8dfc,0x8dfc,0x8e06,0x8e06,0x8e08,0x8e0a,0x8e0f,0x8e10,0x8e14,0x8e14,0x8e1d,0x8e1f,0x8e2a,0x8e2a,0x8e30,0x8e30,0x8e34,0x8e36,0x8e3a,0x8e3a,0x8e3d,0x8e3d,0x8e40,0x8e40,0x8e42,0x8e42,0x8e44,0x8e44,0x8e47,0x8e4a,0x8e4c,0x8e4c,0x8e4f,0x8e4f,0x8e55,0x8e55,0x8e59,0x8e59,0x8e5c,0x8e5c,0x8e5f,0x8e60,0x8e63,0x8e64,0x8e72,0x8e72,0x8e74,0x8e74,0x8e76,0x8e76,0x8e7b,0x8e7b,0x8e81,0x8e81,0x8e85,0x8e85,0x8e87,0x8e87,0x8e89,0x8e8b,0x8e8d,0x8e8d,0x8e90,0x8e91,0x8e93,0x8e94,0x8e99,0x8e99,0x8e9e,0x8e9e,0x8ea1,0x8ea1,0x8ea9,0x8eac,0x8eb1,0x8eb1,0x8eb3,0x8eb3,0x8ebe,0x8ebe,0x8ec0,0x8ec0,0x8ec6,0x8ec6,0x8eca,0x8ecd,0x8ed2,0x8ed2,0x8ede,0x8edf,0x8ee2,0x8ee2,0x8ee8,0x8ee8,0x8eeb,0x8eeb,0x8ef8,0x8efc,0x8efe,0x8efe,0x8f03,0x8f03,0x8f05,0x8f05,0x8f07,0x8f09,0x8f12,0x8f15,0x8f1b,0x8f1f,0x8f26,0x8f2a,0x8f2d,0x8f2d,0x8f2f,0x8f30,0x8f33,0x8f33,0x8f38,0x8f39,0x8f3b,0x8f3b,0x8f3e,0x8f40,0x8f42,0x8f42,0x8f44,0x8f46,0x8f49,0x8f49,0x8f4d,0x8f4e,0x8f52,0x8f52,0x8f54,0x8f54,0x8f57,0x8f58,0x8f5d,0x8f5f,0x8f61,0x8f64,0x8f66,0x8f66,0x8f9b,0x8f9c,0x8f9f,0x8f9f,0x8fa2,0x8fa3,0x8fa6,0x8fa6,0x8fa8,0x8fa8,0x8fad,0x8fb2,0x8fb5,0x8fb6,0x8fbb,0x8fbb,0x8fbf,0x8fc0,0x8fc2,0x8fc5,0x8fcd,0x8fce,0x8fd0,0x8fd1,0x8fd3,0x8fd5,0x8fe2,0x8fe2,0x8fe4,0x8fe6,0x8fe8,0x8fe8,0x8fea,0x8fed,0x8ff0,0x8ff0,0x8ff2,0x8ff2,0x8ff4,0x8ff4,0x8ff7,0x8ffa,0x8ffc,0x8ffd,0x8fff,0x9003,0x9005,0x9006,0x9008,0x9008,0x900b,0x9011,0x9014,0x9017,0x9019,0x901a,0x901d,0x9023,0x902e,0x902e,0x9031,0x9032,0x9034,0x9036,0x9038,0x9038,0x903c,0x903c,0x903e,0x903e,0x9041,0x9042,0x9047,0x9047,0x9049,0x904b,0x904d,0x9055,0x9058,0x9059,0x905b,0x905e,0x9060,0x9061,0x9063,0x9063,0x9068,0x9069,0x906c,0x906f,0x9072,0x9072,0x9075,0x9078,0x907a,0x907a,0x907c,0x9085,0x9087,0x9088,0x908a,0x908a,0x908c,0x908d,0x908f,0x9091,0x9095,0x9095,0x9097,0x9099,0x90a0,0x90a0,0x90a2,0x90a3,0x90a6,0x90a6,0x90a8,0x90a8,0x90aa,0x90aa,0x90af,0x90b1,0x90b3,0x90b3,0x90b5,0x90b5,0x90b8,0x90b8,0x90bd,0x90be,0x90c1,0x90c1,0x90c3,0x90c5,0x90ca,0x90ca,0x90ce,0x90ce,0x90dc,0x90de,0x90e1,0x90e2,0x90e8,0x90e8,0x90ea,0x90eb,0x90ed,0x90ed,0x90ef,0x90ef,0x90f3,0x90f5,0x90fd,0x90fd,0x9102,0x9102,0x9112,0x9112,0x9115,0x9117,0x9119,0x9119,0x911e,0x911e,0x9122,0x9123,0x9127,0x9127,0x912d,0x912d,0x9130,0x9132,0x9134,0x9134,0x913d,0x913d,0x9148,0x914e,0x9152,0x9152,0x9156,0x9157,0x9162,0x9165,0x9169,0x916a,0x916c,0x916c,0x9172,0x9172,0x9174,0x9179,0x9183,0x9183,0x9187,0x9187,0x9189,0x9189,0x918b,0x918b,0x918d,0x918d,0x9190,0x9190,0x9192,0x9192,0x919c,0x919c,0x919e,0x919e,0x91a2,0x91a2,0x91aa,0x91ac,0x91ae,0x91af,0x91b1,0x91b2,0x91b4,0x91b5,0x91bc,0x91bc,0x91c0,0x91c1,0x91c3,0x91c3,0x91c5,0x91c7,0x91c9,0x91c9,0x91cb,0x91d1,0x91d7,0x91d8,0x91dc,0x91dd,0x91e3,0x91e7,0x91e9,0x91ea,0x91ed,0x91ed,0x91f5,0x91f5,0x91ff,0x91ff,0x9207,0x9207,0x920d,0x920d,0x9210,0x9212,0x9214,0x9215,0x9217,0x9217,0x921c,0x921c,0x921e,0x921f,0x9226,0x9226,0x9231,0x9231,0x9234,0x9235,0x9237,0x9238,0x923a,0x923a,0x923f,0x9241,0x9244,0x9245,0x9249,0x9249,0x924b,0x924b,0x924d,0x9252,0x9257,0x9257,0x925b,0x925b,0x925e,0x925e,0x9262,0x9262,0x9264,0x9266,0x9277,0x9278,0x927c,0x927c,0x927e,0x927e,0x9280,0x9280,0x9283,0x9283,0x9285,0x9285,0x928b,0x928b,0x9291,0x9291,0x9293,0x9293,0x9295,0x9296,0x9298,0x929c,0x92b3,0x92b4,0x92b6,0x92b7,0x92b9,0x92b9,0x92c6,0x92c6,0x92cc,0x92cc,0x92cf,0x92cf,0x92d1,0x92d2,0x92d5,0x92d5,0x92d7,0x92d7,0x92df,0x92df,0x92e4,0x92e5,0x92ea,0x92ea,0x92f2,0x92f2,0x92f8,0x92fa,0x92fc,0x92fe,0x9300,0x9300,0x9304,0x9304,0x9306,0x9306,0x930f,0x9310,0x9315,0x9315,0x9318,0x931a,0x931e,0x9324,0x9326,0x9328,0x932a,0x932c,0x932e,0x932f,0x9348,0x934b,0x934d,0x934d,0x9351,0x9351,0x9354,0x9354,0x9357,0x9357,0x935b,0x935d,0x9364,0x9365,0x936b,0x936c,0x936e,0x936e,0x9370,0x9370,0x9372,0x9372,0x9375,0x9375,0x937c,0x937c,0x937e,0x937e,0x938a,0x938a,0x938c,0x938c,0x9394,0x9394,0x9396,0x9397,0x939a,0x939b,0x939f,0x93a1,0x93a3,0x93a4,0x93a7,0x93a7,0x93ac,0x93ad,0x93b0,0x93b0,0x93bb,0x93bb,0x93c3,0x93c3,0x93c7,0x93c8,0x93ca,0x93cc,0x93d1,0x93d1,0x93d6,0x93d8,0x93dc,0x93df,0x93e1,0x93e2,0x93e4,0x93e4,0x93e6,0x93e6,0x93e8,0x93e8,0x93f6,0x93f6,0x93f8,0x93f9,0x93fb,0x93fb,0x9403,0x9404,0x940f,0x9410,0x9413,0x9414,0x9418,0x9419,0x9425,0x9425,0x942a,0x942b,0x9435,0x9436,0x9438,0x9438,0x943a,0x943a,0x9442,0x9442,0x9444,0x9444,0x944a,0x944a,0x944c,0x944c,0x9451,0x9452,0x9455,0x9455,0x945b,0x945b,0x945e,0x945e,0x9460,0x9460,0x9462,0x9463,0x946a,0x946b,0x9470,0x9472,0x9475,0x9475,0x9477,0x9477,0x947c,0x947f,0x9485,0x9485,0x9577,0x9578,0x957f,0x9580,0x9583,0x9583,0x9588,0x958b,0x958e,0x958f,0x9591,0x9594,0x9598,0x9598,0x959c,0x959c,0x959f,0x95a0,0x95a2,0x95a5,0x95a8,0x95a9,0x95ab,0x95ad,0x95b1,0x95b1,0x95b6,0x95b6,0x95b9,0x95b9,0x95bb,0x95be,0x95c3,0x95c3,0x95c7,0x95c8,0x95ca,0x95cd,0x95d3,0x95d6,0x95da,0x95da,0x95dc,0x95dc,0x95de,0x95de,0x95e0,0x95e2,0x95e5,0x95e5,0x95e8,0x95e8,0x961c,0x961d,0x9621,0x9621,0x9624,0x9624,0x9627,0x962a,0x962d,0x962f,0x9632,0x9632,0x963b,0x963b,0x963f,0x9640,0x9642,0x9642,0x9644,0x9644,0x964b,0x964d,0x9650,0x9650,0x9654,0x9654,0x9656,0x9656,0x9658,0x9658,0x965b,0x965f,0x9661,0x9664,0x966a,0x966a,0x966c,0x966c,0x9670,0x9670,0x9672,0x9679,0x967c,0x967d,0x9684,0x9686,0x968a,0x968b,0x968d,0x968f,0x9691,0x9691,0x9694,0x9695,0x9697,0x9698,0x969b,0x969c,0x96a3,0x96a4,0x96a7,0x96aa,0x96b0,0x96b1,0x96b3,0x96b4,0x96b6,0x96b9,0x96bb,0x96bc,0x96c0,0x96c1,0x96c4,0x96c7,0x96c9,0x96c9,0x96cb,0x96ce,0x96d5,0x96d6,0x96d9,0x96de,0x96e2,0x96e3,0x96e8,0x96ea,0x96ef,0x96f0,0x96f2,0x96f2,0x96f6,0x96f7,0x96f9,0x96fb,0x9700,0x9700,0x9704,0x9709,0x970c,0x970f,0x9711,0x9711,0x9713,0x9714,0x9716,0x9716,0x9719,0x9719,0x971c,0x971c,0x971e,0x971e,0x9723,0x9723,0x9726,0x9727,0x972a,0x972a,0x9730,0x9730,0x9732,0x9732,0x9738,0x9739,0x973d,0x973d,0x9742,0x9742,0x9744,0x9744,0x9746,0x9746,0x9748,0x9749,0x974c,0x974c,0x9751,0x9752,0x9755,0x9756,0x9758,0x975e,0x9760,0x9762,0x9766,0x9766,0x9768,0x9769,0x976d,0x976d,0x9773,0x9775,0x9777,0x9777,0x977a,0x977a,0x977c,0x977c,0x9780,0x9781,0x9784,0x9785,0x978b,0x978b,0x978d,0x978d,0x978f,0x978f,0x9798,0x9798,0x97a0,0x97a0,0x97a3,0x97a3,0x97a6,0x97a6,0x97a8,0x97a8,0x97ab,0x97ad,0x97b1,0x97b1,0x97b4,0x97b4,0x97b8,0x97b9,0x97c1,0x97c1,0x97c3,0x97c3,0x97c6,0x97c6,0x97cb,0x97cd,0x97d0,0x97d0,0x97d3,0x97d3,0x97d9,0x97d9,0x97dc,0x97de,0x97e0,0x97e1,0x97e6,0x97e6,0x97ed,0x97ee,0x97f1,0x97f3,0x97f5,0x97f6,0x97fa,0x97fb,0x97fe,0x9803,0x9805,0x9806,0x9808,0x9808,0x980a,0x980a,0x980c,0x9813,0x9816,0x9818,0x981e,0x981e,0x9821,0x9821,0x9823,0x9824,0x9826,0x9826,0x982b,0x982b,0x982d,0x982e,0x9830,0x9830,0x9832,0x9832,0x9837,0x9839,0x983b,0x983c,0x983f,0x983f,0x9842,0x9842,0x9846,0x9848,0x984b,0x984e,0x9852,0x9855,0x9858,0x985a,0x985c,0x985c,0x985e,0x985e,0x9865,0x9867,0x986b,0x986b,0x986f,0x9871,0x9873,0x9875,0x98a8,0x98a8,0x98ad,0x98ad,0x98af,0x98af,0x98b1,0x98b2,0x98b6,0x98b6,0x98ba,0x98ba,0x98bc,0x98bc,0x98bf,0x98bf,0x98c2,0x98c2,0x98c4,0x98c4,0x98c6,0x98c7,0x98c9,0x98c9,0x98cb,0x98cb,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e2,0x98e6,0x98e7,0x98ea,0x98eb,0x98ed,0x98ef,0x98f1,0x98f1,0x98f4,0x98f4,0x98fb,0x98fe,0x9903,0x9903,0x9909,0x990a,0x990c,0x990c,0x9910,0x9910,0x9912,0x9915,0x9918,0x9918,0x991a,0x991a,0x991e,0x991e,0x9920,0x9920,0x9926,0x9928,0x992a,0x992a,0x992c,0x992c,0x992e,0x992e,0x9930,0x9931,0x9933,0x9933,0x9939,0x9939,0x993c,0x993d,0x9942,0x9942,0x9945,0x9945,0x9948,0x9949,0x994b,0x994d,0x9950,0x9952,0x9954,0x9955,0x9957,0x9957,0x995c,0x995c,0x995e,0x995e,0x9963,0x9963,0x9996,0x9999,0x999c,0x999d,0x999f,0x999f,0x99a1,0x99a1,0x99a3,0x99a3,0x99a5,0x99a5,0x99a7,0x99a8,0x99aa,0x99aa,0x99ac,0x99ae,0x99b0,0x99b1,0x99b3,0x99b4,0x99b6,0x99b6,0x99b9,0x99b9,0x99c1,0x99c1,0x99c4,0x99c5,0x99c8,0x99c9,0x99cf,0x99d2,0x99d5,0x99d5,0x99d8,0x99d9,0x99db,0x99df,0x99e2,0x99e2,0x99e8,0x99e8,0x99ea,0x99ea,0x99ed,0x99ee,0x99f1,0x99f1,0x99f8,0x99f8,0x99fa,0x99fb,0x99fd,0x99fd,0x99ff,0x99ff,0x9a01,0x9a05,0x9a08,0x9a08,0x9a0b,0x9a0b,0x9a0d,0x9a0f,0x9a11,0x9a11,0x9a16,0x9a16,0x9a18,0x9a19,0x9a1b,0x9a1b,0x9a2b,0x9a2b,0x9a2d,0x9a2d,0x9a30,0x9a30,0x9a35,0x9a38,0x9a3e,0x9a3e,0x9a40,0x9a45,0x9a4a,0x9a4a,0x9a4c,0x9a4f,0x9a52,0x9a52,0x9a55,0x9a55,0x9a57,0x9a58,0x9a5a,0x9a5b,0x9a5f,0x9a5f,0x9a62,0x9a62,0x9a64,0x9a65,0x9a69,0x9a6a,0x9a6c,0x9a6c,0x9aa8,0x9aa8,0x9aaa,0x9aaa,0x9ab0,0x9ab0,0x9ab8,0x9ab9,0x9abc,0x9abc,0x9abf,0x9ac0,0x9ac6,0x9ac6,0x9acf,0x9acf,0x9ad1,0x9ad1,0x9ad3,0x9ad4,0x9ad6,0x9ad8,0x9adf,0x9adf,0x9ae1,0x9ae1,0x9ae3,0x9ae3,0x9ae5,0x9ae6,0x9aeb,0x9aeb,0x9aed,0x9aee,0x9af0,0x9af0,0x9af2,0x9af2,0x9af4,0x9af4,0x9af9,0x9afb,0x9afd,0x9afd,0x9b02,0x9b02,0x9b05,0x9b06,0x9b0a,0x9b0b,0x9b0d,0x9b0d,0x9b10,0x9b10,0x9b12,0x9b12,0x9b16,0x9b16,0x9b18,0x9b1a,0x9b1f,0x9b1f,0x9b22,0x9b23,0x9b25,0x9b25,0x9b27,0x9b2a,0x9b2e,0x9b2f,0x9b31,0x9b32,0x9b3a,0x9b3a,0x9b3c,0x9b3c,0x9b41,0x9b45,0x9b48,0x9b48,0x9b4b,0x9b4b,0x9b4d,0x9b4f,0x9b51,0x9b51,0x9b54,0x9b54,0x9b58,0x9b58,0x9b5a,0x9b5a,0x9b66,0x9b66,0x9b6f,0x9b6f,0x9b74,0x9b74,0x9b80,0x9b80,0x9b83,0x9b83,0x9b8e,0x9b8e,0x9b90,0x9b93,0x9b97,0x9b97,0x9b9f,0x9b9f,0x9ba7,0x9ba8,0x9baa,0x9bab,0x9bad,0x9bae,0x9bb9,0x9bb9,0x9bc1,0x9bc1,0x9bc6,0x9bc6,0x9bc9,0x9bca,0x9bd4,0x9bd4,0x9bd6,0x9bd6,0x9bdb,0x9bdb,0x9be2,0x9be2,0x9be4,0x9be4,0x9be8,0x9be8,0x9bf7,0x9bf7,0x9c08,0x9c08,0x9c0a,0x9c0a,0x9c0c,0x9c0d,0x9c10,0x9c10,0x9c12,0x9c13,0x9c15,0x9c15,0x9c24,0x9c25,0x9c2d,0x9c2f,0x9c31,0x9c32,0x9c35,0x9c35,0x9c39,0x9c3b,0x9c3e,0x9c3e,0x9c47,0x9c47,0x9c49,0x9c49,0x9c4f,0x9c4f,0x9c52,0x9c53,0x9c57,0x9c57,0x9c60,0x9c60,0x9c63,0x9c63,0x9c67,0x9c67,0x9c78,0x9c78,0x9c7b,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9ce9,0x9cf3,0x9cf4,0x9cf6,0x9cf6,0x9d03,0x9d03,0x9d06,0x9d09,0x9d0c,0x9d0c,0x9d12,0x9d12,0x9d15,0x9d15,0x9d18,0x9d19,0x9d1b,0x9d1b,0x9d1e,0x9d1f,0x9d23,0x9d23,0x9d25,0x9d26,0x9d28,0x9d28,0x9d2f,0x9d30,0x9d36,0x9d36,0x9d3b,0x9d3b,0x9d41,0x9d42,0x9d44,0x9d44,0x9d51,0x9d51,0x9d53,0x9d54,0x9d5d,0x9d5e,0x9d60,0x9d61,0x9d66,0x9d66,0x9d69,0x9d69,0x9d6c,0x9d6c,0x9d6f,0x9d70,0x9d72,0x9d72,0x9d77,0x9d77,0x9d7b,0x9d7b,0x9d7e,0x9d7e,0x9d84,0x9d84,0x9d89,0x9d8a,0x9d96,0x9d96,0x9d9a,0x9d9a,0x9da1,0x9da1,0x9da4,0x9da4,0x9da9,0x9da9,0x9dac,0x9dac,0x9daf,0x9daf,0x9db4,0x9db5,0x9db8,0x9db9,0x9dbb,0x9dbb,0x9dbf,0x9dbf,0x9dc1,0x9dc2,0x9dc4,0x9dc4,0x9dc7,0x9dc7,0x9dd3,0x9dd3,0x9dd6,0x9dd7,0x9dd9,0x9dd9,0x9de6,0x9de6,0x9de9,0x9deb,0x9df0,0x9df3,0x9df8,0x9dfa,0x9dfd,0x9dfd,0x9dff,0x9dff,0x9e07,0x9e07,0x9e0f,0x9e0f,0x9e15,0x9e15,0x9e1a,0x9e1f,0x9e75,0x9e75,0x9e77,0x9e77,0x9e79,0x9e7b,0x9e7d,0x9e7d,0x9e7f,0x9e80,0x9e82,0x9e82,0x9e84,0x9e84,0x9e8b,0x9e8c,0x9e8f,0x9e8f,0x9e91,0x9e93,0x9e97,0x9e98,0x9e9d,0x9e9f,0x9ea4,0x9ea6,0x9ea9,0x9eaa,0x9eaf,0x9eaf,0x9eb4,0x9eb5,0x9ebb,0x9ebb,0x9ebd,0x9ebf,0x9ec3,0x9ec5,0x9ecc,0x9ed1,0x9ed4,0x9ed4,0x9ed6,0x9ed6,0x9ed8,0x9ed8,0x9eda,0x9ede,0x9ee0,0x9ee0,0x9ee5,0x9ee5,0x9ee8,0x9ee8,0x9eee,0x9eef,0x9ef2,0x9ef2,0x9ef4,0x9ef7,0x9ef9,0x9f00,0x9f02,0x9f02,0x9f04,0x9f04,0x9f07,0x9f0a,0x9f0e,0x9f0e,0x9f10,0x9f10,0x9f13,0x9f14,0x9f17,0x9f17,0x9f19,0x9f19,0x9f20,0x9f20,0x9f22,0x9f22,0x9f2b,0x9f2c,0x9f2f,0x9f2f,0x9f34,0x9f34,0x9f38,0x9f39,0x9f3b,0x9f3b,0x9f3e,0x9f3e,0x9f4a,0x9f4b,0x9f4e,0x9f4e,0x9f50,0x9f50,0x9f52,0x9f52,0x9f54,0x9f55,0x9f57,0x9f57,0x9f5f,0x9f61,0x9f66,0x9f67,0x9f69,0x9f6c,0x9f72,0x9f72,0x9f76,0x9f77,0x9f7f,0x9f7f,0x9f8d,0x9f8e,0x9f90,0x9f92,0x9f94,0x9f95,0x9f99,0x9f99,0x9f9c,0x9f9d,0x9f9f,0x9fa0,0x9fa2,0x9fa2,0x9fa5,0x9fa5,0xa960,0xa97c,0xac00,0xd7a3,0xd7b0,0xd7c6,0xd7cb,0xd7fb,0xf900,0xf95e,0xf960,0xf9a9,0xf9ab,0xfa0b,0xfa12,0xfa12,0xfa15,0xfa17,0xfa19,0xfa1e,0xfa22,0xfa22,0xfa26,0xfa26,0xfa2a,0xfa2c,0xfa2e,0xfa31,0xfa33,0xfa3d,0xfa3f,0xfa3f,0xfa41,0xfa41,0xfa43,0xfa55,0xfa57,0xfa57,0xfa59,0xfa68,0xfa6a,0xfa6a,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x200d7,0x200d7,0x2012c,0x2012c,0x205ca,0x205ca,0x20628,0x20628,0x20984,0x20984,0x21155,0x21155,0x2128d,0x2128d,0x21594,0x21594,0x21727,0x21727,0x21f5c,0x21f5c,0x224b0,0x224b0,0x224ed,0x224ed,0x2294f,0x2294f,0x22c6f,0x22c6f,0x22ee0,0x22ee0,0x230fd,0x230fd,0x23343,0x23343,0x2363b,0x2363b,0x23ad9,0x23ad9,0x242f1,0x242f1,0x2439d,0x2439d,0x248e9,0x248e9,0x248f0,0x248f0,0x24a01,0x24a01,0x24a12,0x24a12,0x25055,0x25055,0x2533e,0x2533e,0x253b5,0x253b5,0x253fe,0x253fe,0x25832,0x25832,0x2583a,0x2583a,0x25874,0x25874,0x25978,0x25978,0x25ad7,0x25ad7,0x25b97,0x25b97,0x25e44,0x25e44,0x26057,0x26057,0x265a4,0x265a4,0x267d8,0x267d8,0x26951,0x26951,0x27144,0x27144,0x275ff,0x275ff,0x27625,0x27625,0x278b2,0x278b2,0x27a51,0x27a51,0x27b02,0x27b02,0x27cef,0x27cef,0x27e7d,0x27e7d,0x27f1b,0x27f1b,0x27fb7,0x27fb7,0x283f6,0x283f6,0x284dc,0x284dc,0x28d8a,0x28d8a,0x28da1,0x28da1,0x28e0f,0x28e0f,0x291d5,0x291d5,0x291e3,0x291e3,0x294de,0x294de,0x29509,0x29509,0x2967f,0x2967f,0x29810,0x29810,0x2983b,0x2983b,0x2a2ad,0x2a2ad,0x2a4d0,0x2a4d0,0x2a664,0x2a664,0x2c115,0x2c115,0x2c7d3,0x2c7d3,0x2d544,0x2d544,0x2e569,0x2e569,0x2f815,0x2f815,0x2f818,0x2f818,0x2f81a,0x2f81a,0x2f82c,0x2f82c,0x2f833,0x2f833,0x2f852,0x2f852,0x2f862,0x2f862,0x2f877,0x2f877,0x2f884,0x2f884,0x2f8b2,0x2f8b2,0x2f8ed,0x2f8ed,0x2f8fc,0x2f8fc,0x2f920,0x2f920,0x2f96c,0x2f96c,0x2f9d0,0x2f9d0,0x2f9df,0x2f9df,0x30729,0x30729,0x30ede,0x30ede,]), - NotoFont.fromFlatRanges('Noto Sans Kaithi', 'http://fonts.gstatic.com/s/notosanskaithi/v15/buEtppS9f8_vkXadMBJJu0tWjLwjQi0KdoZIKlo.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x966,0x96f,0x200b,0x200d,0x2010,0x2010,0x25cc,0x25cc,0xa830,0xa839,0x11080,0x110c1,0x110cd,0x110cd,]), - NotoFont.fromFlatRanges('Noto Sans Kannada', 'http://fonts.gstatic.com/s/notosanskannada/v21/8vIs7xs32H97qzQKnzfeXycxXZyUmySvZWItmf1fe6TVmgop9ndpS-BqHEyGrDvNzSIMLsPKrkY.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xc80,0xc8c,0xc8e,0xc90,0xc92,0xca8,0xcaa,0xcb3,0xcb5,0xcb9,0xcbc,0xcc4,0xcc6,0xcc8,0xcca,0xccd,0xcd5,0xcd6,0xcde,0xcde,0xce0,0xce3,0xce6,0xcef,0xcf1,0xcf2,0x1cd0,0x1cd0,0x1cd2,0x1cd2,0x1cda,0x1cda,0x1cf2,0x1cf2,0x1cf4,0x1cf5,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa835,]), - NotoFont.fromFlatRanges('Noto Sans Kayah Li', 'http://fonts.gstatic.com/s/notosanskayahli/v18/B50nF61OpWTRcGrhOVJJwOMXdca6Yecki3E06x2jVTX3WCc3CZH4EXLuKVM.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x200c,0x200d,0x2010,0x2010,0x25cc,0x25cc,0xa900,0xa92f,]), - NotoFont.fromFlatRanges('Noto Sans Kharoshthi', 'http://fonts.gstatic.com/s/notosanskharoshthi/v15/Fh4qPiLjKS30-P4-pGMMXCCfvkc5Vd7KE5z4rFyx5mR1.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x200b,0x200d,0x2010,0x2010,0x25cc,0x25cc,0x10a00,0x10a03,0x10a05,0x10a06,0x10a0c,0x10a13,0x10a15,0x10a17,0x10a19,0x10a35,0x10a38,0x10a3a,0x10a3f,0x10a48,0x10a50,0x10a58,]), - NotoFont.fromFlatRanges('Noto Sans Khmer', 'http://fonts.gstatic.com/s/notosanskhmer/v18/ijw3s5roRME5LLRxjsRb-gssOenAyendxrgV2c-Zw-9vbVUti_Z_dWgtWYuNAJz4kAbrddiA.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1780,0x17dd,0x17e0,0x17e9,0x17f0,0x17f9,0x19e0,0x19ff,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Khojki', 'http://fonts.gstatic.com/s/notosanskhojki/v15/-nFnOHM29Oofr2wohFbTuPPKVWpmK_d709jy92k.ttf', [0x20,0x20,0xa0,0xa0,0xae6,0xaef,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11200,0x11211,0x11213,0x1123e,]), - NotoFont.fromFlatRanges('Noto Sans Khudawadi', 'http://fonts.gstatic.com/s/notosanskhudawadi/v15/fdNi9t6ZsWBZ2k5ltHN73zZ5hc8HANlHIjRnVVXz9MY.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x965,0x200c,0x200d,0x2013,0x2014,0x25cc,0x25cc,0xa830,0xa839,0x112b0,0x112ea,0x112f0,0x112f9,]), - NotoFont.fromFlatRanges('Noto Sans Lao', 'http://fonts.gstatic.com/s/notosanslao/v24/bx6lNx2Ol_ixgdYWLm9BwxM3NW6BOkuf763Clj73CiQ_J1Djx9pidOt4ccbdf5MK3riB2w.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0xe81,0xe82,0xe84,0xe84,0xe87,0xe88,0xe8a,0xe8a,0xe8d,0xe8d,0xe94,0xe97,0xe99,0xe9f,0xea1,0xea3,0xea5,0xea5,0xea7,0xea7,0xeaa,0xeab,0xead,0xeb9,0xebb,0xebd,0xec0,0xec4,0xec6,0xec6,0xec8,0xecd,0xed0,0xed9,0xedc,0xedf,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ad,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Lepcha', 'http://fonts.gstatic.com/s/notosanslepcha/v15/0QI7MWlB_JWgA166SKhu05TekNS32AJstqBXgd4.ttf', [0x20,0x20,0xa0,0xa0,0x1c00,0x1c37,0x1c3b,0x1c49,0x1c4d,0x1c4f,0x200b,0x200d,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Limbu', 'http://fonts.gstatic.com/s/notosanslimbu/v15/3JnlSDv90Gmq2mrzckOBBRRoNJVj0MF3OHRDnA.ttf', [0x20,0x20,0xa0,0xa0,0x965,0x965,0x1900,0x191e,0x1920,0x192b,0x1930,0x193b,0x1940,0x1940,0x1944,0x194f,0x200b,0x200d,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Linear A', 'http://fonts.gstatic.com/s/notosanslineara/v16/oPWS_l16kP4jCuhpgEGmwJOiA18FZj22zmHQAGQicw.ttf', [0x20,0x20,0xa0,0xa0,0x10600,0x10736,0x10740,0x10755,0x10760,0x10767,]), - NotoFont.fromFlatRanges('Noto Sans Linear B', 'http://fonts.gstatic.com/s/notosanslinearb/v15/HhyJU4wt9vSgfHoORYOiXOckKNB737IV3BkFTq4EPw.ttf', [0x20,0x20,0xa0,0xa0,0x10000,0x1000b,0x1000d,0x10026,0x10028,0x1003a,0x1003c,0x1003d,0x1003f,0x1004d,0x10050,0x1005d,0x10080,0x100fa,0x10100,0x10102,0x10107,0x10133,0x10137,0x1013f,]), - NotoFont.fromFlatRanges('Noto Sans Lisu', 'http://fonts.gstatic.com/s/notosanslisu/v21/uk-3EGO3o6EruUbnwovcYhz6kh57_nqbcTdjJnHP2Vwt29IlxkVdig.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2cd,0x2cd,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0x300a,0x300b,0xa4d0,0xa4ff,0x11fb0,0x11fb0,]), - NotoFont.fromFlatRanges('Noto Sans Lycian', 'http://fonts.gstatic.com/s/notosanslycian/v15/QldVNSNMqAsHtsJ7UmqxBQA9r8wA5_naCJwn00E.ttf', [0x20,0x20,0xa0,0xa0,0x10280,0x1029c,]), - NotoFont.fromFlatRanges('Noto Sans Lydian', 'http://fonts.gstatic.com/s/notosanslydian/v15/c4m71mVzGN7s8FmIukZJ1v4ZlcPReUPXMoIjEQI.ttf', [0x20,0x20,0xa0,0xa0,0x10920,0x10939,0x1093f,0x1093f,]), - NotoFont.fromFlatRanges('Noto Sans Mahajani', 'http://fonts.gstatic.com/s/notosansmahajani/v15/-F6sfiVqLzI2JPCgQBnw60Agp0JrvD5Fh8ARHNh4zg.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x96f,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11150,0x11176,]), - NotoFont.fromFlatRanges('Noto Sans Malayalam', 'http://fonts.gstatic.com/s/notosansmalayalam/v21/sJoi3K5XjsSdcnzn071rL37lpAOsUThnDZIfPdbeSNzVakglNM-Qw8EaeB8Nss-_RuD9BFzEr6HxEA.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x323,0x323,0x326,0x328,0x951,0x952,0x964,0x965,0xd00,0xd0c,0xd0e,0xd10,0xd12,0xd44,0xd46,0xd48,0xd4a,0xd4f,0xd54,0xd63,0xd66,0xd7f,0x1cda,0x1cda,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa832,]), - NotoFont.fromFlatRanges('Noto Sans Mandaic', 'http://fonts.gstatic.com/s/notosansmandaic/v15/cIfnMbdWt1w_HgCcilqhKQBo_OsMI5_A_gMk0izH.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x840,0x85b,0x85e,0x85e,0x200c,0x200d,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Manichaean', 'http://fonts.gstatic.com/s/notosansmanichaean/v15/taiVGntiC4--qtsfi4Jp9-_GkPZZCcrfekqCNTtFCtdX.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x200c,0x200d,0x25cc,0x25cc,0xfe00,0xfe00,0x10ac0,0x10ae6,0x10aeb,0x10af6,]), - NotoFont.fromFlatRanges('Noto Sans Marchen', 'http://fonts.gstatic.com/s/notosansmarchen/v15/aFTO7OZ_Y282EP-WyG6QTOX_C8WZMHhPk652ZaHk.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x11c70,0x11c8f,0x11c92,0x11ca7,0x11ca9,0x11cb6,]), - NotoFont.fromFlatRanges('Noto Sans Masaram Gondi', 'http://fonts.gstatic.com/s/notosansmasaramgondi/v15/6xK_dThFKcWIu4bpRBjRYRV7KZCbUq6n_1kPnuGe7RI9WSWX.ttf', [0x20,0x22,0x25,0x25,0x27,0x2f,0x3a,0x3f,0xa0,0xa0,0xd7,0xd7,0xf7,0xf7,0x964,0x965,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x2212,0x2212,0x25cc,0x25cc,0x11d00,0x11d06,0x11d08,0x11d09,0x11d0b,0x11d36,0x11d3a,0x11d3a,0x11d3c,0x11d3d,0x11d3f,0x11d47,0x11d50,0x11d59,]), - NotoFont.fromFlatRanges('Noto Sans Math', 'http://fonts.gstatic.com/s/notosansmath/v15/7Aump_cpkSecTWaHRlH2hyV5UHkG-V048PW0.ttf', [0x20,0x7e,0xa0,0xa0,0xa7,0xa7,0xac,0xac,0xb1,0xb1,0xd7,0xd7,0xf7,0xf7,0x302,0x303,0x305,0x305,0x307,0x308,0x330,0x330,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x3d1,0x3d1,0x3d5,0x3d6,0x3f0,0x3f1,0x3f4,0x3f5,0x2032,0x2037,0x2057,0x2057,0x20d0,0x20dc,0x20e1,0x20e1,0x20e5,0x20ef,0x2102,0x2102,0x210a,0x210e,0x2110,0x2112,0x2115,0x2115,0x2119,0x211d,0x2124,0x2124,0x2128,0x2128,0x212c,0x212d,0x212f,0x2131,0x2133,0x2138,0x213c,0x2140,0x2145,0x2149,0x2190,0x21ae,0x21b0,0x21e5,0x21f1,0x21f2,0x21f4,0x22ff,0x2308,0x230b,0x2310,0x2310,0x2319,0x2319,0x231c,0x2321,0x2336,0x237a,0x237c,0x237c,0x2395,0x2395,0x239b,0x23b6,0x23d0,0x23d0,0x23dc,0x23e1,0x2474,0x2475,0x25af,0x25af,0x25b3,0x25b3,0x25b7,0x25b7,0x25bd,0x25bd,0x25c1,0x25c1,0x25ca,0x25ca,0x25cc,0x25cc,0x25fb,0x25fb,0x266d,0x266f,0x27c0,0x27ff,0x2900,0x2aff,0x2b0e,0x2b11,0x2b30,0x2b4c,0x2bfe,0x2bfe,0xff5b,0xff5b,0xff5d,0xff5d,0x1d400,0x1d454,0x1d456,0x1d49c,0x1d49e,0x1d49f,0x1d4a2,0x1d4a2,0x1d4a5,0x1d4a6,0x1d4a9,0x1d4ac,0x1d4ae,0x1d4b9,0x1d4bb,0x1d4bb,0x1d4bd,0x1d4c3,0x1d4c5,0x1d505,0x1d507,0x1d50a,0x1d50d,0x1d514,0x1d516,0x1d51c,0x1d51e,0x1d539,0x1d53b,0x1d53e,0x1d540,0x1d544,0x1d546,0x1d546,0x1d54a,0x1d550,0x1d552,0x1d6a5,0x1d6a8,0x1d7cb,0x1d7ce,0x1d7ff,0x1ee00,0x1ee03,0x1ee05,0x1ee1f,0x1ee21,0x1ee22,0x1ee24,0x1ee24,0x1ee27,0x1ee27,0x1ee29,0x1ee32,0x1ee34,0x1ee37,0x1ee39,0x1ee39,0x1ee3b,0x1ee3b,0x1ee42,0x1ee42,0x1ee47,0x1ee47,0x1ee49,0x1ee49,0x1ee4b,0x1ee4b,0x1ee4d,0x1ee4f,0x1ee51,0x1ee52,0x1ee54,0x1ee54,0x1ee57,0x1ee57,0x1ee59,0x1ee59,0x1ee5b,0x1ee5b,0x1ee5d,0x1ee5d,0x1ee5f,0x1ee5f,0x1ee61,0x1ee62,0x1ee64,0x1ee64,0x1ee67,0x1ee6a,0x1ee6c,0x1ee72,0x1ee74,0x1ee77,0x1ee79,0x1ee7c,0x1ee7e,0x1ee7e,0x1ee80,0x1ee89,0x1ee8b,0x1ee9b,0x1eea1,0x1eea3,0x1eea5,0x1eea9,0x1eeab,0x1eebb,0x1eef0,0x1eef1,]), - NotoFont.fromFlatRanges('Noto Sans Mayan Numerals', 'http://fonts.gstatic.com/s/notosansmayannumerals/v15/PlIuFk25O6RzLfvNNVSivR09_KqYMwvvDKYjfIiE68oo6eepYQ.ttf', [0x20,0x20,0xa0,0xa0,0x1d2e0,0x1d2f3,]), - NotoFont.fromFlatRanges('Noto Sans Medefaidrin', 'http://fonts.gstatic.com/s/notosansmedefaidrin/v19/WwkzxOq6Dk-wranENynkfeVsNbRZtbOIdLb1exeM4ZeuabBfmErWlT318e5A3rw.ttf', [0x20,0x20,0xa0,0xa0,0x16e40,0x16e9a,]), - NotoFont.fromFlatRanges('Noto Sans Meetei Mayek', 'http://fonts.gstatic.com/s/notosansmeeteimayek/v10/HTxAL3QyKieByqY9eZPFweO0be7M21uSphSdhqILnmrRfJ8t_1TJ_vTW5PgeFYVa.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xaae0,0xaaf6,0xabc0,0xabed,0xabf0,0xabf9,]), - NotoFont.fromFlatRanges('Noto Sans Meroitic', 'http://fonts.gstatic.com/s/notosansmeroitic/v16/IFS5HfRJndhE3P4b5jnZ3ITPvC6i00UDgDhTiKY9KQ.ttf', [0x20,0x20,0x3a,0x3a,0xa0,0xa0,0x2026,0x2026,0x205d,0x205d,0x10980,0x109b7,0x109bc,0x109cf,0x109d2,0x109ff,]), - NotoFont.fromFlatRanges('Noto Sans Miao', 'http://fonts.gstatic.com/s/notosansmiao/v15/Dxxz8jmXMW75w3OmoDXVV4zyZUjgUYVslLhx.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x16f00,0x16f4a,0x16f4f,0x16f87,0x16f8f,0x16f9f,]), - NotoFont.fromFlatRanges('Noto Sans Modi', 'http://fonts.gstatic.com/s/notosansmodi/v15/pe03MIySN5pO62Z5YkFyT7jeav5qWVAgVol-.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11600,0x11644,0x11650,0x11659,]), - NotoFont.fromFlatRanges('Noto Sans Mongolian', 'http://fonts.gstatic.com/s/notosansmongolian/v15/VdGCAYADGIwE0EopZx8xQfHlgEAMsrToxLsg6-av1x0.ttf', [0x20,0x22,0x28,0x29,0x2d,0x2d,0x3f,0x3f,0xa0,0xa0,0x1800,0x180e,0x1810,0x1819,0x1820,0x1878,0x1880,0x18aa,0x200c,0x200d,0x2013,0x2014,0x201c,0x201d,0x202f,0x202f,0x2048,0x2049,0x2460,0x2473,0x25cc,0x25cc,0x3001,0x3002,0x300a,0x300f,0xfe3d,0xfe3e,0xfe41,0xfe44,0x11660,0x1166c,]), - NotoFont.fromFlatRanges('Noto Sans Mro', 'http://fonts.gstatic.com/s/notosansmro/v15/qWcsB6--pZv9TqnUQMhe9b39WDzRtjkho4M.ttf', [0x20,0x20,0xa0,0xa0,0x16a40,0x16a5e,0x16a60,0x16a69,0x16a6e,0x16a6f,]), - NotoFont.fromFlatRanges('Noto Sans Multani', 'http://fonts.gstatic.com/s/notosansmultani/v15/9Bty3ClF38_RfOpe1gCaZ8p30BOFO1A0pfCs5Kos.ttf', [0x20,0x20,0xa0,0xa0,0xa66,0xa6f,0x11280,0x11286,0x11288,0x11288,0x1128a,0x1128d,0x1128f,0x1129d,0x1129f,0x112a9,]), - NotoFont.fromFlatRanges('Noto Sans Myanmar', 'http://fonts.gstatic.com/s/notosansmyanmar/v19/AlZq_y1ZtY3ymOryg38hOCSdOnFq0En23OU4o1AC.ttf', [0x20,0x20,0x3f,0x3f,0xa0,0xa0,0x1000,0x109f,0x200b,0x200d,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x25cc,0x25cc,0xa92e,0xa92e,0xa9e0,0xa9fe,0xaa60,0xaa7f,0xfe00,0xfe00,]), - NotoFont.fromFlatRanges('Noto Sans N Ko', 'http://fonts.gstatic.com/s/notosansnko/v17/6NUP8FqDKBaKKjnr6P8v-sxPpvVBVNmme3gf.ttf', [0x20,0x20,0xa0,0xa0,0x60c,0x60c,0x61b,0x61b,0x61f,0x61f,0x66a,0x66a,0x7c0,0x7fa,0x7fd,0x7ff,0x200c,0x200f,0x25cc,0x25cc,0x2e1c,0x2e1d,0xfd3e,0xfd3f,]), - NotoFont.fromFlatRanges('Noto Sans Nabataean', 'http://fonts.gstatic.com/s/notosansnabataean/v15/IFS4HfVJndhE3P4b5jnZ34DfsjO330dNoBJ9hK8kMK4.ttf', [0x20,0x20,0xa0,0xa0,0x10880,0x1089e,0x108a7,0x108af,]), - NotoFont.fromFlatRanges('Noto Sans New Tai Lue', 'http://fonts.gstatic.com/s/notosansnewtailue/v15/H4c5BW-Pl9DZ0Xe_nHUapt7PovLXAhAnY7wwY55O4AS32A.ttf', [0x20,0x20,0xa0,0xa0,0x1980,0x19ab,0x19b0,0x19c9,0x19d0,0x19da,0x19de,0x19df,0x200c,0x200d,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Newa', 'http://fonts.gstatic.com/s/notosansnewa/v15/7r3fqXp6utEsO9pI4f8ok8sWg8n_qN4R5lNU.ttf', [0x20,0x20,0xa0,0xa0,0xb7,0xb7,0x1dfb,0x1dfb,0x200c,0x200d,0x25cc,0x25cc,0x11400,0x1145b,0x1145d,0x11461,]), - NotoFont.fromFlatRanges('Noto Sans Nushu', 'http://fonts.gstatic.com/s/notosansnushu/v18/rnCw-xRQ3B7652emAbAe_Ai1IYaFWFAMArZKqQ.ttf', [0x20,0x20,0xa0,0xa0,0x16fe1,0x16fe1,0x1b170,0x1b2fb,]), - NotoFont.fromFlatRanges('Noto Sans Ogham', 'http://fonts.gstatic.com/s/notosansogham/v15/kmKlZqk1GBDGN0mY6k5lmEmww4hrt5laQxcoCA.ttf', [0x20,0x20,0xa0,0xa0,0x1680,0x169c,]), - NotoFont.fromFlatRanges('Noto Sans Ol Chiki', 'http://fonts.gstatic.com/s/notosansolchiki/v17/N0b92TJNOPt-eHmFZCdQbrL32r-4CvhzDzRwlxOQYuVALWk267I6gVrz5gQ.ttf', [0x20,0x20,0xa0,0xa0,0x1c50,0x1c7f,0x20b9,0x20b9,]), - NotoFont.fromFlatRanges('Noto Sans Old Hungarian', 'http://fonts.gstatic.com/s/notosansoldhungarian/v15/E213_cD6hP3GwCJPEUssHEM0KqLaHJXg2PiIgRfjbg5nCYXt.ttf', [0x20,0x20,0xa0,0xa0,0x200d,0x200d,0x10c80,0x10cb2,0x10cc0,0x10cf2,0x10cfa,0x10cff,]), - NotoFont.fromFlatRanges('Noto Sans Old Italic', 'http://fonts.gstatic.com/s/notosansolditalic/v15/TuGOUUFzXI5FBtUq5a8bh68BJxxEVam7tWlRdRhtCC4d.ttf', [0x20,0x20,0xa0,0xa0,0x10300,0x10323,0x1032d,0x1032f,]), - NotoFont.fromFlatRanges('Noto Sans Old North Arabian', 'http://fonts.gstatic.com/s/notosansoldnortharabian/v15/esDF30BdNv-KYGGJpKGk2tNiMt7Jar6olZDyNdr81zBQmUo_xw4ABw.ttf', [0x20,0x20,0xa0,0xa0,0x10a80,0x10a9f,]), - NotoFont.fromFlatRanges('Noto Sans Old Permic', 'http://fonts.gstatic.com/s/notosansoldpermic/v16/snf1s1q1-dF8pli1TesqcbUY4Mr-ElrwKLdXgv_dKYB5.ttf', [0x20,0x20,0xa0,0xa0,0x300,0x300,0x306,0x308,0x313,0x313,0x483,0x483,0x20db,0x20db,0x25cc,0x25cc,0x10350,0x1037a,]), - NotoFont.fromFlatRanges('Noto Sans Old Persian', 'http://fonts.gstatic.com/s/notosansoldpersian/v15/wEOjEAbNnc5caQTFG18FHrZr9Bp6-8CmIJ_tqOlQfx9CjA.ttf', [0x20,0x20,0xa0,0xa0,0x103a0,0x103c3,0x103c8,0x103d5,]), - NotoFont.fromFlatRanges('Noto Sans Old Sogdian', 'http://fonts.gstatic.com/s/notosansoldsogdian/v15/3JnjSCH90Gmq2mrzckOBBhFhdrMst48aURt7neIqM-9uyg.ttf', [0x20,0x20,0xa0,0xa0,0x10f00,0x10f27,]), - NotoFont.fromFlatRanges('Noto Sans Old South Arabian', 'http://fonts.gstatic.com/s/notosansoldsoutharabian/v15/3qT5oiOhnSyU8TNFIdhZTice3hB_HWKsEnF--0XCHiKx1OtDT9HwTA.ttf', [0x20,0x20,0xa0,0xa0,0x10a60,0x10a7f,]), - NotoFont.fromFlatRanges('Noto Sans Old Turkic', 'http://fonts.gstatic.com/s/notosansoldturkic/v15/yMJNMJVya43H0SUF_WmcGEQVqoEMKDKbsE2RjEw-Vyws.ttf', [0x20,0x20,0xa0,0xa0,0x10c00,0x10c48,]), - NotoFont.fromFlatRanges('Noto Sans Oriya', 'http://fonts.gstatic.com/s/notosansoriya/v16/AYCTpXfzfccDCstK_hrjDyADv5en5K3DZq1hIg.ttf', [0x20,0x23,0x25,0x25,0x27,0x2c,0x2e,0x3f,0x5b,0x5f,0x7b,0x7e,0xa0,0xa0,0xad,0xad,0xd7,0xd7,0xf7,0xf7,0x964,0x965,0xb01,0xb03,0xb05,0xb0c,0xb0f,0xb10,0xb13,0xb28,0xb2a,0xb30,0xb32,0xb33,0xb35,0xb39,0xb3c,0xb44,0xb47,0xb48,0xb4b,0xb4d,0xb56,0xb57,0xb5c,0xb5d,0xb5f,0xb63,0xb66,0xb77,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x20b9,0x20b9,0x2212,0x2212,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Osage', 'http://fonts.gstatic.com/s/notosansosage/v15/oPWX_kB6kP4jCuhpgEGmw4mtAVtXRlaSxkrMCQ.ttf', [0x20,0x20,0xa0,0xa0,0x301,0x301,0x304,0x304,0x30b,0x30b,0x358,0x358,0x25cc,0x25cc,0x104b0,0x104d3,0x104d8,0x104fb,]), - NotoFont.fromFlatRanges('Noto Sans Osmanya', 'http://fonts.gstatic.com/s/notosansosmanya/v15/8vIS7xs32H97qzQKnzfeWzUyUpOJmz6kR47NCV5Z.ttf', [0x20,0x20,0xa0,0xa0,0x10480,0x1049d,0x104a0,0x104a9,]), - NotoFont.fromFlatRanges('Noto Sans Pahawh Hmong', 'http://fonts.gstatic.com/s/notosanspahawhhmong/v15/bWtp7e_KfBziStx7lIzKKaMUOBEA3UPQDW7krzc_c48aMpM.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x16b00,0x16b45,0x16b50,0x16b59,0x16b5b,0x16b61,0x16b63,0x16b77,0x16b7d,0x16b8f,]), - NotoFont.fromFlatRanges('Noto Sans Palmyrene', 'http://fonts.gstatic.com/s/notosanspalmyrene/v15/ZgNPjOdKPa7CHqq0h37c_ASCWvH93SFCPnK5ZpdNtcA.ttf', [0x20,0x20,0xa0,0xa0,0x10860,0x1087f,]), - NotoFont.fromFlatRanges('Noto Sans Pau Cin Hau', 'http://fonts.gstatic.com/s/notosanspaucinhau/v16/x3d-cl3IZKmUqiMg_9wBLLtzl22EayN7ehIdjEWqKMxsKw.ttf', [0x20,0x20,0xa0,0xa0,0x11ac0,0x11af8,]), - NotoFont.fromFlatRanges('Noto Sans Phags Pa', 'http://fonts.gstatic.com/s/notosansphagspa/v15/pxiZyoo6v8ZYyWh5WuPeJzMkd4SrGChkqkSsrvNXiA.ttf', [0x20,0x20,0xa0,0xa0,0x1801,0x1803,0x1805,0x1805,0x200b,0x200f,0x2025,0x2026,0x25cc,0x25cc,0x3001,0x3002,0x3007,0x3011,0x3014,0x301b,0xa840,0xa877,0xfe00,0xfe00,]), - NotoFont.fromFlatRanges('Noto Sans Phoenician', 'http://fonts.gstatic.com/s/notosansphoenician/v15/jizFRF9Ksm4Bt9PvcTaEkIHiTVtxmFtS5X7Jot-p5561.ttf', [0x20,0x20,0xa0,0xa0,0x10900,0x1091b,0x1091f,0x1091f,]), - NotoFont.fromFlatRanges('Noto Sans Psalter Pahlavi', 'http://fonts.gstatic.com/s/notosanspsalterpahlavi/v15/rP2Vp3K65FkAtHfwd-eISGznYihzggmsicPfud3w1G3KsUQBct4.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x200c,0x200d,0x25cc,0x25cc,0x10b80,0x10b91,0x10b99,0x10b9c,0x10ba9,0x10baf,]), - NotoFont.fromFlatRanges('Noto Sans Rejang', 'http://fonts.gstatic.com/s/notosansrejang/v15/Ktk2AKuMeZjqPnXgyqrib7DIogqwN4O3WYZB_sU.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa930,0xa953,0xa95f,0xa95f,]), - NotoFont.fromFlatRanges('Noto Sans Runic', 'http://fonts.gstatic.com/s/notosansrunic/v15/H4c_BXWPl9DZ0Xe_nHUaus7W68WWaxpvHtgIYg.ttf', [0x20,0x20,0xa0,0xa0,0x16a0,0x16f8,]), - NotoFont.fromFlatRanges('Noto Sans SC', 'http://fonts.gstatic.com/s/notosanssc/v26/k3kXo84MPvpLmixcA63oeALhL4iJ-Q7m8w.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x4db5,0x4e00,0x9fef,0xf900,0xf903,0xf905,0xf906,0xf90b,0xf90c,0xf915,0xf915,0xf917,0xf91a,0xf921,0xf921,0xf92c,0xf92d,0xf92f,0xf92f,0xf931,0xf935,0xf937,0xf93a,0xf943,0xf943,0xf947,0xf94a,0xf94e,0xf94e,0xf952,0xf953,0xf95e,0xf95e,0xf962,0xf967,0xf96e,0xf96e,0xf972,0xf972,0xf974,0xf974,0xf976,0xf976,0xf979,0xf97b,0xf97e,0xf980,0xf984,0xf985,0xf98a,0xf98c,0xf98e,0xf98e,0xf993,0xf993,0xf995,0xf995,0xf998,0xf998,0xf9ae,0xf9ae,0xf9b3,0xf9b3,0xf9b7,0xf9b7,0xf9bb,0xf9bb,0xf9bd,0xf9be,0xf9c0,0xf9c0,0xf9c5,0xf9c6,0xf9d0,0xf9d0,0xf9d8,0xf9d9,0xf9dc,0xf9e0,0xf9e2,0xf9e4,0xf9e7,0xf9e7,0xf9e9,0xf9e9,0xf9f1,0xf9f1,0xf9f4,0xf9f5,0xf9fa,0xf9fa,0xf9fd,0xf9fd,0xf9ff,0xf9ff,0xfa02,0xfa02,0xfa05,0xfa08,0xfa0a,0xfa0a,0xfa0c,0xfa0f,0xfa11,0xfa11,0xfa13,0xfa14,0xfa18,0xfa18,0xfa1f,0xfa21,0xfa23,0xfa24,0xfa27,0xfa29,0xfa2f,0xfa2f,0xfa33,0xfa35,0xfa37,0xfa38,0xfa3a,0xfa3a,0xfa47,0xfa47,0xfa49,0xfa49,0xfa4b,0xfa4b,0xfa5d,0xfa5e,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x20087,0x20087,0x20089,0x20089,0x200cc,0x200cc,0x20164,0x20164,0x20628,0x20628,0x20676,0x20676,0x20cd0,0x20cd0,0x2139a,0x2139a,0x21413,0x21413,0x215d7,0x215d7,0x2298f,0x2298f,0x235cb,0x235cb,0x23c97,0x23c98,0x23e23,0x23e23,0x241fe,0x241fe,0x2420e,0x2420e,0x248e9,0x248e9,0x249db,0x249db,0x24a01,0x24a01,0x24a7d,0x24a7d,0x24ac9,0x24ac9,0x25532,0x25532,0x25562,0x25562,0x255a8,0x255a8,0x25ad7,0x25ad7,0x25ed7,0x25ed7,0x26221,0x26221,0x2648d,0x2648d,0x26676,0x26676,0x2677c,0x2677c,0x26951,0x26951,0x26b5c,0x26b5c,0x26c21,0x26c21,0x278b2,0x278b2,0x27eaf,0x27eaf,0x27fb7,0x27fb7,0x27ff9,0x27ff9,0x28408,0x28408,0x28678,0x28678,0x28695,0x28695,0x287e0,0x287e0,0x28b49,0x28b49,0x28c47,0x28c47,0x28c4f,0x28c4f,0x28c51,0x28c51,0x28c54,0x28c54,0x28e0f,0x28e0f,0x28e99,0x28e99,0x2967f,0x2967f,0x29810,0x29810,0x29f7e,0x29f7e,0x29f83,0x29f83,0x29f8c,0x29f8c,0x2a7dd,0x2a7dd,0x2a8fb,0x2a8fb,0x2a917,0x2a917,0x2aa30,0x2aa30,0x2aa36,0x2aa36,0x2aa58,0x2aa58,0x2afa2,0x2afa2,0x2b127,0x2b128,0x2b137,0x2b138,0x2b1ed,0x2b1ed,0x2b300,0x2b300,0x2b363,0x2b363,0x2b36f,0x2b36f,0x2b372,0x2b372,0x2b37d,0x2b37d,0x2b404,0x2b404,0x2b410,0x2b410,0x2b413,0x2b413,0x2b461,0x2b461,0x2b4e7,0x2b4e7,0x2b4ef,0x2b4ef,0x2b4f6,0x2b4f6,0x2b4f9,0x2b4f9,0x2b50d,0x2b50e,0x2b536,0x2b536,0x2b5ae,0x2b5af,0x2b5b3,0x2b5b3,0x2b5e7,0x2b5e7,0x2b5f4,0x2b5f4,0x2b61c,0x2b61d,0x2b626,0x2b628,0x2b62a,0x2b62a,0x2b62c,0x2b62c,0x2b695,0x2b696,0x2b6ad,0x2b6ad,0x2b6ed,0x2b6ed,0x2b7a9,0x2b7a9,0x2b7c5,0x2b7c5,0x2b7e6,0x2b7e6,0x2b7f9,0x2b7f9,0x2b7fc,0x2b7fc,0x2b806,0x2b806,0x2b80a,0x2b80a,0x2b81c,0x2b81c,0x2b8b8,0x2b8b8,0x2bac7,0x2bac7,0x2bb5f,0x2bb5f,0x2bb62,0x2bb62,0x2bb7c,0x2bb7c,0x2bb83,0x2bb83,0x2bc1b,0x2bc1b,0x2bd77,0x2bd77,0x2bd87,0x2bd87,0x2bdf7,0x2bdf7,0x2be29,0x2be29,0x2c029,0x2c02a,0x2c0a9,0x2c0a9,0x2c0ca,0x2c0ca,0x2c1d5,0x2c1d5,0x2c1d9,0x2c1d9,0x2c1f9,0x2c1f9,0x2c27c,0x2c27c,0x2c288,0x2c288,0x2c2a4,0x2c2a4,0x2c317,0x2c317,0x2c35b,0x2c35b,0x2c361,0x2c361,0x2c364,0x2c364,0x2c488,0x2c488,0x2c494,0x2c494,0x2c497,0x2c497,0x2c542,0x2c542,0x2c613,0x2c613,0x2c618,0x2c618,0x2c621,0x2c621,0x2c629,0x2c629,0x2c62b,0x2c62d,0x2c62f,0x2c62f,0x2c642,0x2c642,0x2c64a,0x2c64b,0x2c72c,0x2c72c,0x2c72f,0x2c72f,0x2c79f,0x2c79f,0x2c7c1,0x2c7c1,0x2c7fd,0x2c7fd,0x2c8d9,0x2c8d9,0x2c8de,0x2c8de,0x2c8e1,0x2c8e1,0x2c8f3,0x2c8f3,0x2c907,0x2c907,0x2c90a,0x2c90a,0x2c91d,0x2c91d,0x2ca02,0x2ca02,0x2ca0e,0x2ca0e,0x2ca7d,0x2ca7d,0x2caa9,0x2caa9,0x2cb29,0x2cb29,0x2cb2d,0x2cb2e,0x2cb31,0x2cb31,0x2cb38,0x2cb39,0x2cb3b,0x2cb3b,0x2cb3f,0x2cb3f,0x2cb41,0x2cb41,0x2cb4a,0x2cb4a,0x2cb4e,0x2cb4e,0x2cb5a,0x2cb5b,0x2cb64,0x2cb64,0x2cb69,0x2cb69,0x2cb6c,0x2cb6c,0x2cb6f,0x2cb6f,0x2cb73,0x2cb73,0x2cb76,0x2cb76,0x2cb78,0x2cb78,0x2cb7c,0x2cb7c,0x2cbb1,0x2cbb1,0x2cbbf,0x2cbc0,0x2cbce,0x2cbce,0x2cc56,0x2cc56,0x2cc5f,0x2cc5f,0x2ccf5,0x2ccf6,0x2ccfd,0x2ccfd,0x2ccff,0x2ccff,0x2cd02,0x2cd03,0x2cd0a,0x2cd0a,0x2cd8b,0x2cd8b,0x2cd8d,0x2cd8d,0x2cd8f,0x2cd90,0x2cd9f,0x2cda0,0x2cda8,0x2cda8,0x2cdad,0x2cdae,0x2cdd5,0x2cdd5,0x2ce18,0x2ce18,0x2ce1a,0x2ce1a,0x2ce23,0x2ce23,0x2ce26,0x2ce26,0x2ce2a,0x2ce2a,0x2ce7c,0x2ce7c,0x2ce88,0x2ce88,0x2ce93,0x2ce93,0x2d544,0x2d544,0x2f884,0x2f884,0x2f8b6,0x2f8b6,0x30edd,0x30ede,0x3106c,0x3106c,]), - NotoFont.fromFlatRanges('Noto Sans Saurashtra', 'http://fonts.gstatic.com/s/notosanssaurashtra/v15/ea8GacQ0Wfz_XKWXe6OtoA8w8zvmYwTef9ndjhPTSIx9.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa880,0xa8c5,0xa8ce,0xa8d9,]), - NotoFont.fromFlatRanges('Noto Sans Sharada', 'http://fonts.gstatic.com/s/notosanssharada/v15/gok0H7rwAEdtF9N8-mdTGALG6p0kwoXLPOwr4H8a.ttf', [0x20,0x20,0xa0,0xa0,0x951,0x951,0x1cd7,0x1cd7,0x1cd9,0x1cd9,0x1cdc,0x1cdd,0x1ce0,0x1ce0,0x200c,0x200d,0x25cc,0x25cc,0x11180,0x111df,]), - NotoFont.fromFlatRanges('Noto Sans Shavian', 'http://fonts.gstatic.com/s/notosansshavian/v15/CHy5V_HZE0jxJBQlqAeCKjJvQBNF4EFQSplv2Cwg.ttf', [0x20,0x20,0xa0,0xa0,0x10450,0x1047f,]), - NotoFont.fromFlatRanges('Noto Sans Siddham', 'http://fonts.gstatic.com/s/notosanssiddham/v15/OZpZg-FwqiNLe9PELUikxTWDoCCeGqndk3Ic92ZH.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x11580,0x115b5,0x115b8,0x115dd,]), - NotoFont.fromFlatRanges('Noto Sans Sinhala', 'http://fonts.gstatic.com/s/notosanssinhala/v25/yMJ2MJBya43H0SUF_WmcBEEf4rQVO2P524V5N_MxQzQtb-tf5dJbC30Fu9zUwg2a5lgLpJwbQRM.ttf', [0x20,0x23,0x25,0x25,0x27,0x3f,0x5b,0x5f,0x7b,0x7e,0xa0,0xa0,0xad,0xad,0xd7,0xd7,0xf7,0xf7,0x964,0x965,0xd81,0xd83,0xd85,0xd96,0xd9a,0xdb1,0xdb3,0xdbb,0xdbd,0xdbd,0xdc0,0xdc6,0xdca,0xdca,0xdcf,0xdd4,0xdd6,0xdd6,0xdd8,0xddf,0xde6,0xdef,0xdf2,0xdf4,0x200b,0x200d,0x2013,0x2014,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x2212,0x2212,0x25cc,0x25cc,0x111e1,0x111f4,]), - NotoFont.fromFlatRanges('Noto Sans Sogdian', 'http://fonts.gstatic.com/s/notosanssogdian/v15/taiQGn5iC4--qtsfi4Jp6eHPnfxQBo--Pm6KHidM.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x200c,0x200c,0x25cc,0x25cc,0x10f30,0x10f59,]), - NotoFont.fromFlatRanges('Noto Sans Sora Sompeng', 'http://fonts.gstatic.com/s/notosanssorasompeng/v17/PlIRFkO5O6RzLfvNNVSioxM2_OTrEhPyDLolKvCsHzCxWuGkYHR818DpZXJQd4Mu.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x2010,0x2010,0x110d0,0x110e8,0x110f0,0x110f9,]), - NotoFont.fromFlatRanges('Noto Sans Soyombo', 'http://fonts.gstatic.com/s/notosanssoyombo/v15/RWmSoL-Y6-8q5LTtXs6MF6q7xsxgY0FrIFOcK25W.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x11a50,0x11aa2,]), - NotoFont.fromFlatRanges('Noto Sans Sundanese', 'http://fonts.gstatic.com/s/notosanssundanese/v17/FwZw7_84xUkosG2xJo2gm7nFwSLQkdymq2mkz3Gz1_b6ctxpNNHCizv7fQES.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x1b80,0x1bbf,0x1cc0,0x1cc7,0x200b,0x200d,0x2010,0x2010,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Syloti Nagri', 'http://fonts.gstatic.com/s/notosanssylotinagri/v15/uU9eCAQZ75uhfF9UoWDRiY3q7Sf_VFV3m4dGFVfxN87gsj0.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x965,0x9e6,0x9ef,0x200b,0x200d,0x2010,0x2011,0x2055,0x2055,0x25cc,0x25cc,0xa800,0xa82c,]), - NotoFont.fromFlatRanges('Noto Sans Syriac', 'http://fonts.gstatic.com/s/notosanssyriac/v15/Ktk2AKuMeZjqPnXgyqribqzQqgW0N4O3WYZB_sU.ttf', [0x20,0x21,0x28,0x2b,0x2d,0x2f,0x3a,0x3a,0x3d,0x3d,0x5b,0x5d,0xa0,0xa0,0xab,0xab,0xb0,0xb0,0xbb,0xbb,0x303,0x304,0x307,0x308,0x30a,0x30a,0x320,0x320,0x323,0x325,0x32d,0x32e,0x330,0x331,0x60c,0x60c,0x61b,0x61b,0x61f,0x61f,0x621,0x621,0x640,0x640,0x64b,0x655,0x660,0x66c,0x670,0x670,0x700,0x70d,0x70f,0x74a,0x74d,0x74f,0x200c,0x200f,0x2026,0x2026,0x2044,0x2044,0x2212,0x2212,0x25cc,0x25cc,0x2670,0x2671,]), - NotoFont.fromFlatRanges('Noto Sans TC', 'http://fonts.gstatic.com/s/notosanstc/v26/-nF7OG829Oofr2wohFbTp9iFOSsLA_ZJ1g.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x3435,0x3435,0x3440,0x3440,0x344a,0x344a,0x344c,0x344c,0x3464,0x3464,0x3473,0x3473,0x347a,0x347a,0x347d,0x347e,0x3493,0x3493,0x3496,0x3496,0x34a5,0x34a5,0x34af,0x34af,0x34bc,0x34bc,0x34c1,0x34c1,0x34c8,0x34c8,0x34df,0x34df,0x34e4,0x34e4,0x34e6,0x34e6,0x34fb,0x34fb,0x3506,0x3506,0x353e,0x353e,0x3551,0x3551,0x3553,0x3553,0x3559,0x3559,0x3561,0x3561,0x356d,0x356d,0x3570,0x3570,0x3572,0x3572,0x3577,0x3578,0x3584,0x3584,0x3597,0x3598,0x35a1,0x35a1,0x35a5,0x35a5,0x35ad,0x35ad,0x35bf,0x35bf,0x35c1,0x35c1,0x35c5,0x35c5,0x35c7,0x35c7,0x35ca,0x35ca,0x35ce,0x35ce,0x35d2,0x35d2,0x35d6,0x35d6,0x35db,0x35db,0x35dd,0x35dd,0x35f1,0x35f3,0x35fb,0x35fb,0x35fe,0x35fe,0x3609,0x3609,0x3618,0x3618,0x361a,0x361a,0x3623,0x3623,0x3625,0x3625,0x362d,0x362d,0x3635,0x3635,0x3639,0x3639,0x363e,0x363e,0x3647,0x3649,0x364e,0x364e,0x365f,0x365f,0x3661,0x3661,0x367a,0x367a,0x3681,0x3681,0x369a,0x369a,0x36a5,0x36a5,0x36aa,0x36aa,0x36ac,0x36ac,0x36b0,0x36b1,0x36b5,0x36b5,0x36b9,0x36b9,0x36bc,0x36bc,0x36c1,0x36c1,0x36c3,0x36c5,0x36c7,0x36c8,0x36d3,0x36d4,0x36d6,0x36d6,0x36dd,0x36dd,0x36e1,0x36e2,0x36e5,0x36e6,0x36f5,0x36f5,0x3701,0x3701,0x3703,0x3703,0x3708,0x3708,0x370a,0x370a,0x370d,0x370d,0x371c,0x371c,0x3722,0x3723,0x3725,0x3725,0x372c,0x372d,0x3730,0x3730,0x3732,0x3733,0x373a,0x373a,0x3740,0x3740,0x3743,0x3743,0x3762,0x3762,0x376f,0x376f,0x3797,0x3797,0x37a0,0x37a0,0x37b9,0x37b9,0x37be,0x37be,0x37d6,0x37d6,0x37f2,0x37f2,0x37f8,0x37f8,0x37fb,0x37fb,0x380f,0x380f,0x3819,0x3819,0x3820,0x3820,0x382d,0x382d,0x3836,0x3836,0x3838,0x3838,0x3863,0x3863,0x3875,0x3875,0x38a0,0x38a0,0x38c3,0x38c3,0x38cc,0x38cc,0x38d1,0x38d1,0x38d4,0x38d4,0x38fa,0x38fa,0x3908,0x3908,0x3914,0x3914,0x3927,0x3927,0x3932,0x3932,0x393f,0x393f,0x394d,0x394d,0x3963,0x3963,0x3978,0x3978,0x3980,0x3980,0x3989,0x398a,0x3992,0x3992,0x3999,0x3999,0x399b,0x399b,0x39a1,0x39a1,0x39a4,0x39a4,0x39b8,0x39b8,0x39dc,0x39dc,0x39e2,0x39e2,0x39e5,0x39e5,0x39ec,0x39ec,0x39f8,0x39f8,0x39fb,0x39fb,0x39fe,0x39fe,0x3a01,0x3a01,0x3a03,0x3a03,0x3a06,0x3a06,0x3a17,0x3a18,0x3a29,0x3a2a,0x3a34,0x3a34,0x3a4b,0x3a4b,0x3a52,0x3a52,0x3a57,0x3a57,0x3a5c,0x3a5c,0x3a5e,0x3a5e,0x3a66,0x3a67,0x3a97,0x3a97,0x3aab,0x3aab,0x3abd,0x3abd,0x3ada,0x3ada,0x3ade,0x3ade,0x3ae0,0x3ae0,0x3af0,0x3af0,0x3af2,0x3af2,0x3af5,0x3af5,0x3afb,0x3afb,0x3b0e,0x3b0e,0x3b19,0x3b19,0x3b22,0x3b22,0x3b2b,0x3b2b,0x3b39,0x3b39,0x3b42,0x3b42,0x3b58,0x3b58,0x3b60,0x3b60,0x3b71,0x3b72,0x3b7b,0x3b7c,0x3b80,0x3b80,0x3b95,0x3b96,0x3b99,0x3b99,0x3ba1,0x3ba1,0x3bbc,0x3bbc,0x3bbe,0x3bbe,0x3bc2,0x3bc2,0x3bc4,0x3bc4,0x3bd7,0x3bd7,0x3bdd,0x3bdd,0x3bec,0x3bec,0x3bf2,0x3bf4,0x3c0d,0x3c0d,0x3c11,0x3c11,0x3c15,0x3c15,0x3c18,0x3c18,0x3c54,0x3c54,0x3c8b,0x3c8b,0x3ccb,0x3ccb,0x3ccd,0x3ccd,0x3cd1,0x3cd1,0x3cd6,0x3cd6,0x3cdc,0x3cdc,0x3ceb,0x3ceb,0x3cef,0x3cef,0x3d12,0x3d13,0x3d1d,0x3d1d,0x3d32,0x3d32,0x3d3b,0x3d3b,0x3d46,0x3d46,0x3d4c,0x3d4c,0x3d4e,0x3d4e,0x3d51,0x3d51,0x3d5f,0x3d5f,0x3d62,0x3d62,0x3d69,0x3d6a,0x3d6f,0x3d6f,0x3d75,0x3d75,0x3d7d,0x3d7d,0x3d85,0x3d85,0x3d88,0x3d88,0x3d8a,0x3d8a,0x3d8f,0x3d8f,0x3d91,0x3d91,0x3da5,0x3da5,0x3dad,0x3dad,0x3db4,0x3db4,0x3dbf,0x3dbf,0x3dc6,0x3dc7,0x3dc9,0x3dc9,0x3dcc,0x3dcd,0x3dd3,0x3dd3,0x3ddb,0x3ddb,0x3de7,0x3de8,0x3deb,0x3deb,0x3df3,0x3df4,0x3df7,0x3df7,0x3dfc,0x3dfd,0x3e06,0x3e06,0x3e40,0x3e40,0x3e43,0x3e43,0x3e48,0x3e48,0x3e55,0x3e55,0x3e74,0x3e74,0x3ea8,0x3eaa,0x3ead,0x3ead,0x3eb1,0x3eb1,0x3eb8,0x3eb8,0x3ebf,0x3ebf,0x3ec2,0x3ec2,0x3ec7,0x3ec7,0x3eca,0x3eca,0x3ecc,0x3ecc,0x3ed0,0x3ed1,0x3ed6,0x3ed7,0x3eda,0x3edb,0x3ede,0x3ede,0x3ee1,0x3ee2,0x3ee7,0x3ee7,0x3ee9,0x3ee9,0x3eeb,0x3eec,0x3ef0,0x3ef0,0x3ef3,0x3ef4,0x3efa,0x3efa,0x3efc,0x3efc,0x3eff,0x3f00,0x3f04,0x3f04,0x3f06,0x3f07,0x3f0e,0x3f0e,0x3f53,0x3f53,0x3f58,0x3f59,0x3f63,0x3f63,0x3f7c,0x3f7c,0x3f93,0x3f93,0x3fc0,0x3fc0,0x3fc8,0x3fc8,0x3fd7,0x3fd7,0x3fdc,0x3fdc,0x3fe5,0x3fe5,0x3fed,0x3fed,0x3ff9,0x3ffa,0x4004,0x4004,0x4009,0x4009,0x401d,0x401d,0x4039,0x4039,0x4045,0x4045,0x4053,0x4053,0x4057,0x4057,0x4062,0x4062,0x4065,0x4065,0x406a,0x406a,0x406f,0x406f,0x4071,0x4071,0x40a8,0x40a8,0x40b4,0x40b4,0x40bb,0x40bb,0x40bf,0x40bf,0x40c8,0x40c8,0x40d8,0x40d8,0x40df,0x40df,0x40f8,0x40f8,0x40fa,0x40fa,0x4102,0x4104,0x4109,0x4109,0x410e,0x410e,0x4131,0x4132,0x4167,0x4167,0x416c,0x416c,0x416e,0x416e,0x417c,0x417c,0x417f,0x417f,0x4181,0x4181,0x4190,0x4190,0x41b2,0x41b2,0x41c4,0x41c4,0x41ca,0x41ca,0x41cf,0x41cf,0x41db,0x41db,0x41ed,0x41ed,0x41ef,0x41ef,0x41f9,0x41f9,0x4211,0x4211,0x4223,0x4223,0x4240,0x4240,0x4260,0x4260,0x426a,0x426a,0x4276,0x4276,0x427a,0x427a,0x428c,0x428c,0x4294,0x4294,0x42a2,0x42a2,0x42b5,0x42b5,0x42b9,0x42b9,0x42bc,0x42bc,0x42f4,0x42f4,0x42fb,0x42fc,0x430a,0x430a,0x432b,0x432b,0x436e,0x436e,0x4397,0x4397,0x439a,0x439a,0x43ba,0x43ba,0x43c1,0x43c1,0x43d9,0x43d9,0x43df,0x43df,0x43ed,0x43ed,0x43f0,0x43f0,0x43f2,0x43f2,0x4401,0x4402,0x4413,0x4413,0x4425,0x4425,0x442d,0x442d,0x447a,0x447a,0x448f,0x448f,0x4491,0x4491,0x449f,0x44a0,0x44a2,0x44a2,0x44b0,0x44b0,0x44b7,0x44b7,0x44bd,0x44bd,0x44c0,0x44c0,0x44c3,0x44c3,0x44c5,0x44c5,0x44ce,0x44ce,0x44dd,0x44df,0x44e1,0x44e1,0x44e4,0x44e4,0x44e9,0x44ec,0x44f4,0x44f4,0x4503,0x4504,0x4509,0x4509,0x450b,0x450b,0x4516,0x4516,0x451b,0x451b,0x451d,0x451d,0x4527,0x4527,0x452e,0x452e,0x4533,0x4533,0x4536,0x4536,0x453b,0x453b,0x453d,0x453d,0x453f,0x453f,0x4543,0x4543,0x4551,0x4552,0x4555,0x4555,0x4558,0x4558,0x455c,0x455c,0x4561,0x4562,0x456a,0x456a,0x456d,0x456d,0x4577,0x4578,0x4585,0x4585,0x45a6,0x45a6,0x45b3,0x45b3,0x45da,0x45da,0x45e9,0x45ea,0x4603,0x4603,0x4606,0x4606,0x460f,0x460f,0x4615,0x4615,0x4617,0x4617,0x465b,0x465b,0x467a,0x467a,0x4680,0x4680,0x46a1,0x46a1,0x46ae,0x46ae,0x46bb,0x46bb,0x46cf,0x46d0,0x46f5,0x46f5,0x46f7,0x46f7,0x4713,0x4713,0x4718,0x4718,0x4736,0x4736,0x4744,0x4744,0x474e,0x474f,0x477c,0x477c,0x4798,0x4798,0x47a6,0x47a6,0x47d5,0x47d5,0x47ed,0x47ed,0x47f4,0x47f4,0x4800,0x4800,0x480b,0x480b,0x4837,0x4837,0x485d,0x485d,0x4871,0x4871,0x489b,0x489b,0x48ad,0x48ae,0x48d0,0x48d0,0x48dd,0x48dd,0x48ed,0x48ed,0x48f3,0x48f3,0x48fa,0x48fa,0x4906,0x4906,0x4911,0x4911,0x491e,0x491e,0x4925,0x4925,0x492a,0x492a,0x492d,0x492d,0x492f,0x4930,0x4935,0x4935,0x493c,0x493c,0x493e,0x493e,0x4945,0x4945,0x4951,0x4951,0x4953,0x4953,0x4965,0x4965,0x496a,0x496a,0x4972,0x4972,0x4989,0x4989,0x49a1,0x49a1,0x49a7,0x49a7,0x49df,0x49df,0x49e5,0x49e5,0x49e7,0x49e7,0x4a0f,0x4a0f,0x4a1d,0x4a1d,0x4a24,0x4a24,0x4a35,0x4a35,0x4a96,0x4a96,0x4aa4,0x4aa4,0x4ab4,0x4ab4,0x4ab8,0x4ab8,0x4ad1,0x4ad1,0x4ae4,0x4ae4,0x4aff,0x4aff,0x4b10,0x4b10,0x4b19,0x4b19,0x4b20,0x4b20,0x4b2c,0x4b2c,0x4b37,0x4b37,0x4b6f,0x4b70,0x4b72,0x4b72,0x4b7b,0x4b7b,0x4b7e,0x4b7e,0x4b8e,0x4b8e,0x4b90,0x4b90,0x4b93,0x4b93,0x4b96,0x4b97,0x4b9d,0x4b9d,0x4bbd,0x4bbe,0x4bc0,0x4bc0,0x4c04,0x4c04,0x4c07,0x4c07,0x4c0e,0x4c0e,0x4c32,0x4c32,0x4c3b,0x4c3b,0x4c3e,0x4c3e,0x4c40,0x4c40,0x4c47,0x4c47,0x4c57,0x4c57,0x4c5b,0x4c5b,0x4c6d,0x4c6d,0x4c77,0x4c77,0x4c7b,0x4c7b,0x4c7d,0x4c7d,0x4c81,0x4c81,0x4c85,0x4c85,0x4ca4,0x4ca4,0x4cae,0x4cae,0x4cb0,0x4cb0,0x4cb7,0x4cb7,0x4ccd,0x4ccd,0x4ce1,0x4ce2,0x4ced,0x4ced,0x4d07,0x4d07,0x4d09,0x4d09,0x4d10,0x4d10,0x4d34,0x4d34,0x4d76,0x4d77,0x4d89,0x4d89,0x4d91,0x4d91,0x4d9c,0x4d9c,0x4e00,0x4e01,0x4e03,0x4e04,0x4e07,0x4e11,0x4e14,0x4e16,0x4e18,0x4e1a,0x4e1c,0x4e1c,0x4e1e,0x4e1f,0x4e21,0x4e22,0x4e24,0x4e24,0x4e26,0x4e26,0x4e28,0x4e28,0x4e2a,0x4e33,0x4e36,0x4e39,0x4e3b,0x4e3d,0x4e3f,0x4e3f,0x4e42,0x4e43,0x4e45,0x4e45,0x4e47,0x4e49,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e52,0x4e53,0x4e56,0x4e56,0x4e58,0x4e5f,0x4e69,0x4e6a,0x4e73,0x4e73,0x4e78,0x4e78,0x4e7e,0x4e89,0x4e8b,0x4e8e,0x4e91,0x4e95,0x4e98,0x4e9b,0x4e9e,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eae,0x4eb3,0x4eb3,0x4eb6,0x4eb7,0x4eb9,0x4ebc,0x4ebf,0x4ec4,0x4ec6,0x4ecb,0x4ecd,0x4ece,0x4ed4,0x4eda,0x4edc,0x4edf,0x4ee1,0x4ee1,0x4ee3,0x4ee5,0x4ee8,0x4eeb,0x4eee,0x4eee,0x4ef0,0x4ef8,0x4efb,0x4efb,0x4efd,0x4efd,0x4eff,0x4f05,0x4f08,0x4f0b,0x4f0d,0x4f15,0x4f17,0x4f1a,0x4f1d,0x4f1d,0x4f22,0x4f22,0x4f28,0x4f29,0x4f2c,0x4f2d,0x4f2f,0x4f30,0x4f32,0x4f34,0x4f36,0x4f3f,0x4f41,0x4f43,0x4f45,0x4f49,0x4f4b,0x4f64,0x4f67,0x4f67,0x4f69,0x4f6c,0x4f6e,0x4f70,0x4f72,0x4f8b,0x4f8d,0x4f8d,0x4f8f,0x4f92,0x4f94,0x4f98,0x4f9a,0x4f9e,0x4fa2,0x4fa2,0x4fa8,0x4fa8,0x4fab,0x4fab,0x4fae,0x4fb0,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbd,0x4fbd,0x4fbf,0x4fc5,0x4fc7,0x4fd1,0x4fd3,0x4fd4,0x4fd6,0x4fe1,0x4fe4,0x4fe5,0x4fec,0x4fec,0x4fee,0x4ffa,0x4ffd,0x4ffe,0x5000,0x5000,0x5003,0x5003,0x5005,0x5009,0x500b,0x500f,0x5011,0x501c,0x501e,0x5023,0x5025,0x5031,0x5033,0x5035,0x5037,0x5037,0x503b,0x503c,0x5040,0x5041,0x5043,0x5043,0x5045,0x504f,0x5051,0x5051,0x5053,0x5053,0x5055,0x5058,0x505a,0x5066,0x5068,0x5070,0x5072,0x5077,0x507a,0x507a,0x507d,0x507d,0x5080,0x5083,0x5085,0x5085,0x5087,0x5088,0x508b,0x508e,0x5090,0x5092,0x5094,0x5096,0x5098,0x509e,0x50a2,0x50a3,0x50a6,0x50a6,0x50ac,0x50b8,0x50ba,0x50bf,0x50c1,0x50c2,0x50c4,0x50cb,0x50cd,0x50d1,0x50d3,0x50d7,0x50d9,0x50db,0x50dd,0x50dd,0x50df,0x50e1,0x50e3,0x50ea,0x50ec,0x50f1,0x50f3,0x50f6,0x50f8,0x50f9,0x50fb,0x510e,0x5110,0x5115,0x5117,0x5118,0x511a,0x511a,0x511c,0x511c,0x511f,0x5122,0x5124,0x5126,0x5129,0x512b,0x512d,0x512e,0x5130,0x5135,0x5137,0x513d,0x513f,0x5141,0x5143,0x5149,0x514b,0x514d,0x5151,0x5152,0x5154,0x5157,0x5159,0x5163,0x5165,0x5165,0x5167,0x516e,0x5171,0x5171,0x5174,0x5179,0x517c,0x517c,0x5180,0x5180,0x5182,0x5182,0x5186,0x518a,0x518d,0x518d,0x518f,0x518f,0x5191,0x5198,0x519a,0x519a,0x519c,0x519c,0x519e,0x519e,0x51a0,0x51a0,0x51a2,0x51a2,0x51a4,0x51a5,0x51a7,0x51a8,0x51aa,0x51ac,0x51ae,0x51ae,0x51b0,0x51b9,0x51bc,0x51be,0x51c3,0x51d4,0x51d7,0x51d8,0x51db,0x51e2,0x51e4,0x51e4,0x51ed,0x51ed,0x51f0,0x51f1,0x51f3,0x51f6,0x51f8,0x51fa,0x51fc,0x51fe,0x5200,0x5203,0x5205,0x520c,0x520e,0x520e,0x5210,0x5213,0x5216,0x5217,0x521c,0x5221,0x5224,0x522a,0x522e,0x522e,0x5230,0x5238,0x523a,0x523c,0x5241,0x5241,0x5243,0x5244,0x5246,0x5247,0x5249,0x524f,0x5252,0x5252,0x5254,0x5257,0x5259,0x5262,0x5268,0x526f,0x5272,0x5275,0x5277,0x527d,0x527f,0x5284,0x5287,0x528d,0x528f,0x5291,0x5293,0x5294,0x5296,0x529b,0x529f,0x52a1,0x52a3,0x52a4,0x52a6,0x52a6,0x52a8,0x52ae,0x52b5,0x52b5,0x52b9,0x52b9,0x52bb,0x52bc,0x52be,0x52be,0x52c0,0x52c3,0x52c5,0x52c5,0x52c7,0x52c7,0x52c9,0x52c9,0x52cc,0x52cd,0x52d0,0x52d3,0x52d5,0x52d9,0x52db,0x52db,0x52dd,0x52e4,0x52e6,0x52e6,0x52e9,0x52e9,0x52eb,0x52eb,0x52ef,0x52f1,0x52f3,0x52f5,0x52f7,0x52fc,0x52fe,0x52ff,0x5301,0x5301,0x5305,0x5306,0x5308,0x530b,0x530d,0x5312,0x5315,0x5317,0x5319,0x531a,0x531c,0x531d,0x531f,0x5324,0x5327,0x5327,0x532a,0x532a,0x532c,0x532d,0x532f,0x5334,0x5337,0x5339,0x533b,0x5345,0x5347,0x534a,0x534c,0x534e,0x5351,0x5354,0x5357,0x5357,0x535a,0x535a,0x535c,0x5361,0x5363,0x5364,0x5366,0x5367,0x5369,0x5369,0x536c,0x5375,0x5377,0x5379,0x537b,0x537f,0x5382,0x5382,0x5384,0x5384,0x538a,0x538a,0x538e,0x538f,0x5392,0x5394,0x5396,0x539a,0x539c,0x53a0,0x53a2,0x53a2,0x53a4,0x53ae,0x53b0,0x53b0,0x53b2,0x53b2,0x53b4,0x53b4,0x53b6,0x53b6,0x53b9,0x53b9,0x53bb,0x53bb,0x53c1,0x53c3,0x53c5,0x53c5,0x53c8,0x53cd,0x53d0,0x53d2,0x53d4,0x53d4,0x53d6,0x53db,0x53df,0x53e6,0x53e8,0x53f3,0x53f5,0x53f8,0x53fb,0x53fc,0x53fe,0x53fe,0x5401,0x5401,0x5403,0x5404,0x5406,0x5414,0x5416,0x5416,0x5418,0x5421,0x5423,0x5439,0x543b,0x5443,0x5445,0x5448,0x544a,0x544f,0x5454,0x5454,0x5460,0x546d,0x546f,0x5478,0x547a,0x5482,0x5484,0x5488,0x548b,0x5498,0x549a,0x549a,0x549c,0x549c,0x549e,0x549e,0x54a0,0x54b4,0x54b6,0x54c9,0x54cb,0x54d0,0x54d6,0x54d6,0x54da,0x54da,0x54de,0x54de,0x54e0,0x54eb,0x54ed,0x54ef,0x54f1,0x54f3,0x54f7,0x54f8,0x54fa,0x54fd,0x54ff,0x54ff,0x5501,0x5514,0x5517,0x5518,0x551a,0x551a,0x551e,0x551e,0x5523,0x5523,0x5525,0x5528,0x552a,0x5539,0x553b,0x553c,0x553e,0x5541,0x5543,0x554b,0x554d,0x5553,0x5555,0x5557,0x555c,0x555f,0x5561,0x5566,0x5569,0x556b,0x5571,0x5573,0x5575,0x5577,0x5579,0x5579,0x557b,0x5584,0x5586,0x5595,0x5598,0x559a,0x559c,0x559d,0x559f,0x559f,0x55a1,0x55ae,0x55b0,0x55b5,0x55b9,0x55bc,0x55bf,0x55df,0x55e1,0x55ea,0x55ec,0x55ec,0x55ee,0x55f2,0x55f5,0x55f7,0x55f9,0x5602,0x5604,0x5606,0x5608,0x5609,0x560c,0x5617,0x561b,0x5623,0x5625,0x5625,0x5627,0x5627,0x5629,0x562a,0x562c,0x5630,0x5632,0x563b,0x563d,0x5643,0x5645,0x5646,0x5648,0x564a,0x564c,0x5650,0x5652,0x5654,0x5657,0x565a,0x565d,0x565e,0x5660,0x5666,0x5668,0x5674,0x5676,0x567c,0x567e,0x5687,0x5689,0x5690,0x5692,0x5693,0x5695,0x5695,0x5697,0x569a,0x569c,0x569f,0x56a1,0x56a1,0x56a4,0x56a8,0x56aa,0x56af,0x56b1,0x56b7,0x56b9,0x56b9,0x56bc,0x56c3,0x56c5,0x56c6,0x56c8,0x56cd,0x56d1,0x56d1,0x56d3,0x56d4,0x56d6,0x56d7,0x56da,0x56db,0x56dd,0x56e2,0x56e4,0x56e5,0x56e7,0x56e7,0x56ea,0x56eb,0x56ed,0x56f1,0x56f7,0x56f7,0x56f9,0x56fb,0x56fd,0x56fd,0x56ff,0x5704,0x5707,0x570d,0x5712,0x5716,0x5718,0x5718,0x571a,0x5720,0x5722,0x5723,0x5728,0x572a,0x572c,0x5730,0x5732,0x5734,0x573b,0x573b,0x573d,0x5743,0x5745,0x5747,0x5749,0x5752,0x5754,0x5754,0x5757,0x5757,0x575b,0x575b,0x575f,0x575f,0x5761,0x5762,0x5764,0x5764,0x5766,0x576b,0x576d,0x576d,0x576f,0x5777,0x577a,0x5780,0x5782,0x5783,0x5788,0x5788,0x578a,0x578d,0x578f,0x5790,0x5793,0x5795,0x5797,0x57a5,0x57a7,0x57a7,0x57aa,0x57aa,0x57ae,0x57ae,0x57b3,0x57b6,0x57b8,0x57bf,0x57c1,0x57c4,0x57c6,0x57c8,0x57cb,0x57cc,0x57ce,0x57d0,0x57d2,0x57d2,0x57d4,0x57d5,0x57d7,0x57d7,0x57dc,0x57e7,0x57e9,0x57e9,0x57ec,0x57fe,0x5800,0x580e,0x5810,0x5810,0x5812,0x5812,0x5814,0x5814,0x5818,0x5819,0x581b,0x581e,0x5820,0x582a,0x582c,0x583b,0x583d,0x583d,0x583f,0x5840,0x5844,0x5844,0x5847,0x584f,0x5851,0x5855,0x5857,0x585f,0x5862,0x5865,0x5868,0x5869,0x586b,0x586d,0x586f,0x586f,0x5871,0x5876,0x5879,0x5883,0x5885,0x588b,0x588e,0x5894,0x5896,0x5896,0x5898,0x589a,0x589c,0x58a1,0x58a3,0x58a3,0x58a5,0x58ac,0x58ae,0x58b1,0x58b3,0x58b3,0x58b5,0x58b6,0x58ba,0x58bf,0x58c1,0x58c2,0x58c5,0x58c9,0x58cb,0x58cb,0x58ce,0x58d6,0x58d8,0x58e0,0x58e2,0x58e4,0x58e7,0x58e9,0x58eb,0x58ec,0x58ef,0x58f0,0x58f2,0x58f4,0x58f9,0x58ff,0x5902,0x5907,0x590a,0x590a,0x590c,0x590f,0x5911,0x5912,0x5914,0x5917,0x5919,0x591a,0x591c,0x591d,0x591f,0x5920,0x5922,0x5922,0x5924,0x5925,0x5927,0x5927,0x5929,0x592f,0x5931,0x5932,0x5934,0x5934,0x5937,0x5938,0x593c,0x593c,0x593e,0x593e,0x5940,0x5940,0x5944,0x5945,0x5947,0x594a,0x594e,0x5951,0x5953,0x5955,0x5957,0x5958,0x595a,0x595a,0x595c,0x595c,0x5960,0x5962,0x5965,0x5965,0x5967,0x5967,0x5969,0x596e,0x5970,0x5979,0x597b,0x5985,0x5989,0x598a,0x598d,0x5990,0x5992,0x5994,0x5996,0x599a,0x599d,0x59a8,0x59ac,0x59ac,0x59ae,0x59c1,0x59c3,0x59d4,0x59d6,0x59d6,0x59d8,0x59de,0x59e0,0x59e1,0x59e3,0x59e6,0x59e8,0x5a03,0x5a09,0x5a0d,0x5a0f,0x5a0f,0x5a11,0x5a13,0x5a15,0x5a1c,0x5a1e,0x5a21,0x5a23,0x5a25,0x5a27,0x5a27,0x5a29,0x5a2e,0x5a33,0x5a33,0x5a35,0x5a39,0x5a3c,0x5a3e,0x5a40,0x5a4a,0x5a4c,0x5a4d,0x5a50,0x5a6e,0x5a70,0x5a71,0x5a77,0x5a7f,0x5a81,0x5a84,0x5a86,0x5a86,0x5a88,0x5a88,0x5a8a,0x5a8c,0x5a8e,0x5a97,0x5a99,0x5aa2,0x5aa4,0x5aa7,0x5aa9,0x5aac,0x5aae,0x5ac4,0x5ac6,0x5acf,0x5ad1,0x5ad1,0x5ad3,0x5ad3,0x5ad5,0x5ae6,0x5ae8,0x5aee,0x5af0,0x5af0,0x5af2,0x5afb,0x5afd,0x5aff,0x5b01,0x5b03,0x5b05,0x5b05,0x5b07,0x5b09,0x5b0b,0x5b0d,0x5b0f,0x5b11,0x5b13,0x5b17,0x5b19,0x5b1b,0x5b1d,0x5b21,0x5b23,0x5b28,0x5b2a,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b38,0x5b38,0x5b3c,0x5b41,0x5b43,0x5b48,0x5b4a,0x5b51,0x5b53,0x5b58,0x5b5a,0x5b5d,0x5b5f,0x5b5f,0x5b62,0x5b66,0x5b68,0x5b69,0x5b6b,0x5b6e,0x5b70,0x5b78,0x5b7a,0x5b7d,0x5b7f,0x5b85,0x5b87,0x5b89,0x5b8b,0x5b8c,0x5b8e,0x5b90,0x5b92,0x5b93,0x5b95,0x5b9f,0x5ba2,0x5ba8,0x5baa,0x5baa,0x5bac,0x5bae,0x5bb0,0x5bb0,0x5bb3,0x5bb9,0x5bbf,0x5bc7,0x5bca,0x5bce,0x5bd0,0x5bd9,0x5bdb,0x5bdb,0x5bde,0x5bec,0x5bee,0x5bf3,0x5bf5,0x5bf6,0x5bf8,0x5bf8,0x5bfa,0x5bfa,0x5bff,0x5bff,0x5c01,0x5c01,0x5c03,0x5c05,0x5c07,0x5c16,0x5c1a,0x5c1a,0x5c1c,0x5c1c,0x5c1e,0x5c20,0x5c22,0x5c25,0x5c28,0x5c28,0x5c2a,0x5c2a,0x5c2c,0x5c2c,0x5c30,0x5c31,0x5c33,0x5c33,0x5c37,0x5c3c,0x5c3e,0x5c41,0x5c44,0x5c51,0x5c53,0x5c56,0x5c58,0x5c59,0x5c5c,0x5c5e,0x5c60,0x5c60,0x5c62,0x5c65,0x5c67,0x5c6a,0x5c6c,0x5c6f,0x5c71,0x5c71,0x5c73,0x5c74,0x5c78,0x5c7c,0x5c7e,0x5c7e,0x5c85,0x5c86,0x5c88,0x5c8d,0x5c8f,0x5c95,0x5c99,0x5c9a,0x5c9c,0x5cb1,0x5cb3,0x5cb3,0x5cb5,0x5cb8,0x5cba,0x5cba,0x5cc1,0x5cc2,0x5cc6,0x5ccc,0x5cce,0x5cdb,0x5cde,0x5cdf,0x5ce5,0x5ce5,0x5ce8,0x5cea,0x5cec,0x5cf1,0x5cf4,0x5cf9,0x5cfb,0x5cfd,0x5cff,0x5d01,0x5d06,0x5d07,0x5d0b,0x5d12,0x5d14,0x5d1b,0x5d1d,0x5d20,0x5d22,0x5d29,0x5d2c,0x5d2c,0x5d2e,0x5d3a,0x5d3c,0x5d43,0x5d45,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d52,0x5d55,0x5d57,0x5d59,0x5d59,0x5d5b,0x5d5b,0x5d5e,0x5d5e,0x5d62,0x5d63,0x5d65,0x5d65,0x5d67,0x5d69,0x5d6b,0x5d6c,0x5d6f,0x5d72,0x5d74,0x5d74,0x5d77,0x5d82,0x5d84,0x5d8b,0x5d8d,0x5d8e,0x5d92,0x5d95,0x5d97,0x5d97,0x5d99,0x5d9a,0x5d9c,0x5da2,0x5da4,0x5da4,0x5da7,0x5db2,0x5db4,0x5dba,0x5dbc,0x5dbd,0x5dc0,0x5dc3,0x5dc6,0x5dc7,0x5dc9,0x5dc9,0x5dcb,0x5dcb,0x5dcd,0x5dcd,0x5dcf,0x5dcf,0x5dd1,0x5dd2,0x5dd4,0x5dd8,0x5ddb,0x5ddb,0x5ddd,0x5de2,0x5de5,0x5de8,0x5deb,0x5deb,0x5dee,0x5dee,0x5df0,0x5df5,0x5df7,0x5df7,0x5df9,0x5df9,0x5dfd,0x5dff,0x5e02,0x5e04,0x5e06,0x5e06,0x5e09,0x5e0c,0x5e0e,0x5e0e,0x5e11,0x5e12,0x5e14,0x5e1b,0x5e1d,0x5e1d,0x5e1f,0x5e25,0x5e28,0x5e29,0x5e2b,0x5e2b,0x5e2d,0x5e2e,0x5e33,0x5e34,0x5e36,0x5e38,0x5e3d,0x5e3e,0x5e40,0x5e45,0x5e48,0x5e48,0x5e4a,0x5e4f,0x5e53,0x5e55,0x5e57,0x5e59,0x5e5b,0x5e63,0x5e66,0x5e70,0x5e72,0x5e76,0x5e78,0x5e80,0x5e82,0x5e84,0x5e86,0x5e8d,0x5e8f,0x5e8f,0x5e92,0x5e92,0x5e95,0x5e97,0x5e99,0x5e9c,0x5ea0,0x5ea0,0x5ea2,0x5ea8,0x5eaa,0x5eae,0x5eb0,0x5eb9,0x5ebd,0x5ebe,0x5ec1,0x5ec2,0x5ec4,0x5ece,0x5ed0,0x5ee3,0x5ee5,0x5ee9,0x5eec,0x5eec,0x5eee,0x5eef,0x5ef1,0x5ef4,0x5ef6,0x5efc,0x5efe,0x5eff,0x5f01,0x5f02,0x5f04,0x5f05,0x5f07,0x5f08,0x5f0a,0x5f0f,0x5f12,0x5f15,0x5f17,0x5f18,0x5f1a,0x5f1b,0x5f1d,0x5f1d,0x5f1f,0x5f1f,0x5f22,0x5f29,0x5f2d,0x5f2e,0x5f30,0x5f31,0x5f33,0x5f33,0x5f35,0x5f38,0x5f3a,0x5f3c,0x5f40,0x5f40,0x5f43,0x5f46,0x5f48,0x5f51,0x5f54,0x5f54,0x5f56,0x5f59,0x5f5c,0x5f5e,0x5f61,0x5f65,0x5f67,0x5f67,0x5f69,0x5f6d,0x5f6f,0x5f74,0x5f76,0x5f79,0x5f7b,0x5f83,0x5f85,0x5f8c,0x5f90,0x5f92,0x5f96,0x5f99,0x5f9b,0x5f9c,0x5f9e,0x5fa1,0x5fa4,0x5faf,0x5fb1,0x5fb2,0x5fb5,0x5fb7,0x5fb9,0x5fc5,0x5fc9,0x5fc9,0x5fcc,0x5fcd,0x5fcf,0x5fd2,0x5fd4,0x5fd9,0x5fdb,0x5fdb,0x5fdd,0x5fe1,0x5fe3,0x5fe5,0x5fe8,0x5fe8,0x5fea,0x5feb,0x5fed,0x5fef,0x5ff1,0x5ff1,0x5ff3,0x5ff5,0x5ff7,0x5ff8,0x5ffa,0x5ffb,0x5ffd,0x5ffd,0x5fff,0x6000,0x6009,0x6017,0x6019,0x601e,0x6020,0x602f,0x6031,0x6035,0x6037,0x6037,0x6039,0x6039,0x603b,0x603b,0x6040,0x6047,0x6049,0x604d,0x6050,0x6050,0x6052,0x6055,0x6058,0x605b,0x605d,0x605f,0x6062,0x6070,0x6072,0x6072,0x6075,0x6075,0x6077,0x6077,0x607e,0x6081,0x6083,0x608a,0x608c,0x608e,0x6090,0x6090,0x6092,0x6092,0x6094,0x6097,0x609a,0x60a0,0x60a2,0x60a4,0x60a6,0x60a8,0x60b0,0x60c1,0x60c3,0x60cf,0x60d1,0x60d1,0x60d3,0x60d5,0x60d7,0x60e4,0x60e6,0x60e9,0x60f0,0x6101,0x6103,0x6110,0x6112,0x6116,0x6118,0x611d,0x611f,0x6120,0x6122,0x6123,0x6127,0x6129,0x612b,0x612c,0x612e,0x6130,0x6132,0x6132,0x6134,0x6134,0x6136,0x6137,0x613b,0x613b,0x613d,0x6142,0x6144,0x6150,0x6152,0x6156,0x6158,0x6168,0x616a,0x616c,0x616e,0x6177,0x6179,0x617a,0x617c,0x617e,0x6180,0x6183,0x6187,0x6187,0x6189,0x618e,0x6190,0x6196,0x6198,0x619d,0x619f,0x619f,0x61a1,0x61a2,0x61a4,0x61a4,0x61a7,0x61ba,0x61bc,0x61bc,0x61be,0x61c3,0x61c5,0x61cd,0x61cf,0x61d0,0x61d3,0x61d3,0x61d6,0x61d6,0x61d8,0x61d8,0x61da,0x61da,0x61de,0x61e0,0x61e2,0x61eb,0x61ed,0x61ee,0x61f0,0x61f2,0x61f5,0x6201,0x6203,0x6204,0x6207,0x620a,0x620c,0x620e,0x6210,0x6212,0x6214,0x6216,0x6219,0x621b,0x621f,0x6225,0x6227,0x6227,0x6229,0x622e,0x6230,0x6230,0x6232,0x6234,0x6236,0x6237,0x6239,0x623a,0x623d,0x6243,0x6246,0x624e,0x6250,0x6254,0x6258,0x625c,0x625e,0x625e,0x6260,0x6266,0x6268,0x6268,0x626d,0x6274,0x6276,0x6277,0x6279,0x628a,0x628c,0x628c,0x628e,0x6298,0x629d,0x629d,0x62a4,0x62a4,0x62a6,0x62a6,0x62a8,0x62b1,0x62b3,0x62b6,0x62b8,0x62b9,0x62bb,0x62bf,0x62c1,0x62dc,0x62df,0x62df,0x62e5,0x62e5,0x62eb,0x6303,0x6307,0x6309,0x630b,0x6311,0x6313,0x6316,0x6318,0x6318,0x6328,0x632f,0x6331,0x633e,0x6340,0x6351,0x6354,0x635a,0x635d,0x635d,0x6364,0x6365,0x6367,0x6369,0x636b,0x6372,0x6375,0x637d,0x637f,0x6385,0x6387,0x6392,0x6394,0x6394,0x6396,0x6399,0x639b,0x63a5,0x63a7,0x63b1,0x63b9,0x63b9,0x63bd,0x63be,0x63c0,0x63d3,0x63d5,0x63eb,0x63ed,0x63f6,0x63f8,0x63f9,0x63fb,0x63fc,0x63fe,0x63fe,0x6406,0x6407,0x6409,0x6410,0x6412,0x6418,0x641a,0x641c,0x641e,0x6428,0x642a,0x6430,0x6432,0x643b,0x643d,0x6441,0x6443,0x6443,0x644b,0x644b,0x644d,0x644e,0x6450,0x6454,0x6458,0x6461,0x6465,0x6469,0x646b,0x647d,0x647f,0x647f,0x6482,0x6482,0x6485,0x6485,0x6487,0x648d,0x648f,0x6493,0x6495,0x649a,0x649c,0x64a0,0x64a2,0x64a6,0x64a9,0x64a9,0x64ab,0x64b4,0x64b6,0x64b6,0x64bb,0x64c5,0x64c7,0x64c7,0x64c9,0x64cb,0x64cd,0x64d0,0x64d2,0x64d4,0x64d6,0x64db,0x64dd,0x64dd,0x64e0,0x64ed,0x64ef,0x64f4,0x64f7,0x64f8,0x64fa,0x6501,0x6503,0x6504,0x6506,0x6507,0x6509,0x650a,0x650c,0x6511,0x6513,0x6519,0x651b,0x6526,0x6529,0x6530,0x6532,0x6539,0x653b,0x653b,0x653d,0x653f,0x6541,0x6541,0x6543,0x6543,0x6545,0x6546,0x6548,0x654a,0x654d,0x654d,0x654f,0x654f,0x6551,0x6551,0x6553,0x655a,0x655c,0x655f,0x6562,0x6568,0x656a,0x656d,0x656f,0x656f,0x6572,0x657c,0x657f,0x6589,0x658b,0x658c,0x6590,0x6592,0x6594,0x6597,0x6599,0x6599,0x659b,0x65a2,0x65a4,0x65a5,0x65a7,0x65a8,0x65aa,0x65ac,0x65ae,0x65b0,0x65b2,0x65b3,0x65b5,0x65b9,0x65bb,0x65bf,0x65c1,0x65c6,0x65cb,0x65d4,0x65d6,0x65d7,0x65da,0x65db,0x65dd,0x65e3,0x65e5,0x65e6,0x65e8,0x65e9,0x65ec,0x65f5,0x65fa,0x65fd,0x65ff,0x6600,0x6602,0x6615,0x6618,0x6618,0x661c,0x6628,0x662b,0x662b,0x662d,0x6636,0x6639,0x663a,0x6641,0x6645,0x6647,0x664d,0x664f,0x664f,0x6651,0x6653,0x6657,0x6657,0x6659,0x6668,0x666a,0x666c,0x666e,0x6674,0x6676,0x667e,0x6680,0x6680,0x6684,0x668e,0x6690,0x6692,0x6694,0x669a,0x669d,0x669d,0x669f,0x66a2,0x66a4,0x66a4,0x66a8,0x66ab,0x66ad,0x66bb,0x66bd,0x66c0,0x66c4,0x66c4,0x66c6,0x66cf,0x66d2,0x66d2,0x66d6,0x66d6,0x66d8,0x66de,0x66e0,0x66e0,0x66e3,0x66e4,0x66e6,0x66e9,0x66eb,0x66ee,0x66f0,0x66f4,0x66f6,0x66f9,0x66fc,0x66fc,0x66fe,0x6705,0x6708,0x6710,0x6712,0x6719,0x671b,0x671b,0x671d,0x6723,0x6725,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6736,0x6738,0x673f,0x6744,0x6749,0x674b,0x6751,0x6753,0x6753,0x6755,0x6757,0x6759,0x675a,0x675c,0x6762,0x6767,0x6767,0x676a,0x677f,0x6781,0x6787,0x6789,0x6789,0x678b,0x6795,0x6797,0x679a,0x679c,0x679d,0x679f,0x67a0,0x67a4,0x67a4,0x67ac,0x67ac,0x67ae,0x67bb,0x67bf,0x67c6,0x67c8,0x67d4,0x67d6,0x67df,0x67e2,0x67e7,0x67e9,0x67fa,0x67fc,0x67fc,0x67fe,0x6804,0x680d,0x680d,0x6810,0x6810,0x6812,0x6814,0x6816,0x6818,0x681a,0x6822,0x6825,0x6826,0x6828,0x682b,0x682d,0x682f,0x6831,0x683e,0x6840,0x6851,0x6853,0x6856,0x685d,0x685d,0x6865,0x6865,0x686b,0x686b,0x686d,0x686f,0x6871,0x6872,0x6874,0x6879,0x687b,0x688c,0x688f,0x6894,0x6896,0x6898,0x689b,0x689d,0x689f,0x68a4,0x68a6,0x68b6,0x68b9,0x68b9,0x68bd,0x68bd,0x68c1,0x68c1,0x68c3,0x68ce,0x68d0,0x68d8,0x68da,0x68da,0x68dc,0x68e1,0x68e3,0x68e4,0x68e6,0x68ec,0x68ee,0x68fd,0x6900,0x6915,0x6917,0x691b,0x6925,0x6925,0x692a,0x692a,0x692c,0x692c,0x692f,0x6930,0x6932,0x6939,0x693b,0x6946,0x6948,0x694c,0x694e,0x694f,0x6951,0x697b,0x6980,0x6980,0x6982,0x6983,0x6985,0x6986,0x698a,0x698a,0x698d,0x698e,0x6990,0x6991,0x6993,0x699c,0x699e,0x69b7,0x69b9,0x69b9,0x69bb,0x69c4,0x69c6,0x69c6,0x69c9,0x69d1,0x69d3,0x69d6,0x69d9,0x69d9,0x69e1,0x69e2,0x69e4,0x69e9,0x69eb,0x69ee,0x69f1,0x69f4,0x69f6,0x6a0d,0x6a0f,0x6a0f,0x6a11,0x6a11,0x6a13,0x6a21,0x6a23,0x6a23,0x6a25,0x6a29,0x6a2b,0x6a2d,0x6a32,0x6a35,0x6a38,0x6a41,0x6a43,0x6a49,0x6a4b,0x6a5b,0x6a5d,0x6a6b,0x6a6d,0x6a6d,0x6a6f,0x6a6f,0x6a71,0x6a71,0x6a74,0x6a74,0x6a76,0x6a76,0x6a7a,0x6a7a,0x6a7e,0x6a85,0x6a87,0x6a87,0x6a89,0x6a8a,0x6a8c,0x6a97,0x6a99,0x6aa8,0x6aab,0x6aaf,0x6ab1,0x6abb,0x6abd,0x6abe,0x6ac2,0x6ac3,0x6ac5,0x6acd,0x6acf,0x6ad1,0x6ad3,0x6ad4,0x6ad8,0x6ae1,0x6ae5,0x6ae5,0x6ae7,0x6ae8,0x6aea,0x6aec,0x6aee,0x6af1,0x6af3,0x6af3,0x6af6,0x6af6,0x6af8,0x6afc,0x6b00,0x6b00,0x6b02,0x6b05,0x6b08,0x6b0b,0x6b0f,0x6b13,0x6b16,0x6b1a,0x6b1d,0x6b1e,0x6b20,0x6b21,0x6b23,0x6b23,0x6b25,0x6b25,0x6b28,0x6b28,0x6b2c,0x6b2d,0x6b2f,0x6b2f,0x6b31,0x6b3f,0x6b41,0x6b43,0x6b45,0x6b4e,0x6b50,0x6b52,0x6b54,0x6b57,0x6b59,0x6b59,0x6b5b,0x6b5c,0x6b5e,0x6b67,0x6b6a,0x6b6a,0x6b6d,0x6b6d,0x6b6f,0x6b6f,0x6b72,0x6b72,0x6b74,0x6b74,0x6b76,0x6b7b,0x6b7e,0x6b84,0x6b86,0x6b86,0x6b88,0x6b8a,0x6b8c,0x6b8f,0x6b91,0x6b91,0x6b94,0x6b99,0x6b9b,0x6b9b,0x6b9e,0x6ba0,0x6ba2,0x6ba7,0x6baa,0x6bab,0x6bad,0x6bb0,0x6bb2,0x6bb3,0x6bb5,0x6bb7,0x6bba,0x6bba,0x6bbc,0x6bbd,0x6bbf,0x6bc1,0x6bc3,0x6bcd,0x6bcf,0x6bd0,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdc,0x6bde,0x6bde,0x6be0,0x6be4,0x6be6,0x6be8,0x6bea,0x6bec,0x6bef,0x6bf0,0x6bf2,0x6bf3,0x6bf7,0x6c06,0x6c08,0x6c09,0x6c0b,0x6c0d,0x6c0f,0x6c11,0x6c13,0x6c16,0x6c18,0x6c1d,0x6c1f,0x6c21,0x6c23,0x6c28,0x6c2a,0x6c2c,0x6c2e,0x6c3b,0x6c3d,0x6c43,0x6c46,0x6c46,0x6c49,0x6c50,0x6c52,0x6c52,0x6c54,0x6c55,0x6c57,0x6c61,0x6c65,0x6c6b,0x6c6d,0x6c76,0x6c78,0x6c7b,0x6c7d,0x6c90,0x6c92,0x6c96,0x6c98,0x6c9d,0x6c9f,0x6c9f,0x6ca2,0x6ca2,0x6caa,0x6cb4,0x6cb6,0x6cc7,0x6cc9,0x6cd7,0x6cd9,0x6ce3,0x6ce5,0x6ce5,0x6ce7,0x6cf3,0x6cf5,0x6cf5,0x6cf9,0x6cf9,0x6cff,0x6d12,0x6d16,0x6d1b,0x6d1d,0x6d20,0x6d22,0x6d22,0x6d24,0x6d42,0x6d4e,0x6d4e,0x6d57,0x6d5c,0x6d5e,0x6d6a,0x6d6c,0x6d72,0x6d74,0x6d98,0x6d9a,0x6d9a,0x6da4,0x6da5,0x6daa,0x6dac,0x6dae,0x6daf,0x6db1,0x6db5,0x6db7,0x6dc0,0x6dc2,0x6dc2,0x6dc4,0x6dcd,0x6dcf,0x6de6,0x6de8,0x6df7,0x6df9,0x6dfe,0x6e00,0x6e00,0x6e02,0x6e05,0x6e0a,0x6e0a,0x6e0f,0x6e0f,0x6e15,0x6e15,0x6e18,0x6e1d,0x6e1f,0x6e36,0x6e38,0x6e41,0x6e43,0x6e47,0x6e49,0x6e4b,0x6e4d,0x6e69,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e71,0x6e74,0x6e76,0x6e79,0x6e7c,0x6e7c,0x6e86,0x6e86,0x6e88,0x6e89,0x6e8b,0x6e8b,0x6e8d,0x6e90,0x6e92,0x6e94,0x6e96,0x6ea7,0x6eaa,0x6eab,0x6eae,0x6ed6,0x6ed8,0x6edd,0x6ee2,0x6ee2,0x6ee8,0x6ee9,0x6eeb,0x6eef,0x6ef1,0x6ef2,0x6ef4,0x6f0f,0x6f12,0x6f1a,0x6f1c,0x6f1c,0x6f1e,0x6f27,0x6f29,0x6f41,0x6f43,0x6f44,0x6f4e,0x6f58,0x6f5a,0x6f64,0x6f66,0x6f67,0x6f69,0x6f70,0x6f72,0x6f74,0x6f76,0x6f82,0x6f84,0x6f8e,0x6f90,0x6f90,0x6f92,0x6f97,0x6f9d,0x6fb6,0x6fb8,0x6fc4,0x6fc6,0x6fcf,0x6fd3,0x6fd5,0x6fd8,0x6fe4,0x6fe6,0x6fe9,0x6feb,0x6ff2,0x6ff4,0x6ff4,0x6ff6,0x6ff8,0x6ffa,0x6ffc,0x6ffe,0x7001,0x7003,0x7007,0x7009,0x700f,0x7011,0x7011,0x7014,0x7024,0x7026,0x702c,0x702f,0x7035,0x7037,0x703c,0x703e,0x7046,0x7048,0x704d,0x7050,0x7052,0x7054,0x7058,0x705a,0x706c,0x706e,0x7071,0x7074,0x707a,0x707c,0x707f,0x7081,0x7086,0x7089,0x708b,0x708e,0x708f,0x7091,0x7096,0x7098,0x709a,0x709f,0x70a1,0x70a3,0x70a7,0x70a9,0x70a9,0x70ab,0x70b1,0x70b3,0x70b5,0x70b7,0x70be,0x70c0,0x70c0,0x70c4,0x70c8,0x70ca,0x70da,0x70dc,0x70e2,0x70e4,0x70e4,0x70ef,0x70f1,0x70f3,0x7100,0x7102,0x7102,0x7104,0x7106,0x7109,0x710e,0x7110,0x7110,0x7113,0x7113,0x7117,0x7117,0x7119,0x7123,0x7125,0x7126,0x7128,0x7129,0x712b,0x712c,0x712e,0x7136,0x713a,0x713b,0x713e,0x713e,0x7140,0x7147,0x7149,0x7154,0x7156,0x715a,0x715c,0x716c,0x716e,0x716e,0x7170,0x7178,0x717a,0x717e,0x7180,0x7182,0x7184,0x718a,0x718c,0x718c,0x718e,0x7192,0x7194,0x7194,0x7196,0x71a5,0x71a7,0x71aa,0x71ac,0x71ad,0x71af,0x71b5,0x71b7,0x71ba,0x71bc,0x71cb,0x71ce,0x71d2,0x71d4,0x71d6,0x71d8,0x71dd,0x71df,0x71e2,0x71e4,0x71e8,0x71eb,0x71ee,0x71f0,0x71f2,0x71f4,0x71f6,0x71f8,0x71f9,0x71fb,0x7203,0x7205,0x7207,0x7209,0x720a,0x720c,0x7210,0x7213,0x7217,0x7219,0x721b,0x721d,0x721f,0x7222,0x722e,0x7230,0x7230,0x7235,0x7236,0x7238,0x723b,0x723d,0x7242,0x7244,0x7244,0x7246,0x724c,0x724f,0x7250,0x7252,0x7253,0x7255,0x7263,0x7266,0x7267,0x7269,0x726a,0x726c,0x726c,0x726e,0x7270,0x7272,0x7274,0x7276,0x7279,0x727b,0x7282,0x7284,0x7289,0x728b,0x7298,0x729a,0x729b,0x729d,0x729f,0x72a1,0x72aa,0x72ac,0x72b0,0x72b2,0x72b2,0x72b4,0x72b5,0x72ba,0x72ba,0x72bd,0x72bd,0x72bf,0x72c6,0x72c9,0x72ce,0x72d0,0x72d2,0x72d4,0x72d4,0x72d6,0x72da,0x72dc,0x72dc,0x72df,0x72e4,0x72e6,0x72e6,0x72e8,0x72eb,0x72f3,0x72f4,0x72f6,0x7302,0x7304,0x7304,0x7307,0x7308,0x730a,0x730c,0x730f,0x7313,0x7316,0x7319,0x731b,0x731e,0x7322,0x7323,0x7325,0x732e,0x7330,0x733c,0x733e,0x7345,0x7348,0x734a,0x734c,0x7352,0x7357,0x735b,0x735d,0x7362,0x7365,0x736c,0x736e,0x7378,0x737a,0x738c,0x738e,0x738f,0x7392,0x7398,0x739c,0x73a2,0x73a4,0x73ad,0x73b2,0x73bc,0x73be,0x73c0,0x73c2,0x73d0,0x73d2,0x73de,0x73e0,0x73eb,0x73ed,0x73ef,0x73f3,0x740d,0x7411,0x7412,0x7414,0x7417,0x7419,0x7426,0x7428,0x743a,0x743c,0x743c,0x743f,0x7457,0x7459,0x7465,0x7467,0x7476,0x7479,0x747a,0x747c,0x7483,0x7485,0x748d,0x7490,0x7490,0x7492,0x7492,0x7494,0x7495,0x7497,0x74a1,0x74a3,0x74ab,0x74ad,0x74ad,0x74af,0x74b2,0x74b4,0x74bb,0x74bd,0x74c3,0x74c5,0x74c6,0x74c8,0x74c8,0x74ca,0x74cc,0x74cf,0x74d0,0x74d3,0x74e9,0x74ec,0x74ec,0x74ee,0x74ee,0x74f0,0x74f2,0x74f4,0x74f8,0x74fb,0x74fb,0x74fd,0x7500,0x7502,0x7505,0x7507,0x7508,0x750b,0x751a,0x751c,0x751f,0x7521,0x7522,0x7525,0x7526,0x7528,0x7535,0x7537,0x753b,0x753d,0x7540,0x7542,0x7542,0x7546,0x7548,0x754a,0x754f,0x7551,0x7551,0x7553,0x7555,0x7559,0x755d,0x755f,0x7560,0x7562,0x7567,0x756a,0x7570,0x7572,0x7572,0x7576,0x757a,0x757d,0x7580,0x7583,0x7584,0x7586,0x7587,0x758a,0x7592,0x7594,0x7595,0x7598,0x759a,0x759d,0x759e,0x75a2,0x75a5,0x75a7,0x75a7,0x75aa,0x75ab,0x75b0,0x75b6,0x75b8,0x75c5,0x75c7,0x75c8,0x75ca,0x75d2,0x75d4,0x75d5,0x75d7,0x75e4,0x75e6,0x75e7,0x75ed,0x75ed,0x75ef,0x7603,0x7607,0x760d,0x760f,0x7611,0x7613,0x7616,0x7619,0x7629,0x762c,0x762d,0x762f,0x7635,0x7638,0x7638,0x763a,0x763d,0x7640,0x7640,0x7642,0x7643,0x7646,0x7649,0x764c,0x7654,0x7656,0x765a,0x765c,0x765c,0x765f,0x7662,0x7664,0x7667,0x7669,0x766a,0x766c,0x7676,0x7678,0x767f,0x7681,0x7682,0x7684,0x7684,0x7686,0x768b,0x768e,0x7690,0x7692,0x7693,0x7695,0x7696,0x7699,0x769e,0x76a1,0x76a1,0x76a4,0x76a6,0x76aa,0x76ab,0x76ad,0x76b0,0x76b4,0x76b5,0x76b7,0x76b8,0x76ba,0x76bb,0x76bd,0x76bf,0x76c2,0x76c6,0x76c8,0x76ca,0x76cc,0x76ce,0x76d2,0x76d4,0x76d6,0x76d6,0x76d9,0x76df,0x76e1,0x76e1,0x76e3,0x76e7,0x76e9,0x76ea,0x76ec,0x76f5,0x76f7,0x76fc,0x76fe,0x76fe,0x7701,0x7701,0x7703,0x7705,0x7707,0x770c,0x770e,0x7713,0x7715,0x7715,0x7719,0x771b,0x771d,0x7720,0x7722,0x7729,0x772b,0x772b,0x772d,0x772d,0x772f,0x772f,0x7731,0x773e,0x7740,0x7740,0x7743,0x7747,0x774a,0x774f,0x7752,0x7752,0x7754,0x7756,0x7758,0x775c,0x775e,0x7763,0x7765,0x776f,0x7772,0x7772,0x7777,0x7785,0x7787,0x7789,0x778b,0x778f,0x7791,0x7791,0x7793,0x7793,0x7795,0x7795,0x7797,0x77a3,0x77a5,0x77a5,0x77a7,0x77a8,0x77aa,0x77ad,0x77af,0x77b7,0x77b9,0x77bf,0x77c2,0x77c5,0x77c7,0x77c7,0x77c9,0x77d0,0x77d3,0x77d5,0x77d7,0x77de,0x77e0,0x77e0,0x77e2,0x77e3,0x77e5,0x77e9,0x77ec,0x77f4,0x77f7,0x77fe,0x7802,0x7803,0x7805,0x7806,0x7808,0x7809,0x780c,0x7814,0x7818,0x7818,0x781c,0x7823,0x7825,0x7835,0x7837,0x7839,0x783c,0x783d,0x7842,0x7845,0x7847,0x784e,0x7850,0x7854,0x785c,0x785e,0x7860,0x7860,0x7862,0x7862,0x7864,0x7866,0x7868,0x7871,0x7879,0x787c,0x787e,0x7881,0x7883,0x7889,0x788c,0x788f,0x7891,0x7891,0x7893,0x789a,0x789e,0x78a5,0x78a7,0x78ad,0x78af,0x78b4,0x78b6,0x78b6,0x78b8,0x78bc,0x78be,0x78be,0x78c1,0x78c1,0x78c3,0x78c5,0x78c7,0x78d5,0x78d7,0x78d8,0x78da,0x78db,0x78dd,0x78e5,0x78e7,0x78ea,0x78ec,0x78f5,0x78f7,0x78f7,0x78f9,0x78ff,0x7901,0x7902,0x7904,0x7906,0x7909,0x7909,0x790c,0x790c,0x790e,0x790e,0x7910,0x7914,0x7917,0x7917,0x7919,0x7919,0x791b,0x791e,0x7921,0x7921,0x7923,0x792f,0x7931,0x7936,0x7938,0x7942,0x7944,0x794c,0x794f,0x7965,0x7967,0x796b,0x796d,0x796d,0x7970,0x7974,0x7979,0x797a,0x797c,0x7983,0x7986,0x7988,0x798a,0x798b,0x798d,0x799d,0x799f,0x79a2,0x79a4,0x79ae,0x79b0,0x79b4,0x79b6,0x79bb,0x79bd,0x79c1,0x79c4,0x79c6,0x79c8,0x79d2,0x79d4,0x79d6,0x79d8,0x79d8,0x79dc,0x79e0,0x79e2,0x79e4,0x79e6,0x79e7,0x79e9,0x79ee,0x79f1,0x79f1,0x79f4,0x79f4,0x79f6,0x79f8,0x79fa,0x79fb,0x7a00,0x7a00,0x7a02,0x7a06,0x7a08,0x7a08,0x7a0a,0x7a0e,0x7a10,0x7a15,0x7a17,0x7a1c,0x7a1e,0x7a20,0x7a22,0x7a22,0x7a26,0x7a26,0x7a28,0x7a28,0x7a2a,0x7a32,0x7a37,0x7a37,0x7a39,0x7a40,0x7a43,0x7a4e,0x7a54,0x7a54,0x7a56,0x7a58,0x7a5a,0x7a5c,0x7a5f,0x7a62,0x7a65,0x7a65,0x7a67,0x7a69,0x7a6b,0x7a6e,0x7a70,0x7a72,0x7a74,0x7a76,0x7a78,0x7a7b,0x7a7d,0x7a81,0x7a83,0x7a8c,0x7a8f,0x7a99,0x7a9e,0x7aa0,0x7aa2,0x7aa3,0x7aa8,0x7aac,0x7aae,0x7ab8,0x7aba,0x7abc,0x7abe,0x7ac5,0x7ac7,0x7acb,0x7acf,0x7acf,0x7ad1,0x7ad1,0x7ad3,0x7ad3,0x7ad8,0x7add,0x7adf,0x7ae0,0x7ae2,0x7ae7,0x7ae9,0x7aeb,0x7aed,0x7aef,0x7af6,0x7af7,0x7af9,0x7b01,0x7b04,0x7b06,0x7b08,0x7b0c,0x7b0e,0x7b14,0x7b18,0x7b1b,0x7b1d,0x7b20,0x7b22,0x7b35,0x7b38,0x7b39,0x7b3b,0x7b3b,0x7b40,0x7b40,0x7b42,0x7b52,0x7b54,0x7b56,0x7b58,0x7b58,0x7b60,0x7b67,0x7b69,0x7b69,0x7b6c,0x7b78,0x7b7b,0x7b7b,0x7b82,0x7b82,0x7b84,0x7b85,0x7b87,0x7b88,0x7b8a,0x7b92,0x7b94,0x7b9d,0x7ba0,0x7ba4,0x7bac,0x7baf,0x7bb1,0x7bb2,0x7bb4,0x7bb5,0x7bb7,0x7bb9,0x7bbe,0x7bbe,0x7bc0,0x7bc1,0x7bc4,0x7bc7,0x7bc9,0x7bcc,0x7bce,0x7bd0,0x7bd4,0x7bd5,0x7bd8,0x7bec,0x7bf0,0x7bf4,0x7bf7,0x7c03,0x7c05,0x7c07,0x7c09,0x7c12,0x7c15,0x7c15,0x7c19,0x7c19,0x7c1b,0x7c23,0x7c25,0x7c2d,0x7c30,0x7c30,0x7c33,0x7c33,0x7c35,0x7c35,0x7c37,0x7c39,0x7c3b,0x7c40,0x7c42,0x7c45,0x7c47,0x7c4a,0x7c4c,0x7c4d,0x7c50,0x7c51,0x7c53,0x7c54,0x7c56,0x7c57,0x7c59,0x7c5d,0x7c5f,0x7c60,0x7c63,0x7c67,0x7c69,0x7c70,0x7c72,0x7c75,0x7c78,0x7c81,0x7c83,0x7c86,0x7c88,0x7c8a,0x7c8c,0x7c8e,0x7c91,0x7c92,0x7c94,0x7c98,0x7c9c,0x7c9c,0x7c9e,0x7c9f,0x7ca1,0x7ca3,0x7ca5,0x7ca8,0x7cac,0x7cac,0x7cae,0x7caf,0x7cb1,0x7cb5,0x7cb8,0x7cbf,0x7cc2,0x7cc3,0x7cc5,0x7cc5,0x7cc7,0x7cce,0x7cd0,0x7cd7,0x7cd9,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce6,0x7ce8,0x7cea,0x7cea,0x7cec,0x7cf9,0x7cfb,0x7cfe,0x7d00,0x7d22,0x7d25,0x7d25,0x7d28,0x7d29,0x7d2b,0x7d2c,0x7d2e,0x7d33,0x7d35,0x7d36,0x7d38,0x7d47,0x7d4a,0x7d4a,0x7d4d,0x7d56,0x7d58,0x7d58,0x7d5a,0x7d5f,0x7d61,0x7d63,0x7d66,0x7d6b,0x7d6d,0x7d73,0x7d79,0x7d7d,0x7d7f,0x7d81,0x7d83,0x7d86,0x7d88,0x7d89,0x7d8b,0x7d8f,0x7d91,0x7d97,0x7d9c,0x7da4,0x7da6,0x7db5,0x7db7,0x7dc2,0x7dc4,0x7dc7,0x7dc9,0x7dd0,0x7dd2,0x7dd4,0x7dd7,0x7de1,0x7de3,0x7dea,0x7dec,0x7dec,0x7dee,0x7df7,0x7df9,0x7dfe,0x7e03,0x7e03,0x7e07,0x7e17,0x7e1a,0x7e25,0x7e27,0x7e27,0x7e29,0x7e2b,0x7e2d,0x7e49,0x7e4c,0x7e4c,0x7e50,0x7e5c,0x7e5e,0x7e63,0x7e65,0x7e65,0x7e67,0x7e70,0x7e72,0x7e82,0x7e86,0x7e88,0x7e8a,0x7e8f,0x7e91,0x7e9c,0x7e9f,0x7e9f,0x7ea4,0x7ea4,0x7eac,0x7eac,0x7eba,0x7eba,0x7ec7,0x7ec7,0x7ecf,0x7ecf,0x7edf,0x7edf,0x7f06,0x7f06,0x7f36,0x7f3a,0x7f3d,0x7f41,0x7f43,0x7f45,0x7f47,0x7f55,0x7f58,0x7f58,0x7f5b,0x7f61,0x7f63,0x7f63,0x7f65,0x7f6e,0x7f70,0x7f73,0x7f75,0x7f7f,0x7f83,0x7f83,0x7f85,0x7f8f,0x7f91,0x7f97,0x7f9a,0x7f9e,0x7fa0,0x7fa9,0x7fac,0x7fc3,0x7fc5,0x7fc5,0x7fc7,0x7fc7,0x7fc9,0x7fd2,0x7fd4,0x7fd5,0x7fd7,0x7fd7,0x7fdb,0x7fe3,0x7fe5,0x7ff5,0x7ff7,0x8008,0x800b,0x8012,0x8014,0x8019,0x801b,0x8021,0x8024,0x8026,0x8028,0x802a,0x802c,0x802c,0x802e,0x8031,0x8033,0x8037,0x8039,0x8039,0x803b,0x803f,0x8043,0x8043,0x8046,0x8048,0x804a,0x804a,0x804f,0x8052,0x8054,0x8054,0x8056,0x8056,0x8058,0x8058,0x805a,0x805e,0x8061,0x8064,0x8066,0x8067,0x806c,0x806c,0x806f,0x8073,0x8075,0x8079,0x807d,0x8080,0x8082,0x8082,0x8084,0x8087,0x8089,0x808c,0x808f,0x8090,0x8092,0x8093,0x8095,0x8096,0x8098,0x809d,0x809f,0x809f,0x80a1,0x80a3,0x80a5,0x80a5,0x80a7,0x80a7,0x80a9,0x80ab,0x80ad,0x80af,0x80b1,0x80b2,0x80b4,0x80b8,0x80ba,0x80ba,0x80bc,0x80bd,0x80c2,0x80ca,0x80cc,0x80d1,0x80d4,0x80de,0x80e0,0x80e1,0x80e3,0x80e6,0x80e9,0x80e9,0x80ec,0x80ed,0x80ef,0x80f6,0x80f8,0x80fe,0x8100,0x8103,0x8105,0x810a,0x810c,0x810c,0x810e,0x810e,0x8112,0x8112,0x8114,0x811b,0x811d,0x811f,0x8121,0x8125,0x8127,0x8127,0x8129,0x812d,0x812f,0x8132,0x8134,0x8134,0x8137,0x8137,0x8139,0x813a,0x813d,0x813e,0x8142,0x8144,0x8146,0x8148,0x814a,0x8156,0x8159,0x815c,0x815e,0x815e,0x8160,0x8162,0x8164,0x8167,0x8169,0x8169,0x816b,0x8174,0x8176,0x817a,0x817c,0x817d,0x817f,0x8180,0x8182,0x8184,0x8186,0x818d,0x818f,0x818f,0x8193,0x8193,0x8195,0x8195,0x8197,0x81a0,0x81a2,0x81a3,0x81a5,0x81ac,0x81ae,0x81ae,0x81b0,0x81b7,0x81b9,0x81ca,0x81cc,0x81cd,0x81cf,0x81d2,0x81d5,0x81d5,0x81d7,0x81db,0x81dd,0x81ea,0x81ec,0x81ef,0x81f2,0x81f4,0x81f6,0x81fc,0x81fe,0x8202,0x8204,0x8205,0x8207,0x820d,0x8210,0x8212,0x8214,0x8216,0x8218,0x8218,0x821a,0x8222,0x8225,0x8226,0x8228,0x822d,0x822f,0x822f,0x8232,0x823a,0x823c,0x8240,0x8242,0x8242,0x8244,0x8245,0x8247,0x8247,0x8249,0x8249,0x824b,0x824b,0x824e,0x825c,0x825e,0x825f,0x8261,0x8266,0x8268,0x8269,0x826b,0x826f,0x8271,0x8272,0x8274,0x8280,0x8283,0x8285,0x8287,0x8287,0x828a,0x828b,0x828d,0x8294,0x8298,0x829b,0x829d,0x82b1,0x82b3,0x82c0,0x82c2,0x82c4,0x82ca,0x82ca,0x82cf,0x82d9,0x82db,0x82dc,0x82de,0x82e8,0x82ea,0x8309,0x830b,0x830d,0x8316,0x831e,0x8320,0x8320,0x8322,0x8322,0x8324,0x832d,0x832f,0x832f,0x8331,0x833d,0x833f,0x8345,0x8347,0x8354,0x8356,0x8357,0x8362,0x8363,0x8366,0x8366,0x836f,0x836f,0x8373,0x8378,0x837a,0x837f,0x8381,0x8381,0x8383,0x8383,0x8385,0x839e,0x83a0,0x83a0,0x83a2,0x83ac,0x83ae,0x83b0,0x83b9,0x83b9,0x83bd,0x83cf,0x83d1,0x83d1,0x83d3,0x83d9,0x83db,0x83e5,0x83e7,0x83f6,0x83f8,0x83ff,0x8401,0x8401,0x8403,0x8407,0x8409,0x8414,0x8416,0x8416,0x8418,0x8418,0x841b,0x841c,0x8420,0x8421,0x8423,0x8424,0x8426,0x8426,0x8429,0x8429,0x842b,0x8440,0x8442,0x844e,0x8450,0x8469,0x846b,0x847a,0x847d,0x8480,0x8482,0x8482,0x8484,0x8484,0x8486,0x8486,0x8488,0x8488,0x848d,0x8494,0x8496,0x84a4,0x84a7,0x84b2,0x84b4,0x84b4,0x84b6,0x84b6,0x84b8,0x84c2,0x84c4,0x84c7,0x84c9,0x84d4,0x84d6,0x84d7,0x84da,0x84db,0x84de,0x84de,0x84e1,0x84e2,0x84e4,0x84e5,0x84e7,0x84ec,0x84ee,0x84f4,0x84f6,0x8500,0x8502,0x851a,0x851c,0x8521,0x8523,0x8531,0x8533,0x8534,0x8538,0x8538,0x853b,0x853b,0x853d,0x853e,0x8540,0x854e,0x8551,0x855b,0x855d,0x8571,0x8573,0x8573,0x8575,0x857c,0x857e,0x857e,0x8580,0x8591,0x8593,0x85a4,0x85a6,0x85aa,0x85af,0x85b1,0x85b3,0x85ba,0x85bd,0x85c9,0x85cb,0x85cb,0x85cd,0x85d2,0x85d5,0x85da,0x85dc,0x85e6,0x85e8,0x85f2,0x85f4,0x85f4,0x85f6,0x8602,0x8604,0x8607,0x8609,0x860d,0x860f,0x8611,0x8613,0x8614,0x8616,0x861c,0x861e,0x862a,0x862c,0x862f,0x8631,0x8636,0x8638,0x863c,0x863e,0x8640,0x8642,0x8643,0x8645,0x8648,0x864b,0x864e,0x8650,0x8650,0x8652,0x8656,0x8659,0x8659,0x865b,0x865c,0x865e,0x865f,0x8661,0x8665,0x8667,0x8674,0x8677,0x8677,0x8679,0x867c,0x867e,0x867e,0x8685,0x8687,0x868a,0x868e,0x8690,0x869a,0x869c,0x869e,0x86a0,0x86a5,0x86a7,0x86aa,0x86ad,0x86ad,0x86af,0x86c9,0x86cb,0x86cc,0x86d0,0x86d1,0x86d3,0x86d4,0x86d6,0x86df,0x86e2,0x86e4,0x86e6,0x86e6,0x86e8,0x86ed,0x86ef,0x86ef,0x86f5,0x86fb,0x86fe,0x86fe,0x8700,0x870e,0x8711,0x8713,0x8715,0x8715,0x8718,0x871c,0x871e,0x871e,0x8720,0x872a,0x872c,0x872e,0x8730,0x8735,0x8737,0x8738,0x873a,0x873c,0x873e,0x8743,0x8746,0x8746,0x874c,0x8771,0x8773,0x877b,0x877d,0x877d,0x8781,0x8789,0x878b,0x878d,0x878f,0x8794,0x8796,0x8798,0x879a,0x879f,0x87a2,0x87a5,0x87a9,0x87c6,0x87c8,0x87cc,0x87ce,0x87ce,0x87d1,0x87d4,0x87d6,0x87e8,0x87ea,0x87ef,0x87f2,0x87f7,0x87f9,0x87fc,0x87fe,0x8806,0x8808,0x880d,0x880f,0x8811,0x8813,0x8819,0x881b,0x881d,0x881f,0x8833,0x8835,0x8839,0x883b,0x8846,0x8848,0x8848,0x884a,0x884f,0x8852,0x8853,0x8855,0x8857,0x8859,0x885b,0x885d,0x885e,0x8860,0x8865,0x8867,0x886b,0x886d,0x8872,0x8874,0x8877,0x8879,0x8879,0x887c,0x8884,0x8887,0x8889,0x888b,0x8893,0x8895,0x88a2,0x88a4,0x88a4,0x88a7,0x88a8,0x88aa,0x88ac,0x88ae,0x88ae,0x88b1,0x88b2,0x88b4,0x88ba,0x88bc,0x88c2,0x88c5,0x88c5,0x88c7,0x88c7,0x88c9,0x88d0,0x88d2,0x88d2,0x88d4,0x88df,0x88e1,0x88e1,0x88e6,0x88e8,0x88eb,0x88ec,0x88ee,0x8902,0x8905,0x8907,0x8909,0x890c,0x890e,0x890e,0x8910,0x891a,0x891e,0x891f,0x8921,0x8927,0x8929,0x8933,0x8935,0x8938,0x893b,0x893e,0x8941,0x8944,0x8946,0x8947,0x8949,0x8949,0x894b,0x894d,0x894f,0x8954,0x8956,0x8966,0x8969,0x896f,0x8971,0x8974,0x8976,0x8977,0x8979,0x897c,0x897e,0x8983,0x8985,0x898b,0x898f,0x898f,0x8991,0x8991,0x8993,0x8998,0x899b,0x899f,0x89a1,0x89a7,0x89a9,0x89aa,0x89ac,0x89af,0x89b2,0x89b2,0x89b6,0x89b7,0x89b9,0x89ba,0x89bc,0x89c1,0x89c6,0x89c6,0x89d2,0x89d6,0x89d9,0x89dd,0x89df,0x89e9,0x89eb,0x89ed,0x89f0,0x89f4,0x89f6,0x89f8,0x89fa,0x89fc,0x89fe,0x8a00,0x8a02,0x8a04,0x8a07,0x8a08,0x8a0a,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a13,0x8a15,0x8a18,0x8a1b,0x8a1f,0x8a22,0x8a23,0x8a25,0x8a25,0x8a27,0x8a27,0x8a29,0x8a2d,0x8a30,0x8a31,0x8a34,0x8a34,0x8a36,0x8a36,0x8a38,0x8a41,0x8a44,0x8a46,0x8a48,0x8a4a,0x8a4c,0x8a52,0x8a54,0x8a59,0x8a5b,0x8a5b,0x8a5e,0x8a5e,0x8a60,0x8a63,0x8a66,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a77,0x8a79,0x8a7c,0x8a7e,0x8a7f,0x8a81,0x8a87,0x8a8b,0x8a8d,0x8a8f,0x8a96,0x8a98,0x8a9a,0x8a9c,0x8a9c,0x8a9e,0x8a9e,0x8aa0,0x8aa1,0x8aa3,0x8aac,0x8aaf,0x8ab0,0x8ab2,0x8ab2,0x8ab4,0x8ab4,0x8ab6,0x8ab6,0x8ab8,0x8ac0,0x8ac2,0x8ac9,0x8acb,0x8acd,0x8acf,0x8acf,0x8ad1,0x8ae2,0x8ae4,0x8ae4,0x8ae6,0x8ae8,0x8aea,0x8aeb,0x8aed,0x8afc,0x8afe,0x8b02,0x8b04,0x8b08,0x8b0a,0x8b20,0x8b22,0x8b28,0x8b2a,0x8b31,0x8b33,0x8b33,0x8b35,0x8b37,0x8b39,0x8b43,0x8b45,0x8b5a,0x8b5c,0x8b60,0x8b62,0x8b63,0x8b65,0x8b6d,0x8b6f,0x8b70,0x8b74,0x8b74,0x8b77,0x8b7b,0x8b7d,0x8b86,0x8b88,0x8b88,0x8b8a,0x8b8c,0x8b8e,0x8b90,0x8b92,0x8b96,0x8b98,0x8b9c,0x8b9e,0x8ba0,0x8bbe,0x8bbe,0x8be2,0x8be2,0x8c37,0x8c37,0x8c39,0x8c39,0x8c3b,0x8c3f,0x8c41,0x8c43,0x8c45,0x8c51,0x8c54,0x8c57,0x8c5a,0x8c5a,0x8c5c,0x8c5d,0x8c5f,0x8c5f,0x8c61,0x8c62,0x8c64,0x8c66,0x8c68,0x8c6d,0x8c6f,0x8c73,0x8c75,0x8c7b,0x8c7d,0x8c7d,0x8c80,0x8c82,0x8c84,0x8c86,0x8c89,0x8c8a,0x8c8c,0x8c8d,0x8c8f,0x8c95,0x8c97,0x8ca5,0x8ca7,0x8cad,0x8caf,0x8cb0,0x8cb2,0x8cc5,0x8cc7,0x8cc8,0x8cca,0x8cca,0x8ccc,0x8ccd,0x8ccf,0x8ccf,0x8cd1,0x8cd7,0x8cd9,0x8cee,0x8cf0,0x8cf5,0x8cf7,0x8cfe,0x8d00,0x8d00,0x8d02,0x8d0d,0x8d0f,0x8d19,0x8d1b,0x8d1d,0x8d64,0x8d64,0x8d66,0x8d69,0x8d6b,0x8d70,0x8d72,0x8d74,0x8d76,0x8d7b,0x8d7d,0x8d7d,0x8d80,0x8d82,0x8d84,0x8d85,0x8d89,0x8d8a,0x8d8c,0x8d96,0x8d99,0x8d99,0x8d9b,0x8d9c,0x8d9f,0x8da1,0x8da3,0x8da3,0x8da5,0x8daf,0x8db2,0x8db7,0x8db9,0x8dba,0x8dbc,0x8dbc,0x8dbe,0x8dc3,0x8dc5,0x8dc8,0x8dcb,0x8dd1,0x8dd3,0x8ddd,0x8ddf,0x8de4,0x8de6,0x8dec,0x8dee,0x8df4,0x8dfa,0x8dfa,0x8dfc,0x8e07,0x8e09,0x8e0a,0x8e0d,0x8e2b,0x8e2d,0x8e2e,0x8e30,0x8e31,0x8e33,0x8e36,0x8e38,0x8e3a,0x8e3c,0x8e42,0x8e44,0x8e50,0x8e53,0x8e57,0x8e59,0x8e6a,0x8e6c,0x8e6d,0x8e6f,0x8e6f,0x8e71,0x8e78,0x8e7a,0x8e7c,0x8e7e,0x8e7e,0x8e80,0x8e82,0x8e84,0x8e8e,0x8e90,0x8e98,0x8e9a,0x8e9a,0x8e9d,0x8ea1,0x8ea3,0x8ead,0x8eb0,0x8eb0,0x8eb2,0x8eb2,0x8eb6,0x8eb6,0x8eb9,0x8eba,0x8ebc,0x8ebd,0x8ec0,0x8ec0,0x8ec2,0x8ec3,0x8ec9,0x8ecf,0x8ed1,0x8ed4,0x8ed7,0x8ed8,0x8eda,0x8ee2,0x8ee4,0x8ee9,0x8eeb,0x8eef,0x8ef1,0x8ef2,0x8ef4,0x8efc,0x8efe,0x8f03,0x8f05,0x8f0b,0x8f0d,0x8f0e,0x8f10,0x8f20,0x8f23,0x8f26,0x8f29,0x8f2a,0x8f2c,0x8f30,0x8f32,0x8f39,0x8f3b,0x8f3c,0x8f3e,0x8f4b,0x8f4d,0x8f64,0x8f66,0x8f67,0x8f6e,0x8f6e,0x8f93,0x8f93,0x8f9b,0x8f9c,0x8f9f,0x8fa0,0x8fa3,0x8fa3,0x8fa5,0x8fa8,0x8fad,0x8fbc,0x8fbe,0x8fbf,0x8fc1,0x8fc2,0x8fc4,0x8fc6,0x8fc9,0x8fd7,0x8fda,0x8fda,0x8fe0,0x8fe6,0x8fe8,0x8fe8,0x8fea,0x8feb,0x8fed,0x8fee,0x8ff0,0x8ff0,0x8ff4,0x9006,0x9008,0x9008,0x900b,0x900d,0x900f,0x9012,0x9014,0x9017,0x9019,0x9024,0x902d,0x902f,0x9031,0x9038,0x903c,0x903f,0x9041,0x9042,0x9044,0x9044,0x9046,0x9047,0x9049,0x9056,0x9058,0x9059,0x905b,0x905e,0x9060,0x9064,0x9067,0x9069,0x906b,0x9070,0x9072,0x9088,0x908a,0x908b,0x908d,0x908d,0x908f,0x9091,0x9094,0x9095,0x9097,0x9099,0x909b,0x909b,0x909e,0x90a3,0x90a5,0x90a8,0x90aa,0x90aa,0x90ae,0x90b6,0x90b8,0x90b8,0x90bb,0x90bb,0x90bd,0x90bf,0x90c1,0x90c1,0x90c3,0x90c5,0x90c7,0x90c8,0x90ca,0x90cb,0x90ce,0x90ce,0x90d4,0x90dd,0x90df,0x90e5,0x90e8,0x90ed,0x90ef,0x90f5,0x90f9,0x9109,0x910b,0x910b,0x910d,0x9112,0x9114,0x9114,0x9116,0x9124,0x9126,0x9136,0x9138,0x913b,0x913e,0x9141,0x9143,0x9153,0x9155,0x915a,0x915c,0x915c,0x915e,0x9165,0x9167,0x916a,0x916c,0x916c,0x916e,0x9170,0x9172,0x917a,0x917c,0x917c,0x9180,0x9187,0x9189,0x9193,0x9196,0x9196,0x9199,0x91a3,0x91a5,0x91a5,0x91a7,0x91b7,0x91b9,0x91be,0x91c0,0x91c7,0x91c9,0x91c9,0x91cb,0x91d1,0x91d3,0x91da,0x91dc,0x91dd,0x91df,0x91df,0x91e2,0x91ee,0x91f1,0x91f1,0x91f3,0x91fa,0x91fd,0x920a,0x920c,0x921a,0x921c,0x921c,0x921e,0x921e,0x9221,0x9221,0x9223,0x9228,0x922a,0x922b,0x922d,0x922e,0x9230,0x923a,0x923c,0x9241,0x9244,0x9246,0x9248,0x9258,0x925a,0x925b,0x925d,0x9267,0x926b,0x9270,0x9272,0x9272,0x9276,0x928f,0x9291,0x9291,0x9293,0x929d,0x92a0,0x92ac,0x92ae,0x92ae,0x92b1,0x92b7,0x92b9,0x92bc,0x92be,0x92d5,0x92d7,0x92d9,0x92db,0x92db,0x92dd,0x92e1,0x92e3,0x92f4,0x92f6,0x9304,0x9306,0x9309,0x930b,0x9310,0x9312,0x9316,0x9318,0x931b,0x931d,0x9331,0x9333,0x9336,0x9338,0x9339,0x933c,0x933c,0x9340,0x9352,0x9354,0x935c,0x935e,0x936e,0x9370,0x9371,0x9373,0x937e,0x9380,0x938a,0x938c,0x9392,0x9394,0x93aa,0x93ac,0x93b5,0x93b7,0x93b8,0x93bb,0x93bb,0x93bd,0x93bd,0x93bf,0x93c0,0x93c2,0x93c4,0x93c6,0x93c8,0x93ca,0x93e4,0x93e6,0x93e8,0x93ec,0x93ec,0x93ee,0x93ee,0x93f0,0x93f1,0x93f3,0x9401,0x9403,0x9404,0x9406,0x9419,0x941b,0x941b,0x941d,0x941d,0x9420,0x9420,0x9424,0x9433,0x9435,0x9440,0x9442,0x944d,0x944f,0x9452,0x9454,0x9455,0x9457,0x9458,0x945b,0x945b,0x945d,0x945e,0x9460,0x9460,0x9462,0x9465,0x9467,0x9479,0x947b,0x9483,0x9485,0x9485,0x949f,0x949f,0x94a2,0x94a2,0x94c1,0x94c1,0x94c3,0x94c3,0x94dc,0x94dc,0x94f6,0x94f6,0x952d,0x952d,0x9547,0x9547,0x9577,0x9578,0x957a,0x957d,0x957f,0x9580,0x9582,0x9583,0x9585,0x9586,0x9588,0x9589,0x958b,0x9594,0x9596,0x9599,0x959b,0x959c,0x959e,0x95ae,0x95b0,0x95b2,0x95b5,0x95b7,0x95b9,0x95c0,0x95c3,0x95c3,0x95c5,0x95cd,0x95d0,0x95d6,0x95da,0x95dc,0x95de,0x95e5,0x95e8,0x95e8,0x95f4,0x95f4,0x961c,0x961e,0x9620,0x9624,0x9628,0x9628,0x962a,0x962a,0x962c,0x9633,0x9638,0x963d,0x963f,0x9645,0x964a,0x9651,0x9653,0x9654,0x9656,0x9656,0x9658,0x9658,0x965b,0x965f,0x9661,0x9664,0x9669,0x966d,0x966f,0x9678,0x967b,0x967e,0x9680,0x9681,0x9683,0x968b,0x968d,0x968f,0x9691,0x9699,0x969b,0x969c,0x969e,0x969e,0x96a1,0x96a5,0x96a7,0x96aa,0x96ac,0x96ac,0x96ae,0x96ae,0x96b0,0x96b1,0x96b3,0x96b4,0x96b6,0x96b6,0x96b8,0x96b9,0x96bb,0x96bd,0x96bf,0x96ce,0x96d2,0x96df,0x96e1,0x96e3,0x96e5,0x96e5,0x96e8,0x96ea,0x96ef,0x96f2,0x96f4,0x96fb,0x96fd,0x96fd,0x96ff,0x9700,0x9702,0x9709,0x970b,0x970b,0x970d,0x9713,0x9716,0x9716,0x9718,0x9719,0x971b,0x972c,0x972e,0x9732,0x9734,0x9736,0x9738,0x973a,0x973d,0x9744,0x9746,0x974b,0x9751,0x9752,0x9755,0x9758,0x975a,0x9762,0x9766,0x9766,0x9768,0x976a,0x976c,0x976e,0x9770,0x9774,0x9776,0x9778,0x977a,0x9785,0x9787,0x978b,0x978d,0x978f,0x9794,0x9794,0x9797,0x97a6,0x97a8,0x97a8,0x97aa,0x97ae,0x97b1,0x97b4,0x97b6,0x97bb,0x97bd,0x97c9,0x97cb,0x97d0,0x97d2,0x97d9,0x97dc,0x97e1,0x97e3,0x97e3,0x97e5,0x97e6,0x97ed,0x97ee,0x97f0,0x97f3,0x97f5,0x97f6,0x97f8,0x97fb,0x97fd,0x9808,0x980a,0x980a,0x980c,0x9818,0x981b,0x9821,0x9823,0x9824,0x9826,0x9829,0x982b,0x982b,0x982d,0x9830,0x9832,0x9835,0x9837,0x9839,0x983b,0x983b,0x9841,0x9841,0x9843,0x9853,0x9856,0x9859,0x985b,0x9860,0x9862,0x986c,0x986f,0x9875,0x98a8,0x98a9,0x98ac,0x98af,0x98b1,0x98b4,0x98b6,0x98c4,0x98c6,0x98cc,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e3,0x98e5,0x98e7,0x98e9,0x98ed,0x98ef,0x98ef,0x98f1,0x98f2,0x98f4,0x98f6,0x98f9,0x98fa,0x98fc,0x98fe,0x9900,0x9900,0x9902,0x9903,0x9905,0x9905,0x9907,0x990a,0x990c,0x990c,0x990e,0x990e,0x9910,0x991c,0x991e,0x991f,0x9921,0x9921,0x9924,0x9925,0x9927,0x9933,0x9935,0x9935,0x9937,0x9943,0x9945,0x9945,0x9947,0x994e,0x9950,0x9959,0x995b,0x995f,0x9961,0x9963,0x9996,0x9999,0x999b,0x999e,0x99a1,0x99a1,0x99a3,0x99a8,0x99aa,0x99b5,0x99b8,0x99bd,0x99c1,0x99c5,0x99c7,0x99c7,0x99c9,0x99c9,0x99cb,0x99dd,0x99df,0x99e7,0x99e9,0x99ea,0x99ec,0x99ee,0x99f0,0x99f1,0x99f4,0x99ff,0x9a01,0x9a07,0x9a09,0x9a11,0x9a14,0x9a16,0x9a19,0x9a27,0x9a29,0x9a32,0x9a34,0x9a46,0x9a48,0x9a4a,0x9a4c,0x9a50,0x9a52,0x9a5c,0x9a5e,0x9a60,0x9a62,0x9a6c,0x9a8f,0x9a8f,0x9aa8,0x9aa8,0x9aab,0x9aab,0x9aad,0x9aad,0x9aaf,0x9ab4,0x9ab6,0x9ac2,0x9ac6,0x9ac7,0x9aca,0x9aca,0x9acd,0x9acd,0x9acf,0x9ad8,0x9adc,0x9adc,0x9adf,0x9ae3,0x9ae6,0x9ae7,0x9aeb,0x9aef,0x9af1,0x9af4,0x9af6,0x9af7,0x9af9,0x9aff,0x9b01,0x9b06,0x9b08,0x9b12,0x9b14,0x9b1a,0x9b1e,0x9b20,0x9b22,0x9b25,0x9b27,0x9b2b,0x9b2d,0x9b2f,0x9b31,0x9b35,0x9b37,0x9b37,0x9b39,0x9b3c,0x9b3e,0x9b46,0x9b48,0x9b48,0x9b4a,0x9b52,0x9b54,0x9b56,0x9b58,0x9b5b,0x9b5f,0x9b61,0x9b64,0x9b64,0x9b66,0x9b69,0x9b6c,0x9b6c,0x9b6f,0x9b71,0x9b74,0x9b77,0x9b7a,0x9b83,0x9b85,0x9b88,0x9b8b,0x9b8b,0x9b8d,0x9b93,0x9b95,0x9b95,0x9b97,0x9b97,0x9b9a,0x9b9b,0x9b9d,0x9ba2,0x9ba4,0x9ba6,0x9ba8,0x9ba8,0x9baa,0x9bab,0x9bad,0x9bb0,0x9bb5,0x9bb6,0x9bb8,0x9bb9,0x9bbd,0x9bbd,0x9bbf,0x9bc1,0x9bc3,0x9bc4,0x9bc6,0x9bca,0x9bcf,0x9bcf,0x9bd3,0x9bd7,0x9bd9,0x9bde,0x9be0,0x9be2,0x9be4,0x9bed,0x9bf0,0x9bf1,0x9bf4,0x9bf4,0x9bf7,0x9bf8,0x9bfd,0x9bfd,0x9bff,0x9bff,0x9c02,0x9c02,0x9c05,0x9c0e,0x9c10,0x9c10,0x9c12,0x9c15,0x9c17,0x9c17,0x9c1b,0x9c1d,0x9c1f,0x9c21,0x9c23,0x9c26,0x9c28,0x9c29,0x9c2b,0x9c2d,0x9c2f,0x9c2f,0x9c31,0x9c37,0x9c39,0x9c41,0x9c44,0x9c50,0x9c52,0x9c59,0x9c5d,0x9c60,0x9c62,0x9c63,0x9c66,0x9c68,0x9c6d,0x9c6e,0x9c71,0x9c75,0x9c77,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9cea,0x9ced,0x9ced,0x9cf1,0x9cf7,0x9cf9,0x9cfd,0x9cff,0x9d00,0x9d02,0x9d09,0x9d0c,0x9d0c,0x9d10,0x9d10,0x9d12,0x9d12,0x9d14,0x9d19,0x9d1b,0x9d1b,0x9d1d,0x9d23,0x9d25,0x9d26,0x9d28,0x9d29,0x9d2d,0x9d31,0x9d33,0x9d34,0x9d36,0x9d39,0x9d3b,0x9d3b,0x9d3d,0x9d45,0x9d49,0x9d4c,0x9d4e,0x9d54,0x9d56,0x9d61,0x9d67,0x9d75,0x9d77,0x9d79,0x9d7b,0x9d8c,0x9d90,0x9d90,0x9d92,0x9d94,0x9d96,0x9dad,0x9daf,0x9daf,0x9db1,0x9dc5,0x9dc7,0x9ddf,0x9de1,0x9de6,0x9de8,0x9de9,0x9deb,0x9df0,0x9df2,0x9e07,0x9e09,0x9e15,0x9e17,0x9e1f,0x9e75,0x9e75,0x9e79,0x9e7d,0x9e7f,0x9e8e,0x9e90,0x9ea2,0x9ea4,0x9eb1,0x9eb4,0x9eb7,0x9ebb,0x9ec4,0x9ec6,0x9ec8,0x9ecc,0x9ed1,0x9ed3,0x9ed6,0x9ed8,0x9ed8,0x9eda,0x9ee0,0x9ee2,0x9ee2,0x9ee4,0x9ee8,0x9eeb,0x9eeb,0x9eed,0x9f02,0x9f06,0x9f0a,0x9f0e,0x9f10,0x9f12,0x9f13,0x9f15,0x9f1c,0x9f1e,0x9f1e,0x9f20,0x9f20,0x9f22,0x9f39,0x9f3b,0x9f3b,0x9f3d,0x9f3e,0x9f40,0x9f50,0x9f52,0x9f67,0x9f69,0x9f6c,0x9f6e,0x9f72,0x9f74,0x9f7b,0x9f7e,0x9f7f,0x9f8d,0x9f8e,0x9f90,0x9f92,0x9f94,0x9f99,0x9f9c,0x9f9c,0x9f9f,0x9fa0,0x9fa2,0x9fa2,0x9fa4,0x9fb3,0x9fc7,0x9fcb,0x9fd0,0x9fd0,0xf900,0xf903,0xf905,0xf907,0xf90b,0xf90b,0xf90d,0xf90d,0xf915,0xf915,0xf917,0xf917,0xf91a,0xf91a,0xf922,0xf922,0xf92d,0xf92d,0xf931,0xf931,0xf937,0xf937,0xf939,0xf93a,0xf943,0xf943,0xf947,0xf948,0xf94a,0xf94a,0xf952,0xf952,0xf95e,0xf95e,0xf962,0xf962,0xf965,0xf965,0xf967,0xf967,0xf972,0xf972,0xf976,0xf976,0xf978,0xf979,0xf97e,0xf97e,0xf980,0xf980,0xf986,0xf986,0xf98a,0xf98a,0xf98e,0xf98e,0xf995,0xf995,0xf99c,0xf99c,0xf99f,0xf99f,0xf9b5,0xf9b5,0xf9bb,0xf9bb,0xf9bd,0xf9bd,0xf9c5,0xf9c6,0xf9c8,0xf9c8,0xf9d8,0xf9d8,0xf9dc,0xf9de,0xf9e0,0xf9e0,0xf9e4,0xf9e4,0xf9e7,0xf9e7,0xf9e9,0xf9e9,0xf9f4,0xf9f5,0xf9fa,0xf9fa,0xf9fd,0xf9fd,0xf9ff,0xf9ff,0xfa02,0xfa02,0xfa05,0xfa08,0xfa0a,0xfa0a,0xfa0c,0xfa0d,0xfa33,0xfa35,0xfa3a,0xfa3a,0xfa49,0xfa49,0xfa4b,0xfa4b,0xfa5d,0xfa5e,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x20021,0x20021,0x2003e,0x2003e,0x20046,0x20046,0x2004e,0x2004e,0x20068,0x20068,0x20086,0x20087,0x2008a,0x2008a,0x20094,0x20094,0x200ca,0x200cd,0x200d1,0x200d1,0x200ee,0x200ee,0x2010c,0x2010c,0x2010e,0x2010e,0x20118,0x20118,0x201a4,0x201a4,0x201a9,0x201a9,0x201ab,0x201ab,0x201c1,0x201c1,0x201d4,0x201d4,0x201f2,0x201f2,0x20204,0x20204,0x2020c,0x2020c,0x20214,0x20214,0x20239,0x20239,0x2025b,0x2025b,0x20274,0x20275,0x20299,0x20299,0x2029e,0x2029e,0x202a0,0x202a0,0x202b7,0x202b7,0x202bf,0x202c0,0x202e5,0x202e5,0x2030a,0x2030a,0x20325,0x20325,0x20341,0x20341,0x20345,0x20347,0x2037e,0x20380,0x203a0,0x203a0,0x203a7,0x203a7,0x203b5,0x203b5,0x203c9,0x203c9,0x203cb,0x203cb,0x203f5,0x203f5,0x203fc,0x203fc,0x20413,0x20414,0x2041f,0x2041f,0x20465,0x20465,0x20487,0x20487,0x2048e,0x2048e,0x20491,0x20492,0x204a3,0x204a3,0x204d7,0x204d7,0x204fc,0x204fc,0x204fe,0x204fe,0x20547,0x20547,0x2058e,0x2058e,0x205a5,0x205a5,0x205b3,0x205b3,0x205c3,0x205c3,0x205ca,0x205ca,0x205d0,0x205d0,0x205d5,0x205d5,0x205df,0x205e0,0x205eb,0x205eb,0x20611,0x20611,0x20615,0x20615,0x20619,0x2061a,0x20628,0x20628,0x20630,0x20630,0x20656,0x20656,0x20676,0x20676,0x2070e,0x2070e,0x20731,0x20731,0x20779,0x20779,0x2082c,0x2082c,0x20873,0x20873,0x208d5,0x208d5,0x20916,0x20916,0x20923,0x20923,0x20954,0x20954,0x20979,0x20979,0x209e7,0x209e7,0x20a11,0x20a11,0x20a50,0x20a50,0x20a6f,0x20a6f,0x20a8a,0x20a8a,0x20ab4,0x20ab4,0x20ac2,0x20ac2,0x20acd,0x20acd,0x20b0d,0x20b0d,0x20b8f,0x20b8f,0x20b9f,0x20b9f,0x20ba8,0x20ba9,0x20bbf,0x20bbf,0x20bc6,0x20bc6,0x20bcb,0x20bcb,0x20be2,0x20be2,0x20beb,0x20beb,0x20bfb,0x20bfb,0x20bff,0x20bff,0x20c0b,0x20c0b,0x20c0d,0x20c0d,0x20c20,0x20c20,0x20c34,0x20c34,0x20c3a,0x20c3b,0x20c41,0x20c43,0x20c53,0x20c53,0x20c65,0x20c65,0x20c77,0x20c78,0x20c7c,0x20c7c,0x20c8d,0x20c8d,0x20c96,0x20c96,0x20c9c,0x20c9c,0x20cb5,0x20cb5,0x20cb8,0x20cb8,0x20ccf,0x20ccf,0x20cd3,0x20cd6,0x20cdd,0x20cdd,0x20ced,0x20ced,0x20cff,0x20cff,0x20d15,0x20d15,0x20d28,0x20d28,0x20d31,0x20d32,0x20d46,0x20d49,0x20d4c,0x20d4e,0x20d6f,0x20d6f,0x20d71,0x20d71,0x20d74,0x20d74,0x20d7c,0x20d7c,0x20d7e,0x20d7f,0x20d96,0x20d96,0x20d9c,0x20d9c,0x20da7,0x20da7,0x20db2,0x20db2,0x20dc8,0x20dc8,0x20e04,0x20e04,0x20e09,0x20e0a,0x20e0d,0x20e11,0x20e16,0x20e16,0x20e1d,0x20e1d,0x20e4c,0x20e4c,0x20e6d,0x20e6d,0x20e73,0x20e73,0x20e75,0x20e7b,0x20e8c,0x20e8c,0x20e96,0x20e96,0x20e98,0x20e98,0x20e9d,0x20e9d,0x20ea2,0x20ea2,0x20eaa,0x20eac,0x20eb6,0x20eb6,0x20ed7,0x20ed8,0x20edd,0x20edd,0x20ef8,0x20efb,0x20f1d,0x20f1d,0x20f26,0x20f26,0x20f2d,0x20f2e,0x20f30,0x20f31,0x20f3b,0x20f3b,0x20f4c,0x20f4c,0x20f64,0x20f64,0x20f8d,0x20f8d,0x20f90,0x20f90,0x20fad,0x20fad,0x20fb4,0x20fb6,0x20fbc,0x20fbc,0x20fdf,0x20fdf,0x20fea,0x20fed,0x21014,0x21014,0x2101d,0x2101e,0x2104f,0x2104f,0x2105c,0x2105c,0x2106f,0x2106f,0x21075,0x21078,0x2107b,0x2107b,0x21088,0x21088,0x21096,0x21096,0x2109d,0x2109d,0x210b4,0x210b4,0x210bf,0x210c1,0x210c7,0x210c9,0x210cf,0x210cf,0x210d3,0x210d3,0x210e4,0x210e4,0x210f4,0x210f6,0x2112f,0x2112f,0x2113b,0x2113b,0x2113d,0x2113d,0x21145,0x21145,0x21148,0x21148,0x2114f,0x2114f,0x21180,0x21180,0x21187,0x21187,0x211d9,0x211d9,0x2123c,0x2123c,0x2124f,0x2124f,0x2127c,0x2127c,0x212a8,0x212a9,0x212b0,0x212b0,0x212e3,0x212e3,0x212fe,0x212fe,0x21302,0x21305,0x21336,0x21336,0x2133a,0x2133a,0x21375,0x21376,0x2138e,0x2138e,0x21398,0x21398,0x2139c,0x2139c,0x213c5,0x213c6,0x213ed,0x213ed,0x213fe,0x213fe,0x21413,0x21413,0x21416,0x21416,0x21424,0x21424,0x2143f,0x2143f,0x21452,0x21452,0x21454,0x21455,0x2148a,0x2148a,0x21497,0x21497,0x214b6,0x214b6,0x214e8,0x214e8,0x214fd,0x214fd,0x21577,0x21577,0x21582,0x21582,0x21596,0x21596,0x2160a,0x2160a,0x21613,0x21613,0x21619,0x21619,0x2163e,0x2163e,0x21661,0x21661,0x21692,0x21692,0x216b8,0x216b8,0x216ba,0x216ba,0x216c0,0x216c2,0x216d3,0x216d3,0x216d5,0x216d5,0x216df,0x216df,0x216e6,0x216e8,0x216fa,0x216fc,0x216fe,0x216fe,0x2170d,0x2170d,0x21710,0x21710,0x21726,0x21726,0x2173a,0x2173c,0x21757,0x21757,0x2176c,0x21771,0x21773,0x21774,0x217ab,0x217ab,0x217b0,0x217b5,0x217c3,0x217c3,0x217c7,0x217c7,0x217d9,0x217dc,0x217df,0x217df,0x217ef,0x217ef,0x217f5,0x217f6,0x217f8,0x217fc,0x21820,0x21820,0x21828,0x2182a,0x2182d,0x2182d,0x21839,0x2183b,0x21840,0x21840,0x21845,0x21845,0x21852,0x21852,0x2185e,0x2185e,0x21861,0x21864,0x21877,0x21877,0x2187b,0x2187b,0x21883,0x21885,0x2189e,0x218a2,0x218be,0x218bf,0x218d1,0x218d1,0x218d6,0x218d9,0x218fa,0x218fa,0x21903,0x21905,0x21910,0x21912,0x21915,0x21915,0x2191c,0x2191c,0x21922,0x21922,0x21927,0x21927,0x2193b,0x2193b,0x21944,0x21944,0x21958,0x21958,0x2196a,0x2196a,0x2197c,0x2197c,0x21980,0x21980,0x21983,0x21983,0x21988,0x21988,0x21996,0x21996,0x219db,0x219db,0x219f3,0x219f3,0x21a2d,0x21a2d,0x21a34,0x21a34,0x21a45,0x21a45,0x21a4b,0x21a4b,0x21a63,0x21a63,0x21b44,0x21b44,0x21bc1,0x21bc2,0x21c2a,0x21c2a,0x21c70,0x21c70,0x21ca2,0x21ca2,0x21ca5,0x21ca5,0x21cac,0x21cac,0x21d46,0x21d46,0x21d53,0x21d53,0x21d5e,0x21d5e,0x21d90,0x21d90,0x21db6,0x21db6,0x21dba,0x21dba,0x21dca,0x21dca,0x21dd1,0x21dd1,0x21deb,0x21deb,0x21df9,0x21df9,0x21e1c,0x21e1c,0x21e23,0x21e23,0x21e37,0x21e37,0x21e3d,0x21e3d,0x21e89,0x21e89,0x21ea4,0x21ea4,0x21ea8,0x21ea8,0x21ec8,0x21ec8,0x21ed5,0x21ed5,0x21f0f,0x21f0f,0x21f15,0x21f15,0x21f6a,0x21f6a,0x21f9e,0x21f9e,0x21fa1,0x21fa1,0x21fe8,0x21fe8,0x22045,0x22045,0x22049,0x22049,0x2207e,0x2207e,0x2209a,0x2209a,0x220c7,0x220c7,0x220fc,0x220fc,0x2212a,0x2212a,0x2215b,0x2215b,0x22173,0x22173,0x2217a,0x2217a,0x221a1,0x221a1,0x221c1,0x221c1,0x221c3,0x221c3,0x22208,0x22208,0x2227c,0x2227c,0x22321,0x22321,0x22325,0x22325,0x223bd,0x223bd,0x223d0,0x223d0,0x223d7,0x223d7,0x223fa,0x223fa,0x22465,0x22465,0x22471,0x22471,0x2248b,0x2248b,0x22491,0x22491,0x224b0,0x224b0,0x224bc,0x224bc,0x224c1,0x224c1,0x224c9,0x224c9,0x224cc,0x224cc,0x224ed,0x224ed,0x22513,0x22513,0x2251b,0x2251b,0x22530,0x22530,0x22554,0x22554,0x2258d,0x2258d,0x225af,0x225af,0x225be,0x225be,0x2261b,0x2261c,0x2262b,0x2262b,0x22668,0x22668,0x2267a,0x2267a,0x22696,0x22696,0x22698,0x22698,0x226f4,0x226f6,0x22712,0x22712,0x22714,0x22714,0x2271b,0x2271b,0x2271f,0x2271f,0x2272a,0x2272a,0x22775,0x22775,0x22781,0x22781,0x22796,0x22796,0x227b4,0x227b5,0x227cd,0x227cd,0x22803,0x22803,0x2285f,0x22860,0x22871,0x22871,0x228ad,0x228ad,0x228c1,0x228c1,0x228f7,0x228f7,0x22926,0x22926,0x22939,0x22939,0x2294f,0x2294f,0x22967,0x22967,0x2296b,0x2296b,0x22980,0x22980,0x22993,0x22993,0x22a66,0x22a66,0x22acf,0x22acf,0x22ad5,0x22ad5,0x22ae6,0x22ae6,0x22ae8,0x22ae8,0x22b0e,0x22b0e,0x22b22,0x22b22,0x22b3f,0x22b3f,0x22b43,0x22b43,0x22b6a,0x22b6a,0x22bca,0x22bca,0x22bce,0x22bce,0x22c26,0x22c27,0x22c38,0x22c38,0x22c4c,0x22c4c,0x22c51,0x22c51,0x22c55,0x22c55,0x22c62,0x22c62,0x22c88,0x22c88,0x22c9b,0x22c9b,0x22ca1,0x22ca1,0x22ca9,0x22ca9,0x22cb2,0x22cb2,0x22cb7,0x22cb7,0x22cc2,0x22cc2,0x22cc6,0x22cc6,0x22cc9,0x22cc9,0x22d07,0x22d08,0x22d12,0x22d12,0x22d44,0x22d44,0x22d4c,0x22d4c,0x22d67,0x22d67,0x22d8d,0x22d8d,0x22d95,0x22d95,0x22da0,0x22da0,0x22da3,0x22da4,0x22db7,0x22db7,0x22dee,0x22dee,0x22e0d,0x22e0d,0x22e36,0x22e36,0x22e42,0x22e42,0x22e78,0x22e78,0x22e8b,0x22e8b,0x22eb3,0x22eb3,0x22eef,0x22eef,0x22f74,0x22f74,0x22fcc,0x22fcc,0x22fe3,0x22fe3,0x23033,0x23033,0x23044,0x23044,0x2304b,0x2304b,0x23066,0x23066,0x2307d,0x2307e,0x2308e,0x2308e,0x230b7,0x230b7,0x230bc,0x230bc,0x230da,0x230da,0x23103,0x23103,0x2313d,0x2313d,0x2317d,0x2317d,0x23182,0x23182,0x231a4,0x231a5,0x231b3,0x231b3,0x231c8,0x231c9,0x231ea,0x231ea,0x231f7,0x231f9,0x2320f,0x2320f,0x23225,0x23225,0x2322f,0x2322f,0x23231,0x23234,0x23256,0x23256,0x2325e,0x2325e,0x23262,0x23262,0x23281,0x23281,0x23289,0x2328a,0x232ab,0x232ad,0x232d2,0x232d2,0x232e0,0x232e1,0x23300,0x23300,0x2330a,0x2330a,0x2331f,0x2331f,0x233b4,0x233b4,0x233cc,0x233cc,0x233de,0x233de,0x233e6,0x233e6,0x233f4,0x233f5,0x233f9,0x233fa,0x233fe,0x233fe,0x23400,0x23400,0x2343f,0x2343f,0x23450,0x23450,0x2346f,0x2346f,0x23472,0x23472,0x234e5,0x234e5,0x23519,0x23519,0x23530,0x23530,0x23551,0x23551,0x2355a,0x2355a,0x23567,0x23567,0x23595,0x23595,0x23599,0x23599,0x2359c,0x2359c,0x235bb,0x235bb,0x235cd,0x235cf,0x235f3,0x235f3,0x23600,0x23600,0x23617,0x23617,0x2361a,0x2361a,0x2363c,0x2363c,0x23640,0x23640,0x23659,0x23659,0x2365f,0x2365f,0x23677,0x23677,0x2368e,0x2368e,0x2369e,0x2369e,0x236a6,0x236a6,0x236ad,0x236ad,0x236ba,0x236ba,0x236df,0x236df,0x236ee,0x236ee,0x23703,0x23703,0x23716,0x23716,0x23720,0x23720,0x2372d,0x2372d,0x2372f,0x2372f,0x2373f,0x2373f,0x23766,0x23766,0x23781,0x23781,0x237a2,0x237a2,0x237bc,0x237bc,0x237c2,0x237c2,0x237d5,0x237d7,0x2383a,0x2383a,0x239c2,0x239c2,0x23aa7,0x23aa7,0x23adb,0x23adb,0x23aee,0x23aee,0x23afa,0x23afa,0x23b1a,0x23b1a,0x23b5a,0x23b5a,0x23c63,0x23c63,0x23c99,0x23c9b,0x23cb5,0x23cb5,0x23cb7,0x23cb7,0x23cc7,0x23cc9,0x23cfc,0x23cff,0x23d40,0x23d40,0x23d5b,0x23d5b,0x23d7e,0x23d7e,0x23d8f,0x23d8f,0x23db6,0x23dbd,0x23de3,0x23de3,0x23df8,0x23df8,0x23e06,0x23e06,0x23e11,0x23e11,0x23e2c,0x23e31,0x23e39,0x23e39,0x23e88,0x23e8b,0x23eb9,0x23eb9,0x23ebf,0x23ebf,0x23ed7,0x23ed7,0x23ef7,0x23efc,0x23f35,0x23f35,0x23f41,0x23f41,0x23f4a,0x23f4a,0x23f61,0x23f61,0x23f7f,0x23f82,0x23f8f,0x23f8f,0x23fb4,0x23fb4,0x23fb7,0x23fb7,0x23fc0,0x23fc0,0x23fc5,0x23fc5,0x23feb,0x23ff0,0x24011,0x24011,0x24039,0x2403d,0x24057,0x24057,0x24085,0x24085,0x2408b,0x2408d,0x24091,0x24091,0x240c9,0x240c9,0x240e1,0x240e1,0x240ec,0x240ec,0x24104,0x24104,0x2410f,0x2410f,0x24119,0x24119,0x2413f,0x24140,0x24144,0x24144,0x2414e,0x2414e,0x24155,0x24157,0x2415c,0x2415c,0x2415f,0x2415f,0x24161,0x24161,0x24177,0x24177,0x2417a,0x2417a,0x241a3,0x241a5,0x241ac,0x241ac,0x241b5,0x241b5,0x241cd,0x241cd,0x241e2,0x241e2,0x241fc,0x241fc,0x2421b,0x2421b,0x2424b,0x2424b,0x24256,0x24256,0x24259,0x24259,0x24276,0x24278,0x24284,0x24284,0x24293,0x24293,0x24295,0x24295,0x242a5,0x242a5,0x242bf,0x242bf,0x242c1,0x242c1,0x242c9,0x242ca,0x242ee,0x242ee,0x242fa,0x242fa,0x2430d,0x2430d,0x2431a,0x2431a,0x24334,0x24334,0x24348,0x24348,0x24362,0x24365,0x2438c,0x2438c,0x24396,0x24396,0x2439c,0x2439c,0x243bd,0x243bd,0x243c1,0x243c1,0x243e9,0x243ea,0x243f2,0x243f2,0x243f8,0x243f8,0x24404,0x24404,0x24435,0x24436,0x2445a,0x2445b,0x24473,0x24473,0x24487,0x24488,0x244b9,0x244b9,0x244bc,0x244bc,0x244ce,0x244ce,0x244d3,0x244d3,0x244d6,0x244d6,0x24505,0x24505,0x24521,0x24521,0x24578,0x24578,0x245c8,0x245c8,0x24618,0x24618,0x2462a,0x2462a,0x24665,0x24665,0x24674,0x24674,0x24697,0x24697,0x246d4,0x246d4,0x24706,0x24706,0x24725,0x24725,0x2472f,0x2472f,0x2478f,0x2478f,0x247e0,0x247e0,0x24812,0x24812,0x24823,0x24823,0x24882,0x24882,0x248e9,0x248e9,0x248f0,0x248f3,0x248fb,0x248fb,0x248ff,0x24901,0x2490c,0x2490c,0x24916,0x24917,0x24919,0x24919,0x2492f,0x2492f,0x24933,0x24934,0x2493e,0x24943,0x24962,0x24963,0x24974,0x24976,0x2497b,0x2497b,0x2497f,0x2497f,0x24982,0x24982,0x24988,0x2498f,0x24994,0x24994,0x249a4,0x249a4,0x249a7,0x249a7,0x249a9,0x249a9,0x249ab,0x249ad,0x249b7,0x249bb,0x249c5,0x249c5,0x249d0,0x249d0,0x249da,0x249da,0x249de,0x249df,0x249e3,0x249e3,0x249e5,0x249e5,0x249ec,0x249ed,0x249f6,0x249f9,0x249fb,0x249fb,0x24a0e,0x24a0e,0x24a12,0x24a13,0x24a15,0x24a15,0x24a21,0x24a2a,0x24a3e,0x24a3e,0x24a42,0x24a42,0x24a45,0x24a45,0x24a4a,0x24a4a,0x24a4e,0x24a51,0x24a5d,0x24a5d,0x24a65,0x24a67,0x24a71,0x24a71,0x24a77,0x24a7a,0x24a8c,0x24a8c,0x24a93,0x24a96,0x24aa4,0x24aa7,0x24ab1,0x24ab3,0x24aba,0x24abc,0x24ac0,0x24ac0,0x24ac7,0x24ac7,0x24aca,0x24aca,0x24ad1,0x24ad1,0x24adf,0x24adf,0x24ae2,0x24ae2,0x24ae9,0x24ae9,0x24b0f,0x24b0f,0x24b6e,0x24b6e,0x24bf5,0x24bf5,0x24c09,0x24c09,0x24c9e,0x24c9f,0x24cc9,0x24cc9,0x24cd9,0x24cd9,0x24d06,0x24d06,0x24d13,0x24d13,0x24db8,0x24db8,0x24dea,0x24deb,0x24e3b,0x24e3b,0x24e50,0x24e50,0x24ea5,0x24ea5,0x24ea7,0x24ea7,0x24f0e,0x24f0e,0x24f5c,0x24f5c,0x24f82,0x24f82,0x24f86,0x24f86,0x24f97,0x24f97,0x24f9a,0x24f9a,0x24fa9,0x24fa9,0x24fb8,0x24fb8,0x24fc2,0x24fc2,0x2502c,0x2502c,0x25052,0x25052,0x2509d,0x2509d,0x2512b,0x2512b,0x25148,0x25148,0x2517d,0x2517e,0x251cd,0x251cd,0x251e3,0x251e3,0x251e6,0x251e7,0x25220,0x25221,0x25250,0x25250,0x25299,0x25299,0x252c7,0x252c7,0x252d8,0x252d8,0x2530e,0x2530e,0x25311,0x25311,0x25313,0x25313,0x25419,0x25419,0x25425,0x25425,0x2542f,0x25430,0x25446,0x25446,0x2546c,0x2546c,0x2546e,0x2546e,0x2549a,0x2549a,0x25531,0x25531,0x25535,0x25535,0x2553f,0x2553f,0x2555b,0x2555e,0x25562,0x25562,0x25565,0x25566,0x25581,0x25581,0x25584,0x25584,0x2558f,0x2558f,0x255b9,0x255b9,0x255d5,0x255d5,0x255db,0x255db,0x255e0,0x255e0,0x25605,0x25605,0x25635,0x25635,0x25651,0x25651,0x25683,0x25683,0x25695,0x25695,0x256e3,0x256e3,0x256f6,0x256f6,0x25706,0x25706,0x2571d,0x2571d,0x25725,0x25725,0x2573d,0x2573d,0x25772,0x25772,0x257c7,0x257c7,0x257df,0x257e1,0x25857,0x25857,0x2585d,0x2585d,0x25872,0x25872,0x258c8,0x258c8,0x258de,0x258de,0x258e1,0x258e1,0x25903,0x25903,0x25946,0x25946,0x25956,0x25956,0x259ac,0x259ac,0x259cc,0x259cc,0x25a54,0x25a54,0x25a95,0x25a95,0x25a9c,0x25a9c,0x25aae,0x25aaf,0x25ad7,0x25ad7,0x25ae9,0x25ae9,0x25b74,0x25b74,0x25b89,0x25b89,0x25bb3,0x25bb4,0x25bc6,0x25bc6,0x25be4,0x25be4,0x25be8,0x25be8,0x25c01,0x25c01,0x25c06,0x25c06,0x25c21,0x25c21,0x25c4a,0x25c4a,0x25c65,0x25c65,0x25c91,0x25c91,0x25ca4,0x25ca4,0x25cc0,0x25cc1,0x25cfe,0x25cfe,0x25d20,0x25d20,0x25d30,0x25d30,0x25d43,0x25d43,0x25d99,0x25d99,0x25db9,0x25db9,0x25e0e,0x25e0e,0x25e49,0x25e49,0x25e81,0x25e83,0x25ea6,0x25ea6,0x25ebc,0x25ebc,0x25ed7,0x25ed8,0x25f1a,0x25f1a,0x25f4b,0x25f4b,0x25fe1,0x25fe2,0x26021,0x26021,0x26029,0x26029,0x26048,0x26048,0x26064,0x26064,0x26083,0x26083,0x26097,0x26097,0x260a4,0x260a5,0x26102,0x26102,0x26121,0x26121,0x26159,0x2615c,0x261ad,0x261ae,0x261b2,0x261b2,0x261dd,0x261dd,0x26258,0x26258,0x26261,0x26261,0x2626a,0x2626b,0x262d0,0x262d0,0x26335,0x26335,0x2634b,0x2634c,0x26351,0x26351,0x263be,0x263be,0x263f5,0x263f5,0x263f8,0x263f8,0x26402,0x26402,0x26410,0x26412,0x2644a,0x2644a,0x26469,0x26469,0x26484,0x26484,0x26488,0x26489,0x2648d,0x2648d,0x26498,0x26498,0x26512,0x26512,0x26572,0x26572,0x265a0,0x265a0,0x265ad,0x265ad,0x265bf,0x265bf,0x26612,0x26612,0x26626,0x26626,0x266af,0x266af,0x266b1,0x266b1,0x266b5,0x266b5,0x266da,0x266da,0x266e8,0x266e8,0x266fc,0x266fc,0x26716,0x26716,0x26741,0x26741,0x26799,0x26799,0x267b3,0x267b4,0x267cc,0x267cc,0x2681c,0x2681c,0x26846,0x26846,0x2685e,0x2685e,0x2686e,0x2686e,0x26888,0x26888,0x2688a,0x2688a,0x26893,0x26893,0x268c7,0x268c7,0x2690e,0x2690e,0x26911,0x26911,0x26926,0x26926,0x26939,0x26939,0x26951,0x26951,0x269a8,0x269a8,0x269b5,0x269b5,0x269f2,0x269f2,0x269fa,0x269fa,0x26a2d,0x26a2e,0x26a34,0x26a34,0x26a42,0x26a42,0x26a51,0x26a52,0x26b05,0x26b05,0x26b0a,0x26b0a,0x26b13,0x26b13,0x26b15,0x26b15,0x26b23,0x26b23,0x26b28,0x26b28,0x26b50,0x26b53,0x26b5b,0x26b5b,0x26b75,0x26b75,0x26b82,0x26b82,0x26b96,0x26b97,0x26b9d,0x26b9d,0x26bb3,0x26bb3,0x26bc0,0x26bc0,0x26bf7,0x26bf7,0x26c21,0x26c21,0x26c40,0x26c41,0x26c46,0x26c46,0x26c7e,0x26c82,0x26ca4,0x26ca4,0x26cb7,0x26cb8,0x26cbd,0x26cbd,0x26cc0,0x26cc0,0x26cc3,0x26cc3,0x26cd1,0x26cd1,0x26d22,0x26d2a,0x26d51,0x26d51,0x26d74,0x26d74,0x26da0,0x26da7,0x26dae,0x26dae,0x26ddc,0x26ddc,0x26dea,0x26deb,0x26df0,0x26df0,0x26e00,0x26e00,0x26e05,0x26e05,0x26e07,0x26e07,0x26e12,0x26e12,0x26e42,0x26e45,0x26e6e,0x26e6e,0x26e72,0x26e72,0x26e77,0x26e77,0x26e84,0x26e84,0x26e88,0x26e88,0x26e8b,0x26e8b,0x26e99,0x26e99,0x26ed0,0x26ed7,0x26f26,0x26f26,0x26f73,0x26f74,0x26f9f,0x26f9f,0x26fa1,0x26fa1,0x26fbe,0x26fbe,0x26fde,0x26fdf,0x2700e,0x2700e,0x2704b,0x2704b,0x27052,0x27053,0x27088,0x27088,0x270ad,0x270af,0x270cd,0x270cd,0x270d2,0x270d2,0x270f0,0x270f0,0x270f8,0x270f8,0x27109,0x27109,0x2710c,0x2710d,0x27126,0x27127,0x27164,0x27165,0x27175,0x27175,0x271cd,0x271cd,0x2721b,0x2721b,0x27267,0x27267,0x27280,0x27280,0x27285,0x27285,0x2728b,0x2728b,0x272b2,0x272b2,0x272b6,0x272b6,0x272e6,0x272e6,0x27352,0x27352,0x2739a,0x2739a,0x273ff,0x273ff,0x27422,0x27422,0x27450,0x27450,0x27484,0x27484,0x27486,0x27486,0x27574,0x27574,0x275a3,0x275a3,0x275e0,0x275e0,0x275e4,0x275e4,0x275fd,0x275fe,0x27607,0x27607,0x2760c,0x2760c,0x27632,0x27632,0x27639,0x27639,0x27655,0x27657,0x27694,0x27694,0x2770f,0x2770f,0x27735,0x27736,0x27741,0x27741,0x2775e,0x2775e,0x27784,0x27785,0x277cc,0x277cc,0x27858,0x27858,0x27870,0x27870,0x2789d,0x2789d,0x278b2,0x278b2,0x278c8,0x278c8,0x27924,0x27924,0x27967,0x27967,0x2797a,0x2797a,0x279a0,0x279a0,0x279dd,0x279dd,0x279fd,0x279fd,0x27a0a,0x27a0a,0x27a0e,0x27a0e,0x27a3e,0x27a3e,0x27a53,0x27a53,0x27a59,0x27a59,0x27a79,0x27a79,0x27a84,0x27a84,0x27abd,0x27abe,0x27af4,0x27af4,0x27b06,0x27b06,0x27b0b,0x27b0b,0x27b18,0x27b18,0x27b38,0x27b3a,0x27b48,0x27b48,0x27b65,0x27b65,0x27bef,0x27bef,0x27bf4,0x27bf4,0x27c12,0x27c12,0x27c6c,0x27c6c,0x27cb1,0x27cb1,0x27cc5,0x27cc5,0x27d2f,0x27d2f,0x27d53,0x27d54,0x27d66,0x27d66,0x27d73,0x27d73,0x27d84,0x27d84,0x27d8f,0x27d8f,0x27d98,0x27d98,0x27dbd,0x27dbd,0x27ddc,0x27ddc,0x27e4d,0x27e4d,0x27e4f,0x27e4f,0x27f2e,0x27f2e,0x27fb7,0x27fb7,0x27ff9,0x27ff9,0x28002,0x28002,0x28009,0x28009,0x2801e,0x2801e,0x28023,0x28024,0x28048,0x28048,0x28083,0x28083,0x28090,0x28090,0x280bd,0x280be,0x280e8,0x280e9,0x280f4,0x280f4,0x2812e,0x2812e,0x2814f,0x2814f,0x2815d,0x2815d,0x2816f,0x2816f,0x28189,0x28189,0x281af,0x281af,0x281bc,0x281bc,0x28207,0x28207,0x28218,0x28218,0x2821a,0x2821a,0x28256,0x28256,0x2827c,0x2827c,0x2829b,0x2829b,0x282cd,0x282cd,0x282e2,0x282e2,0x28306,0x28306,0x28318,0x28318,0x2832f,0x2832f,0x2833a,0x2833a,0x28365,0x28365,0x2836d,0x2836d,0x2837d,0x2837d,0x2838a,0x2838a,0x28412,0x28412,0x28468,0x28468,0x2846c,0x2846c,0x28473,0x28473,0x28482,0x28482,0x28501,0x28501,0x2853c,0x2853d,0x2856c,0x2856c,0x285e8,0x285e8,0x285f4,0x285f4,0x28600,0x28600,0x2860b,0x2860b,0x28625,0x28625,0x2863b,0x2863b,0x286aa,0x286ab,0x286b2,0x286b2,0x286bc,0x286bc,0x286d8,0x286d8,0x286e6,0x286e6,0x2870f,0x2870f,0x28713,0x28713,0x28804,0x28804,0x2882b,0x2882b,0x2890d,0x2890d,0x28933,0x28933,0x28948,0x28949,0x28956,0x28956,0x28964,0x28964,0x28968,0x28968,0x2896c,0x2896d,0x2897e,0x2897e,0x28989,0x28989,0x289a8,0x289a8,0x289aa,0x289ab,0x289b8,0x289b8,0x289bc,0x289bc,0x289c0,0x289c0,0x289dc,0x289dc,0x289de,0x289de,0x289e1,0x289e1,0x289e3,0x289e4,0x289e7,0x289e8,0x289f9,0x289fc,0x28a0f,0x28a0f,0x28a16,0x28a16,0x28a25,0x28a25,0x28a29,0x28a29,0x28a32,0x28a32,0x28a36,0x28a36,0x28a44,0x28a4b,0x28a59,0x28a5a,0x28a81,0x28a83,0x28a9a,0x28a9c,0x28ac0,0x28ac0,0x28ac6,0x28ac6,0x28acb,0x28acc,0x28ace,0x28ace,0x28ade,0x28ae3,0x28ae5,0x28ae5,0x28aea,0x28aea,0x28afc,0x28afc,0x28b0c,0x28b0c,0x28b13,0x28b13,0x28b21,0x28b22,0x28b2b,0x28b2d,0x28b2f,0x28b2f,0x28b46,0x28b46,0x28b4c,0x28b4c,0x28b4e,0x28b4e,0x28b50,0x28b50,0x28b63,0x28b66,0x28b6c,0x28b6c,0x28b8f,0x28b8f,0x28b99,0x28b99,0x28b9c,0x28b9d,0x28bb9,0x28bb9,0x28bc2,0x28bc2,0x28bc5,0x28bc5,0x28bd4,0x28bd4,0x28bd7,0x28bd7,0x28bd9,0x28bda,0x28be7,0x28bec,0x28bf5,0x28bf5,0x28bff,0x28bff,0x28c03,0x28c03,0x28c09,0x28c09,0x28c1c,0x28c1d,0x28c23,0x28c23,0x28c26,0x28c26,0x28c2b,0x28c2b,0x28c30,0x28c30,0x28c39,0x28c39,0x28c3b,0x28c3b,0x28cca,0x28cca,0x28ccd,0x28ccd,0x28cd2,0x28cd2,0x28d34,0x28d34,0x28d99,0x28d99,0x28db9,0x28db9,0x28e0f,0x28e0f,0x28e36,0x28e36,0x28e39,0x28e39,0x28e65,0x28e66,0x28e97,0x28e97,0x28eac,0x28eac,0x28eb2,0x28eb3,0x28ed9,0x28ed9,0x28ee7,0x28ee7,0x28fc5,0x28fc5,0x29079,0x29079,0x29088,0x29088,0x2908b,0x2908b,0x29093,0x29093,0x290af,0x290b1,0x290c0,0x290c0,0x290e4,0x290e5,0x290ec,0x290ed,0x2910d,0x2910d,0x29110,0x29110,0x2913c,0x2913c,0x2914d,0x2914d,0x2915b,0x2915b,0x2915e,0x2915e,0x29170,0x29170,0x2919c,0x2919c,0x291a8,0x291a8,0x291d5,0x291d5,0x291eb,0x291eb,0x2941d,0x2941d,0x29420,0x29420,0x29433,0x29433,0x2943f,0x2943f,0x29448,0x29448,0x294d0,0x294d0,0x294d9,0x294da,0x294e5,0x294e5,0x294e7,0x294e7,0x2959e,0x2959e,0x295b0,0x295b0,0x295b8,0x295b8,0x295d7,0x295d7,0x295e9,0x295e9,0x295f4,0x295f4,0x2967f,0x2967f,0x29720,0x29720,0x29732,0x29732,0x297d4,0x297d4,0x29810,0x29810,0x29857,0x29857,0x298a4,0x298a4,0x298d1,0x298d1,0x298ea,0x298ea,0x298f1,0x298f1,0x298fa,0x298fa,0x29903,0x29903,0x29905,0x29905,0x2992f,0x2992f,0x29945,0x29945,0x29947,0x29949,0x2995d,0x2995d,0x2996a,0x2996a,0x2999d,0x2999d,0x299c3,0x299c3,0x299c9,0x299c9,0x29a28,0x29a28,0x29a4d,0x29a4d,0x29b05,0x29b05,0x29b0e,0x29b0e,0x29bd5,0x29bd5,0x29c73,0x29c73,0x29cad,0x29cad,0x29d3e,0x29d3e,0x29d5a,0x29d5a,0x29d7c,0x29d7c,0x29d98,0x29d98,0x29d9b,0x29d9b,0x29df6,0x29df6,0x29e06,0x29e06,0x29e2d,0x29e2d,0x29e68,0x29e68,0x29eac,0x29eac,0x29eb0,0x29eb0,0x29ec3,0x29ec3,0x29ef8,0x29ef8,0x29f23,0x29f23,0x29f30,0x29f30,0x29fb7,0x29fb7,0x29fde,0x29fde,0x2a014,0x2a014,0x2a087,0x2a087,0x2a0b9,0x2a0b9,0x2a0e1,0x2a0e1,0x2a0ed,0x2a0ed,0x2a0f3,0x2a0f3,0x2a0f8,0x2a0f8,0x2a0fe,0x2a0fe,0x2a107,0x2a107,0x2a123,0x2a123,0x2a133,0x2a134,0x2a150,0x2a150,0x2a192,0x2a193,0x2a1ab,0x2a1ab,0x2a1b4,0x2a1b5,0x2a1df,0x2a1df,0x2a1f5,0x2a1f5,0x2a220,0x2a220,0x2a233,0x2a233,0x2a293,0x2a293,0x2a29f,0x2a29f,0x2a2b2,0x2a2b2,0x2a2b4,0x2a2b4,0x2a2b6,0x2a2b6,0x2a2ba,0x2a2ba,0x2a2bd,0x2a2bd,0x2a2df,0x2a2df,0x2a2ff,0x2a2ff,0x2a351,0x2a351,0x2a3a9,0x2a3a9,0x2a3ed,0x2a3ed,0x2a434,0x2a434,0x2a45b,0x2a45b,0x2a5c6,0x2a5c6,0x2a5cb,0x2a5cb,0x2a601,0x2a601,0x2a632,0x2a632,0x2a64a,0x2a64a,0x2a65b,0x2a65b,0x2a6a9,0x2a6a9,0x2adff,0x2adff,0x2d544,0x2d544,0x2f825,0x2f825,0x2f83b,0x2f83b,0x2f840,0x2f840,0x2f878,0x2f878,0x2f894,0x2f894,0x2f8a6,0x2f8a6,0x2f8cd,0x2f8cd,0x2f8db,0x2f8db,0x2f994,0x2f994,0x2f9b2,0x2f9b2,0x2f9bc,0x2f9bc,0x2f9d4,0x2f9d4,0x30edd,0x30ede,0x3106c,0x3106c,]), - NotoFont.fromFlatRanges('Noto Sans Tagalog', 'http://fonts.gstatic.com/s/notosanstagalog/v15/J7aFnoNzCnFcV9ZI-sUYuvote1R0wwEAA8jHexnL.ttf', [0x20,0x20,0xa0,0xa0,0x1700,0x170c,0x170e,0x1714,0x1735,0x1736,0x200b,0x200d,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Tagbanwa', 'http://fonts.gstatic.com/s/notosanstagbanwa/v15/Y4GWYbB8VTEp4t3MKJSMmQdIKjRtt_nZRjQEaYpGoQ.ttf', [0x20,0x20,0xa0,0xa0,0x1735,0x1736,0x1760,0x176c,0x176e,0x1770,0x1772,0x1773,0x200b,0x200d,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Tai Le', 'http://fonts.gstatic.com/s/notosanstaile/v15/vEFK2-VODB8RrNDvZSUmVxEATwR58tK1W77HtMo.ttf', [0x20,0x20,0xa0,0xa0,0x300,0x301,0x307,0x308,0x30c,0x30c,0x1040,0x1049,0x1950,0x196d,0x1970,0x1974,0x200b,0x200d,0x25cc,0x25cc,0x3001,0x3002,0x3008,0x300b,]), - NotoFont.fromFlatRanges('Noto Sans Tai Tham', 'http://fonts.gstatic.com/s/notosanstaitham/v17/kJEbBv0U4hgtwxDUw2x9q7tbjLIfbPGHBoaVSAZ3MdLJBCUbPgquyaRGKMw.ttf', [0x20,0x20,0xa0,0xa0,0x1a20,0x1a5e,0x1a60,0x1a7c,0x1a7f,0x1a89,0x1a90,0x1a99,0x1aa0,0x1aad,0x200b,0x200d,0x2219,0x2219,]), - NotoFont.fromFlatRanges('Noto Sans Tai Viet', 'http://fonts.gstatic.com/s/notosanstaiviet/v15/8QIUdj3HhN_lv4jf9vsE-9GMOLsaSPZr644fWsRO9w.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa78b,0xa78c,0xaa80,0xaac2,0xaadb,0xaadf,]), - NotoFont.fromFlatRanges('Noto Sans Takri', 'http://fonts.gstatic.com/s/notosanstakri/v15/TuGJUVpzXI5FBtUq5a8bnKIOdTwQNO_W3khJXg.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x965,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11680,0x116b8,0x116c0,0x116c9,]), - NotoFont.fromFlatRanges('Noto Sans Tamil', 'http://fonts.gstatic.com/s/notosanstamil/v21/ieVc2YdFI3GCY6SyQy1KfStzYKZgzN1z4LKDbeZce-0429tBManUktuex7vGo70RqKDt_EvT.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xb82,0xb83,0xb85,0xb8a,0xb8e,0xb90,0xb92,0xb95,0xb99,0xb9a,0xb9c,0xb9c,0xb9e,0xb9f,0xba3,0xba4,0xba8,0xbaa,0xbae,0xbb9,0xbbe,0xbc2,0xbc6,0xbc8,0xbca,0xbcd,0xbd0,0xbd0,0xbd7,0xbd7,0xbe6,0xbfa,0x1cda,0x1cda,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x2074,0x2074,0x2082,0x2084,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa8f3,0xa8f3,0x11301,0x11301,0x11303,0x11303,0x1133b,0x1133c,]), - NotoFont.fromFlatRanges('Noto Sans Tamil Supplement', 'http://fonts.gstatic.com/s/notosanstamilsupplement/v19/DdTz78kEtnooLS5rXF1DaruiCd_bFp_Ph4sGcn7ax_vsAeMkeq1x.ttf', [0x11fc0,0x11ff1,0x11fff,0x11fff,]), - NotoFont.fromFlatRanges('Noto Sans Telugu', 'http://fonts.gstatic.com/s/notosanstelugu/v19/0FlxVOGZlE2Rrtr-HmgkMWJNjJ5_RyT8o8c7fHkeg-esVC5dzHkHIJQqrEntezbqQUbf-3v37w.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xc00,0xc0c,0xc0e,0xc10,0xc12,0xc28,0xc2a,0xc39,0xc3d,0xc44,0xc46,0xc48,0xc4a,0xc4d,0xc55,0xc56,0xc58,0xc5a,0xc60,0xc63,0xc66,0xc6f,0xc77,0xc7f,0x1cda,0x1cda,0x1cf2,0x1cf2,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Thaana', 'http://fonts.gstatic.com/s/notosansthaana/v16/C8c14dM-vnz-s-3jaEsxlxHkBH-WZOETXfoQrfQ9Y4XrbhLhnu4-tbNu.ttf', [0x20,0x21,0x28,0x29,0x2c,0x2c,0x2e,0x2e,0x3a,0x3b,0xa0,0xa0,0x60c,0x60c,0x61b,0x61b,0x61f,0x61f,0x660,0x66c,0x780,0x7b1,0x200b,0x200f,0x2018,0x2019,0x201c,0x201d,0x25cc,0x25cc,0xfdf2,0xfdf2,0xfdfd,0xfdfd,]), - NotoFont.fromFlatRanges('Noto Sans Thai', 'http://fonts.gstatic.com/s/notosansthai/v20/iJWnBXeUZi_OHPqn4wq6hQ2_hbJ1xyN9wd43SofNWcd1MKVQt_So_9CdU5RtpzF-QRvzzXg.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2d7,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x331,0x331,0xe01,0xe3a,0xe3f,0xe5b,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), - NotoFont.fromFlatRanges('Noto Sans Tifinagh', 'http://fonts.gstatic.com/s/notosanstifinagh/v15/I_uzMoCduATTei9eI8dawkHIwvmhCvbn6rnEcXfs4Q.ttf', [0x20,0x20,0xa0,0xa0,0x2c7,0x2c7,0x301,0x302,0x304,0x304,0x306,0x307,0x309,0x309,0x323,0x323,0x331,0x331,0x200c,0x200d,0x202e,0x202e,0x25cc,0x25cc,0x2d30,0x2d67,0x2d6f,0x2d70,0x2d7f,0x2d7f,]), - NotoFont.fromFlatRanges('Noto Sans Tirhuta', 'http://fonts.gstatic.com/s/notosanstirhuta/v15/t5t6IQYRNJ6TWjahPR6X-M-apUyby7uGUBsTrn5P.ttf', [0x20,0x20,0xa0,0xa0,0x951,0x952,0x964,0x965,0x9f4,0x9f7,0x1cf2,0x1cf2,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11480,0x114c7,0x114d0,0x114d9,]), - NotoFont.fromFlatRanges('Noto Sans Ugaritic', 'http://fonts.gstatic.com/s/notosansugaritic/v15/3qTwoiqhnSyU8TNFIdhZVCwbjCpkAXXkMhoIkiazfg.ttf', [0x20,0x20,0xa0,0xa0,0x10380,0x1039d,0x1039f,0x1039f,]), - NotoFont.fromFlatRanges('Noto Sans Vai', 'http://fonts.gstatic.com/s/notosansvai/v15/NaPecZTSBuhTirw6IaFn_UrURMTsDIRSfr0.ttf', [0x20,0x20,0xa0,0xa0,0xa500,0xa62b,]), - NotoFont.fromFlatRanges('Noto Sans Wancho', 'http://fonts.gstatic.com/s/notosanswancho/v15/zrf-0GXXyfn6Fs0lH9P4cUubP0GBqAPopiRfKp8.ttf', [0x20,0x20,0x22,0x22,0x27,0x29,0x2c,0x2f,0x5b,0x5d,0x7b,0x7b,0x7d,0x7d,0xa0,0xa0,0x201c,0x201d,0x25cc,0x25cc,0x1e2c0,0x1e2f9,0x1e2ff,0x1e2ff,]), - NotoFont.fromFlatRanges('Noto Sans Warang Citi', 'http://fonts.gstatic.com/s/notosanswarangciti/v15/EYqtmb9SzL1YtsZSScyKDXIeOv3w-zgsNvKRpeVCCXzdgA.ttf', [0x20,0x20,0x27,0x27,0xa0,0xa0,0x200c,0x200d,0x118a0,0x118f2,0x118ff,0x118ff,]), - NotoFont.fromFlatRanges('Noto Sans Yi', 'http://fonts.gstatic.com/s/notosansyi/v15/sJoD3LFXjsSdcnzn071rO3apxVDJNVgSNg.ttf', [0x20,0x20,0xa0,0xa0,0x3001,0x3002,0x3008,0x3011,0x3014,0x301b,0x30fb,0x30fb,0xa000,0xa48c,0xa490,0xa4c6,0xff61,0xff65,]), - NotoFont.fromFlatRanges('Noto Sans Zanabazar Square', 'http://fonts.gstatic.com/s/notosanszanabazarsquare/v15/Cn-jJsuGWQxOjaGwMQ6fOicyxLBEMRfDtkzl4uagQtJxOCEgN0Gc.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x11a00,0x11a47,]), -]; diff --git a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart index 9550db92c02fd..40a915f44876c 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:convert'; import 'dart:typed_data'; import '../dom.dart'; @@ -10,11 +11,9 @@ import '../font_change_util.dart'; import '../platform_dispatcher.dart'; import '../util.dart'; import 'canvaskit_api.dart'; -import 'font_fallback_data.dart'; import 'fonts.dart'; import 'initialization.dart'; import 'interval_tree.dart'; -import 'noto_font.dart'; /// Global static font fallback data. class FontFallbackData { @@ -28,9 +27,13 @@ class FontFallbackData { /// Used for tests. static void debugReset() { _instance = FontFallbackData(); - notoDownloadQueue = FallbackFontDownloadQueue(); } + /// Whether or not "Noto Sans Symbols" and "Noto Color Emoji" fonts have been + /// downloaded. We download these as fallbacks when no other font covers the + /// given code units. + bool registeredSymbolsAndEmoji = false; + /// Code units that no known font has a glyph for. final Set codeUnitsWithNoKnownFont = {}; @@ -44,9 +47,15 @@ class FontFallbackData { final Map> ranges = >{}; - for (final NotoFont font in fallbackFonts) { + for (final NotoFont font in _notoFonts) { + // TODO(yjbanov): instead of mutating the font tree during reset, it's + // better to construct an immutable tree of resolved fonts + // pointing back to the original NotoFont objects. Then + // resetting the tree would be a matter of reconstructing + // the new resolved tree. + font.reset(); // ignore: prefer_foreach - for (final CodeunitRange range in font.computeUnicodeRanges()) { + for (final CodeunitRange range in font.approximateUnicodeRanges) { ranges.putIfAbsent(font, () => []).add(range); } } @@ -59,6 +68,8 @@ class FontFallbackData { final List globalFontFallbacks = ['Roboto']; + final Map fontFallbackCounts = {}; + /// A list of code units to check against the global fallback fonts. final Set _codeUnitsToCheckAgainstFallbackFonts = {}; @@ -154,9 +165,6 @@ class FontFallbackData { _scheduledCodeUnitCheck = false; // We don't know if the remaining code units are covered by our fallback // fonts. Check them and update the cache. - if (_codeUnitsToCheckAgainstFallbackFonts.isEmpty) { - return; - } final List codeUnits = _codeUnitsToCheckAgainstFallbackFonts.toList(); _codeUnitsToCheckAgainstFallbackFonts.clear(); final List codeUnitsSupported = @@ -217,19 +225,23 @@ class FontFallbackData { printWarning('Failed to parse fallback font $family as a font.'); return; } + fontFallbackCounts.putIfAbsent(family, () => 0); + final int fontFallbackTag = fontFallbackCounts[family]!; + fontFallbackCounts[family] = fontFallbackCounts[family]! + 1; + final String countedFamily = '$family $fontFallbackTag'; // Insert emoji font before all other fallback fonts so we use the emoji // whenever it's available. - registeredFallbackFonts.add(RegisteredFont(bytes, family, typeface)); + registeredFallbackFonts.add(RegisteredFont(bytes, countedFamily, typeface)); // Insert emoji font before all other fallback fonts so we use the emoji // whenever it's available. - if (family == 'Noto Emoji') { + if (family == 'Noto Color Emoji Compat') { if (globalFontFallbacks.first == 'Roboto') { - globalFontFallbacks.insert(1, family); + globalFontFallbacks.insert(1, countedFamily); } else { - globalFontFallbacks.insert(0, family); + globalFontFallbacks.insert(0, countedFamily); } } else { - globalFontFallbacks.add(family); + globalFontFallbacks.add(countedFamily); } } } @@ -250,24 +262,209 @@ Future findFontsForMissingCodeunits(List codeUnits) async { } } + for (final NotoFont font in fonts) { + await font.ensureResolved(); + } + // The call to `findMinimumFontsForCodeUnits` will remove all code units that // were matched by `fonts` from `unmatchedCodeUnits`. final Set unmatchedCodeUnits = Set.from(coveredCodeUnits); fonts = findMinimumFontsForCodeUnits(unmatchedCodeUnits, fonts); - fonts.forEach(notoDownloadQueue.add); + final Set<_ResolvedNotoSubset> resolvedFonts = <_ResolvedNotoSubset>{}; + for (final int codeUnit in coveredCodeUnits) { + for (final NotoFont font in fonts) { + if (font.resolvedFont == null) { + // We failed to resolve the font earlier. + continue; + } + resolvedFonts.addAll(font.resolvedFont!.tree.intersections(codeUnit)); + } + } + resolvedFonts.forEach(notoDownloadQueue.add); // We looked through the Noto font tree and didn't find any font families // covering some code units, or we did find a font family, but when we // downloaded the fonts we found that they actually didn't cover them. So // we try looking them up in the symbols and emojis fonts. if (missingCodeUnits.isNotEmpty || unmatchedCodeUnits.isNotEmpty) { - if (!notoDownloadQueue.isPending) { - printWarning('Could not find a set of Noto fonts to display all missing ' - 'characters. Please add a font asset for the missing characters.' - ' See: https://flutter.dev/docs/cookbook/design/fonts'); - data.codeUnitsWithNoKnownFont.addAll(missingCodeUnits); + if (!data.registeredSymbolsAndEmoji) { + await _registerSymbolsAndEmoji(); + } else { + if (!notoDownloadQueue.isPending) { + printWarning( + 'Could not find a set of Noto fonts to display all missing ' + 'characters. Please add a font asset for the missing characters.' + ' See: https://flutter.dev/docs/cookbook/design/fonts'); + data.codeUnitsWithNoKnownFont.addAll(missingCodeUnits); + } + } + } +} + +/// Parse the CSS file for a font and make a list of resolved subsets. +/// +/// A CSS file from Google Fonts looks like this: +/// +/// /* [0] */ +/// @font-face { +/// font-family: 'Noto Sans KR'; +/// font-style: normal; +/// font-weight: 400; +/// src: url(https://fonts.gstatic.com/s/notosanskr/v13/PbykFmXiEBPT4ITbgNA5Cgm20xz64px_1hVWr0wuPNGmlQNMEfD4.0.woff2) format('woff2'); +/// unicode-range: U+f9ca-fa0b, U+ff03-ff05, U+ff07, U+ff0a-ff0b, U+ff0d-ff19, U+ff1b, U+ff1d, U+ff20-ff5b, U+ff5d, U+ffe0-ffe3, U+ffe5-ffe6; +/// } +/// /* [1] */ +/// @font-face { +/// font-family: 'Noto Sans KR'; +/// font-style: normal; +/// font-weight: 400; +/// src: url(https://fonts.gstatic.com/s/notosanskr/v13/PbykFmXiEBPT4ITbgNA5Cgm20xz64px_1hVWr0wuPNGmlQNMEfD4.1.woff2) format('woff2'); +/// unicode-range: U+f92f-f980, U+f982-f9c9; +/// } +/// /* [2] */ +/// @font-face { +/// font-family: 'Noto Sans KR'; +/// font-style: normal; +/// font-weight: 400; +/// src: url(https://fonts.gstatic.com/s/notosanskr/v13/PbykFmXiEBPT4ITbgNA5Cgm20xz64px_1hVWr0wuPNGmlQNMEfD4.2.woff2) format('woff2'); +/// unicode-range: U+d723-d728, U+d72a-d733, U+d735-d748, U+d74a-d74f, U+d752-d753, U+d755-d757, U+d75a-d75f, U+d762-d764, U+d766-d768, U+d76a-d76b, U+d76d-d76f, U+d771-d787, U+d789-d78b, U+d78d-d78f, U+d791-d797, U+d79a, U+d79c, U+d79e-d7a3, U+f900-f909, U+f90b-f92e; +/// } +_ResolvedNotoFont? _makeResolvedNotoFontFromCss(String css, String name) { + final List<_ResolvedNotoSubset> subsets = <_ResolvedNotoSubset>[]; + bool resolvingFontFace = false; + String? fontFaceUrl; + List? fontFaceUnicodeRanges; + for (final String line in LineSplitter.split(css)) { + // Search for the beginning of a @font-face. + if (!resolvingFontFace) { + if (line == '@font-face {') { + resolvingFontFace = true; + } else { + continue; + } + } else { + // We are resolving a @font-face, read out the url and ranges. + if (line.startsWith(' src:')) { + final int urlStart = line.indexOf('url('); + if (urlStart == -1) { + printWarning('Unable to resolve Noto font URL: $line'); + return null; + } + final int urlEnd = line.indexOf(')'); + fontFaceUrl = line.substring(urlStart + 4, urlEnd); + } else if (line.startsWith(' unicode-range:')) { + fontFaceUnicodeRanges = []; + final String rangeString = line.substring(17, line.length - 1); + final List rawRanges = rangeString.split(', '); + for (final String rawRange in rawRanges) { + final List startEnd = rawRange.split('-'); + if (startEnd.length == 1) { + final String singleRange = startEnd.single; + assert(singleRange.startsWith('U+')); + final int rangeValue = + int.parse(singleRange.substring(2), radix: 16); + fontFaceUnicodeRanges.add(CodeunitRange(rangeValue, rangeValue)); + } else { + assert(startEnd.length == 2); + final String startRange = startEnd[0]; + final String endRange = startEnd[1]; + assert(startRange.startsWith('U+')); + final int startValue = + int.parse(startRange.substring(2), radix: 16); + final int endValue = int.parse(endRange, radix: 16); + fontFaceUnicodeRanges.add(CodeunitRange(startValue, endValue)); + } + } + } else if (line == '}') { + if (fontFaceUrl == null || fontFaceUnicodeRanges == null) { + printWarning('Unable to parse Google Fonts CSS: $css'); + return null; + } + subsets + .add(_ResolvedNotoSubset(fontFaceUrl, name, fontFaceUnicodeRanges)); + resolvingFontFace = false; + } else { + continue; + } + } + } + + if (resolvingFontFace) { + printWarning('Unable to parse Google Fonts CSS: $css'); + return null; + } + + final Map<_ResolvedNotoSubset, List> rangesMap = + <_ResolvedNotoSubset, List>{}; + for (final _ResolvedNotoSubset subset in subsets) { + // ignore: prefer_foreach + for (final CodeunitRange range in subset.ranges) { + rangesMap.putIfAbsent(subset, () => []).add(range); + } + } + + if (rangesMap.isEmpty) { + printWarning('Parsed Google Fonts CSS was empty: $css'); + return null; + } + + final IntervalTree<_ResolvedNotoSubset> tree = + IntervalTree<_ResolvedNotoSubset>.createFromRanges(rangesMap); + + return _ResolvedNotoFont(name, subsets, tree); +} + +/// In the case where none of the known Noto Fonts cover a set of code units, +/// try the Symbols and Emoji fonts. We don't know the exact range of code units +/// that are covered by these fonts, so we download them and hope for the best. +Future _registerSymbolsAndEmoji() async { + final FontFallbackData data = FontFallbackData.instance; + if (data.registeredSymbolsAndEmoji) { + return; + } + data.registeredSymbolsAndEmoji = true; + const String emojiUrl = + 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'; + const String symbolsUrl = + 'https://fonts.googleapis.com/css2?family=Noto+Sans+Symbols'; + + final String emojiCss = + await notoDownloadQueue.downloader.downloadAsString(emojiUrl); + final String symbolsCss = + await notoDownloadQueue.downloader.downloadAsString(symbolsUrl); + + String? extractUrlFromCss(String css) { + for (final String line in LineSplitter.split(css)) { + if (line.startsWith(' src:')) { + final int urlStart = line.indexOf('url('); + if (urlStart == -1) { + printWarning('Unable to resolve Noto font URL: $line'); + return null; + } + final int urlEnd = line.indexOf(')'); + return line.substring(urlStart + 4, urlEnd); + } } + printWarning('Unable to determine URL for Noto font'); + return null; + } + + final String? emojiFontUrl = extractUrlFromCss(emojiCss); + final String? symbolsFontUrl = extractUrlFromCss(symbolsCss); + + if (emojiFontUrl != null) { + notoDownloadQueue.add(_ResolvedNotoSubset( + emojiFontUrl, 'Noto Color Emoji Compat', const [])); + } else { + printWarning('Error parsing CSS for Noto Emoji font.'); + } + + if (symbolsFontUrl != null) { + notoDownloadQueue.add(_ResolvedNotoSubset( + symbolsFontUrl, 'Noto Sans Symbols', const [])); + } else { + printWarning('Error parsing CSS for Noto Symbols font.'); } } @@ -296,7 +493,7 @@ Set findMinimumFontsForCodeUnits( for (final NotoFont font in fonts) { int codeUnitsCovered = 0; for (final int codeUnit in codeUnits) { - if (font.contains(codeUnit)) { + if (font.resolvedFont?.tree.containsDeep(codeUnit) ?? false) { codeUnitsCovered++; } } @@ -338,43 +535,321 @@ Set findMinimumFontsForCodeUnits( if (bestFonts.contains(_notoSansJP)) { bestFont = _notoSansJP; } - } else if (language == 'ko') { - if (bestFonts.contains(_notoSansKR)) { - bestFont = _notoSansKR; - } - } else if (bestFonts.contains(_notoSansSC)) { - bestFont = _notoSansSC; - } - } else { - // To be predictable, if Simplified Chinese is one of the best fonts, - // choose that since it is the most common script. - if (bestFonts.contains(_notoSansSC)) { - bestFont = _notoSansSC; } } } codeUnits.removeWhere((int codeUnit) { - return bestFont.contains(codeUnit); + return bestFont.resolvedFont!.tree.containsDeep(codeUnit); }); - minimumFonts.add(bestFont); + minimumFonts.addAll(bestFonts); } return minimumFonts; } -NotoFont _notoSansSC = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans SC'); -NotoFont _notoSansTC = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans TC'); -NotoFont _notoSansHK = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans HK'); -NotoFont _notoSansJP = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans JP'); -NotoFont _notoSansKR = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans KR'); -List _cjkFonts = [_notoSansSC, _notoSansTC, _notoSansHK, _notoSansJP, _notoSansKR]; +class NotoFont { + NotoFont(this.name, this.approximateUnicodeRanges); + + final String name; + final List approximateUnicodeRanges; + + Completer? _decodingCompleter; + _ResolvedNotoFont? resolvedFont; + + String get googleFontsCssUrl => + 'https://fonts.googleapis.com/css2?family=${name.replaceAll(' ', '+')}'; + + Future ensureResolved() async { + if (resolvedFont == null) { + if (_decodingCompleter == null) { + _decodingCompleter = Completer(); + final String googleFontCss = await notoDownloadQueue.downloader + .downloadAsString(googleFontsCssUrl); + final _ResolvedNotoFont? googleFont = + _makeResolvedNotoFontFromCss(googleFontCss, name); + resolvedFont = googleFont; + _decodingCompleter!.complete(); + } else { + await _decodingCompleter!.future; + } + } + } + + void reset() { + resolvedFont = null; + _decodingCompleter = null; + } +} + +class CodeunitRange { + const CodeunitRange(this.start, this.end); + + final int start; + final int end; + + bool contains(int codeUnit) { + return start <= codeUnit && codeUnit <= end; + } + + @override + bool operator ==(dynamic other) { + if (other is! CodeunitRange) { + return false; + } + final CodeunitRange range = other; + return range.start == start && range.end == end; + } + + @override + int get hashCode => Object.hash(start, end); + + @override + String toString() => '[$start, $end]'; +} + +class _ResolvedNotoFont { + const _ResolvedNotoFont(this.name, this.subsets, this.tree); + + final String name; + final List<_ResolvedNotoSubset> subsets; + final IntervalTree<_ResolvedNotoSubset> tree; +} + +class _ResolvedNotoSubset { + _ResolvedNotoSubset(this.url, this.family, this.ranges); + + final String url; + final String family; + final List ranges; + + @override + String toString() => '_ResolvedNotoSubset($family, $url)'; +} + +NotoFont _notoSansSC = NotoFont('Noto Sans SC', [ + const CodeunitRange(12288, 12591), + const CodeunitRange(12800, 13311), + const CodeunitRange(19968, 40959), + const CodeunitRange(65072, 65135), + const CodeunitRange(65280, 65519), +]); + +NotoFont _notoSansTC = NotoFont('Noto Sans TC', [ + const CodeunitRange(12288, 12351), + const CodeunitRange(12549, 12585), + const CodeunitRange(19968, 40959), +]); + +NotoFont _notoSansHK = NotoFont('Noto Sans HK', [ + const CodeunitRange(12288, 12351), + const CodeunitRange(12549, 12585), + const CodeunitRange(19968, 40959), +]); + +NotoFont _notoSansJP = NotoFont('Noto Sans JP', [ + const CodeunitRange(12288, 12543), + const CodeunitRange(19968, 40959), + const CodeunitRange(65280, 65519), +]); + +List _cjkFonts = [ + _notoSansSC, + _notoSansTC, + _notoSansHK, + _notoSansJP, +]; + +List _notoFonts = [ + _notoSansSC, + _notoSansTC, + _notoSansHK, + _notoSansJP, + NotoFont('Noto Naskh Arabic UI', [ + const CodeunitRange(1536, 1791), + const CodeunitRange(8204, 8206), + const CodeunitRange(8208, 8209), + const CodeunitRange(8271, 8271), + const CodeunitRange(11841, 11841), + const CodeunitRange(64336, 65023), + const CodeunitRange(65132, 65276), + ]), + NotoFont('Noto Sans Armenian', [ + const CodeunitRange(1328, 1424), + const CodeunitRange(64275, 64279), + ]), + NotoFont('Noto Sans Bengali UI', [ + const CodeunitRange(2404, 2405), + const CodeunitRange(2433, 2555), + const CodeunitRange(8204, 8205), + const CodeunitRange(8377, 8377), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans Myanmar UI', [ + const CodeunitRange(4096, 4255), + const CodeunitRange(8204, 8205), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans Egyptian Hieroglyphs', [ + const CodeunitRange(77824, 78894), + ]), + NotoFont('Noto Sans Ethiopic', [ + const CodeunitRange(4608, 5017), + const CodeunitRange(11648, 11742), + const CodeunitRange(43777, 43822), + ]), + NotoFont('Noto Sans Georgian', [ + const CodeunitRange(1417, 1417), + const CodeunitRange(4256, 4351), + const CodeunitRange(11520, 11567), + ]), + NotoFont('Noto Sans Gujarati UI', [ + const CodeunitRange(2404, 2405), + const CodeunitRange(2688, 2815), + const CodeunitRange(8204, 8205), + const CodeunitRange(8377, 8377), + const CodeunitRange(9676, 9676), + const CodeunitRange(43056, 43065), + ]), + NotoFont('Noto Sans Gurmukhi UI', [ + const CodeunitRange(2404, 2405), + const CodeunitRange(2561, 2677), + const CodeunitRange(8204, 8205), + const CodeunitRange(8377, 8377), + const CodeunitRange(9676, 9676), + const CodeunitRange(9772, 9772), + const CodeunitRange(43056, 43065), + ]), + NotoFont('Noto Sans Hebrew', [ + const CodeunitRange(1424, 1535), + const CodeunitRange(8362, 8362), + const CodeunitRange(9676, 9676), + const CodeunitRange(64285, 64335), + ]), + NotoFont('Noto Sans Devanagari UI', [ + const CodeunitRange(2304, 2431), + const CodeunitRange(7376, 7414), + const CodeunitRange(7416, 7417), + const CodeunitRange(8204, 8205), + const CodeunitRange(8360, 8360), + const CodeunitRange(8377, 8377), + const CodeunitRange(9676, 9676), + const CodeunitRange(43056, 43065), + const CodeunitRange(43232, 43259), + ]), + NotoFont('Noto Sans Kannada UI', [ + const CodeunitRange(2404, 2405), + const CodeunitRange(3202, 3314), + const CodeunitRange(8204, 8205), + const CodeunitRange(8377, 8377), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans Khmer UI', [ + const CodeunitRange(6016, 6143), + const CodeunitRange(8204, 8204), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans KR', [ + const CodeunitRange(12593, 12686), + const CodeunitRange(12800, 12828), + const CodeunitRange(12896, 12923), + const CodeunitRange(44032, 55215), + ]), + NotoFont('Noto Sans Lao UI', [ + const CodeunitRange(3713, 3807), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans Malayalam UI', [ + const CodeunitRange(775, 775), + const CodeunitRange(803, 803), + const CodeunitRange(2404, 2405), + const CodeunitRange(3330, 3455), + const CodeunitRange(8204, 8205), + const CodeunitRange(8377, 8377), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans Sinhala', [ + const CodeunitRange(2404, 2405), + const CodeunitRange(3458, 3572), + const CodeunitRange(8204, 8205), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans Tamil UI', [ + const CodeunitRange(2404, 2405), + const CodeunitRange(2946, 3066), + const CodeunitRange(8204, 8205), + const CodeunitRange(8377, 8377), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans Telugu UI', [ + const CodeunitRange(2385, 2386), + const CodeunitRange(2404, 2405), + const CodeunitRange(3072, 3199), + const CodeunitRange(7386, 7386), + const CodeunitRange(8204, 8205), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans Thai UI', [ + const CodeunitRange(3585, 3675), + const CodeunitRange(8204, 8205), + const CodeunitRange(9676, 9676), + ]), + NotoFont('Noto Sans', [ + const CodeunitRange(0, 255), + const CodeunitRange(305, 305), + const CodeunitRange(338, 339), + const CodeunitRange(699, 700), + const CodeunitRange(710, 710), + const CodeunitRange(730, 730), + const CodeunitRange(732, 732), + const CodeunitRange(8192, 8303), + const CodeunitRange(8308, 8308), + const CodeunitRange(8364, 8364), + const CodeunitRange(8482, 8482), + const CodeunitRange(8593, 8593), + const CodeunitRange(8595, 8595), + const CodeunitRange(8722, 8722), + const CodeunitRange(8725, 8725), + const CodeunitRange(65279, 65279), + const CodeunitRange(65533, 65533), + const CodeunitRange(1024, 1119), + const CodeunitRange(1168, 1169), + const CodeunitRange(1200, 1201), + const CodeunitRange(8470, 8470), + const CodeunitRange(1120, 1327), + const CodeunitRange(7296, 7304), + const CodeunitRange(8372, 8372), + const CodeunitRange(11744, 11775), + const CodeunitRange(42560, 42655), + const CodeunitRange(65070, 65071), + const CodeunitRange(880, 1023), + const CodeunitRange(7936, 8191), + const CodeunitRange(256, 591), + const CodeunitRange(601, 601), + const CodeunitRange(7680, 7935), + const CodeunitRange(8224, 8224), + const CodeunitRange(8352, 8363), + const CodeunitRange(8365, 8399), + const CodeunitRange(8467, 8467), + const CodeunitRange(11360, 11391), + const CodeunitRange(42784, 43007), + const CodeunitRange(258, 259), + const CodeunitRange(272, 273), + const CodeunitRange(296, 297), + const CodeunitRange(360, 361), + const CodeunitRange(416, 417), + const CodeunitRange(431, 432), + const CodeunitRange(7840, 7929), + const CodeunitRange(8363, 8363), + ]), +]; class FallbackFontDownloadQueue { NotoDownloader downloader = NotoDownloader(); - final Set downloadedFonts = {}; - final Map pendingFonts = {}; + final Set<_ResolvedNotoSubset> downloadedSubsets = <_ResolvedNotoSubset>{}; + final Map pendingSubsets = + {}; - bool get isPending => pendingFonts.isNotEmpty || _fontsLoading != null; + bool get isPending => pendingSubsets.isNotEmpty || _fontsLoading != null; Future? _fontsLoading; bool get debugIsLoadingFonts => _fontsLoading != null; @@ -386,9 +861,9 @@ class FallbackFontDownloadQueue { if (_fontsLoading != null) { await _fontsLoading; } - if (pendingFonts.isNotEmpty) { + if (pendingSubsets.isNotEmpty) { await Future.delayed(const Duration(milliseconds: 100)); - if (pendingFonts.isEmpty) { + if (pendingSubsets.isEmpty) { await Future.delayed(const Duration(milliseconds: 100)); } } @@ -398,13 +873,13 @@ class FallbackFontDownloadQueue { } } - void add(NotoFont font) { - if (downloadedFonts.contains(font) || - pendingFonts.containsKey(font.url)) { + void add(_ResolvedNotoSubset subset) { + if (downloadedSubsets.contains(subset) || + pendingSubsets.containsKey(subset.url)) { return; } - final bool firstInBatch = pendingFonts.isEmpty; - pendingFonts[font.url] = font; + final bool firstInBatch = pendingSubsets.isEmpty; + pendingSubsets[subset.url] = subset; if (firstInBatch) { Timer.run(startDownloads); } @@ -413,20 +888,20 @@ class FallbackFontDownloadQueue { Future startDownloads() async { final Map> downloads = >{}; final Map downloadedData = {}; - for (final NotoFont font in pendingFonts.values) { - downloads[font.url] = Future(() async { + for (final _ResolvedNotoSubset subset in pendingSubsets.values) { + downloads[subset.url] = Future(() async { ByteBuffer buffer; try { - buffer = await downloader.downloadAsBytes(font.url, - debugDescription: font.name); + buffer = await downloader.downloadAsBytes(subset.url, + debugDescription: subset.family); } catch (e) { - pendingFonts.remove(font.url); - printWarning('Failed to load font ${font.name} at ${font.url}'); + pendingSubsets.remove(subset.url); + printWarning('Failed to load font ${subset.family} at ${subset.url}'); printWarning(e.toString()); return; } - downloadedFonts.add(font); - downloadedData[font.url] = buffer.asUint8List(); + downloadedSubsets.add(subset); + downloadedData[subset.url] = buffer.asUint8List(); }); } @@ -438,10 +913,10 @@ class FallbackFontDownloadQueue { final List downloadOrder = (downloadedData.keys.toList()..sort()).reversed.toList(); for (final String url in downloadOrder) { - final NotoFont font = pendingFonts.remove(url)!; + final _ResolvedNotoSubset subset = pendingSubsets.remove(url)!; final Uint8List bytes = downloadedData[url]!; - FontFallbackData.instance.registerFallbackFont(font.name, bytes); - if (pendingFonts.isEmpty) { + FontFallbackData.instance.registerFallbackFont(subset.family, bytes); + if (pendingSubsets.isEmpty) { _fontsLoading = skiaFontCollection.ensureFontsLoaded(); try { await _fontsLoading; @@ -452,7 +927,7 @@ class FallbackFontDownloadQueue { } } - if (pendingFonts.isNotEmpty) { + if (pendingSubsets.isNotEmpty) { await startDownloads(); } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart index 7f10373c51527..29d16421bbb5b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart @@ -4,7 +4,7 @@ import 'dart:math' as math; -import 'noto_font.dart' show CodeunitRange; +import 'font_fallbacks.dart' show CodeunitRange; /// A tree which stores a set of intervals that can be queried for intersection. class IntervalTree { diff --git a/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart b/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart deleted file mode 100644 index 83964c6f4222c..0000000000000 --- a/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart +++ /dev/null @@ -1,98 +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. - -class NotoFont { - const NotoFont(this.name, this.url, this._rangeStarts, this._rangeEnds); - - factory NotoFont.fromFlatRanges(String name, String url, List flatRanges) { - final List starts = []; - final List ends = []; - for (int i = 0; i < flatRanges.length; i += 2) { - starts.add(flatRanges[i]); - ends.add(flatRanges[i+1]); - } - return NotoFont(name, url, starts, ends); - } - - final String name; - final String url; - // A sorted list of Unicode range start points. - final List _rangeStarts; - - // A sorted list of Unicode range end points. - final List _rangeEnds; - - List computeUnicodeRanges() { - final List result = []; - for (int i = 0; i < _rangeStarts.length; i++) { - result.add(CodeunitRange(_rangeStarts[i], _rangeEnds[i])); - } - return result; - } - - // Returns `true` if this font has a glyph for the given [codeunit]. - bool contains(int codeUnit) { - // Binary search through the starts and ends to see if there - // is a range that contains the codeunit. - int min = 0; - int max = _rangeStarts.length - 1; - // Search for the first rangeStart that is greater than codeunit. - while (min < max) { - final int mid = (min + max) ~/ 2; - if (_rangeStarts[mid] > codeUnit) { - if (mid == 0) { - final int rangeStart = _rangeStarts[mid]; - final int rangeEnd = _rangeEnds[mid]; - return rangeStart <= codeUnit && codeUnit <= rangeEnd; - } - final int rangeStart = _rangeStarts[mid - 1]; - if (rangeStart <= codeUnit) { - final int rangeEnd = _rangeEnds[mid - 1]; - return rangeStart <= codeUnit && codeUnit <= rangeEnd; - } else { - max = mid - 1; - } - } else if (_rangeStarts[mid] < codeUnit) { - // If this is the last index, check if the codeunit is contained within it. - if (mid == _rangeStarts.length) { - final int rangeStart = _rangeStarts[mid]; - final int rangeEnd = _rangeEnds[mid]; - return rangeStart <= codeUnit && codeUnit <= rangeEnd; - } - min = mid + 1; - } else { - // _rangeStarts[mid] == codeUnit - return true; - } - } - return false; - } -} - -class CodeunitRange { - const CodeunitRange(this.start, this.end); - - final int start; - final int end; - - - bool contains(int codeUnit) { - return start <= codeUnit && codeUnit <= end; - } - - @override - bool operator ==(dynamic other) { - if (other is! CodeunitRange) { - return false; - } - final CodeunitRange range = other; - return range.start == start && range.end == end; - } - - @override - int get hashCode => Object.hash(start, end); - - @override - String toString() => '[$start, $end]'; -} diff --git a/lib/web_ui/test/canvaskit/canvas_golden_test.dart b/lib/web_ui/test/canvaskit/canvas_golden_test.dart index 8e90dd50a2938..77a3a57eb7fc5 100644 --- a/lib/web_ui/test/canvaskit/canvas_golden_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_golden_test.dart @@ -33,7 +33,6 @@ void testMain() { setUp(() { expect(notoDownloadQueue.downloader.debugActiveDownloadCount, 0); expect(notoDownloadQueue.isPending, isFalse); - FontFallbackData.debugReset(); }); tearDown(() { @@ -566,6 +565,7 @@ void testMain() { // some of these symbols. To make sure the test produces predictable // results we reset the fallback data forcing the engine to reload // fallbacks, which for this test will only load Noto Symbols. + FontFallbackData.debugReset(); await testTextStyle( 'symbols', outerText: '← ↑ → ↓ ', @@ -821,6 +821,7 @@ void testMain() { Future testSampleText(String language, String text, {ui.TextDirection textDirection = ui.TextDirection.ltr, bool write = false}) async { + FontFallbackData.debugReset(); const double testWidth = 300; double paragraphHeight = 0; final CkPicture picture = await generatePictureWhenFontsStable(() { @@ -1329,7 +1330,7 @@ Future testTextStyle( write: write, ); expect(notoDownloadQueue.debugIsLoadingFonts, isFalse); - expect(notoDownloadQueue.pendingFonts, isEmpty); + expect(notoDownloadQueue.pendingSubsets, isEmpty); expect(notoDownloadQueue.downloader.debugActiveDownloadCount, 0); } diff --git a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart index adfeef58d6f76..ed1293b813e23 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -28,20 +28,10 @@ void testMain() { ui.PlatformMessageCallback? savedCallback; setUp(() { - FontFallbackData.debugReset(); notoDownloadQueue.downloader = TestDownloader(); TestDownloader.mockDownloads.clear(); - final String notoSansArabicUrl = fallbackFonts - .singleWhere((NotoFont font) => font.name == 'Noto Sans Arabic') - .url; - final String notoEmojiUrl = fallbackFonts - .singleWhere((NotoFont font) => font.name == 'Noto Emoji') - .url; - TestDownloader.mockDownloads[notoSansArabicUrl] = - '/assets/fonts/NotoNaskhArabic-Regular.ttf'; - TestDownloader.mockDownloads[notoEmojiUrl] = - '/assets/fonts/NotoColorEmoji.ttf'; savedCallback = ui.window.onPlatformMessage; + FontFallbackData.debugReset(); }); tearDown(() { @@ -52,7 +42,20 @@ void testMain() { expect(FontFallbackData.instance.globalFontFallbacks, contains('Roboto')); }); - test('will download Noto Sans Arabic if Arabic text is added', () async { + test('will download Noto Naskh Arabic if Arabic text is added', () async { + TestDownloader.mockDownloads[ + 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = + ''' +/* arabic */ +@font-face { + font-family: 'Noto Naskh Arabic UI'; + font-style: normal; + font-weight: 400; + src: url(/assets/fonts/NotoNaskhArabic-Regular.ttf) format('ttf'); + unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC; +} +'''; + expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); // Creating this paragraph should cause us to start to download the @@ -67,7 +70,7 @@ void testMain() { await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, - contains('Noto Sans Arabic')); + contains('Noto Naskh Arabic UI 0')); final CkPictureRecorder recorder = CkPictureRecorder(); final CkCanvas canvas = recorder.beginRecording(kDefaultRegion); @@ -93,6 +96,28 @@ void testMain() { test('will put the Noto Emoji font before other fallback fonts in the list', () async { + TestDownloader.mockDownloads[ + 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'] = + ''' +@font-face { + font-family: 'Noto Color Emoji'; + src: url(/assets/fonts/NotoColorEmoji.ttf) format('ttf'); +} +'''; + + TestDownloader.mockDownloads[ + 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = + ''' +/* arabic */ +@font-face { + font-family: 'Noto Naskh Arabic UI'; + font-style: normal; + font-weight: 400; + src: url(/assets/fonts/NotoNaskhArabic-Regular.ttf) format('ttf'); + unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC; +} +'''; + expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); // Creating this paragraph should cause us to start to download the @@ -107,7 +132,7 @@ void testMain() { await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, - ['Roboto', 'Noto Sans Arabic']); + ['Roboto', 'Noto Naskh Arabic UI 0']); pb = CkParagraphBuilder( CkParagraphStyle(), @@ -124,13 +149,22 @@ void testMain() { expect(FontFallbackData.instance.globalFontFallbacks, [ 'Roboto', - 'Noto Emoji', - 'Noto Sans Arabic', + 'Noto Color Emoji Compat 0', + 'Noto Naskh Arabic UI 0', ]); }); test('will download Noto Emojis and Noto Symbols if no matching Noto Font', () async { + TestDownloader.mockDownloads[ + 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'] = + ''' +@font-face { + font-family: 'Noto Color Emoji'; + src: url(/assets/fonts/NotoColorEmoji.ttf) format('ttf'); +} +'''; + expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); // Creating this paragraph should cause us to start to download the @@ -145,7 +179,7 @@ void testMain() { await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, - contains('Noto Emoji')); + contains('Noto Color Emoji Compat 0')); final CkPictureRecorder recorder = CkPictureRecorder(); final CkCanvas canvas = recorder.beginRecording(kDefaultRegion); @@ -169,6 +203,30 @@ void testMain() { // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); + test('will gracefully fail if we cannot parse the Google Fonts CSS', + () async { + TestDownloader.mockDownloads[ + 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = + 'invalid CSS... this should cause our parser to fail'; + + expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); + + // Creating this paragraph should cause us to start to download the + // fallback font. + final CkParagraphBuilder pb = CkParagraphBuilder( + CkParagraphStyle(), + ); + pb.addText('مرحبا'); + + // Flush microtasks and test that we didn't start any downloads. + EnginePlatformDispatcher.instance.rasterizer! + .debugRunPostFrameCallbacks(); + await Future.delayed(Duration.zero); + + expect(notoDownloadQueue.isPending, isFalse); + expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); + }); + // Regression test for https://github.com/flutter/flutter/issues/75836 // When we had this bug our font fallback resolution logic would end up in an // infinite loop and this test would freeze and time out. @@ -183,12 +241,16 @@ void testMain() { CkParagraphBuilder(CkParagraphStyle()).addText('ヽಠ'); EnginePlatformDispatcher.instance.rasterizer! .debugRunPostFrameCallbacks(); - await notoDownloadQueue.debugWhenIdle(); + await notoDownloadQueue.downloader.debugWhenIdle(); expect( loggingDownloader.log, [ + 'https://fonts.googleapis.com/css2?family=Noto+Sans+SC', + 'https://fonts.googleapis.com/css2?family=Noto+Sans+JP', + 'https://fonts.googleapis.com/css2?family=Noto+Sans+Kannada+UI', 'Noto Sans SC', - 'Noto Sans Kannada', + 'Noto Sans JP', + 'Noto Sans Kannada UI', ], ); @@ -197,7 +259,7 @@ void testMain() { CkParagraphBuilder(CkParagraphStyle()).addText('ヽಠ'); EnginePlatformDispatcher.instance.rasterizer! .debugRunPostFrameCallbacks(); - await notoDownloadQueue.debugWhenIdle(); + await notoDownloadQueue.downloader.debugWhenIdle(); expect(loggingDownloader.log, isEmpty); }); @@ -214,7 +276,7 @@ void testMain() { FontFallbackData.instance.notoTree; for (final NotoFont font in notoTree.root.enumerateAllElements()) { testedFonts.add(font.name); - for (final CodeunitRange range in font.computeUnicodeRanges()) { + for (final CodeunitRange range in font.approximateUnicodeRanges) { for (int codeUnit = range.start; codeUnit < range.end; codeUnit += 1) { @@ -229,146 +291,30 @@ void testMain() { testedFonts, unorderedEquals({ 'Noto Sans', - 'Noto Emoji', - 'Noto Sans Symbols', - 'Noto Sans Symbols 2', - 'Noto Sans Adlam', - 'Noto Sans Anatolian Hieroglyphs', - 'Noto Sans Arabic', + 'Noto Sans Malayalam UI', 'Noto Sans Armenian', - 'Noto Sans Avestan', - 'Noto Sans Balinese', - 'Noto Sans Bamum', - 'Noto Sans Bassa Vah', - 'Noto Sans Batak', - 'Noto Sans Bengali', - 'Noto Sans Bhaiksuki', - 'Noto Sans Brahmi', - 'Noto Sans Buginese', - 'Noto Sans Buhid', - 'Noto Sans Canadian Aboriginal', - 'Noto Sans Carian', - 'Noto Sans Caucasian Albanian', - 'Noto Sans Chakma', - 'Noto Sans Cham', - 'Noto Sans Cherokee', - 'Noto Sans Coptic', - 'Noto Sans Cuneiform', - 'Noto Sans Cypriot', - 'Noto Sans Deseret', - 'Noto Sans Devanagari', - 'Noto Sans Duployan', - 'Noto Sans Egyptian Hieroglyphs', - 'Noto Sans Elbasan', - 'Noto Sans Elymaic', 'Noto Sans Georgian', - 'Noto Sans Glagolitic', - 'Noto Sans Gothic', - 'Noto Sans Grantha', - 'Noto Sans Gujarati', - 'Noto Sans Gunjala Gondi', - 'Noto Sans Gurmukhi', - 'Noto Sans HK', - 'Noto Sans Hanunoo', - 'Noto Sans Hatran', 'Noto Sans Hebrew', - 'Noto Sans Imperial Aramaic', - 'Noto Sans Indic Siyaq Numbers', - 'Noto Sans Inscriptional Pahlavi', - 'Noto Sans Inscriptional Parthian', - 'Noto Sans JP', - 'Noto Sans Javanese', - 'Noto Sans KR', - 'Noto Sans Kaithi', - 'Noto Sans Kannada', - 'Noto Sans Kayah Li', - 'Noto Sans Kharoshthi', - 'Noto Sans Khmer', - 'Noto Sans Khojki', - 'Noto Sans Khudawadi', - 'Noto Sans Lao', - 'Noto Sans Lepcha', - 'Noto Sans Limbu', - 'Noto Sans Linear A', - 'Noto Sans Linear B', - 'Noto Sans Lisu', - 'Noto Sans Lycian', - 'Noto Sans Lydian', - 'Noto Sans Mahajani', - 'Noto Sans Malayalam', - 'Noto Sans Mandaic', - 'Noto Sans Manichaean', - 'Noto Sans Marchen', - 'Noto Sans Masaram Gondi', - 'Noto Sans Math', - 'Noto Sans Mayan Numerals', - 'Noto Sans Medefaidrin', - 'Noto Sans Meetei Mayek', - 'Noto Sans Meroitic', - 'Noto Sans Miao', - 'Noto Sans Modi', - 'Noto Sans Mongolian', - 'Noto Sans Mro', - 'Noto Sans Multani', - 'Noto Sans Myanmar', - 'Noto Sans N Ko', - 'Noto Sans Nabataean', - 'Noto Sans New Tai Lue', - 'Noto Sans Newa', - 'Noto Sans Nushu', - 'Noto Sans Ogham', - 'Noto Sans Ol Chiki', - 'Noto Sans Old Hungarian', - 'Noto Sans Old Italic', - 'Noto Sans Old North Arabian', - 'Noto Sans Old Permic', - 'Noto Sans Old Persian', - 'Noto Sans Old Sogdian', - 'Noto Sans Old South Arabian', - 'Noto Sans Old Turkic', - 'Noto Sans Oriya', - 'Noto Sans Osage', - 'Noto Sans Osmanya', - 'Noto Sans Pahawh Hmong', - 'Noto Sans Palmyrene', - 'Noto Sans Pau Cin Hau', - 'Noto Sans Phags Pa', - 'Noto Sans Phoenician', - 'Noto Sans Psalter Pahlavi', - 'Noto Sans Rejang', - 'Noto Sans Runic', - 'Noto Sans SC', - 'Noto Sans Saurashtra', - 'Noto Sans Sharada', - 'Noto Sans Shavian', - 'Noto Sans Siddham', + 'Noto Naskh Arabic UI', + 'Noto Sans Devanagari UI', + 'Noto Sans Telugu UI', + 'Noto Sans Tamil UI', + 'Noto Sans Kannada UI', 'Noto Sans Sinhala', - 'Noto Sans Sogdian', - 'Noto Sans Sora Sompeng', - 'Noto Sans Soyombo', - 'Noto Sans Sundanese', - 'Noto Sans Syloti Nagri', - 'Noto Sans Syriac', + 'Noto Sans Gurmukhi UI', + 'Noto Sans Gujarati UI', + 'Noto Sans Bengali UI', + 'Noto Sans Thai UI', + 'Noto Sans Lao UI', + 'Noto Sans Myanmar UI', + 'Noto Sans Ethiopic', + 'Noto Sans Khmer UI', + 'Noto Sans SC', + 'Noto Sans JP', 'Noto Sans TC', - 'Noto Sans Tagalog', - 'Noto Sans Tagbanwa', - 'Noto Sans Tai Le', - 'Noto Sans Tai Tham', - 'Noto Sans Tai Viet', - 'Noto Sans Takri', - 'Noto Sans Tamil', - 'Noto Sans Tamil Supplement', - 'Noto Sans Telugu', - 'Noto Sans Thaana', - 'Noto Sans Thai', - 'Noto Sans Tifinagh', - 'Noto Sans Tirhuta', - 'Noto Sans Ugaritic', - 'Noto Sans Vai', - 'Noto Sans Wancho', - 'Noto Sans Warang Citi', - 'Noto Sans Yi', - 'Noto Sans Zanabazar Square', + 'Noto Sans HK', + 'Noto Sans KR', + 'Noto Sans Egyptian Hieroglyphs', })); // Construct random paragraphs out of supported code units. @@ -412,34 +358,16 @@ void testMain() { } class TestDownloader extends NotoDownloader { - // Where to redirect downloads to. static final Map mockDownloads = {}; @override Future downloadAsString(String url, {String? debugDescription}) async { if (mockDownloads.containsKey(url)) { - url = mockDownloads[url]!; - final Uri uri = Uri.parse(url); - expect(uri.isScheme('http'), isFalse); - expect(uri.isScheme('https'), isFalse); - return super.downloadAsString(url); + return mockDownloads[url]!; } else { return ''; } } - - @override - Future downloadAsBytes(String url, {String? debugDescription}) { - if (mockDownloads.containsKey(url)) { - url = mockDownloads[url]!; - final Uri uri = Uri.parse(url); - expect(uri.isScheme('http'), isFalse); - expect(uri.isScheme('https'), isFalse); - return super.downloadAsBytes(url); - } else { - return Future.value(Uint8List(0).buffer); - } - } } class LoggingDownloader implements NotoDownloader { From 7db434b2087d09689eb3ce6a3a46fbb06e9b0879 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 09:32:27 -0400 Subject: [PATCH 425/558] Roll Dart SDK from d6387a631d60 to 2bfe7945d2aa (1 revision) (#35536) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 9a55c31eebc7e..15b2e65f34119 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'd6387a631d6060fba37d2c0c5f6b10017b74a85c', + 'dart_revision': '2bfe7945d2aa24afaacb34d99e17215a80ef478c', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index b4647fb516544..548492218a7cf 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 2f94bdf454754437e7d871aa49d74179 +Signature: 08d3ae27d4967d586a61824c57e6b876 UNUSED LICENSES: @@ -10750,6 +10750,7 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/js_shared/lib/synced/embedded_ FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/ffi_native_finalizer_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/finalizer_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/vm/lib/hash_factories.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/core_patch.dart @@ -10772,6 +10773,8 @@ FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/math_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/object_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/print_patch.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/regexp_helper.dart +FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/regexp_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/stack_trace_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/stopwatch_patch.dart FILE: ../../../third_party/dart/sdk/lib/_internal/wasm/lib/string_buffer_patch.dart From 544c34102586e4c8ea77c6b536cb726c3686e810 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Fri, 19 Aug 2022 10:01:01 -0700 Subject: [PATCH 426/558] Revert "Pushing BackdropFilter Mutator (#34355)" (#35543) This reverts commit 3ec9f21b22e3ce7fcc6cd32b1876f193c4a5bf3a. --- flow/embedded_views.h | 17 ------ flow/layers/backdrop_filter_layer.cc | 3 - flow/layers/platform_view_layer.cc | 1 - flow/mutators_stack_unittests.cc | 27 --------- .../shell_test_external_view_embedder.cc | 36 +----------- .../shell_test_external_view_embedder.h | 22 +------ shell/common/shell_unittests.cc | 58 +------------------ .../framework/Source/FlutterPlatformViews.mm | 9 --- .../Source/FlutterPlatformViews_Internal.h | 9 --- .../darwin/ios/ios_external_view_embedder.h | 7 --- .../darwin/ios/ios_external_view_embedder.mm | 11 ---- 11 files changed, 5 insertions(+), 195 deletions(-) diff --git a/flow/embedded_views.h b/flow/embedded_views.h index cc252ae527835..1839a8aa2e3f8 100644 --- a/flow/embedded_views.h +++ b/flow/embedded_views.h @@ -248,11 +248,6 @@ class EmbeddedViewParams { // Clippings are ignored. const SkRect& finalBoundingRect() const { return final_bounding_rect_; } - // Pushes the stored DlImageFilter object to the mutators stack. - void PushImageFilter(std::shared_ptr filter) { - mutators_stack_.PushBackdropFilter(filter); - } - // Whether the embedder should construct DisplayList objects to hold the // rendering commands for each between-view slice of the layer tree. bool display_list_enabled() const { return display_list_enabled_; } @@ -444,18 +439,6 @@ class ExternalViewEmbedder { // 'EndFrame', otherwise returns false. bool GetUsedThisFrame() const { return used_this_frame_; } - // Pushes the platform view id of a visited platform view to a list of - // visited platform views. - virtual void PushVisitedPlatformView(int64_t view_id) {} - - // Pushes a DlImageFilter object to each platform view within a list of - // visited platform views. - // - // See also: |PushVisitedPlatformView| for pushing platform view ids to the - // visited platform views list. - virtual void PushFilterToVisitedPlatformViews( - std::shared_ptr filter) {} - private: bool used_this_frame_ = false; diff --git a/flow/layers/backdrop_filter_layer.cc b/flow/layers/backdrop_filter_layer.cc index 9f67b746b1c9b..d52ac787c44c0 100644 --- a/flow/layers/backdrop_filter_layer.cc +++ b/flow/layers/backdrop_filter_layer.cc @@ -43,9 +43,6 @@ void BackdropFilterLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context, true, bool(filter_)); - if (context->view_embedder != nullptr) { - context->view_embedder->PushFilterToVisitedPlatformViews(filter_); - } SkRect child_paint_bounds = SkRect::MakeEmpty(); PrerollChildren(context, matrix, &child_paint_bounds); child_paint_bounds.join(context->cull_rect); diff --git a/flow/layers/platform_view_layer.cc b/flow/layers/platform_view_layer.cc index a86886fb1b04f..8a46cbbce127c 100644 --- a/flow/layers/platform_view_layer.cc +++ b/flow/layers/platform_view_layer.cc @@ -29,7 +29,6 @@ void PlatformViewLayer::Preroll(PrerollContext* context, context->display_list_enabled); context->view_embedder->PrerollCompositeEmbeddedView(view_id_, std::move(params)); - context->view_embedder->PushVisitedPlatformView(view_id_); } void PlatformViewLayer::Paint(PaintContext& context) const { diff --git a/flow/mutators_stack_unittests.cc b/flow/mutators_stack_unittests.cc index c93838cfa68bf..a460125ef9627 100644 --- a/flow/mutators_stack_unittests.cc +++ b/flow/mutators_stack_unittests.cc @@ -163,8 +163,6 @@ TEST(MutatorsStack, Equality) { stack.PushClipPath(path); int alpha = 240; stack.PushOpacity(alpha); - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - stack.PushBackdropFilter(filter); MutatorsStack stackOther; SkMatrix matrixOther = SkMatrix::Scale(1, 1); @@ -177,9 +175,6 @@ TEST(MutatorsStack, Equality) { stackOther.PushClipPath(otherPath); int otherAlpha = 240; stackOther.PushOpacity(otherAlpha); - auto otherFilter = - std::make_shared(5, 5, DlTileMode::kClamp); - stackOther.PushBackdropFilter(otherFilter); ASSERT_TRUE(stack == stackOther); } @@ -209,11 +204,6 @@ TEST(Mutator, Initialization) { int alpha = 240; Mutator mutator5 = Mutator(alpha); ASSERT_TRUE(mutator5.GetType() == MutatorType::kOpacity); - - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - Mutator mutator6 = Mutator(filter); - ASSERT_TRUE(mutator6.GetType() == MutatorType::kBackdropFilter); - ASSERT_TRUE(mutator6.GetFilter() == *filter); } TEST(Mutator, CopyConstructor) { @@ -242,11 +232,6 @@ TEST(Mutator, CopyConstructor) { Mutator mutator5 = Mutator(alpha); Mutator copy5 = Mutator(mutator5); ASSERT_TRUE(mutator5 == copy5); - - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - Mutator mutator6 = Mutator(filter); - Mutator copy6 = Mutator(mutator6); - ASSERT_TRUE(mutator6 == copy6); } TEST(Mutator, Equality) { @@ -275,11 +260,6 @@ TEST(Mutator, Equality) { Mutator mutator5 = Mutator(alpha); Mutator otherMutator5 = Mutator(alpha); ASSERT_TRUE(mutator5 == otherMutator5); - - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - Mutator mutator6 = Mutator(filter); - Mutator otherMutator6 = Mutator(filter); - ASSERT_TRUE(mutator6 == otherMutator6); } TEST(Mutator, UnEquality) { @@ -295,13 +275,6 @@ TEST(Mutator, UnEquality) { Mutator mutator2 = Mutator(alpha); Mutator otherMutator2 = Mutator(alpha2); ASSERT_TRUE(mutator2 != otherMutator2); - - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - auto filter2 = - std::make_shared(10, 10, DlTileMode::kClamp); - Mutator mutator3 = Mutator(filter); - Mutator otherMutator3 = Mutator(filter2); - ASSERT_TRUE(mutator3 != otherMutator3); } } // namespace testing diff --git a/shell/common/shell_test_external_view_embedder.cc b/shell/common/shell_test_external_view_embedder.cc index 579f682089517..a366e6f99075c 100644 --- a/shell/common/shell_test_external_view_embedder.cc +++ b/shell/common/shell_test_external_view_embedder.cc @@ -28,14 +28,6 @@ SkISize ShellTestExternalViewEmbedder::GetLastSubmittedFrameSize() { return last_submitted_frame_size_; } -std::vector ShellTestExternalViewEmbedder::GetVisitedPlatformViews() { - return visited_platform_views_; -} - -MutatorsStack ShellTestExternalViewEmbedder::GetStack(int64_t view_id) { - return mutators_stacks_[view_id]; -} - // |ExternalViewEmbedder| void ShellTestExternalViewEmbedder::CancelFrame() {} @@ -49,16 +41,7 @@ void ShellTestExternalViewEmbedder::BeginFrame( // |ExternalViewEmbedder| void ShellTestExternalViewEmbedder::PrerollCompositeEmbeddedView( int view_id, - std::unique_ptr params) { - SkRect view_bounds = SkRect::Make(frame_size_); - std::unique_ptr view; - if (params->display_list_enabled()) { - view = std::make_unique(view_bounds); - } else { - view = std::make_unique(view_bounds); - } - slices_.insert_or_assign(view_id, std::move(view)); -} + std::unique_ptr params) {} // |ExternalViewEmbedder| PostPrerollResult ShellTestExternalViewEmbedder::PostPrerollAction( @@ -79,24 +62,9 @@ ShellTestExternalViewEmbedder::GetCurrentBuilders() { } // |ExternalViewEmbedder| -void ShellTestExternalViewEmbedder::PushVisitedPlatformView(int64_t view_id) { - visited_platform_views_.push_back(view_id); -} - -// |ExternalViewEmbedder| -void ShellTestExternalViewEmbedder::PushFilterToVisitedPlatformViews( - std::shared_ptr filter) { - for (int64_t id : visited_platform_views_) { - EmbeddedViewParams params = current_composition_params_[id]; - params.PushImageFilter(filter); - current_composition_params_[id] = params; - mutators_stacks_[id] = params.mutatorsStack(); - } -} - EmbedderPaintContext ShellTestExternalViewEmbedder::CompositeEmbeddedView( int view_id) { - return {slices_[view_id]->canvas(), slices_[view_id]->builder()}; + return {nullptr, nullptr}; } // |ExternalViewEmbedder| diff --git a/shell/common/shell_test_external_view_embedder.h b/shell/common/shell_test_external_view_embedder.h index 583a09182e5fc..1bb70fd131e07 100644 --- a/shell/common/shell_test_external_view_embedder.h +++ b/shell/common/shell_test_external_view_embedder.h @@ -7,7 +7,6 @@ #include "flutter/flow/embedded_views.h" #include "flutter/fml/raster_thread_merger.h" -#include "third_party/skia/include/core/SkPictureRecorder.h" namespace flutter { @@ -33,15 +32,9 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { // the external view embedder. int GetSubmittedFrameCount(); - // Returns the size of last submitted frame surface. + // Returns the size of last submitted frame surface SkISize GetLastSubmittedFrameSize(); - // Returns the mutators stack for the given platform view. - MutatorsStack GetStack(int64_t); - - // Returns the list of visited platform views. - std::vector GetVisitedPlatformViews(); - private: // |ExternalViewEmbedder| void CancelFrame() override; @@ -71,13 +64,6 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { // |ExternalViewEmbedder| EmbedderPaintContext CompositeEmbeddedView(int view_id) override; - // |ExternalViewEmbedder| - void PushVisitedPlatformView(int64_t view_id) override; - - // |ExternalViewEmbedder| - void PushFilterToVisitedPlatformViews( - std::shared_ptr filter) override; - // |ExternalViewEmbedder| void SubmitFrame(GrDirectContext* context, std::unique_ptr frame) override; @@ -98,11 +84,7 @@ class ShellTestExternalViewEmbedder final : public ExternalViewEmbedder { PostPrerollResult post_preroll_result_; bool support_thread_merging_; - SkISize frame_size_; - std::map> slices_; - std::map mutators_stacks_; - std::map current_composition_params_; - std::vector visited_platform_views_; + std::atomic submitted_frame_count_; std::atomic last_submitted_frame_size_; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 5d513b5239541..e2193d9be7d24 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -13,10 +13,8 @@ #include "assets/directory_asset_bundle.h" #include "common/graphics/persistent_cache.h" -#include "flutter/flow/layers/backdrop_filter_layer.h" #include "flutter/flow/layers/display_list_layer.h" #include "flutter/flow/layers/layer_raster_cache_item.h" -#include "flutter/flow/layers/platform_view_layer.h" #include "flutter/flow/layers/transform_layer.h" #include "flutter/fml/command_line.h" #include "flutter/fml/dart/dart_converter.h" @@ -767,62 +765,8 @@ TEST_F(ShellTest, ExternalEmbedderNoThreadMerger) { PumpOneFrame(shell.get(), 100, 100, builder); end_frame_latch.Wait(); - ASSERT_TRUE(end_frame_called); - - DestroyShell(std::move(shell)); -} - -TEST_F(ShellTest, PushBackdropFilterToVisitedPlatformViews) { - auto settings = CreateSettingsForFixture(); - fml::AutoResetWaitableEvent end_frame_latch; - bool end_frame_called = false; - auto end_frame_callback = - [&](bool should_resubmit_frame, - fml::RefPtr raster_thread_merger) { - ASSERT_TRUE(raster_thread_merger.get() == nullptr); - ASSERT_FALSE(should_resubmit_frame); - end_frame_called = true; - end_frame_latch.Signal(); - }; - auto external_view_embedder = std::make_shared( - end_frame_callback, PostPrerollResult::kResubmitFrame, false); - auto shell = CreateShell(std::move(settings), GetTaskRunnersForFixture(), - false, external_view_embedder); - - // Create the surface needed by rasterizer - PlatformViewNotifyCreated(shell.get()); - - auto configuration = RunConfiguration::InferFromSettings(settings); - configuration.SetEntrypoint("emptyMain"); - RunEngine(shell.get(), std::move(configuration)); - - LayerTreeBuilder builder = [&](std::shared_ptr root) { - auto platform_view_layer = std::make_shared( - SkPoint::Make(10, 10), SkSize::Make(10, 10), 50); - root->Add(platform_view_layer); - auto filter = std::make_shared(5, 5, DlTileMode::kClamp); - auto backdrop_filter_layer = - std::make_shared(filter, DlBlendMode::kSrcOver); - root->Add(backdrop_filter_layer); - auto platform_view_layer2 = std::make_shared( - SkPoint::Make(10, 10), SkSize::Make(10, 10), 75); - backdrop_filter_layer->Add(platform_view_layer2); - }; - - PumpOneFrame(shell.get(), 100, 100, builder); - end_frame_latch.Wait(); - ASSERT_EQ(external_view_embedder->GetVisitedPlatformViews().size(), - (const unsigned long)2); - ASSERT_EQ(external_view_embedder->GetVisitedPlatformViews()[0], 50); - ASSERT_EQ(external_view_embedder->GetVisitedPlatformViews()[1], 75); - ASSERT_TRUE(external_view_embedder->GetStack(75).is_empty()); - ASSERT_FALSE(external_view_embedder->GetStack(50).is_empty()); - - auto filter = DlBlurImageFilter(5, 5, DlTileMode::kClamp); - auto mutator = *external_view_embedder->GetStack(50).Begin(); - ASSERT_EQ(mutator->GetType(), MutatorType::kBackdropFilter); - ASSERT_EQ(mutator->GetFilter(), filter); + ASSERT_TRUE(end_frame_called); DestroyShell(std::move(shell)); } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index 9987fe6dd8265..bea122558e458 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -318,15 +318,6 @@ - (BOOL)flt_hasFirstResponderInViewHierarchySubtree { } } -void FlutterPlatformViewsController::PushFilterToVisitedPlatformViews( - std::shared_ptr filter) { - for (int64_t id : visited_platform_views_) { - EmbeddedViewParams params = current_composition_params_[id]; - params.PushImageFilter(filter); - current_composition_params_[id] = params; - } -} - void FlutterPlatformViewsController::PrerollCompositeEmbeddedView( int view_id, std::unique_ptr params) { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index c7877dc7601ed..0a2e134f876dd 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -186,12 +186,6 @@ class FlutterPlatformViewsController { // responder. Returns -1 if no such platform view is found. long FindFirstResponderPlatformViewId(); - // Pushes backdrop filter mutation to the mutator stack of each visited platform view. - void PushFilterToVisitedPlatformViews(std::shared_ptr filter); - - // Pushes the view id of a visted platform view to the list of visied platform views. - void PushVisitedPlatformView(int64_t view_id) { visited_platform_views_.push_back(view_id); } - private: static const size_t kMaxLayerAllocations = 2; @@ -299,9 +293,6 @@ class FlutterPlatformViewsController { // The last ID in this vector belond to the that is composited on top of all others. std::vector composition_order_; - // A vector of visited platform view IDs. - std::vector visited_platform_views_; - // The latest composition order that was presented in Present(). std::vector active_composition_order_; diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.h b/shell/platform/darwin/ios/ios_external_view_embedder.h index 03cec910bae39..3a5a0b3c17613 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.h +++ b/shell/platform/darwin/ios/ios_external_view_embedder.h @@ -67,13 +67,6 @@ class IOSExternalViewEmbedder : public ExternalViewEmbedder { // |ExternalViewEmbedder| bool SupportsDynamicThreadMerging() override; - // |ExternalViewEmbedder| - void PushFilterToVisitedPlatformViews( - std::shared_ptr filter) override; - - // |ExternalViewEmbedder| - void PushVisitedPlatformView(int64_t view_id) override; - FML_DISALLOW_COPY_AND_ASSIGN(IOSExternalViewEmbedder); }; diff --git a/shell/platform/darwin/ios/ios_external_view_embedder.mm b/shell/platform/darwin/ios/ios_external_view_embedder.mm index 76995be2c56ad..e67983321c770 100644 --- a/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -98,15 +98,4 @@ return true; } -// |ExternalViewEmbedder| -void IOSExternalViewEmbedder::PushFilterToVisitedPlatformViews( - std::shared_ptr filter) { - platform_views_controller_->PushFilterToVisitedPlatformViews(filter); -} - -// |ExternalViewEmbedder| -void IOSExternalViewEmbedder::PushVisitedPlatformView(int64_t view_id) { - platform_views_controller_->PushVisitedPlatformView(view_id); -} - } // namespace flutter From 232967ba7af123a232bcdc5b3bb20d1803ad8b4f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 13:11:01 -0400 Subject: [PATCH 427/558] Roll Skia from 38cd049145b2 to 4c4a0d21cbb0 (1 revision) (#35537) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 15b2e65f34119..2c05ed2a61810 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': '38cd049145b2b22f2e6e89b10c3a80d1c19b92ff', + 'skia_revision': '4c4a0d21cbb0b8117924245ef06092e8b1d56cbe', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index fd00ffb32108b..7bfb199091c89 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: f63f699b39764bc0710ac78bcc86983e +Signature: 83a782dab232d1616f34bbcda46a0cfc UNUSED LICENSES: From 360923e606e7293e7a7485a8abbcce520d3a4f4c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 13:57:12 -0400 Subject: [PATCH 428/558] Roll Dart SDK from 2bfe7945d2aa to 74b964226fc6 (1 revision) (#35545) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 2c05ed2a61810..33c67c8baf927 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '2bfe7945d2aa24afaacb34d99e17215a80ef478c', + 'dart_revision': '74b964226fc6a0532b7fef760a28568caea12464', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 92bc431e097d57ac4a1f21c25e996c98d23197b4 Mon Sep 17 00:00:00 2001 From: Bernardo Eilert Trevisan <43152751+betrevisan@users.noreply.github.com> Date: Fri, 19 Aug 2022 11:00:04 -0700 Subject: [PATCH 429/558] [Impeller] sRGB to Linear Gamma filter implementation. (#35441) * Update display list dispatcher * Add new shader * add filter contents files * update filter contents * Update content context * update unit tests * Update build file. * Formatting. * Formatting. * Fix typo * Update filter. * Formatting. * Update license * license * Remove unnecessary library * Fix typo * Formatting * Formatting --- ci/licenses_golden/licenses_flutter | 4 + .../display_list/display_list_dispatcher.cc | 7 +- impeller/entity/BUILD.gn | 4 + impeller/entity/contents/content_context.cc | 2 + impeller/entity/contents/content_context.h | 10 +++ .../contents/filters/filter_contents.cc | 8 ++ .../entity/contents/filters/filter_contents.h | 3 + .../filters/srgb_to_linear_filter_contents.cc | 83 +++++++++++++++++++ .../filters/srgb_to_linear_filter_contents.h | 29 +++++++ impeller/entity/entity_unittests.cc | 51 ++++++++++++ .../entity/shaders/srgb_to_linear_filter.frag | 27 ++++++ .../entity/shaders/srgb_to_linear_filter.vert | 15 ++++ 12 files changed, 240 insertions(+), 3 deletions(-) create mode 100644 impeller/entity/contents/filters/srgb_to_linear_filter_contents.cc create mode 100644 impeller/entity/contents/filters/srgb_to_linear_filter_contents.h create mode 100644 impeller/entity/shaders/srgb_to_linear_filter.frag create mode 100644 impeller/entity/shaders/srgb_to_linear_filter.vert diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e32f53958103f..ff50b5a9d01f5 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -584,6 +584,8 @@ FILE: ../../../flutter/impeller/entity/contents/filters/inputs/texture_filter_in FILE: ../../../flutter/impeller/entity/contents/filters/inputs/texture_filter_input.h FILE: ../../../flutter/impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc FILE: ../../../flutter/impeller/entity/contents/filters/linear_to_srgb_filter_contents.h +FILE: ../../../flutter/impeller/entity/contents/filters/srgb_to_linear_filter_contents.cc +FILE: ../../../flutter/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.cc FILE: ../../../flutter/impeller/entity/contents/linear_gradient_contents.h FILE: ../../../flutter/impeller/entity/contents/radial_gradient_contents.cc @@ -655,6 +657,8 @@ FILE: ../../../flutter/impeller/entity/shaders/solid_fill.frag FILE: ../../../flutter/impeller/entity/shaders/solid_fill.vert FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.frag FILE: ../../../flutter/impeller/entity/shaders/solid_stroke.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/texture_fill.frag FILE: ../../../flutter/impeller/entity/shaders/texture_fill.vert diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 0fbd95d891b24..8cdc086523f0e 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -438,9 +438,10 @@ void DisplayListDispatcher::setColorFilter( return; } case flutter::DlColorFilterType::kSrgbToLinearGamma: - FML_LOG(ERROR) << "requested DlColorFilterType::kSrgbToLinearGamma"; - UNIMPLEMENTED; - break; + paint_.color_filter = [](FilterInput::Ref input) { + return FilterContents::MakeSrgbToLinearFilter({input}); + }; + return; case flutter::DlColorFilterType::kLinearToSrgbGamma: paint_.color_filter = [](FilterInput::Ref input) { return FilterContents::MakeLinearToSrgbFilter({input}); diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 270f3c8a64baf..ec16b8e5849ae 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -47,6 +47,8 @@ impeller_shaders("entity_shaders") { "shaders/solid_fill.vert", "shaders/solid_stroke.frag", "shaders/solid_stroke.vert", + "shaders/srgb_to_linear_filter.frag", + "shaders/srgb_to_linear_filter.vert", "shaders/sweep_gradient_fill.frag", "shaders/texture_fill.frag", "shaders/texture_fill.vert", @@ -89,6 +91,8 @@ impeller_component("entity") { "contents/filters/inputs/texture_filter_input.h", "contents/filters/linear_to_srgb_filter_contents.cc", "contents/filters/linear_to_srgb_filter_contents.h", + "contents/filters/srgb_to_linear_filter_contents.cc", + "contents/filters/srgb_to_linear_filter_contents.h", "contents/linear_gradient_contents.cc", "contents/linear_gradient_contents.h", "contents/radial_gradient_contents.cc", diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 030fb6b1398d4..7dd30168df53e 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -201,6 +201,8 @@ ContentContext::ContentContext(std::shared_ptr context) CreateDefaultPipeline(*context_); linear_to_srgb_filter_pipelines_[{}] = CreateDefaultPipeline(*context_); + srgb_to_linear_filter_pipelines_[{}] = + CreateDefaultPipeline(*context_); solid_stroke_pipelines_[{}] = CreateDefaultPipeline(*context_); glyph_atlas_pipelines_[{}] = diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index f984a1da068a1..7c79b72e746a7 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -51,6 +51,8 @@ #include "impeller/entity/solid_fill.vert.h" #include "impeller/entity/solid_stroke.frag.h" #include "impeller/entity/solid_stroke.vert.h" +#include "impeller/entity/srgb_to_linear_filter.frag.h" +#include "impeller/entity/srgb_to_linear_filter.vert.h" #include "impeller/entity/sweep_gradient_fill.frag.h" #include "impeller/entity/texture_fill.frag.h" #include "impeller/entity/texture_fill.vert.h" @@ -117,6 +119,8 @@ using ColorMatrixColorFilterPipeline = ColorMatrixColorFilterFragmentShader>; using LinearToSrgbFilterPipeline = PipelineT; +using SrgbToLinearFilterPipeline = + PipelineT; using SolidStrokePipeline = PipelineT; using GlyphAtlasPipeline = @@ -220,6 +224,11 @@ class ContentContext { return GetPipeline(linear_to_srgb_filter_pipelines_, opts); } + std::shared_ptr GetSrgbToLinearFilterPipeline( + ContentContextOptions opts) const { + return GetPipeline(srgb_to_linear_filter_pipelines_, opts); + } + std::shared_ptr GetSolidStrokePipeline( ContentContextOptions opts) const { return GetPipeline(solid_stroke_pipelines_, opts); @@ -355,6 +364,7 @@ class ContentContext { mutable Variants color_matrix_color_filter_pipelines_; mutable Variants linear_to_srgb_filter_pipelines_; + mutable Variants srgb_to_linear_filter_pipelines_; mutable Variants solid_stroke_pipelines_; mutable Variants clip_pipelines_; mutable Variants glyph_atlas_pipelines_; diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index 48a79fd87849f..694c56ef952ca 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -20,6 +20,7 @@ #include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/entity/contents/filters/linear_to_srgb_filter_contents.h" +#include "impeller/entity/contents/filters/srgb_to_linear_filter_contents.h" #include "impeller/entity/contents/texture_contents.h" #include "impeller/entity/entity.h" #include "impeller/geometry/path_builder.h" @@ -130,6 +131,13 @@ std::shared_ptr FilterContents::MakeLinearToSrgbFilter( return filter; } +std::shared_ptr FilterContents::MakeSrgbToLinearFilter( + FilterInput::Ref input) { + auto filter = std::make_shared(); + filter->SetInputs({input}); + return filter; +} + FilterContents::FilterContents() = default; FilterContents::~FilterContents() = default; diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 677ebc1dbae15..1ee7a5813aef0 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -69,6 +69,9 @@ class FilterContents : public Contents { static std::shared_ptr MakeLinearToSrgbFilter( FilterInput::Ref input); + static std::shared_ptr MakeSrgbToLinearFilter( + FilterInput::Ref input); + FilterContents(); ~FilterContents() override; diff --git a/impeller/entity/contents/filters/srgb_to_linear_filter_contents.cc b/impeller/entity/contents/filters/srgb_to_linear_filter_contents.cc new file mode 100644 index 0000000000000..bef5543d24a37 --- /dev/null +++ b/impeller/entity/contents/filters/srgb_to_linear_filter_contents.cc @@ -0,0 +1,83 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "impeller/entity/contents/filters/srgb_to_linear_filter_contents.h" + +#include "impeller/entity/contents/content_context.h" +#include "impeller/entity/contents/contents.h" +#include "impeller/geometry/point.h" +#include "impeller/geometry/vector.h" +#include "impeller/renderer/render_pass.h" +#include "impeller/renderer/sampler_library.h" + +namespace impeller { + +SrgbToLinearFilterContents::SrgbToLinearFilterContents() = default; + +SrgbToLinearFilterContents::~SrgbToLinearFilterContents() = default; + +std::optional SrgbToLinearFilterContents::RenderFilter( + const FilterInput::Vector& inputs, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const { + if (inputs.empty()) { + return std::nullopt; + } + + using VS = SrgbToLinearFilterPipeline::VertexShader; + using FS = SrgbToLinearFilterPipeline::FragmentShader; + + auto input_snapshot = inputs[0]->GetSnapshot(renderer, entity); + if (!input_snapshot.has_value()) { + return std::nullopt; + } + + ContentContext::SubpassCallback callback = [&](const ContentContext& renderer, + RenderPass& pass) { + Command cmd; + cmd.label = "sRGB to Linear Filter"; + + auto options = OptionsFromPass(pass); + options.blend_mode = Entity::BlendMode::kSource; + cmd.pipeline = renderer.GetSrgbToLinearFilterPipeline(options); + + VertexBufferBuilder vtx_builder; + vtx_builder.AddVertices({ + {Point(0, 0)}, + {Point(1, 0)}, + {Point(1, 1)}, + {Point(0, 0)}, + {Point(1, 1)}, + {Point(0, 1)}, + }); + + auto& host_buffer = pass.GetTransientsBuffer(); + auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer); + cmd.BindVertices(vtx_buffer); + + VS::FrameInfo frame_info; + frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); + + auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({}); + FS::BindInputTexture(cmd, input_snapshot->texture, sampler); + + VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info)); + + return pass.AddCommand(std::move(cmd)); + }; + + auto out_texture = + renderer.MakeSubpass(input_snapshot->texture->GetSize(), callback); + if (!out_texture) { + return std::nullopt; + } + out_texture->SetLabel("SrgbToLinear Texture"); + + return Snapshot{.texture = out_texture, + .transform = input_snapshot->transform, + .sampler_descriptor = input_snapshot->sampler_descriptor}; +} + +} // namespace impeller diff --git a/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h b/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h new file mode 100644 index 0000000000000..099aced7bffd5 --- /dev/null +++ b/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h @@ -0,0 +1,29 @@ +// 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 "impeller/entity/contents/filters/filter_contents.h" +#include "impeller/entity/contents/filters/inputs/filter_input.h" + +namespace impeller { + +class SrgbToLinearFilterContents final : public FilterContents { + public: + SrgbToLinearFilterContents(); + + ~SrgbToLinearFilterContents() override; + + private: + // |FilterContents| + std::optional RenderFilter( + const FilterInput::Vector& input_textures, + const ContentContext& renderer, + const Entity& entity, + const Rect& coverage) const override; + + FML_DISALLOW_COPY_AND_ASSIGN(SrgbToLinearFilterContents); +}; + +} // namespace impeller diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 260b9e480505a..76c62dc976fa7 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -1594,5 +1594,56 @@ TEST_P(EntityTest, LinearToSrgbFilter) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +TEST_P(EntityTest, SrgbToLinearFilterCoverageIsCorrect) { + // Set up a simple color background. + auto fill = std::make_shared(); + fill->SetPath( + PathBuilder{}.AddRect(Rect::MakeXYWH(0, 0, 300, 400)).TakePath()); + fill->SetColor(Color::DeepPink()); + + auto filter = FilterContents::MakeSrgbToLinearFilter(FilterInput::Make(fill)); + + Entity e; + e.SetTransformation(Matrix()); + + // Confirm that the actual filter coverage matches the expected coverage. + auto actual = filter->GetCoverage(e); + auto expected = Rect::MakeXYWH(0, 0, 300, 400); + + ASSERT_TRUE(actual.has_value()); + ASSERT_RECT_NEAR(actual.value(), expected); +} + +TEST_P(EntityTest, SrgbToLinearFilter) { + auto image = CreateTextureForFixture("embarcadero.jpg"); + ASSERT_TRUE(image); + + auto callback = [&](ContentContext& context, RenderPass& pass) -> bool { + auto filtered = + FilterContents::MakeSrgbToLinearFilter(FilterInput::Make(image)); + + // Define the entity that will serve as the control image as a Gaussian blur + // filter with no filter at all. + Entity entity_left; + entity_left.SetTransformation(Matrix::MakeScale(GetContentScale()) * + Matrix::MakeTranslation({100, 300}) * + Matrix::MakeScale(Vector2{0.5, 0.5})); + auto unfiltered = FilterContents::MakeGaussianBlur(FilterInput::Make(image), + Sigma{0}, Sigma{0}); + entity_left.SetContents(unfiltered); + + // Define the entity that will be filtered from sRGB to linear. + Entity entity_right; + entity_right.SetTransformation(Matrix::MakeScale(GetContentScale()) * + Matrix::MakeTranslation({500, 300}) * + Matrix::MakeScale(Vector2{0.5, 0.5})); + entity_right.SetContents(filtered); + return entity_left.Render(context, pass) && + entity_right.Render(context, pass); + }; + + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/shaders/srgb_to_linear_filter.frag b/impeller/entity/shaders/srgb_to_linear_filter.frag new file mode 100644 index 0000000000000..6c51b59a1de4c --- /dev/null +++ b/impeller/entity/shaders/srgb_to_linear_filter.frag @@ -0,0 +1,27 @@ +// 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 + +// Creates a color filter that applies the inverse of the sRGB gamma curve +// to the RGB channels. + +uniform sampler2D input_texture; + +in vec2 v_position; +out vec4 frag_color; + +void main() { + vec4 input_color = texture(input_texture, v_position); + + for (int i = 0; i < 4; i++) { + if (input_color[i] <= 0.04045) { + input_color[i] = input_color[i] / 12.92; + } else { + input_color[i] = pow((input_color[i] + 0.055) / 1.055, 2.4); + } + } + + frag_color = input_color; +} diff --git a/impeller/entity/shaders/srgb_to_linear_filter.vert b/impeller/entity/shaders/srgb_to_linear_filter.vert new file mode 100644 index 0000000000000..b741b2744ec60 --- /dev/null +++ b/impeller/entity/shaders/srgb_to_linear_filter.vert @@ -0,0 +1,15 @@ +// 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. + +uniform FrameInfo { + mat4 mvp; +} frame_info; + +in vec2 position; +out vec2 v_position; + +void main() { + v_position = position; + gl_Position = frame_info.mvp * vec4(position, 0.0, 1.0); +} From c1ce554ac5bd3686a2e8c29ce0ff93266b568182 Mon Sep 17 00:00:00 2001 From: Kaushik Iska Date: Fri, 19 Aug 2022 14:41:46 -0400 Subject: [PATCH 430/558] Do not override partial repaint support globally (#35539) --- flow/surface_frame.h | 2 +- shell/gpu/gpu_surface_gl_delegate.h | 2 +- shell/gpu/gpu_surface_gl_skia.cc | 8 +++----- shell/gpu/gpu_surface_gl_skia.h | 8 ++++---- .../android/android_surface_gl_skia.cc | 2 ++ .../platform/embedder/embedder_surface_gl.cc | 11 ++++++++++ shell/platform/embedder/embedder_surface_gl.h | 3 +++ .../embedder/tests/embedder_unittests_gl.cc | 20 +++++++++++++++++++ 8 files changed, 45 insertions(+), 11 deletions(-) diff --git a/flow/surface_frame.h b/flow/surface_frame.h index 961bfe5965241..d630ab331be40 100644 --- a/flow/surface_frame.h +++ b/flow/surface_frame.h @@ -51,7 +51,7 @@ class SurfaceFrame { // If existing damage is unspecified (nullopt), entire frame will be // rasterized (no partial redraw). To signal that there is no existing // damage use an empty SkIRect. - std::optional existing_damage; + std::optional existing_damage = std::nullopt; }; SurfaceFrame(sk_sp surface, diff --git a/shell/gpu/gpu_surface_gl_delegate.h b/shell/gpu/gpu_surface_gl_delegate.h index d1e31b96559f5..f097cba2d0266 100644 --- a/shell/gpu/gpu_surface_gl_delegate.h +++ b/shell/gpu/gpu_surface_gl_delegate.h @@ -30,7 +30,7 @@ struct GLFBOInfo { // This boolean flags whether the returned FBO supports partial repaint. const bool partial_repaint_enabled; // The frame buffer's existing damage (i.e. damage since it was last used). - const SkIRect existing_damage; + const std::optional existing_damage; }; // Information passed during presentation of a frame. diff --git a/shell/gpu/gpu_surface_gl_skia.cc b/shell/gpu/gpu_surface_gl_skia.cc index eafb6120b3774..06b3d5d3c5748 100644 --- a/shell/gpu/gpu_surface_gl_skia.cc +++ b/shell/gpu/gpu_surface_gl_skia.cc @@ -196,7 +196,6 @@ bool GPUSurfaceGLSkia::CreateOrUpdateSurfaces(const SkISize& size) { onscreen_surface_ = std::move(onscreen_surface); fbo_id_ = fbo_info.fbo_id; - supports_partial_repaint_ = fbo_info.partial_repaint_enabled; existing_damage_ = fbo_info.existing_damage; return true; @@ -250,9 +249,9 @@ std::unique_ptr GPUSurfaceGLSkia::AcquireFrame( }; framebuffer_info = delegate_->GLContextFramebufferInfo(); - // Partial repaint is enabled by default - framebuffer_info.supports_partial_repaint = supports_partial_repaint_; - framebuffer_info.existing_damage = existing_damage_; + if (!framebuffer_info.existing_damage.has_value()) { + framebuffer_info.existing_damage = existing_damage_; + } return std::make_unique(surface, std::move(framebuffer_info), submit_callback, std::move(context_switch)); @@ -303,7 +302,6 @@ bool GPUSurfaceGLSkia::PresentSurface(const SurfaceFrame& frame, onscreen_surface_ = std::move(new_onscreen_surface); fbo_id_ = fbo_info.fbo_id; - supports_partial_repaint_ = fbo_info.partial_repaint_enabled; existing_damage_ = fbo_info.existing_damage; } diff --git a/shell/gpu/gpu_surface_gl_skia.h b/shell/gpu/gpu_surface_gl_skia.h index 39f6e3f607dfe..35caee497eb6f 100644 --- a/shell/gpu/gpu_surface_gl_skia.h +++ b/shell/gpu/gpu_surface_gl_skia.h @@ -67,8 +67,10 @@ class GPUSurfaceGLSkia : public Surface { sk_sp onscreen_surface_; /// FBO backing the current `onscreen_surface_`. uint32_t fbo_id_ = 0; - // Private variable used to keep track of the current FBO's existing damage. - SkIRect existing_damage_ = SkIRect::MakeEmpty(); + // The current FBO's existing damage, as tracked by the GPU surface, delegates + // still have an option of overriding this damage with their own in + // `GLContextFrameBufferInfo`. + std::optional existing_damage_ = std::nullopt; bool context_owner_ = false; // TODO(38466): Refactor GPU surface APIs take into account the fact that an // external view embedder may want to render to the root surface. This is a @@ -76,8 +78,6 @@ class GPUSurfaceGLSkia : public Surface { // external view embedder is present. const bool render_to_surface_ = true; bool valid_ = false; - // Partial repaint is on by default. - bool supports_partial_repaint_ = true; // WeakPtrFactory must be the last member. fml::TaskRunnerAffineWeakPtrFactory weak_factory_; diff --git a/shell/platform/android/android_surface_gl_skia.cc b/shell/platform/android/android_surface_gl_skia.cc index 50ac30835bb1f..f4e3d5acd24c3 100644 --- a/shell/platform/android/android_surface_gl_skia.cc +++ b/shell/platform/android/android_surface_gl_skia.cc @@ -167,6 +167,8 @@ GLFBOInfo AndroidSurfaceGLSkia::GLContextFBO(GLFrameInfo frame_info) const { // The default window bound framebuffer on Android. return GLFBOInfo{ .fbo_id = 0, + .partial_repaint_enabled = onscreen_surface_->SupportsPartialRepaint(), + .existing_damage = onscreen_surface_->InitialDamage(), }; } diff --git a/shell/platform/embedder/embedder_surface_gl.cc b/shell/platform/embedder/embedder_surface_gl.cc index 88cdb316c5e5b..f08793429c4d5 100644 --- a/shell/platform/embedder/embedder_surface_gl.cc +++ b/shell/platform/embedder/embedder_surface_gl.cc @@ -80,6 +80,17 @@ EmbedderSurfaceGL::GLProcResolver EmbedderSurfaceGL::GetGLProcResolver() const { return gl_dispatch_table_.gl_proc_resolver; } +// |GPUSurfaceGLDelegate| +SurfaceFrame::FramebufferInfo EmbedderSurfaceGL::GLContextFramebufferInfo() + const { + // Enable partial repaint by default on the embedders. + auto info = SurfaceFrame::FramebufferInfo{}; + info.supports_readback = true; + info.supports_partial_repaint = + gl_dispatch_table_.gl_populate_existing_damage != nullptr; + return info; +} + // |EmbedderSurface| std::unique_ptr EmbedderSurfaceGL::CreateGPUSurface() { const bool render_to_surface = !external_view_embedder_; diff --git a/shell/platform/embedder/embedder_surface_gl.h b/shell/platform/embedder/embedder_surface_gl.h index 583f0f469a0e7..695aeea84b860 100644 --- a/shell/platform/embedder/embedder_surface_gl.h +++ b/shell/platform/embedder/embedder_surface_gl.h @@ -71,6 +71,9 @@ class EmbedderSurfaceGL final : public EmbedderSurface, // |GPUSurfaceGLDelegate| GLProcResolver GetGLProcResolver() const override; + // |GPUSurfaceGLDelegate| + SurfaceFrame::FramebufferInfo GLContextFramebufferInfo() const override; + FML_DISALLOW_COPY_AND_ASSIGN(EmbedderSurfaceGL); }; diff --git a/shell/platform/embedder/tests/embedder_unittests_gl.cc b/shell/platform/embedder/tests/embedder_unittests_gl.cc index cd12376085349..08f653495f379 100644 --- a/shell/platform/embedder/tests/embedder_unittests_gl.cc +++ b/shell/platform/embedder/tests/embedder_unittests_gl.cc @@ -4065,6 +4065,26 @@ TEST_F(EmbedderTest, ExternalTextureGLRefreshedTooOften) { EXPECT_TRUE(resolve_called); } +TEST_F(EmbedderTest, + PresentInfoReceivesNoDamageWhenPopulateExistingDamageIsUndefined) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kOpenGLContext); + + EmbedderConfigBuilder builder(context); + builder.SetOpenGLRendererConfig(SkISize::Make(800, 600)); + builder.SetDartEntrypoint("render_gradient"); + builder.GetRendererConfig().open_gl.populate_existing_damage = nullptr; + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + // No damage should be passed. + static_cast(context).SetGLPresentCallback( + [](FlutterPresentInfo present_info) { + ASSERT_EQ(present_info.frame_damage.damage, nullptr); + ASSERT_EQ(present_info.buffer_damage.damage, nullptr); + }); +} + INSTANTIATE_TEST_SUITE_P( EmbedderTestGlVk, EmbedderTestMultiBackend, From ab9034ff187c0e7f8f24207bdd2e68c2311e3813 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 15:34:13 -0400 Subject: [PATCH 431/558] Roll Fuchsia Linux SDK from -NNSCH3WIpT1x-ZpP... to qkLLOLyDJFclyuGN7... (#35551) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 33c67c8baf927..535db3d4da2b6 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': '-NNSCH3WIpT1x-ZpP3cDjMDYEmdhGciRL4ixvBkopcEC' + 'version': 'qkLLOLyDJFclyuGN7WP78QrAKS80W6F6H6WNl_K4pzIC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index e71e92d463d46..2798bc67ee9b3 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 12ea8269e6915822944b0d05c09c0c62 +Signature: b47424a813c87d11af55d4d1964cbe78 UNUSED LICENSES: From 02f9602f7c2b6c62a60a7e109007d8fd0270f1ac Mon Sep 17 00:00:00 2001 From: JsouLiang Date: Sat, 20 Aug 2022 03:43:29 +0800 Subject: [PATCH 432/558] Make ShaderMaskLayer code builder aware (#35534) --- flow/layers/shader_mask_layer.cc | 33 +++++++++++++++------- flow/layers/shader_mask_layer_unittests.cc | 13 +++++---- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index b7dd47e48d99e..9a99a807ea2fe 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -54,19 +54,32 @@ void ShaderMaskLayer::Paint(PaintContext& context) const { return; } } + auto shader_rect = SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()); - Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( - context, paint_bounds(), cache_paint.sk_paint()); - PaintChildren(context); + if (context.leaf_nodes_builder) { + context.builder_multiplexer->saveLayer(&paint_bounds(), + cache_paint.dl_paint()); + PaintChildren(context); - SkPaint paint; - paint.setBlendMode(ToSk(blend_mode_)); - if (shader_) { - paint.setShader(shader_->skia_object()); + DlPaint dl_paint; + dl_paint.setBlendMode(blend_mode_); + if (shader_) { + dl_paint.setColorSource(shader_.get()); + } + context.leaf_nodes_builder->translate(mask_rect_.left(), mask_rect_.top()); + context.leaf_nodes_builder->drawRect(shader_rect, dl_paint); + } else { + Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( + context, paint_bounds(), cache_paint.sk_paint()); + PaintChildren(context); + SkPaint paint; + paint.setBlendMode(ToSk(blend_mode_)); + if (shader_) { + paint.setShader(shader_->skia_object()); + } + context.leaf_nodes_canvas->translate(mask_rect_.left(), mask_rect_.top()); + context.leaf_nodes_canvas->drawRect(shader_rect, paint); } - context.leaf_nodes_canvas->translate(mask_rect_.left(), mask_rect_.top()); - context.leaf_nodes_canvas->drawRect( - SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()), paint); } } // namespace flutter diff --git a/flow/layers/shader_mask_layer_unittests.cc b/flow/layers/shader_mask_layer_unittests.cc index 5f6c38b76a0f1..c4f863ac01eaa 100644 --- a/flow/layers/shader_mask_layer_unittests.cc +++ b/flow/layers/shader_mask_layer_unittests.cc @@ -373,17 +373,18 @@ TEST_F(ShaderMaskLayerTest, OpacityInheritance) { { expected_builder.translate(offset.fX, offset.fY); /* ShaderMaskLayer::Paint() */ { - expected_builder.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&child_path.getBounds(), true); + DlPaint sl_paint; + sl_paint.setColor(opacity_alpha << 24); + expected_builder.saveLayer(&child_path.getBounds(), &sl_paint); { /* child layer paint */ { - expected_builder.setColor(0xFF000000); - expected_builder.drawPath(child_path); + expected_builder.drawPath(child_path, + DlPaint().setColor(0xFF000000)); } expected_builder.translate(mask_rect.fLeft, mask_rect.fTop); - expected_builder.setBlendMode(DlBlendMode::kSrc); expected_builder.drawRect( - SkRect::MakeWH(mask_rect.width(), mask_rect.height())); + SkRect::MakeWH(mask_rect.width(), mask_rect.height()), + DlPaint().setBlendMode(DlBlendMode::kSrc)); } expected_builder.restore(); } From ee7842c4d5c3b830cfb5d33a57aaad57ccc3bc43 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 15:59:04 -0400 Subject: [PATCH 433/558] Roll Skia from 4c4a0d21cbb0 to 3fbcfbbd908e (23 revisions) (#35552) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index 535db3d4da2b6..382ec533a3285 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': '4c4a0d21cbb0b8117924245ef06092e8b1d56cbe', + 'skia_revision': '3fbcfbbd908e05e6511003355df6b593205641bf', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 7bfb199091c89..3f302c8597680 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 83a782dab232d1616f34bbcda46a0cfc +Signature: 7d71b9695cd4213f1229bf927a59ec8f UNUSED LICENSES: @@ -2575,7 +2575,6 @@ FILE: ../../../third_party/skia/src/gpu/graphite/Caps.h FILE: ../../../third_party/skia/src/gpu/graphite/CommandBuffer.cpp FILE: ../../../third_party/skia/src/gpu/graphite/CommandBuffer.h FILE: ../../../third_party/skia/src/gpu/graphite/Context.cpp -FILE: ../../../third_party/skia/src/gpu/graphite/ContextPriv.cpp FILE: ../../../third_party/skia/src/gpu/graphite/ContextPriv.h FILE: ../../../third_party/skia/src/gpu/graphite/ContextUtils.cpp FILE: ../../../third_party/skia/src/gpu/graphite/ContextUtils.h @@ -5579,7 +5578,6 @@ FILE: ../../../third_party/skia/src/gpu/graphite/PaintParams.cpp FILE: ../../../third_party/skia/src/gpu/graphite/PaintParams.h FILE: ../../../third_party/skia/src/gpu/graphite/QueueManager.cpp FILE: ../../../third_party/skia/src/gpu/graphite/QueueManager.h -FILE: ../../../third_party/skia/src/gpu/graphite/RecorderPriv.cpp FILE: ../../../third_party/skia/src/gpu/graphite/RecorderPriv.h FILE: ../../../third_party/skia/src/gpu/graphite/RecordingPriv.h FILE: ../../../third_party/skia/src/gpu/graphite/Resource.cpp @@ -6568,6 +6566,7 @@ FILE: ../../../third_party/skia/gm/drawlines_with_local_matrix.cpp FILE: ../../../third_party/skia/gm/palette.cpp FILE: ../../../third_party/skia/include/core/SkOpenTypeSVGDecoder.h FILE: ../../../third_party/skia/modules/skottie/src/BlendModes.cpp +FILE: ../../../third_party/skia/modules/skunicode/src/SkUnicode_client.cpp FILE: ../../../third_party/skia/modules/svg/include/SkSVGOpenTypeSVGDecoder.h FILE: ../../../third_party/skia/modules/svg/src/SkSVGOpenTypeSVGDecoder.cpp FILE: ../../../third_party/skia/samplecode/SampleSBIX.cpp From a418ffad89a99c2a32f4e843b715fd217f3e5764 Mon Sep 17 00:00:00 2001 From: joshualitt Date: Fri, 19 Aug 2022 13:08:35 -0700 Subject: [PATCH 434/558] [dart2wasm] Fix non-static interop class. (#35407) --- lib/web_ui/lib/src/engine/safe_browser_api.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 3029fb06ba566..eb0ca60c689b3 100644 --- a/lib/web_ui/lib/src/engine/safe_browser_api.dart +++ b/lib/web_ui/lib/src/engine/safe_browser_api.dart @@ -328,7 +328,10 @@ class DecodeOptions { /// * https://www.w3.org/TR/webcodecs/#videoframe-interface @JS() @anonymous -class VideoFrame implements DomCanvasImageSource { +@staticInterop +class VideoFrame implements DomCanvasImageSource {} + +extension VideoFrameExtension on VideoFrame { external int allocationSize(); external JsPromise copyTo(Uint8List destination); external String? get format; From 6dfb38a84140e2707b1fb39e102d564be9395694 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Fri, 19 Aug 2022 13:54:47 -0700 Subject: [PATCH 435/558] Updates accessible_navigation trigger in Android (#35478) * Updates accessible_navigation trigger in Android * update doc comments * comment * addressing comment --- .../io/flutter/view/AccessibilityBridge.java | 34 ++++++++++++++--- .../flutter/view/AccessibilityBridgeTest.java | 38 +++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index 28b09507214b3..6168954f58bb0 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -257,6 +257,30 @@ public int getHoveredObjectId() { @Nullable private OnAccessibilityChangeListener onAccessibilityChangeListener; + // Whether the users are using assistive technologies to interact with the devices. + // + // The getter returns true when at least one of the assistive technologies is running: + // TalkBack, SwitchAccess, or VoiceAccess. + @VisibleForTesting + public boolean getAccessibleNavigation() { + return accessibleNavigation; + } + + private boolean accessibleNavigation = false; + + private void setAccessibleNavigation(boolean value) { + if (accessibleNavigation == value) { + return; + } + accessibleNavigation = value; + if (accessibleNavigation) { + accessibilityFeatureFlags |= AccessibilityFeature.ACCESSIBLE_NAVIGATION.value; + } else { + accessibilityFeatureFlags &= ~AccessibilityFeature.ACCESSIBLE_NAVIGATION.value; + } + sendLatestAccessibilityFlagsToFlutter(); + } + // Set to true after {@code release} has been invoked. private boolean isReleased = false; @@ -331,6 +355,7 @@ public void onAccessibilityStateChanged(boolean accessibilityEnabled) { accessibilityChannel.setAccessibilityMessageHandler(accessibilityMessageHandler); accessibilityChannel.onAndroidAccessibilityEnabled(); } else { + setAccessibleNavigation(false); accessibilityChannel.setAccessibilityMessageHandler(null); accessibilityChannel.onAndroidAccessibilityDisabled(); } @@ -409,7 +434,6 @@ public AccessibilityBridge( this.contentResolver = contentResolver; this.accessibilityViewEmbedder = accessibilityViewEmbedder; this.platformViewsAccessibilityDelegate = platformViewsAccessibilityDelegate; - // Tell Flutter whether accessibility is initially active or not. Then register a listener // to be notified of changes in the future. accessibilityStateChangeListener.onAccessibilityStateChanged(accessibilityManager.isEnabled()); @@ -425,13 +449,10 @@ public void onTouchExplorationStateChanged(boolean isTouchExplorationEnabled) { if (isReleased) { return; } - if (isTouchExplorationEnabled) { - accessibilityFeatureFlags |= AccessibilityFeature.ACCESSIBLE_NAVIGATION.value; - } else { + if (!isTouchExplorationEnabled) { + setAccessibleNavigation(false); onTouchExplorationExit(); - accessibilityFeatureFlags &= ~AccessibilityFeature.ACCESSIBLE_NAVIGATION.value; } - sendLatestAccessibilityFlagsToFlutter(); if (onAccessibilityChangeListener != null) { onAccessibilityChangeListener.onAccessibilityChanged( @@ -551,6 +572,7 @@ public AccessibilityNodeInfo obtainAccessibilityNodeInfo(View rootView, int virt // Suppressing Lint warning for new API, as we are version guarding all calls to newer APIs @SuppressLint("NewApi") public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { + setAccessibleNavigation(true); if (virtualViewId >= MIN_ENGINE_GENERATED_NODE_ID) { // The node is in the engine generated range, and is provided by the accessibility view // embedder. diff --git a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java index 324331d9d1817..155401992df05 100644 --- a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java +++ b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java @@ -124,6 +124,44 @@ public void itTakesGlobalCoordinatesOfFlutterViewIntoAccount() { assertEquals(position, outBoundsInScreen.top); } + @Test + public void itSetsAccessibleNavigation() { + AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); + AccessibilityViewEmbedder mockViewEmbedder = mock(AccessibilityViewEmbedder.class); + AccessibilityManager mockManager = mock(AccessibilityManager.class); + View mockRootView = mock(View.class); + Context context = mock(Context.class); + when(mockRootView.getContext()).thenReturn(context); + when(context.getPackageName()).thenReturn("test"); + when(mockManager.isTouchExplorationEnabled()).thenReturn(false); + AccessibilityBridge accessibilityBridge = + setUpBridge( + /*rootAccessibilityView=*/ mockRootView, + /*accessibilityChannel=*/ mockChannel, + /*accessibilityManager=*/ mockManager, + /*contentResolver=*/ null, + /*accessibilityViewEmbedder=*/ mockViewEmbedder, + /*platformViewsAccessibilityDelegate=*/ null); + ArgumentCaptor listenerCaptor = + ArgumentCaptor.forClass(AccessibilityManager.TouchExplorationStateChangeListener.class); + verify(mockManager).addTouchExplorationStateChangeListener(listenerCaptor.capture()); + + assertEquals(accessibilityBridge.getAccessibleNavigation(), false); + verify(mockChannel).setAccessibilityFeatures(0); + reset(mockChannel); + + // Simulate assistive technology accessing accessibility tree. + accessibilityBridge.createAccessibilityNodeInfo(0); + verify(mockChannel).setAccessibilityFeatures(1); + assertEquals(accessibilityBridge.getAccessibleNavigation(), true); + + // Simulate turning off TalkBack. + reset(mockChannel); + listenerCaptor.getValue().onTouchExplorationStateChanged(false); + verify(mockChannel).setAccessibilityFeatures(0); + assertEquals(accessibilityBridge.getAccessibleNavigation(), false); + } + @Test public void itDoesNotContainADescriptionIfScopesRoute() { AccessibilityBridge accessibilityBridge = setUpBridge(); From 2360bca56a1a4349271e3af0cf62ae24a8292e38 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 17:40:03 -0400 Subject: [PATCH 436/558] Roll Skia from 3fbcfbbd908e to 35fa09015a76 (5 revisions) (#35553) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 382ec533a3285..0f85f717bdf9d 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': '3fbcfbbd908e05e6511003355df6b593205641bf', + 'skia_revision': '35fa09015a76d37a0edd354cabc6cb43aacc964f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 3f302c8597680..ca2f253cec729 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 7d71b9695cd4213f1229bf927a59ec8f +Signature: e2dd8ad3815a2a9165a27e69b685fea3 UNUSED LICENSES: From 94d07855d7a4fee611abdd61775d88a158fcdba0 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 18:12:57 -0400 Subject: [PATCH 437/558] Roll Dart SDK from 74b964226fc6 to 220698d69c17 (1 revision) (#35555) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 0f85f717bdf9d..a2863e630a3fc 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '74b964226fc6a0532b7fef760a28568caea12464', + 'dart_revision': '220698d69c1737184658dd513f567d795909f8f4', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From c01d510f6fc6e6a79f48aa480789f66d83937c22 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 18:41:12 -0400 Subject: [PATCH 438/558] Roll Fuchsia Mac SDK from MQoH-sefjYwKG_X2h... to kTnpJXzVrlaAf7ayc... (#35556) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index a2863e630a3fc..2df2c88d7ff56 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'MQoH-sefjYwKG_X2hv8qKJfSW15nnrtuAJbJMEHFsOsC' + 'version': 'kTnpJXzVrlaAf7aycDF3ql8314jLLTrqhWheqF9PQiUC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 0c0e8cd4eee5178c118bddb190fe9a1faa13f464 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 19:19:59 -0400 Subject: [PATCH 439/558] Roll Skia from 35fa09015a76 to 4c3c98cdb1d3 (3 revisions) (#35558) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index 2df2c88d7ff56..24fc436050ca7 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': '35fa09015a76d37a0edd354cabc6cb43aacc964f', + 'skia_revision': '4c3c98cdb1d343431ddca7eaad78d654b9278251', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index ca2f253cec729..f052b33edece6 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e2dd8ad3815a2a9165a27e69b685fea3 +Signature: 54b226856cfe153ff14686940324e1fe UNUSED LICENSES: @@ -1318,8 +1318,6 @@ FILE: ../../../third_party/skia/src/opts/BUILD.bazel FILE: ../../../third_party/skia/src/pathops/BUILD.bazel FILE: ../../../third_party/skia/src/pdf/BUILD.bazel FILE: ../../../third_party/skia/src/ports/BUILD.bazel -FILE: ../../../third_party/skia/src/ports/SkTLS_pthread.cpp -FILE: ../../../third_party/skia/src/ports/SkTLS_win.cpp FILE: ../../../third_party/skia/src/sfnt/BUILD.bazel FILE: ../../../third_party/skia/src/shaders/BUILD.bazel FILE: ../../../third_party/skia/src/shaders/gradients/BUILD.bazel From a7868e9567fc898a81fd827c9904f73b8de48c35 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 19 Aug 2022 16:28:30 -0700 Subject: [PATCH 440/558] Include TextureViews in the output of Scene.toImage[Sync] (#35527) Update Picture rasterization for toImage to accept a layer tree, optionally flattening on the raster thread if present. Update Deferred GPU image for toImageSync to accept a layer tree, flattening it the first time it creates an image, storing the resulting display list. This is also a performance fix for the zoom page transition, which currently does too much work on the UI thread on frame 1 --- flow/layers/layer_tree.cc | 14 ++++--- flow/layers/layer_tree.h | 6 ++- lib/ui/compositing.dart | 1 + lib/ui/compositing/scene.cc | 39 ++++++++++++------ lib/ui/compositing/scene.h | 25 +++++++---- .../display_list_deferred_image_gpu.cc | 41 ++++++++++++++++++- .../display_list_deferred_image_gpu.h | 21 +++++++++- lib/ui/painting/picture.cc | 35 +++++++++++++--- lib/ui/painting/picture.h | 12 ++++++ lib/ui/snapshot_delegate.h | 3 ++ runtime/runtime_delegate.h | 2 +- shell/common/animator.cc | 2 +- shell/common/animator.h | 2 +- shell/common/animator_unittests.cc | 4 +- shell/common/engine.cc | 2 +- shell/common/engine.h | 2 +- shell/common/engine_unittests.cc | 2 +- shell/common/pipeline.h | 4 +- shell/common/rasterizer.cc | 8 +++- shell/common/rasterizer.h | 9 ++-- shell/common/rasterizer_unittests.cc | 26 ++++++------ shell/common/shell_test.cc | 2 +- testing/dart/compositing_test.dart | 22 ++++++++++ 23 files changed, 220 insertions(+), 64 deletions(-) diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index de7573ef4ac39..3b4907b5336bf 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -171,7 +171,10 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, } } -sk_sp LayerTree::Flatten(const SkRect& bounds) { +sk_sp LayerTree::Flatten( + const SkRect& bounds, + std::shared_ptr texture_registry, + GrDirectContext* gr_context) { TRACE_EVENT0("flutter", "LayerTree::Flatten"); DisplayListCanvasRecorder builder(bounds); @@ -179,13 +182,14 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { MutatorsStack unused_stack; const FixedRefreshRateStopwatch unused_stopwatch; SkMatrix root_surface_transformation; + // No root surface transformation. So assume identity. root_surface_transformation.reset(); PrerollContext preroll_context{ // clang-format off .raster_cache = nullptr, - .gr_context = nullptr, + .gr_context = gr_context, .view_embedder = nullptr, .mutators_stack = unused_stack, .dst_color_space = nullptr, @@ -193,7 +197,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .surface_needs_readback = false, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = nullptr, + .texture_registry = texture_registry, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_ // clang-format on @@ -209,12 +213,12 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { // clang-format off .internal_nodes_canvas = &internal_nodes_canvas, .leaf_nodes_canvas = &builder, - .gr_context = nullptr, + .gr_context = gr_context, .dst_color_space = nullptr, .view_embedder = nullptr, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = nullptr, + .texture_registry = texture_registry, .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_, diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index c7daa5f809e9f..167500400b758 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -8,6 +8,7 @@ #include #include +#include "flutter/common/graphics/texture.h" #include "flutter/flow/compositor_context.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" @@ -41,7 +42,10 @@ class LayerTree { void Paint(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache = false) const; - sk_sp Flatten(const SkRect& bounds); + sk_sp Flatten( + const SkRect& bounds, + std::shared_ptr texture_registry = nullptr, + GrDirectContext* gr_context = nullptr); Layer* root_layer() const { return root_layer_.get(); } diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index 528fc027c043a..384d1b500ccb3 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -38,6 +38,7 @@ class Scene extends NativeFieldWrapperClass1 { external String? _toImageSync(int width, int height, _Image outImage); /// Creates a raster image representation of the current state of the scene. + /// /// This is a slow operation that is performed on a background thread. /// /// Callers must dispose the [Image] when they are done with it. If the result diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 734a67ef2481c..5a8601b90effe 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -5,6 +5,7 @@ #include "flutter/lib/ui/compositing/scene.h" #include "flutter/fml/trace_event.h" +#include "flutter/lib/ui/painting/display_list_deferred_image_gpu.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/picture.h" #include "flutter/lib/ui/ui_dart_state.h" @@ -42,7 +43,7 @@ Scene::Scene(std::shared_ptr rootLayer, ->get_window(0) ->viewport_metrics(); - layer_tree_ = std::make_unique( + layer_tree_ = std::make_shared( SkISize::Make(viewport_metrics.physical_width, viewport_metrics.physical_height), static_cast(viewport_metrics.device_pixel_ratio)); @@ -69,12 +70,7 @@ Dart_Handle Scene::toImageSync(uint32_t width, return tonic::ToDart("Scene did not contain a layer tree."); } - auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height)); - if (!picture) { - return tonic::ToDart("Could not flatten scene into a layer tree."); - } - - Picture::RasterizeToImageSync(picture, width, height, raw_image_handle); + Scene::RasterizeToImage(width, height, raw_image_handle); return Dart_Null(); } @@ -87,15 +83,32 @@ Dart_Handle Scene::toImage(uint32_t width, return tonic::ToDart("Scene did not contain a layer tree."); } - auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height)); - if (!picture) { - return tonic::ToDart("Could not flatten scene into a layer tree."); - } + return Picture::RasterizeLayerTreeToImage(std::move(layer_tree_), width, + height, raw_image_callback); +} - return Picture::RasterizeToImage(picture, width, height, raw_image_callback); +void Scene::RasterizeToImage(uint32_t width, + uint32_t height, + Dart_Handle raw_image_handle) { + auto* dart_state = UIDartState::Current(); + if (!dart_state) { + return; + } + auto unref_queue = dart_state->GetSkiaUnrefQueue(); + auto snapshot_delegate = dart_state->GetSnapshotDelegate(); + auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); + + auto image = CanvasImage::Create(); + const SkImageInfo image_info = SkImageInfo::Make( + width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType); + auto dl_image = DlDeferredImageGPU::MakeFromLayerTree( + image_info, std::move(layer_tree_), std::move(snapshot_delegate), + std::move(raster_task_runner), std::move(unref_queue)); + image->set_image(dl_image); + image->AssociateWithDartWrapper(raw_image_handle); } -std::unique_ptr Scene::takeLayerTree() { +std::shared_ptr Scene::takeLayerTree() { return std::move(layer_tree_); } diff --git a/lib/ui/compositing/scene.h b/lib/ui/compositing/scene.h index 1cf95aad4ec43..aca797836fcb1 100644 --- a/lib/ui/compositing/scene.h +++ b/lib/ui/compositing/scene.h @@ -26,7 +26,7 @@ class Scene : public RefCountedDartWrappable { bool checkerboardRasterCacheImages, bool checkerboardOffscreenLayers); - std::unique_ptr takeLayerTree(); + std::shared_ptr takeLayerTree(); Dart_Handle toImageSync(uint32_t width, uint32_t height, @@ -34,17 +34,26 @@ class Scene : public RefCountedDartWrappable { Dart_Handle toImage(uint32_t width, uint32_t height, - Dart_Handle image_callback); + Dart_Handle raw_image_handle); void dispose(); private: - explicit Scene(std::shared_ptr rootLayer, - uint32_t rasterizerTracingThreshold, - bool checkerboardRasterCacheImages, - bool checkerboardOffscreenLayers); - - std::unique_ptr layer_tree_; + Scene(std::shared_ptr rootLayer, + uint32_t rasterizerTracingThreshold, + bool checkerboardRasterCacheImages, + bool checkerboardOffscreenLayers); + + void RasterizeToImage(uint32_t width, + uint32_t height, + Dart_Handle raw_image_handle); + + // This is a shared_ptr to support flattening the layer tree from the UI + // thread onto the raster thread - allowing access to the texture registry + // required to render TextureLayers. + // + // No longer valid after calling `takeLayerTree`. + std::shared_ptr layer_tree_; }; } // namespace flutter diff --git a/lib/ui/painting/display_list_deferred_image_gpu.cc b/lib/ui/painting/display_list_deferred_image_gpu.cc index beeb0ccf80404..4ea7ad7ab1666 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.cc +++ b/lib/ui/painting/display_list_deferred_image_gpu.cc @@ -22,6 +22,19 @@ sk_sp DlDeferredImageGPU::Make( raster_task_runner)); } +sk_sp DlDeferredImageGPU::MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + return sk_sp(new DlDeferredImageGPU( + ImageWrapper::MakeFromLayerTree( + image_info, std::move(layer_tree), std::move(snapshot_delegate), + raster_task_runner, std::move(unref_queue)), + raster_task_runner)); +} + DlDeferredImageGPU::DlDeferredImageGPU( std::shared_ptr image_wrapper, fml::RefPtr raster_task_runner) @@ -92,6 +105,20 @@ DlDeferredImageGPU::ImageWrapper::Make( return wrapper; } +std::shared_ptr +DlDeferredImageGPU::ImageWrapper::MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + auto wrapper = std::shared_ptr( + new ImageWrapper(image_info, nullptr, std::move(snapshot_delegate), + std::move(raster_task_runner), std::move(unref_queue))); + wrapper->SnapshotDisplayList(std::move(layer_tree)); + return wrapper; +} + DlDeferredImageGPU::ImageWrapper::ImageWrapper( const SkImageInfo& image_info, sk_sp display_list, @@ -131,9 +158,11 @@ bool DlDeferredImageGPU::ImageWrapper::isTextureBacked() const { return texture_.isValid(); } -void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { +void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList( + std::shared_ptr layer_tree) { fml::TaskRunner::RunNowOrPostTask( - raster_task_runner_, [weak_this = weak_from_this()]() { + raster_task_runner_, + [weak_this = weak_from_this(), layer_tree = std::move(layer_tree)]() { auto wrapper = weak_this.lock(); if (!wrapper) { return; @@ -142,6 +171,14 @@ void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { if (!snapshot_delegate) { return; } + if (layer_tree) { + auto display_list = + layer_tree->Flatten(SkRect::MakeWH(wrapper->image_info_.width(), + wrapper->image_info_.height()), + snapshot_delegate.get()->GetTextureRegistry(), + snapshot_delegate.get()->GetGrContext()); + wrapper->display_list_ = std::move(display_list); + } auto result = snapshot_delegate->MakeGpuImage(wrapper->display_list_, wrapper->image_info_); if (result->texture.isValid()) { diff --git a/lib/ui/painting/display_list_deferred_image_gpu.h b/lib/ui/painting/display_list_deferred_image_gpu.h index 429dcd873a101..5f04eb25d0765 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.h +++ b/lib/ui/painting/display_list_deferred_image_gpu.h @@ -11,6 +11,7 @@ #include "flutter/common/graphics/texture.h" #include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_image.h" +#include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/fml/macros.h" #include "flutter/fml/memory/weak_ptr.h" @@ -28,6 +29,13 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); + static sk_sp MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + // |DlImage| ~DlDeferredImageGPU() override; @@ -73,6 +81,13 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); + static std::shared_ptr MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + const SkImageInfo image_info() const { return image_info_; } const GrBackendTexture& texture() const { return texture_; } bool isTextureBacked() const; @@ -103,7 +118,11 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); - void SnapshotDisplayList(); + // If a layer tree is provided, it will be flattened during the raster + // thread task spwaned by this method. After being flattened into a display + // list, the image wrapper will be updated to hold this display list and the + // layer tree can be dropped. + void SnapshotDisplayList(std::shared_ptr layer_tree = nullptr); // |ContextListener| void OnGrContextCreated() override; diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 4d5411d1830f6..849b5cc634c35 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -95,11 +95,21 @@ Dart_Handle Picture::RasterizeToImage(sk_sp display_list, Dart_Handle raw_image_callback) { return RasterizeToImage( [display_list](SkCanvas* canvas) { display_list->RenderTo(canvas); }, - width, height, raw_image_callback); + nullptr, width, height, raw_image_callback); +} + +Dart_Handle Picture::RasterizeLayerTreeToImage( + std::shared_ptr layer_tree, + uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback) { + return RasterizeToImage(nullptr, std::move(layer_tree), width, height, + raw_image_callback); } Dart_Handle Picture::RasterizeToImage( std::function draw_callback, + std::shared_ptr layer_tree, uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { @@ -158,10 +168,25 @@ Dart_Handle Picture::RasterizeToImage( // Kick things off on the raster rask runner. fml::TaskRunner::RunNowOrPostTask( - raster_task_runner, [ui_task_runner, snapshot_delegate, draw_callback, - picture_bounds, ui_task] { - sk_sp raster_image = snapshot_delegate->MakeRasterSnapshot( - draw_callback, picture_bounds); + raster_task_runner, + [ui_task_runner, snapshot_delegate, draw_callback, picture_bounds, + ui_task, layer_tree = std::move(layer_tree)] { + sk_sp raster_image; + if (layer_tree) { + auto display_list = layer_tree->Flatten( + SkRect::MakeWH(picture_bounds.width(), picture_bounds.height()), + snapshot_delegate.get()->GetTextureRegistry(), + snapshot_delegate.get()->GetGrContext()); + + raster_image = snapshot_delegate->MakeRasterSnapshot( + [display_list](SkCanvas* canvas) { + display_list->RenderTo(canvas); + }, + picture_bounds); + } else { + raster_image = snapshot_delegate->MakeRasterSnapshot(draw_callback, + picture_bounds); + } fml::TaskRunner::RunNowOrPostTask( ui_task_runner, diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index 1cb390a182138..77fda55884c3d 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -6,6 +6,7 @@ #define FLUTTER_LIB_UI_PAINTING_PICTURE_H_ #include "flutter/display_list/display_list.h" +#include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/image.h" @@ -51,8 +52,19 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + static Dart_Handle RasterizeLayerTreeToImage( + std::shared_ptr layer_tree, + uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback); + + // Callers may provide either a draw_callback (which should reference a + // display list) or a layer tree. If a layer tree is provided, it will be + // flattened on the raster thread. In this case the draw callback will be + // ignored. static Dart_Handle RasterizeToImage( std::function draw_callback, + std::shared_ptr layer_tree, uint32_t width, uint32_t height, Dart_Handle raw_image_callback); diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 4158d28701cbb..3b59ffed9fb23 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -13,6 +13,7 @@ #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkPromiseImageTexture.h" #include "third_party/skia/include/gpu/GrContextThreadSafeProxy.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" namespace flutter { @@ -52,6 +53,8 @@ class SnapshotDelegate { /// virtual std::shared_ptr GetTextureRegistry() = 0; + virtual GrDirectContext* GetGrContext() = 0; + virtual std::unique_ptr MakeGpuImage( sk_sp display_list, const SkImageInfo& image_info) = 0; diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index 540e47dd09ba4..ad680677338e0 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -24,7 +24,7 @@ class RuntimeDelegate { virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0; - virtual void Render(std::unique_ptr layer_tree) = 0; + virtual void Render(std::shared_ptr layer_tree) = 0; virtual void UpdateSemantics(SemanticsNodeUpdates update, CustomAccessibilityActionUpdates actions) = 0; diff --git a/shell/common/animator.cc b/shell/common/animator.cc index 31bd0cdfb5eb5..d8614dc22f69c 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -144,7 +144,7 @@ void Animator::BeginFrame( } } -void Animator::Render(std::unique_ptr layer_tree) { +void Animator::Render(std::shared_ptr layer_tree) { has_rendered_ = true; last_layer_tree_size_ = layer_tree->frame_size(); diff --git a/shell/common/animator.h b/shell/common/animator.h index d822935307ac8..6550452ba481e 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -54,7 +54,7 @@ class Animator final { void RequestFrame(bool regenerate_layer_tree = true); - void Render(std::unique_ptr layer_tree); + void Render(std::shared_ptr layer_tree); const std::weak_ptr GetVsyncWaiter() const; diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc index 628d7eb9afbc0..91c2bad1b033f 100644 --- a/shell/common/animator_unittests.cc +++ b/shell/common/animator_unittests.cc @@ -157,7 +157,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyIdleBeforeRender) { [&] { ASSERT_FALSE(delegate.notify_idle_called_); auto layer_tree = - std::make_unique(SkISize::Make(600, 800), 1.0); + std::make_shared(SkISize::Make(600, 800), 1.0); animator->Render(std::move(layer_tree)); task_runners.GetPlatformTaskRunner()->PostTask(flush_vsync_task); }, @@ -240,7 +240,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyDelegateIfPipelineIsNotEmpty) { PostTaskSync(task_runners.GetUITaskRunner(), [&] { auto layer_tree = - std::make_unique(SkISize::Make(600, 800), 1.0); + std::make_shared(SkISize::Make(600, 800), 1.0); animator->Render(std::move(layer_tree)); }); } diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 9a0e5d03e4883..c2cbc9f512b98 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -439,7 +439,7 @@ void Engine::ScheduleFrame(bool regenerate_layer_tree) { animator_->RequestFrame(regenerate_layer_tree); } -void Engine::Render(std::unique_ptr layer_tree) { +void Engine::Render(std::shared_ptr layer_tree) { if (!layer_tree) { return; } diff --git a/shell/common/engine.h b/shell/common/engine.h index 491ec4f0e5fe3..04b968f106c41 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -879,7 +879,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { std::string DefaultRouteName() override; // |RuntimeDelegate| - void Render(std::unique_ptr layer_tree) override; + void Render(std::shared_ptr layer_tree) override; // |RuntimeDelegate| void UpdateSemantics(SemanticsNodeUpdates update, diff --git a/shell/common/engine_unittests.cc b/shell/common/engine_unittests.cc index 62674947f9e87..6dfc93c555c36 100644 --- a/shell/common/engine_unittests.cc +++ b/shell/common/engine_unittests.cc @@ -48,7 +48,7 @@ class MockRuntimeDelegate : public RuntimeDelegate { public: MOCK_METHOD0(DefaultRouteName, std::string()); MOCK_METHOD1(ScheduleFrame, void(bool)); - MOCK_METHOD1(Render, void(std::unique_ptr)); + MOCK_METHOD1(Render, void(std::shared_ptr)); MOCK_METHOD2(UpdateSemantics, void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates)); MOCK_METHOD1(HandlePlatformMessage, void(std::unique_ptr)); diff --git a/shell/common/pipeline.h b/shell/common/pipeline.h index 35f90f39f2c6a..f9546d0816125 100644 --- a/shell/common/pipeline.h +++ b/shell/common/pipeline.h @@ -222,11 +222,11 @@ class Pipeline { }; struct LayerTreeItem { - LayerTreeItem(std::unique_ptr layer_tree, + LayerTreeItem(std::shared_ptr layer_tree, std::unique_ptr frame_timings_recorder) : layer_tree(std::move(layer_tree)), frame_timings_recorder(std::move(frame_timings_recorder)) {} - std::unique_ptr layer_tree; + std::shared_ptr layer_tree; std::unique_ptr frame_timings_recorder; }; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index d3ecb11fee8ec..6e0b22d1ff1df 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -145,6 +145,10 @@ std::shared_ptr Rasterizer::GetTextureRegistry() { return compositor_context_->texture_registry(); } +GrDirectContext* Rasterizer::GetGrContext() { + return surface_->GetContext(); +} + flutter::LayerTree* Rasterizer::GetLastLayerTree() { return last_layer_tree_.get(); } @@ -181,7 +185,7 @@ RasterStatus Rasterizer::Draw(std::shared_ptr pipeline, RasterStatus raster_status = RasterStatus::kFailed; LayerTreePipeline::Consumer consumer = [&](std::unique_ptr item) { - std::unique_ptr layer_tree = std::move(item->layer_tree); + std::shared_ptr layer_tree = std::move(item->layer_tree); std::unique_ptr frame_timings_recorder = std::move(item->frame_timings_recorder); if (discard_callback(*layer_tree.get())) { @@ -488,7 +492,7 @@ fml::Milliseconds Rasterizer::GetFrameBudget() const { RasterStatus Rasterizer::DoDraw( std::unique_ptr frame_timings_recorder, - std::unique_ptr layer_tree) { + std::shared_ptr layer_tree) { TRACE_EVENT_WITH_FRAME_NUMBER(frame_timings_recorder, "flutter", "Rasterizer::DoDraw"); FML_DCHECK(delegate_.GetTaskRunners() diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 2f90ed5b1fe66..7052b664e1791 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -26,6 +26,7 @@ #include "flutter/shell/common/pipeline.h" #include "flutter/shell/common/snapshot_surface_producer.h" #include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" namespace flutter { @@ -213,6 +214,8 @@ class Rasterizer final : public SnapshotDelegate, std::unique_ptr frame_timings_recorder); // |SnapshotDelegate| + GrDirectContext* GetGrContext() override; + std::shared_ptr GetTextureRegistry() override; using LayerTreeDiscardCallback = std::function; @@ -496,7 +499,7 @@ class Rasterizer final : public SnapshotDelegate, RasterStatus DoDraw( std::unique_ptr frame_timings_recorder, - std::unique_ptr layer_tree); + std::shared_ptr layer_tree); RasterStatus DrawToSurface(FrameTimingsRecorder& frame_timings_recorder, flutter::LayerTree& layer_tree); @@ -515,11 +518,11 @@ class Rasterizer final : public SnapshotDelegate, std::unique_ptr snapshot_surface_producer_; std::unique_ptr compositor_context_; // This is the last successfully rasterized layer tree. - std::unique_ptr last_layer_tree_; + std::shared_ptr last_layer_tree_; // Set when we need attempt to rasterize the layer tree again. This layer_tree // has not successfully rasterized. This can happen due to the change in the // thread configuration. This will be inserted to the front of the pipeline. - std::unique_ptr resubmitted_layer_tree_; + std::shared_ptr resubmitted_layer_tree_; std::unique_ptr resubmitted_recorder_; fml::closure next_frame_callback_; bool user_override_resource_cache_bytes_; diff --git a/shell/common/rasterizer_unittests.cc b/shell/common/rasterizer_unittests.cc index 45232840bf2b1..af14fcc1675cf 100644 --- a/shell/common/rasterizer_unittests.cc +++ b/shell/common/rasterizer_unittests.cc @@ -176,7 +176,7 @@ TEST(RasterizerTest, fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -238,7 +238,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -306,7 +306,7 @@ TEST( rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -376,7 +376,7 @@ TEST(RasterizerTest, rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -423,7 +423,7 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) { fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -476,7 +476,7 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) { fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -573,7 +573,7 @@ TEST(RasterizerTest, fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -627,7 +627,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -681,7 +681,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -734,7 +734,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -811,7 +811,7 @@ TEST(RasterizerTest, auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = - std::make_unique(/*frame_size=*/SkISize(), + std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i])); @@ -972,7 +972,7 @@ TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) { auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = - std::make_unique(/*frame_size=*/SkISize(), + std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i])); @@ -1045,7 +1045,7 @@ TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) { thread_host.raster_thread->GetTaskRunner()->PostTask([&] { rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(first_timestamp)); diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index 27f6b0f65f527..eca345058787f 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -197,7 +197,7 @@ void ShellTest::PumpOneFrame(Shell* shell, fml::WeakPtr runtime_delegate = shell->weak_engine_; shell->GetTaskRunners().GetUITaskRunner()->PostTask( [&latch, runtime_delegate, &builder, viewport_metrics]() { - auto layer_tree = std::make_unique( + auto layer_tree = std::make_shared( SkISize::Make(viewport_metrics.physical_width, viewport_metrics.physical_height), static_cast(viewport_metrics.device_pixel_ratio)); diff --git a/testing/dart/compositing_test.dart b/testing/dart/compositing_test.dart index 10c70978d22b5..01320919a52dd 100644 --- a/testing/dart/compositing_test.dart +++ b/testing/dart/compositing_test.dart @@ -36,6 +36,28 @@ void main() { expect(data.buffer.asUint8List()[3], 0xFF); }); + test('Scene.toImageSync succeeds with texture layer', () async { + final SceneBuilder builder = SceneBuilder(); + builder.pushOffset(10, 10); + builder.addTexture(0, width: 10, height: 10); + + final Scene scene = builder.build(); + final Image image = scene.toImageSync(10, 10); + scene.dispose(); + + expect(image.width, 10); + expect(image.height, 10); + + final ByteData? data = await image.toByteData(); + + expect(data, isNotNull); + expect(data!.lengthInBytes, 10 * 10 * 4); + expect(data.buffer.asUint8List()[0], 0); + expect(data.buffer.asUint8List()[1], 0); + expect(data.buffer.asUint8List()[2], 0); + expect(data.buffer.asUint8List()[3], 0); + }); + test('addPicture with disposed picture does not crash', () { bool assertsEnabled = false; assert(() { From a0dcde4fb611f36bfabc95d526949c2669b6e63f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 20:34:37 -0400 Subject: [PATCH 441/558] Roll Skia from 4c3c98cdb1d3 to 00ddb61588a2 (1 revision) (#35559) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 24fc436050ca7..bfb202d373d06 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': '4c3c98cdb1d343431ddca7eaad78d654b9278251', + 'skia_revision': '00ddb61588a21b41192d36accead310f1ea2d8e6', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f052b33edece6..064a27f160753 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 54b226856cfe153ff14686940324e1fe +Signature: 55e58e86363ba9d31e7e7fe54b83b354 UNUSED LICENSES: @@ -7782,6 +7782,11 @@ ORIGIN: ../../../third_party/skia/src/gpu/ganesh/dawn/GrDawnAsyncWait.cpp + ../. TYPE: LicenseType.bsd FILE: ../../../third_party/skia/src/gpu/ganesh/dawn/GrDawnAsyncWait.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/dawn/GrDawnAsyncWait.h +FILE: ../../../third_party/skia/src/gpu/piet/PietTypes.h +FILE: ../../../third_party/skia/src/gpu/piet/Render.cpp +FILE: ../../../third_party/skia/src/gpu/piet/Render.h +FILE: ../../../third_party/skia/src/gpu/piet/Scene.cpp +FILE: ../../../third_party/skia/src/gpu/piet/Scene.h FILE: ../../../third_party/skia/src/gpu/tessellate/MidpointContourParser.h FILE: ../../../third_party/skia/src/sksl/SkSLPosition.cpp ---------------------------------------------------------------------------------------------------- From a9783b2ba4032763f09a2072a15e746a119d6f49 Mon Sep 17 00:00:00 2001 From: David Worsham Date: Fri, 19 Aug 2022 17:58:53 -0700 Subject: [PATCH 442/558] [fuchsia] Migrate integration test to CFv2 (#35318) --- ci/licenses_golden/licenses_flutter | 12 - shell/platform/fuchsia/flutter/BUILD.gn | 30 +- .../flutter/integration_flutter_tests/OWNERS | 5 - .../embedder/BUILD.gn | 67 -- .../embedder/README.md | 173 ----- .../embedder/child-view2/BUILD.gn | 38 -- .../embedder/child-view2/meta/child-view2.cmx | 13 - .../embedder/flutter-embedder-test2.cc | 218 ------- .../embedder/flutter-embedder-test2.h | 234 ------- .../embedder/meta/flutter-embedder-test2.cmx | 25 - .../embedder/parent-view2/BUILD.gn | 46 -- .../parent-view2/meta/parent-view2.cmx | 14 - .../src/lib/ui/base_view/BUILD.gn | 30 - .../src/lib/ui/base_view/base_view.cc | 240 ------- .../src/lib/ui/base_view/base_view.h | 210 ------ .../lib/ui/base_view/embedded_view_utils.cc | 48 -- .../lib/ui/base_view/embedded_view_utils.h | 58 -- .../src/lib/ui/base_view/math.h | 92 --- .../src/ui/testing/views/BUILD.gn | 24 - .../src/ui/testing/views/embedder_view.cc | 88 --- .../src/ui/testing/views/embedder_view.h | 59 -- .../integration}/BUILD.gn | 6 +- .../flutter/tests/integration/README.md | 84 +++ .../tests/integration/embedder/BUILD.gn | 65 ++ .../integration/embedder/child-view/BUILD.gn | 26 + .../embedder/child-view/lib/child_view.dart} | 16 +- .../embedder/child-view/meta/child-view.cml | 21 + .../embedder/child-view}/pubspec.yaml | 0 .../integration/embedder}/color.cc | 3 +- .../integration/embedder}/color.h | 0 .../embedder/flutter-embedder-test.cc | 602 ++++++++++++++++++ .../embedder/meta/flutter-embedder-test.cml | 27 + .../embedder/meta/gtest_runner.shard.cml | 14 + .../integration/embedder/parent-view/BUILD.gn | 36 ++ .../parent-view/lib/parent_view.dart} | 149 +++-- .../embedder/parent-view/meta/parent-view.cml | 33 + .../embedder/parent-view}/pubspec.yaml | 0 testing/fuchsia/test_suites.yaml | 14 +- tools/fuchsia/fuchsia_archive.gni | 89 +-- 39 files changed, 1102 insertions(+), 1807 deletions(-) delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/OWNERS delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/BUILD.gn delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/README.md delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/BUILD.gn delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/BUILD.gn delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/BUILD.gn delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/BUILD.gn delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.cc delete mode 100644 shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.h rename shell/platform/fuchsia/flutter/{integration_flutter_tests => tests/integration}/BUILD.gn (73%) create mode 100644 shell/platform/fuchsia/flutter/tests/integration/README.md create mode 100644 shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn create mode 100644 shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/BUILD.gn rename shell/platform/fuchsia/flutter/{integration_flutter_tests/embedder/child-view2/child_view2.dart => tests/integration/embedder/child-view/lib/child_view.dart} (85%) create mode 100644 shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml rename shell/platform/fuchsia/flutter/{integration_flutter_tests/embedder/child-view2 => tests/integration/embedder/child-view}/pubspec.yaml (100%) rename shell/platform/fuchsia/flutter/{integration_flutter_tests/fuchsia_testing/src/ui/testing/views => tests/integration/embedder}/color.cc (98%) rename shell/platform/fuchsia/flutter/{integration_flutter_tests/fuchsia_testing/src/ui/testing/views => tests/integration/embedder}/color.h (100%) create mode 100644 shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc create mode 100644 shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml create mode 100644 shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml create mode 100644 shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/BUILD.gn rename shell/platform/fuchsia/flutter/{integration_flutter_tests/embedder/parent-view2/parent_view2.dart => tests/integration/embedder/parent-view/lib/parent_view.dart} (71%) create mode 100644 shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml rename shell/platform/fuchsia/flutter/{integration_flutter_tests/embedder/parent-view2 => tests/integration/embedder/parent-view}/pubspec.yaml (100%) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ff50b5a9d01f5..c78b93d5c0076 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -2129,18 +2129,6 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/gfx_platform_view.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/gfx_platform_view.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/gfx_session_connection.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/gfx_session_connection.h -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child_view2.dart -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h -FILE: ../../../flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/isolate_configurator.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/kernel/extract_far.dart diff --git a/shell/platform/fuchsia/flutter/BUILD.gn b/shell/platform/fuchsia/flutter/BUILD.gn index 0680f42913021..01a1f2e3ce106 100644 --- a/shell/platform/fuchsia/flutter/BUILD.gn +++ b/shell/platform/fuchsia/flutter/BUILD.gn @@ -457,6 +457,34 @@ jit_runner("flutter_jit_product_runner") { product = true } +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +aot_runner("oot_flutter_aot_runner") { + product = false +} + +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +aot_runner("oot_flutter_aot_product_runner") { + product = true +} + +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +jit_runner("oot_flutter_jit_runner") { + product = false +} + +# "OOT" copy of the runner used by tests, to avoid conflicting with the runner +# in the base fuchsia image. +# TODO(fxbug.dev/106575): Fix this with subpackages. +jit_runner("oot_flutter_jit_product_runner") { + product = true +} + test_fixtures("flutter_runner_fixtures") { fixtures = [] } @@ -885,7 +913,7 @@ if (enable_unittests) { ":testing_tests", ":txt_tests", ":ui_tests", - "integration_flutter_tests", + "tests/integration", ] } } diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/OWNERS b/shell/platform/fuchsia/flutter/integration_flutter_tests/OWNERS deleted file mode 100644 index aa90637fa8ff3..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/OWNERS +++ /dev/null @@ -1,5 +0,0 @@ -dworsham@google.com -sanjayc@google.com -richkadel@google.com - -# COMPONENT: FlutteronFuchsia diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/BUILD.gn b/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/BUILD.gn deleted file mode 100644 index bba0da5c26dff..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/BUILD.gn +++ /dev/null @@ -1,67 +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. - -assert(is_fuchsia) - -import("//build/fuchsia/sdk.gni") -import("//flutter/tools/fuchsia/fuchsia_archive.gni") - -group("tests") { - testonly = true - deps = [ - ":flutter-embedder-test2", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2", - ] -} - -executable("flutter-embedder-test2-bin") { - testonly = true - - output_name = "flutter-embedder-test2" - - sources = [ - "flutter-embedder-test2.cc", - "flutter-embedder-test2.h", - ] - - # This is needed for //third_party/googletest for linking zircon symbols. - libs = [ "$fuchsia_sdk_path/arch/$target_cpu/sysroot/lib/libzircon.so" ] - - include_dirs = [ "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing" ] - - public_deps = [ "//third_party/googletest:gtest" ] - - deps = [ - "$fuchsia_sdk_root/fidl:fuchsia.sys", - "$fuchsia_sdk_root/fidl:fuchsia.ui.app", - "$fuchsia_sdk_root/fidl:fuchsia.ui.input", - "$fuchsia_sdk_root/fidl:fuchsia.ui.lifecycle", - "$fuchsia_sdk_root/fidl:fuchsia.ui.policy", - "$fuchsia_sdk_root/fidl:fuchsia.ui.scenic", - "$fuchsia_sdk_root/pkg:async-loop-cpp", - "$fuchsia_sdk_root/pkg:async-loop-default", - "$fuchsia_sdk_root/pkg:fit", - "$fuchsia_sdk_root/pkg:scenic_cpp", - "$fuchsia_sdk_root/pkg:sys_cpp", - "$fuchsia_sdk_root/pkg:sys_cpp_testing", - "$fuchsia_sdk_root/pkg:zx", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views", - "//third_party/dart/runtime:libdart_jit", - "//third_party/googletest:gtest_main", - ] -} - -fuchsia_test_archive("flutter-embedder-test2") { - deps = [ - ":flutter-embedder-test2-bin", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2:package", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2:package", - ] - - binary = "$target_name" - - cmx_file = rebase_path("meta/$target_name.cmx") -} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/README.md b/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/README.md deleted file mode 100644 index 6b5190b9af804..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# `flutter scenic embedder tests` - -## Configure and build fuchsia - -For tests that require scenic, for example, run `fx set` with the required -targets; for example: - -```shell -$ cd "$FUCHSIA_DIR" -$ fx set core.x64 \ - --with //src/ui/scenic \ - --with //src/ui/bin/root_presenter \ - --with //src/ui/bin/hardware_display_controller_provider -$ fx build -``` - -Note 1: You could use `--with-base` here, instead of `--with`, but if so, you -would also need to add `--with-base //garnet/bin/run_test_component`. More on -this below, under [Start the package servers](#start-the-package-servers). - -Note 2: The `fx set` flags, above, offer a minimized fuchsia platform -configuration to successfully execute the test, but some optional services may -be missing. Be aware that the Fuchsia system logs may include multiple -occurrences `WARNING: error resolving ...` messages, such as the following, -which can be ignored: - -``` -[pkg-resolver] WARNING: error resolving fuchsia-pkg://fuchsia.com/fonts/0 ... -[pkg-resolver] WARNING: error resolving fuchsia-pkg://fuchsia.com/ime_service/0 ... -[pkg-resolver] WARNING: error resolving fuchsia-pkg://fuchsia.com/intl_property_manager/0 ... -``` - -## Restart and reboot your device - -_(Optional)_ If developing with the emulator, launch (or shutdown and relaunch) -the emulator. - -```shell -fx vdl start -N -``` - -NOTE: Do _not_ run the default package server. The instructions below describe -how to launch a flutter-specific package server. - -Or if you've rebuilt fuchsia for a device that is already running a version of -fuchsia, you may be able to reboot without restarting the device: - -```shell -$ fx reboot -r -``` - -If you are building a device that launches the UI at startup, you will likely -need to kill Scenic before running the test. - -```shell -$ fx shell killall scenic.cmx -``` - -## Build the test - -You can specify the test's package target to build only the test package, with -its dependencies. This will also build the required runner. - -```shell -$ cd "$FLUTTER_ENGINE_DIR/src" -$ ./flutter/tools/gn --fuchsia \ - # for example: --goma --fuchsia-cpu=x64 --runtime-mode=debug -$ ninja -C out/fuchsia_debug_x64 \ - flutter/shell/platform/fuchsia/flutter/integration_flutter_tests -``` - -## Publish the test packages to the Fuchsia package server - -The tests currently specify the Fuchsia package server's standard domain, -`fuchsia.com`, as the server to use to resolve (locate and load) the test -packages. So, before running the test, the most recently built `.far` files -need to be published to the Fuchsia package repo: - -```shell -$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ - -f "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64/flutter-embedder-test2-0.far -$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ - -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name parent-view2.far) -$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ - -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name child-view2.far) -``` - -## Run the test (using the package server at `fuchsia.com`) - -```shell -$ fx test flutter-embedder-test2 -``` - -## Make a change and re-run the test - -If, for example, you only make a change to the Dart code in `parent-view2`, you -can rebuild only the parent-view2 package target, republish it, and then re-run -the test, with: - -```shell -$ ninja -C out/fuchsia_debug_x64 \ - flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2:package -$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ - -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name parent-view2.far) -$ fx test flutter-embedder-test2 -``` - -From here, you can modify the Flutter test, rebuild flutter, and usually rerun -the test without rebooting, by repeating the commands above. - -The embedder tests must be run on a product without a graphical base shell, -such as `core` because it starts and stops Scenic. - -## (Alternative) Serving flutter packages from a custom package server - -If you want to use a custom package server, you will need to edit these sources: - - * `//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc` - * `//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart` - -Search for the component URLs with `fuchsia.com`, and change it to `engine`, -which is the domain currently registered with the custom package server in -`//tools/fuchsia/devshell/serve.sh`. - -WARNING: Be careful not to check in that change because CI requires using the -`fuchsia.com` domain/package server. - -The default fuchsia package server (launched via `fx serve`) is normally -required, unless all of your test's package dependencies are included in the -fuchsia system image. You can force additional packages into the system image -with `fx set ... --with-base ` (instead of using `--with`). For -example, in the `fx set` command above, using, `--with-base scenic`, and so on. -Note, however, that the default `core.x64` configuration bundles the test -runner as if it was included via -`--with //garnet/bin/run_test_component`, so to include the test runner in the -system image requires adding that package as well, via `--with-base`, instead. - -In order to serve fuchsia package dependencies (like `scenic`, `root_presenter`, -and `hardware-display-controller-provider`), without forcing them into the -system image, you will need to run the fuchsia default package server, via `fx -serve`. - -The `flutter/engine` packages (tests and flutter runners, for dart-based tests) -are served from a separate package server. The `flutter/engine` repo's -`serve.sh` script launches this secondary package server, and configures -package URL rewrite rules to redirect fuchsia's requests for flutter- and -dart-runner packages from `fuchsia.com` to flutter's package server instead. - -**IMPORTANT:** _The flutter package server must be launched **after** the -default package server, because both `fx serve` and flutter's `serve.sh` set -package URL rewrite rules, and only the last one wins._ - -Launch each package server in a separate window or shell: - -```shell -$ cd "${FUCHSIA_DIR}" -$ fx serve -``` - -From the flutter engine `src` directory, run the following script to launch the -`engine` package server, to serve the flutter runner and test components. - -```shell -$ flutter/tools/fuchsia/devshell/serve.sh --out out/fuchsia_debug_x64 --only-serve-runners -``` - -## Run the test, using `engine` as the package server domain - -```shell -$ fx test flutter-embedder-test2 -``` - -You can recompile and run the test without needing to re-publish the `.far`. diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/BUILD.gn b/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/BUILD.gn deleted file mode 100644 index 93e836386931b..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/BUILD.gn +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build/fuchsia/sdk.gni") -import("//flutter/tools/fuchsia/dart/dart_library.gni") -import("//flutter/tools/fuchsia/flutter/flutter_component.gni") -import("//flutter/tools/fuchsia/gn-sdk/package.gni") - -dart_library("child-view2_dart_library") { - package_name = "child-view2" - - source_dir = "." - sources = [ "child_view2.dart" ] - - deps = [] -} - -flutter_component("child-view2_flutter_component") { - main_package = "child-view2" - component_name = "child-view2" - main_dart = "child_view2.dart" - manifest = rebase_path("meta/child-view2.cmx") - deps = [ ":child-view2_dart_library" ] -} - -# TODO(richkadel): The target name is set differently compared to fuchsia.git's flutter_app(). -# Unlike in fuchsia.git's version of fuchsia_component, the Fuchsia GN SDK -# version passes the component name to fuchsia_component via it's target_name only. -# GN SDK's fuchsia_component doesn't have a `component_name` argument! So I'm forced to set -# the component name via "target_name". This is a problem in fuchsia_package, which uses -# the target_name to name the fuchsia_pm_tool target, creating duplicate target IDs! -# So I have to change the fuchsia_package name to something that is NOT the component name, -# and then set the package_name (which fuchsia_package does support). -fuchsia_package("package") { - package_name = "child-view2" - deps = [ ":child-view2_flutter_component" ] -} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx b/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx deleted file mode 100644 index 2157ca2190988..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/meta/child-view2.cmx +++ /dev/null @@ -1,13 +0,0 @@ -{ - "program": { - "data": "data/child-view2" - }, - "sandbox": { - "services": [ - "fuchsia.fonts.Provider", - "fuchsia.sys.Environment", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc b/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc deleted file mode 100644 index 63a5cd197ab30..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.cc +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter-embedder-test2.h" - -namespace flutter_embedder_test2 { - -// TODO(richkadel): To run the test serving the runner and test packages from -// the flutter/engine package server (via -// `//flutter/tools/fuchsia/devshell/serve.sh`), change `fuchsia.com` to -// `engine`. -constexpr char kParentViewUrl[] = - "fuchsia-pkg://fuchsia.com/parent-view2#meta/parent-view2.cmx"; - -constexpr scenic::Color kParentBackgroundColor = {0x00, 0x00, 0xFF, - 0xFF}; // Blue -constexpr scenic::Color kParentTappedColor = {0x00, 0x00, 0x00, 0xFF}; // Black -constexpr scenic::Color kChildBackgroundColor = {0xFF, 0x00, 0xFF, - 0xFF}; // Pink -constexpr scenic::Color kChildTappedColor = {0xFF, 0xFF, 0x00, 0xFF}; // Yellow - -// TODO(fxb/94000): The new flutter renderer draws overlays as a single, large -// layer. Some parts of this layer are fully transparent, so we want the -// compositor to treat the layer as transparent and blend it with the contents -// below. -// -// The gfx Scenic API only provides one way to mark this layer as transparent -// which is to set an opacity < 1.0 for the entire layer. In practice, we use -// 0.9961 (254 / 255) as an opacity value to force transparency. Unfortunately -// this causes the overlay to blend very slightly and it looks wrong. -// -// Flatland allows marking a layer as transparent while still using a 1.0 -// opacity value when blending, so migrating flutter to Flatland will fix this -// issue. For now we just hard-code the broken, blended values. -constexpr scenic::Color kOverlayBackgroundColor1 = { - 0x00, 0xFF, 0x0E, 0xFF}; // Green, blended with blue (FEMU local) -constexpr scenic::Color kOverlayBackgroundColor2 = { - 0x0E, 0xFF, 0x0E, 0xFF}; // Green, blended with pink (FEMU local) -constexpr scenic::Color kOverlayBackgroundColor3 = { - 0x00, 0xFF, 0x0D, 0xFF}; // Green, blended with blue (AEMU infra) -constexpr scenic::Color kOverlayBackgroundColor4 = { - 0x0D, 0xFF, 0x0D, 0xFF}; // Green, blended with pink (AEMU infra) -constexpr scenic::Color kOverlayBackgroundColor5 = { - 0x00, 0xFE, 0x0D, 0xFF}; // Green, blended with blue (NUC) -constexpr scenic::Color kOverlayBackgroundColor6 = { - 0x0D, 0xFF, 0x00, 0xFF}; // Green, blended with pink (NUC) - -static size_t OverlayPixelCount(std::map& histogram) { - return histogram[kOverlayBackgroundColor1] + - histogram[kOverlayBackgroundColor2] + - histogram[kOverlayBackgroundColor3] + - histogram[kOverlayBackgroundColor4] + - histogram[kOverlayBackgroundColor5] + - histogram[kOverlayBackgroundColor6]; -} - -/// Defines a list of services that are injected into the test environment. -/// Unlike the injected-services in CMX which are injected per test package, -/// these are injected per test and result in a more hermetic test environment. -const std::vector> GetInjectedServices() { - std::vector> injected_services = {{ - {"fuchsia.accessibility.semantics.SemanticsManager", - "fuchsia-pkg://fuchsia.com/a11y-manager#meta/a11y-manager.cmx"}, - {"fuchsia.fonts.Provider", - "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx"}, - {"fuchsia.hardware.display.Provider", - "fuchsia-pkg://fuchsia.com/" - "fake-hardware-display-controller-provider#meta/hdcp.cmx"}, - {"fuchsia.intl.PropertyProvider", - "fuchsia-pkg://fuchsia.com/intl_property_manager#meta/" - "intl_property_manager.cmx"}, - {"fuchsia.netstack.Netstack", - "fuchsia-pkg://fuchsia.com/network-legacy-deprecated#meta/netstack.cmx"}, - {"fuchsia.posix.socket.Provider", - "fuchsia-pkg://fuchsia.com/network-legacy-deprecated#meta/netstack.cmx"}, - {"fuchsia.tracing.provider.Registry", - "fuchsia-pkg://fuchsia.com/trace_manager#meta/trace_manager.cmx"}, - {"fuchsia.ui.input.ImeService", - "fuchsia-pkg://fuchsia.com/text_manager#meta/text_manager.cmx"}, - {"fuchsia.ui.input.ImeVisibilityService", - "fuchsia-pkg://fuchsia.com/text_manager#meta/text_manager.cmx"}, - {"fuchsia.ui.scenic.Scenic", - "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx"}, - {"fuchsia.ui.pointerinjector.Registry", - "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx"}, // For - // root_presenter - // TODO(fxbug.dev/82655): Remove this after migrating to RealmBuilder. - {"fuchsia.ui.lifecycle.LifecycleController", - "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx"}, - {"fuchsia.ui.policy.Presenter", - "fuchsia-pkg://fuchsia.com/root_presenter#meta/root_presenter.cmx"}, - {"fuchsia.ui.input.InputDeviceRegistry", - "fuchsia-pkg://fuchsia.com/root_presenter#meta/root_presenter.cmx"}, - }}; - return injected_services; -} - -TEST_F(FlutterScenicEmbedderTests, Embedding) { - RunAppWithArgs(kParentViewUrl); - - // Take screenshot until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil( - kChildBackgroundColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent and child background colors, with parent color > child - // color. - EXPECT_GT(histogram[kParentBackgroundColor], 0u); - EXPECT_GT(histogram[kChildBackgroundColor], 0u); - EXPECT_GT(histogram[kParentBackgroundColor], - histogram[kChildBackgroundColor]); - - // Expect all corners to be the parent-view2 background color - EXPECT_EQ(kParentBackgroundColor, screenshot.ColorAtPixelXY(10, 10)); - EXPECT_EQ(kParentBackgroundColor, - screenshot.ColorAtPixelXY(screenshot.width() - 10, 0)); - EXPECT_EQ(kParentBackgroundColor, - screenshot.ColorAtPixelXY(0, screenshot.height() - 10)); - EXPECT_EQ(kParentBackgroundColor, - screenshot.ColorAtPixelXY(screenshot.width() - 10, - screenshot.height() - 10)); - })); -} - -TEST_F(FlutterScenicEmbedderTests, HittestEmbedding) { - RunAppWithArgs(kParentViewUrl); - - // Take screenshot until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); - - // Tap the center of child view2. - InjectInput(); - - // Take screenshot until we see the child-view2's tapped color. - ASSERT_TRUE(TakeScreenshotUntil( - kChildTappedColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent and child background colors, with parent color > child - // color. - EXPECT_GT(histogram[kParentBackgroundColor], 0u); - EXPECT_EQ(histogram[kChildBackgroundColor], 0u); - EXPECT_GT(histogram[kChildTappedColor], 0u); - EXPECT_GT(histogram[kParentBackgroundColor], - histogram[kChildTappedColor]); - })); -} - -TEST_F(FlutterScenicEmbedderTests, HittestDisabledEmbedding) { - RunAppWithArgs(kParentViewUrl, {"--no-hitTestable"}); - - // Take screenshots until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); - - // Tap the center of child view2. Since it's not hit-testable, the tap should - // go to the parent. - InjectInput(); - - // The parent-view2 should change color. - ASSERT_TRUE(TakeScreenshotUntil( - kParentTappedColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent and child background colors, with parent color > child - // color. - EXPECT_EQ(histogram[kParentBackgroundColor], 0u); - EXPECT_GT(histogram[kParentTappedColor], 0u); - EXPECT_GT(histogram[kChildBackgroundColor], 0u); - EXPECT_EQ(histogram[kChildTappedColor], 0u); - EXPECT_GT(histogram[kParentTappedColor], - histogram[kChildBackgroundColor]); - })); -} - -TEST_F(FlutterScenicEmbedderTests, EmbeddingWithOverlay) { - RunAppWithArgs(kParentViewUrl, {"--showOverlay"}); - - // Take screenshot until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil( - kChildBackgroundColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent, overlay and child background colors. - // With parent color > child color and overlay color > child color. - const size_t overlay_pixel_count = OverlayPixelCount(histogram); - EXPECT_GT(histogram[kParentBackgroundColor], 0u); - EXPECT_GT(overlay_pixel_count, 0u); - EXPECT_GT(histogram[kChildBackgroundColor], 0u); - EXPECT_GT(histogram[kParentBackgroundColor], - histogram[kChildBackgroundColor]); - EXPECT_GT(overlay_pixel_count, histogram[kChildBackgroundColor]); - })); -} - -TEST_F(FlutterScenicEmbedderTests, HittestEmbeddingWithOverlay) { - RunAppWithArgs(kParentViewUrl, {"--showOverlay"}); - - // Take screenshot until we see the child-view2's embedded color. - ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); - - // Tap the center of child view2. - InjectInput(); - - // Take screenshot until we see the child-view2's tapped color. - ASSERT_TRUE(TakeScreenshotUntil( - kChildTappedColor, [](scenic::Screenshot screenshot, - std::map histogram) { - // Expect parent, overlay and child background colors. - // With parent color > child color and overlay color > child color. - const size_t overlay_pixel_count = OverlayPixelCount(histogram); - EXPECT_GT(histogram[kParentBackgroundColor], 0u); - EXPECT_GT(overlay_pixel_count, 0u); - EXPECT_EQ(histogram[kChildBackgroundColor], 0u); - EXPECT_GT(histogram[kChildTappedColor], 0u); - EXPECT_GT(histogram[kParentBackgroundColor], - histogram[kChildTappedColor]); - EXPECT_GT(overlay_pixel_count, histogram[kChildTappedColor]); - })); -} - -} // namespace flutter_embedder_test2 diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h b/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h deleted file mode 100644 index 1a8cbf54e4b07..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/flutter-embedder-test2.h +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SRC_UI_TESTS_INTEGRATION_FLUTTER_TESTS_EMBEDDER_flutter_embedder_test2_H_ -#define SRC_UI_TESTS_INTEGRATION_FLUTTER_TESTS_EMBEDDER_flutter_embedder_test2_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "flutter/fml/logging.h" - -#include - -#include "src/lib/ui/base_view/embedded_view_utils.h" -#include "src/ui/testing/views/color.h" -#include "src/ui/testing/views/embedder_view.h" - -namespace flutter_embedder_test2 { - -/// Defines a list of services that are injected into the test environment. -/// Unlike the injected-services in CMX which are injected per test package, -/// these are injected per test and result in a more hermetic test environment. -const std::vector> GetInjectedServices(); - -// Timeout when waiting on Scenic API calls like |GetDisplayInfo|. -constexpr zx::duration kCallTimeout = zx::sec(5); -// Timeout for Scenic's |TakeScreenshot| FIDL call. -constexpr zx::duration kScreenshotTimeout = zx::sec(10); -// Timeout to fail the test if it goes beyond this duration. -constexpr zx::duration kTestTimeout = zx::min(1); - -class FlutterScenicEmbedderTests : public sys::testing::TestWithEnvironment, - public ::testing::Test { - public: - // |testing::Test| - void SetUp() override { - Test::SetUp(); - - // Create test-specific launchable services. - auto services = TestWithEnvironment::CreateServices(); - for (const auto& service_info : GetInjectedServices()) { - zx_status_t status = services->AddServiceWithLaunchInfo( - {.url = service_info.second}, service_info.first); - FML_CHECK(status == ZX_OK) - << "Failed to add service " << service_info.first; - } - - environment_ = CreateNewEnclosingEnvironment( - "flutter-embedder-test2s", std::move(services), - {.inherit_parent_services = true}); - WaitForEnclosingEnvToStart(environment()); - - FML_VLOG(fml::LOG_INFO) << "Created test environment."; - - // Connects to scenic lifecycle controller in order to shutdown scenic at - // the end of the test. This ensures the correct ordering of shutdown under - // CFv1: first scenic, then the fake display controller. - // - // TODO(fxbug.dev/82655): Remove this after migrating to RealmBuilder. - environment_->ConnectToService( - scenic_lifecycle_controller_.NewRequest()); - - environment_->ConnectToService(scenic_.NewRequest()); - scenic_.set_error_handler([](zx_status_t status) { - FAIL() << "Lost connection to Scenic: " << zx_status_get_string(status); - }); - - // Post a "just in case" quit task, if the test hangs. - async::PostDelayedTask( - dispatcher(), - [] { - FML_LOG(FATAL) - << "\n\n>> Test did not complete in time, terminating. <<\n\n"; - }, - kTestTimeout); - } - - // |testing::Test| - void TearDown() override { - // Avoid spurious errors since we are about to kill scenic. - // - // TODO(fxbug.dev/82655): Remove this after migrating to RealmBuilder. - scenic_.set_error_handler(nullptr); - - zx_status_t terminate_status = scenic_lifecycle_controller_->Terminate(); - FML_CHECK(terminate_status == ZX_OK) - << "Failed to terminate Scenic with status: " - << zx_status_get_string(terminate_status); - } - - sys::testing::EnclosingEnvironment* environment() { - return environment_.get(); - } - - fuchsia::ui::views::ViewToken CreatePresentationViewToken() { - auto [view_token, view_holder_token] = scenic::ViewTokenPair::New(); - - auto presenter = - environment()->ConnectToService(); - presenter.set_error_handler([](zx_status_t status) { - FAIL() << "presenter: " << zx_status_get_string(status); - }); - presenter->PresentView(std::move(view_holder_token), nullptr); - - return std::move(view_token); - } - - void RunAppWithArgs(const std::string& component_url, - const std::vector& component_args = {}) { - scenic::EmbeddedViewInfo flutter_runner = - scenic::LaunchComponentAndCreateView(environment()->launcher_ptr(), - component_url, component_args); - flutter_runner.controller.events().OnTerminated = [](auto...) { FAIL(); }; - - // Present the view. - embedder_view_.emplace(scenic::ViewContext{ - .session_and_listener_request = - scenic::CreateScenicSessionPtrAndListenerRequest(scenic_.get()), - .view_token = CreatePresentationViewToken(), - }); - - // Embed the view. - bool is_rendering = false; - embedder_view_->EmbedView( - std::move(flutter_runner), - [&is_rendering](fuchsia::ui::gfx::ViewState view_state) { - is_rendering = view_state.is_rendering; - }); - RunLoopUntil([&is_rendering] { return is_rendering; }); - FML_LOG(INFO) << "Launched component: " << component_url; - } - - scenic::Screenshot TakeScreenshot() { - FML_LOG(INFO) << "Taking screenshot... "; - fuchsia::ui::scenic::ScreenshotData screenshot_out; - scenic_->TakeScreenshot( - [this, &screenshot_out](fuchsia::ui::scenic::ScreenshotData screenshot, - bool status) { - EXPECT_TRUE(status) << "Failed to take screenshot"; - screenshot_out = std::move(screenshot); - QuitLoop(); - }); - EXPECT_FALSE(RunLoopWithTimeout(kScreenshotTimeout)) - << "Timed out waiting for screenshot."; - FML_LOG(INFO) << "Screenshot captured."; - - return scenic::Screenshot(screenshot_out); - } - - bool TakeScreenshotUntil( - scenic::Color color, - fit::function)> - callback = nullptr, - zx::duration timeout = kTestTimeout) { - return RunLoopWithTimeoutOrUntil( - [this, &callback, &color] { - auto screenshot = TakeScreenshot(); - auto histogram = screenshot.Histogram(); - - bool color_found = histogram[color] > 0; - if (color_found && callback != nullptr) { - callback(std::move(screenshot), std::move(histogram)); - } - return color_found; - }, - timeout); - } - - // Inject directly into Root Presenter, using fuchsia.ui.input FIDLs. - void InjectInput() { - using fuchsia::ui::input::InputReport; - // Device parameters - auto parameters = fuchsia::ui::input::TouchscreenDescriptor::New(); - *parameters = {.x = {.range = {.min = -1000, .max = 1000}}, - .y = {.range = {.min = -1000, .max = 1000}}, - .max_finger_id = 10}; - - FML_LOG(INFO) << "Injecting input... "; - // Register it against Root Presenter. - fuchsia::ui::input::DeviceDescriptor device{.touchscreen = - std::move(parameters)}; - auto registry = - environment() - ->ConnectToService(); - fuchsia::ui::input::InputDevicePtr connection; - registry->RegisterDevice(std::move(device), connection.NewRequest()); - - { - // Inject one input report, then a conclusion (empty) report. - auto touch = fuchsia::ui::input::TouchscreenReport::New(); - *touch = { - .touches = {{.finger_id = 1, .x = 0, .y = 0}}}; // center of display - InputReport report{ - .event_time = static_cast(zx::clock::get_monotonic().get()), - .touchscreen = std::move(touch)}; - connection->DispatchReport(std::move(report)); - } - - { - auto touch = fuchsia::ui::input::TouchscreenReport::New(); - InputReport report{ - .event_time = static_cast(zx::clock::get_monotonic().get()), - .touchscreen = std::move(touch)}; - connection->DispatchReport(std::move(report)); - } - FML_LOG(INFO) << "Input dispatched."; - } - - private: - const std::unique_ptr component_context_; - std::unique_ptr environment_; - - fuchsia::ui::lifecycle::LifecycleControllerSyncPtr - scenic_lifecycle_controller_; - fuchsia::ui::scenic::ScenicPtr scenic_; - - // Wrapped in optional since the view is not created until the middle of SetUp - std::optional embedder_view_; -}; - -} // namespace flutter_embedder_test2 - -#endif // SRC_UI_TESTS_INTEGRATION_FLUTTER_TESTS_EMBEDDER_flutter_embedder_test2_H_ diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx b/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx deleted file mode 100644 index 0e21e6dc387a4..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/meta/flutter-embedder-test2.cmx +++ /dev/null @@ -1,25 +0,0 @@ -{ - "facets": { - "fuchsia.test": { - "system-services": [ - "fuchsia.scheduler.ProfileProvider", - "fuchsia.sysmem.Allocator", - "fuchsia.vulkan.loader.Loader" - ] - } - }, - "program": { - "binary": "bin/app" - }, - "sandbox": { - "services": [ - "fuchsia.logger.LogSink", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.sys.Loader", - "fuchsia.sysmem.Allocator", - "fuchsia.tracing.provider.Registry", - "fuchsia.vulkan.loader.Loader" - ] - } -} \ No newline at end of file diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/BUILD.gn b/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/BUILD.gn deleted file mode 100644 index 0b2ec390b39ce..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/BUILD.gn +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build/fuchsia/sdk.gni") -import("//flutter/tools/fuchsia/dart/dart_library.gni") -import("//flutter/tools/fuchsia/flutter/flutter_component.gni") -import("//flutter/tools/fuchsia/gn-sdk/package.gni") - -dart_library("parent-view2_dart_library") { - package_name = "parent-view2" - - source_dir = "." - sources = [ "parent_view2.dart" ] - - deps = [ - "//flutter/shell/platform/fuchsia/dart:args", - "//flutter/shell/platform/fuchsia/dart:vector_math", - "//flutter/tools/fuchsia/dart:fuchsia_services", - "//flutter/tools/fuchsia/dart:zircon", - "//flutter/tools/fuchsia/fidl:fuchsia.sys", - "//flutter/tools/fuchsia/fidl:fuchsia.ui.app", - "//flutter/tools/fuchsia/fidl:fuchsia.ui.views", - ] -} - -flutter_component("parent-view2_flutter_component") { - main_package = "parent-view2" - component_name = "parent-view2" - main_dart = "parent_view2.dart" - manifest = rebase_path("meta/parent-view2.cmx") - deps = [ ":parent-view2_dart_library" ] -} - -# TODO(richkadel): The target name is set differently compared to fuchsia.git's flutter_app(). -# Unlike in fuchsia.git's version of fuchsia_component, the Fuchsia GN SDK -# version passes the component name to fuchsia_component via it's target_name only. -# GN SDK's fuchsia_component doesn't have a `component_name` argument! So I'm forced to set -# the component name via "target_name". This is a problem in fuchsia_package, which uses -# the target_name to name the fuchsia_pm_tool target, creating duplicate target IDs! -# So I have to change the fuchsia_package name to something that is NOT the component name, -# and then set the package_name (which fuchsia_package does support). -fuchsia_package("package") { - package_name = "parent-view2" - deps = [ ":parent-view2_flutter_component" ] -} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx b/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx deleted file mode 100644 index b839053be4c13..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/meta/parent-view2.cmx +++ /dev/null @@ -1,14 +0,0 @@ -{ - "program": { - "data": "data/parent-view2" - }, - "sandbox": { - "services": [ - "fuchsia.fonts.Provider", - "fuchsia.sys.Environment", - "fuchsia.sys.Launcher", - "fuchsia.ui.input.ImeService", - "fuchsia.ui.scenic.Scenic" - ] - } -} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/BUILD.gn b/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/BUILD.gn deleted file mode 100644 index 36d862c7136dd..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/BUILD.gn +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build/fuchsia/sdk.gni") - -source_set("base_view") { - sources = [ - "base_view.cc", - "base_view.h", - "embedded_view_utils.cc", - "embedded_view_utils.h", - "math.h", - ] - - include_dirs = [ "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing" ] - - public_deps = [ - "$fuchsia_sdk_root/fidl:fuchsia.sys", - "$fuchsia_sdk_root/fidl:fuchsia.ui.app", - "$fuchsia_sdk_root/fidl:fuchsia.ui.gfx", - "$fuchsia_sdk_root/fidl:fuchsia.ui.input", - "$fuchsia_sdk_root/fidl:fuchsia.ui.views", - "$fuchsia_sdk_root/pkg:scenic_cpp", - "$fuchsia_sdk_root/pkg:sys_cpp", - "//flutter/fml", - ] - - deps = [ "$fuchsia_sdk_root/pkg:trace" ] -} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc b/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc deleted file mode 100644 index e4756f0bb8c7e..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.cc +++ /dev/null @@ -1,240 +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 "src/lib/ui/base_view/base_view.h" - -#include -#include -#include -#include -#include "flutter/fml/logging.h" - -namespace scenic { - -BaseView::BaseView(ViewContext context, const std::string& debug_name) - : component_context_(context.component_context), - listener_binding_(this, - std::move(context.session_and_listener_request.second)), - session_(std::move(context.session_and_listener_request.first)), - root_node_(&session_), - ime_client_(this), - enable_ime_(context.enable_ime) { - if (!context.view_ref_pair) { - context.view_ref_pair = scenic::ViewRefPair::New(); - } - view_.emplace(&session_, std::move(context.view_token), - std::move(context.view_ref_pair->control_ref), - std::move(context.view_ref_pair->view_ref), debug_name); - FML_DCHECK(view_); - - session_.SetDebugName(debug_name); - - // Listen for metrics events on our top node. - root_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask); - view_->AddChild(root_node_); - - if (enable_ime_) { - ime_manager_ = - component_context_->svc()->Connect(); - - ime_.set_error_handler([](zx_status_t status) { - FML_LOG(ERROR) << "Interface error on: Input Method Editor " - << zx_status_get_string(status); - }); - ime_manager_.set_error_handler([](zx_status_t status) { - FML_LOG(ERROR) << "Interface error on: Text Sync Service " - << zx_status_get_string(status); - }); - } - - // We must immediately invalidate the scene, otherwise we wouldn't ever hook - // the View up to the ViewHolder. An alternative would be to require - // subclasses to call an Init() method to set up the initial connection. - InvalidateScene(); -} - -void BaseView::SetReleaseHandler(fit::function callback) { - listener_binding_.set_error_handler(std::move(callback)); -} - -void BaseView::InvalidateScene(PresentCallback present_callback) { - TRACE_DURATION("view", "BaseView::InvalidateScene"); - if (present_callback) { - callbacks_for_next_present_.push_back(std::move(present_callback)); - } - if (invalidate_pending_) - return; - - invalidate_pending_ = true; - - // Present the scene ASAP. Pass in the last presentation time; otherwise, if - // presentation_time argument is less than the previous time passed to - // PresentScene, the Session will be closed. - // (We cannot use the current time because the last requested presentation - // time, |last_presentation_time_|, could still be in the future. This is - // because Session.Present() returns after it _begins_ preparing the given - // frame, not after it is presented.) - if (!present_pending_) - PresentScene(last_presentation_time_); -} - -void BaseView::PresentScene() { - PresentScene(last_presentation_time_); -} - -void BaseView::OnScenicEvent(std::vector events) { - TRACE_DURATION("view", "BaseView::OnScenicEvent"); - for (auto& event : events) { - switch (event.Which()) { - case ::fuchsia::ui::scenic::Event::Tag::kGfx: - switch (event.gfx().Which()) { - case ::fuchsia::ui::gfx::Event::Tag::kViewPropertiesChanged: { - auto& evt = event.gfx().view_properties_changed(); - FML_DCHECK(view_->id() == evt.view_id); - auto old_props = view_properties_; - view_properties_ = evt.properties; - - ::fuchsia::ui::gfx::BoundingBox layout_box = - ViewPropertiesLayoutBox(view_properties_); - - logical_size_ = scenic::Max(layout_box.max - layout_box.min, 0.f); - physical_size_.x = logical_size_.x * metrics_.scale_x; - physical_size_.y = logical_size_.y * metrics_.scale_y; - physical_size_.z = logical_size_.z * metrics_.scale_z; - - OnPropertiesChanged(std::move(old_props)); - InvalidateScene(); - break; - } - case fuchsia::ui::gfx::Event::Tag::kMetrics: { - auto& evt = event.gfx().metrics(); - if (evt.node_id == root_node_.id()) { - auto old_metrics = metrics_; - metrics_ = std::move(evt.metrics); - physical_size_.x = logical_size_.x * metrics_.scale_x; - physical_size_.y = logical_size_.y * metrics_.scale_y; - physical_size_.z = logical_size_.z * metrics_.scale_z; - OnMetricsChanged(std::move(old_metrics)); - InvalidateScene(); - } - break; - } - default: { - OnScenicEvent(std::move(event)); - } - } - break; - case ::fuchsia::ui::scenic::Event::Tag::kInput: { - if (event.input().Which() == - fuchsia::ui::input::InputEvent::Tag::kFocus && - enable_ime_) { - OnHandleFocusEvent(event.input().focus()); - } - OnInputEvent(std::move(event.input())); - break; - } - case ::fuchsia::ui::scenic::Event::Tag::kUnhandled: { - OnUnhandledCommand(std::move(event.unhandled())); - break; - } - default: { - OnScenicEvent(std::move(event)); - } - } - } -} - -void BaseView::PresentScene(zx_time_t presentation_time) { - TRACE_DURATION("view", "BaseView::PresentScene"); - // TODO(fxbug.dev/24406): Remove this when BaseView::PresentScene() is - // deprecated, see fxbug.dev/24573. - if (present_pending_) - return; - - present_pending_ = true; - - // Keep track of the most recent presentation time we've passed to - // Session.Present(), for use in InvalidateScene(). - last_presentation_time_ = presentation_time; - - TRACE_FLOW_BEGIN("gfx", "Session::Present", session_present_count_); - ++session_present_count_; - - session()->Present( - presentation_time, - [this, present_callbacks = std::move(callbacks_for_next_present_)]( - fuchsia::images::PresentationInfo info) mutable { - TRACE_DURATION("view", "BaseView::PresentationCallback"); - TRACE_FLOW_END("gfx", "present_callback", info.presentation_time); - - FML_DCHECK(present_pending_); - - zx_time_t next_presentation_time = - info.presentation_time + info.presentation_interval; - - bool present_needed = false; - if (invalidate_pending_) { - invalidate_pending_ = false; - OnSceneInvalidated(std::move(info)); - present_needed = true; - } - - for (auto& callback : present_callbacks) { - callback(info); - } - - present_pending_ = false; - if (present_needed) - PresentScene(next_presentation_time); - }); - callbacks_for_next_present_.clear(); -} - -// |fuchsia::ui::input::InputMethodEditorClient| -void BaseView::DidUpdateState( - fuchsia::ui::input::TextInputState state, - std::unique_ptr input_event) { - if (input_event) { - const fuchsia::ui::input::InputEvent& input = *input_event; - fuchsia::ui::input::InputEvent input_event_copy; - fidl::Clone(input, &input_event_copy); - OnInputEvent(std::move(input_event_copy)); - } -} - -// |fuchsia::ui::input::InputMethodEditorClient| -void BaseView::OnAction(fuchsia::ui::input::InputMethodAction action) {} - -bool BaseView::OnHandleFocusEvent(const fuchsia::ui::input::FocusEvent& focus) { - if (focus.focused) { - ActivateIme(); - return true; - } else if (!focus.focused) { - DeactivateIme(); - return true; - } - return false; -} - -void BaseView::ActivateIme() { - ime_manager_->GetInputMethodEditor( - fuchsia::ui::input::KeyboardType::TEXT, // keyboard type - fuchsia::ui::input::InputMethodAction::DONE, // input method action - fuchsia::ui::input::TextInputState{}, // initial state - ime_client_.NewBinding(), // client - ime_.NewRequest() // editor - ); -} - -void BaseView::DeactivateIme() { - if (ime_) { - ime_manager_->HideKeyboard(); - ime_ = nullptr; - } - if (ime_client_.is_bound()) { - ime_client_.Unbind(); - } -} - -} // namespace scenic diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h b/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h deleted file mode 100644 index 6ad0257ca5547..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/base_view.h +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SRC_LIB_UI_BASE_VIEW_BASE_VIEW_H_ -#define SRC_LIB_UI_BASE_VIEW_BASE_VIEW_H_ - -#include -#include -#include -#include -#include -#include -#include - -#include "src/lib/ui/base_view/embedded_view_utils.h" -#include "src/lib/ui/base_view/math.h" - -namespace scenic { - -// Parameters for creating a BaseView. -struct ViewContext { - scenic::SessionPtrAndListenerRequest session_and_listener_request; - fuchsia::ui::views::ViewToken view_token; - std::optional view_ref_pair; - sys::ComponentContext* component_context; - bool enable_ime = false; -}; - -// Abstract base implementation of a view for simple applications. -// Subclasses must handle layout and provide content for the scene by -// overriding the virtual methods defined in this class. -// -// It is not necessary to use this class to implement all Views. -// This class is merely intended to make the simple apps easier to write. -class BaseView : private fuchsia::ui::scenic::SessionListener, - private fuchsia::ui::input::InputMethodEditorClient { - public: - using PresentCallback = - fit::function; - - // Subclasses are typically created by ViewProviderService::CreateView(), - // which provides the necessary args to pass down to this base class. - BaseView(ViewContext context, const std::string& debug_name); - - BaseView(const BaseView&) = delete; - - // |root_node| is the node directly under our View; i.e. it's the top-most - // node within the tree under our View. Use it to attach any resources for - // your UI. - scenic::EntityNode& root_node() { return root_node_; } - Session* session() { return &session_; } - sys::ComponentContext* component_context() { return component_context_; } - - fuchsia::ui::gfx::ViewProperties view_properties() const { - return view_properties_; - } - - // Returns true if the view has a non-empty size in logical pixels. - bool has_logical_size() const { - auto& sz = logical_size(); - return sz.x > 0.f && sz.y > 0.f && sz.z > 0.f; - } - - // Gets the size of the view in logical pixels. - // This value is zero until the view receives a layout from its parent. - const fuchsia::ui::gfx::vec3& logical_size() const { return logical_size_; } - - // Returns true if the view has a non-empty size in physical pixels. - bool has_physical_size() const { - auto& sz = physical_size(); - return sz.x > 0.f && sz.y > 0.f && sz.z > 0.f; - } - - // Gets the size of the view in physical pixels. - // This value is zero until the view receives a layout from its parent - // and metrics from its session. - const fuchsia::ui::gfx::vec3& physical_size() const { return physical_size_; } - - // Returns true if the view has received metrics from its session. - bool has_metrics() const { - return metrics_.scale_x > 0.f && metrics_.scale_y > 0.f && - metrics_.scale_z > 0.f; - } - - // Gets the view's metrics. - // This value is zero until the view receives metrics from its session. - const fuchsia::ui::gfx::Metrics& metrics() const { return metrics_; } - - // Sets a callback which is invoked when the view's owner releases the - // view causing the view manager to unregister it. - // - // This should be used to implement cleanup policies to release resources - // associated with the view (including the object itself). - void SetReleaseHandler(fit::function callback); - - // Invalidates the scene, causing |OnSceneInvalidated()| to be invoked - // during the next frame. When the Present() callback corresponding to this - // invalidate is invoked, the optional |present_callback| will also be - // invoked. - void InvalidateScene(PresentCallback present_callback = nullptr); - - // Called when it's time for the view to update its scene contents due to - // invalidation. The new contents are presented once this function returns. - // - // The default implementation does nothing. - virtual void OnSceneInvalidated( - fuchsia::images::PresentationInfo presentation_info) {} - - // Called when the view's properties have changed. - // - // The subclass should compare the old and new properties and make note of - // whether these property changes will affect the layout or content of - // the view then update accordingly. - // - // The default implementation does nothing. - virtual void OnPropertiesChanged( - fuchsia::ui::gfx::ViewProperties old_properties) {} - - // Called when the view's metrics have changed. - // - // The subclass should compare the old and new metrics and make note of - // whether this change will affect the layout or content of the view then - // update accordingly. - // - // The default implementation does nothing. - virtual void OnMetricsChanged(fuchsia::ui::gfx::Metrics old_metrics){}; - - // Called to handle an input event. - // - // The default implementation does nothing. - virtual void OnInputEvent(fuchsia::ui::input::InputEvent event) {} - - // Called when a command sent by the client was not handled by Scenic. - // - // The default implementation does nothing. - virtual void OnUnhandledCommand(fuchsia::ui::scenic::Command unhandled) {} - - // Called when an event that is not handled directly by BaseView is received. - // For example, BaseView handles fuchsia::ui::gfx::ViewPropertiesChangedEvent, - // and notifies the subclass via OnPropertiesChanged(); not all events are - // handled in this way. - // - // The default implementation does nothing. - virtual void OnScenicEvent(fuchsia::ui::scenic::Event) {} - - protected: - // An alternative way to update the scene. Provide a faster way to cause a - // present in comparison to InvalidateScene(). Caller should update the - // scene contents before calling this method. - void PresentScene(); - - private: - // |scenic::SessionListener| - // - // Iterates over the received events and either handles them in a sensible way - // (e.g. fuchsia::ui::gfx::ViewPropertiesChangedEvent is handled by invoking - // the virtual method OnPropertiesChanged()), or delegates handling to the - // subclass via the single-event version of OnEvent() above. - // - // Subclasses should not override this. - void OnScenicEvent(std::vector events) override; - - // |fuchsia::ui::input::InputMethodEditorClient| - void DidUpdateState( - fuchsia::ui::input::TextInputState state, - std::unique_ptr event) override; - - // |fuchsia::ui::input::InputMethodEditorClient| - void OnAction(fuchsia::ui::input::InputMethodAction action) override; - - void PresentScene(zx_time_t presentation_time); - - // Handles focus event when IME is enabled. This event is used to activate - // or deactivate the IME client. - bool OnHandleFocusEvent(const fuchsia::ui::input::FocusEvent& focus); - - // Gets a new input method editor from the IME manager. - void ActivateIme(); - - // Detaches the input method editor connection, ending the edit session and - // closing the onscreen keyboard. - void DeactivateIme(); - - sys::ComponentContext* const component_context_; - fidl::Binding listener_binding_; - Session session_; - std::optional view_; - scenic::EntityNode root_node_; - - fidl::Binding ime_client_; - fuchsia::ui::input::InputMethodEditorPtr ime_; - fuchsia::ui::input::ImeServicePtr ime_manager_; - - fuchsia::ui::gfx::vec3 logical_size_; - fuchsia::ui::gfx::vec3 physical_size_; - fuchsia::ui::gfx::ViewProperties view_properties_; - fuchsia::ui::gfx::Metrics metrics_; - - zx_time_t last_presentation_time_ = 0; - size_t session_present_count_ = 0; - bool invalidate_pending_ = false; - std::vector callbacks_for_next_present_; - bool present_pending_ = false; - bool enable_ime_ = false; -}; - -} // namespace scenic - -#endif // SRC_LIB_UI_BASE_VIEW_BASE_VIEW_H_ diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc b/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc deleted file mode 100644 index 6235b8d29c1e3..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.cc +++ /dev/null @@ -1,48 +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 "src/lib/ui/base_view/embedded_view_utils.h" - -#include -#include -#include "flutter/fml/logging.h" - -namespace scenic { - -EmbeddedViewInfo LaunchComponentAndCreateView( - const fuchsia::sys::LauncherPtr& launcher, - const std::string& component_url, - const std::vector& component_args) { - FML_DCHECK(launcher); - - EmbeddedViewInfo info; - - // Configure the information to launch the component with. - fuchsia::sys::LaunchInfo launch_info; - info.app_services = - sys::ServiceDirectory::CreateWithRequest(&launch_info.directory_request); - launch_info.url = component_url; - launch_info.arguments = fidl::VectorPtr( - std::vector(component_args.begin(), component_args.end())); - - launcher->CreateComponent(std::move(launch_info), - info.controller.NewRequest()); - - info.view_provider = - info.app_services->Connect(); - - auto [view_token, view_holder_token] = scenic::ViewTokenPair::New(); - info.view_holder_token = std::move(view_holder_token); - - auto [view_ref_control, view_ref] = scenic::ViewRefPair::New(); - fidl::Clone(view_ref, &info.view_ref); - - info.view_provider->CreateViewWithViewRef(std::move(view_token.value), - std::move(view_ref_control), - std::move(view_ref)); - - return info; -} - -} // namespace scenic diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h b/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h deleted file mode 100644 index ff087d4a03c6e..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/embedded_view_utils.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SRC_LIB_UI_BASE_VIEW_EMBEDDED_VIEW_UTILS_H_ -#define SRC_LIB_UI_BASE_VIEW_EMBEDDED_VIEW_UTILS_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace scenic { - -// Serves as the return value for LaunchAppAndCreateView(), below. -struct EmbeddedViewInfo { - // Controls the launched app. The app will be destroyed if this connection - // is closed. - fuchsia::sys::ComponentControllerPtr controller; - - // Services provided by the launched app. Must not be destroyed - // immediately, otherwise the |view_provider| connection may not be - // established. - std::shared_ptr app_services; - - // ViewProvider service obtained from the app via |app_services|. Must not - // be destroyed immediately, otherwise the call to CreateView() might not be - // processed. - fuchsia::ui::app::ViewProviderPtr view_provider; - - // A token that can be used to create a ViewHolder; the corresponding token - // was provided to |view_provider| via ViewProvider.CreateView(). The - // launched app is expected to create a View, which will be connected to the - // ViewHolder created with this token. - fuchsia::ui::views::ViewHolderToken view_holder_token; - - // The ViewRef of the embedded View. - fuchsia::ui::views::ViewRef view_ref; -}; - -// Launch a component and connect to its ViewProvider service, passing it the -// necessary information to attach itself as a child view2. Populates the -// returned EmbeddedViewInfo, which the caller can use to embed the child. -// For example, an interface to a ViewProvider is obtained, a pair of -// zx::eventpairs is created, CreateView is called, etc. This encapsulates -// the boilerplate the client would otherwise write themselves. -EmbeddedViewInfo LaunchComponentAndCreateView( - const fuchsia::sys::LauncherPtr& launcher, - const std::string& component_url, - const std::vector& component_args = {}); - -} // namespace scenic - -#endif // SRC_LIB_UI_BASE_VIEW_EMBEDDED_VIEW_UTILS_H_ diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h b/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h deleted file mode 100644 index 9cf99ce8276bd..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view/math.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SRC_LIB_UI_BASE_VIEW_MATH_H_ -#define SRC_LIB_UI_BASE_VIEW_MATH_H_ - -#include - -namespace scenic { - -// Return a vec3 consisting of the component-wise sum of the two arguments. -inline fuchsia::ui::gfx::vec3 operator+(const fuchsia::ui::gfx::vec3& a, - const fuchsia::ui::gfx::vec3& b) { - return {.x = a.x + b.x, .y = a.y + b.y, .z = a.z + b.z}; -} - -// Return a vec3 consisting of the component-wise difference of the two args. -inline fuchsia::ui::gfx::vec3 operator-(const fuchsia::ui::gfx::vec3& a, - const fuchsia::ui::gfx::vec3& b) { - return {.x = a.x - b.x, .y = a.y - b.y, .z = a.z - b.z}; -} - -// Return true if |point| is contained by |box|, including when it is on the -// box boundary, and false otherwise. -inline bool ContainsPoint(const fuchsia::ui::gfx::BoundingBox& box, - const fuchsia::ui::gfx::vec3& point) { - return point.x >= box.min.x && point.y >= box.min.y && point.z >= box.min.z && - point.x <= box.max.x && point.y <= box.max.y && point.z <= box.max.z; -} - -// Similar to fuchsia::ui::gfx::ViewProperties: adds the inset to box.min, and -// subtracts it from box.max. -inline fuchsia::ui::gfx::BoundingBox InsetBy( - const fuchsia::ui::gfx::BoundingBox& box, - const fuchsia::ui::gfx::vec3& inset) { - return {.min = box.min + inset, .max = box.max - inset}; -} - -// Similar to fuchsia::ui::gfx::ViewProperties: adds the inset to box.min, and -// subtracts it from box.max. -inline fuchsia::ui::gfx::BoundingBox InsetBy( - const fuchsia::ui::gfx::BoundingBox& box, - const fuchsia::ui::gfx::vec3& inset_from_min, - const fuchsia::ui::gfx::vec3& inset_from_max) { - return {.min = box.min + inset_from_min, .max = box.max - inset_from_max}; -} - -// Inset the view properties' outer box by its insets. -inline fuchsia::ui::gfx::BoundingBox ViewPropertiesLayoutBox( - const fuchsia::ui::gfx::ViewProperties& view_properties) { - return InsetBy(view_properties.bounding_box, view_properties.inset_from_min, - view_properties.inset_from_max); -} - -// Return a vec3 consisting of the maximum x/y/z from the two arguments. -inline fuchsia::ui::gfx::vec3 Max(const fuchsia::ui::gfx::vec3& a, - const fuchsia::ui::gfx::vec3& b) { - return {.x = std::max(a.x, b.x), - .y = std::max(a.y, b.y), - .z = std::max(a.z, b.z)}; -} - -// Return a vec3 consisting of the maximum of the x/y/z components of |v|, -// compared with |min_val|. -inline fuchsia::ui::gfx::vec3 Max(const fuchsia::ui::gfx::vec3& v, - float min_val) { - return {.x = std::max(v.x, min_val), - .y = std::max(v.y, min_val), - .z = std::max(v.z, min_val)}; -} - -// Return a vec3 consisting of the minimum x/y/z from the two arguments. -inline fuchsia::ui::gfx::vec3 Min(const fuchsia::ui::gfx::vec3& a, - const fuchsia::ui::gfx::vec3& b) { - return {.x = std::min(a.x, b.x), - .y = std::min(a.y, b.y), - .z = std::min(a.z, b.z)}; -} - -// Return a vec3 consisting of the minimum of the x/y/z components of |v|, -// compared with |max_val|. -inline fuchsia::ui::gfx::vec3 Min(const fuchsia::ui::gfx::vec3& v, - float max_val) { - return {.x = std::min(v.x, max_val), - .y = std::min(v.y, max_val), - .z = std::min(v.z, max_val)}; -} - -} // namespace scenic - -#endif // SRC_LIB_UI_BASE_VIEW_MATH_H_ diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/BUILD.gn b/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/BUILD.gn deleted file mode 100644 index f97e927c2dc77..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/BUILD.gn +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2013 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//build/fuchsia/sdk.gni") - -source_set("views") { - testonly = true - - sources = [ - "color.cc", - "color.h", - "embedder_view.cc", - "embedder_view.h", - ] - - include_dirs = [ "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing" ] - - public_deps = [ - "$fuchsia_sdk_root/pkg:scenic_cpp", - "//flutter/fml", - "//flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/lib/ui/base_view", - ] -} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.cc b/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.cc deleted file mode 100644 index 0d1128256bece..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.cc +++ /dev/null @@ -1,88 +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 - -#include "flutter/fml/logging.h" -#include "src/ui/testing/views/embedder_view.h" - -namespace scenic { - -EmbedderView::EmbedderView(ViewContext context, const std::string& debug_name) - : binding_(this, std::move(context.session_and_listener_request.second)), - session_(std::move(context.session_and_listener_request.first)), - view_(&session_, std::move(context.view_token), debug_name), - top_node_(&session_) { - binding_.set_error_handler([](zx_status_t status) { - FML_LOG(FATAL) << "Session listener binding: " - << zx_status_get_string(status); - }); - view_.AddChild(top_node_); - // Call |Session::Present| in order to flush events having to do with - // creation of |view_| and |top_node_|. - session_.Present(0, [](auto) {}); -} - -// Sets the EmbeddedViewInfo and attaches the embedded View to the scene. Any -// callbacks for the embedded View's ViewState are delivered to the supplied -// callback. -void EmbedderView::EmbedView(EmbeddedViewInfo info, - std::function - view_state_changed_callback) { - // Only one EmbeddedView is currently supported. - FML_CHECK(!embedded_view_); - embedded_view_ = std::make_unique( - std::move(info), &session_, std::move(view_state_changed_callback)); - - // Attach the embedded view to the scene. - top_node_.Attach(embedded_view_->view_holder); - - // Call |Session::Present| to apply the embedded view to the scene graph. - session_.Present(0, [](auto) {}); -} - -void EmbedderView::OnScenicEvent( - std::vector events) { - for (const auto& event : events) { - if (event.Which() == fuchsia::ui::scenic::Event::Tag::kGfx && - event.gfx().Which() == - fuchsia::ui::gfx::Event::Tag::kViewPropertiesChanged) { - const auto& evt = event.gfx().view_properties_changed(); - // Naively apply the parent's ViewProperties to any EmbeddedViews. - if (embedded_view_) { - embedded_view_->view_holder.SetViewProperties( - std::move(evt.properties)); - session_.Present(0, [](auto) {}); - } - } else if (event.Which() == fuchsia::ui::scenic::Event::Tag::kGfx && - event.gfx().Which() == - fuchsia::ui::gfx::Event::Tag::kViewStateChanged) { - const auto& evt = event.gfx().view_state_changed(); - if (embedded_view_ && - evt.view_holder_id == embedded_view_->view_holder.id()) { - // Clients of |EmbedderView| *must* set a view state changed - // callback. Failure to do so is a usage error. - FML_CHECK(embedded_view_->view_state_changed_callback); - embedded_view_->view_state_changed_callback(evt.state); - } - } - } -} - -void EmbedderView::OnScenicError(std::string error) { - FML_LOG(FATAL) << "OnScenicError: " << error; -} - -EmbedderView::EmbeddedView::EmbeddedView( - EmbeddedViewInfo info, - Session* session, - std::function view_state_callback, - const std::string& debug_name) - : embedded_info(std::move(info)), - view_holder(session, - std::move(embedded_info.view_holder_token), - debug_name + " ViewHolder"), - view_state_changed_callback(std::move(view_state_callback)) {} - -} // namespace scenic diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.h b/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.h deleted file mode 100644 index 4514d0f850fd3..0000000000000 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/embedder_view.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SRC_UI_TESTING_VIEWS_EMBEDDER_VIEW_H_ -#define SRC_UI_TESTING_VIEWS_EMBEDDER_VIEW_H_ - -#include -#include -#include - -#include "src/lib/ui/base_view/base_view.h" - -namespace scenic { - -// This is a simplified |BaseView| that exposes view state events. -// -// See also lib/ui/base_view. -class EmbedderView : public fuchsia::ui::scenic::SessionListener { - public: - EmbedderView(ViewContext context, - const std::string& debug_name = "EmbedderView"); - - // Sets the EmbeddedViewInfo and attaches the embedded View to the scene. Any - // callbacks for the embedded View's ViewState are delivered to the supplied - // callback. - void EmbedView(EmbeddedViewInfo info, - std::function - view_state_changed_callback); - - private: - // |fuchsia::ui::scenic::SessionListener| - void OnScenicEvent(std::vector events) override; - // |fuchsia::ui::scenic::SessionListener| - void OnScenicError(std::string error) override; - - struct EmbeddedView { - EmbeddedView( - EmbeddedViewInfo info, - Session* session, - std::function view_state_callback, - const std::string& debug_name = "EmbedderView"); - - EmbeddedViewInfo embedded_info; - ViewHolder view_holder; - std::function - view_state_changed_callback; - }; - - fidl::Binding binding_; - Session session_; - View view_; - EntityNode top_node_; - std::optional embedded_view_properties_; - std::unique_ptr embedded_view_; -}; - -} // namespace scenic -#endif // SRC_UI_TESTING_VIEWS_EMBEDDER_VIEW_H_ diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/BUILD.gn b/shell/platform/fuchsia/flutter/tests/integration/BUILD.gn similarity index 73% rename from shell/platform/fuchsia/flutter/integration_flutter_tests/BUILD.gn rename to shell/platform/fuchsia/flutter/tests/integration/BUILD.gn index 6e5e43e0b05ea..c25f18aaa8b70 100644 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/BUILD.gn +++ b/shell/platform/fuchsia/flutter/tests/integration/BUILD.gn @@ -2,7 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -group("integration_flutter_tests") { +assert(is_fuchsia) + +import("//build/fuchsia/sdk.gni") + +group("integration") { testonly = true deps = [ "embedder:tests" ] } diff --git a/shell/platform/fuchsia/flutter/tests/integration/README.md b/shell/platform/fuchsia/flutter/tests/integration/README.md new file mode 100644 index 0000000000000..2e86aa702868a --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/README.md @@ -0,0 +1,84 @@ +# `flutter integration tests` + +## Configure and build fuchsia + +```shell +$ cd "$FUCHSIA_DIR" +$ fx set terminal.x64 +$ fx build +``` + +## Build the test + +You can specify the test's package target to build only the test package, with +its dependencies. This will also build the required runner. + +```shell +$ cd "$ENGINE_DIR/src" +$ ./flutter/tools/gn --fuchsia \ + # for example: --goma --fuchsia-cpu=x64 --runtime-mode=debug +$ ninja -C out/fuchsia_debug_x64 \ + flutter/shell/platform/fuchsia/flutter/tests/integration +``` + + +## Start an emulator + +```shell +ffx emu start --net tap +``` + +NOTE: Do _not_ run the default package server. The instructions below describe +how to launch a flutter-specific package server. + +## Publish the test packages to the Fuchsia package server + +The tests currently specify the Fuchsia package server's standard domain, +`fuchsia.com`, as the server to use to resolve (locate and load) the test +packages. So, before running the test, the most recently built `.far` files +need to be published to the Fuchsia package repo: + +```shell +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64/oot_flutter_jit_runner-0.far +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64/flutter-embedder-test-0.far +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name parent-view.far) +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name child-view.far) +``` + +## Run the test + +```shell +$ ffx test run fuchsia-pkg:://fuchsia.com/flutter-embedder-test#meta/flutter-embedder-test.cm +``` + +If, for example, you only make a change to the Dart code in `parent-view`, you +can rebuild only the parent-view package target, and republish it. + +```shell +$ ninja -C out/fuchsia_debug_x64 \ + flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view:package +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name parent-view.far) +``` + +Then re-run the test as above. + +The tests use a flutter runner with "oot_" prefixed to its package name, to +avoid conflicting with any flutter_runner package in the base fuchsia image. +After making a change to the flutter_runner you can re-deploy it with: + +```shell +$ ninja -C out/fuchsia_debug_x64 \ + flutter/shell/platform/fuchsia/flutter:oot_flutter_jit_runner +$ fx pm publish -a -repo "$(cat $FUCHSIA_DIR/.fx-build-dir)/amber-files/" \ + -f $(find "$FLUTTER_ENGINE_DIR"/src/out/fuchsia_*64 -name oot_flutter_jit_runner.far) +``` + +Then re-run the test as above. + +From here, you can modify the Flutter test, rebuild flutter, and usually rerun +the test without rebooting, by repeating the commands above. diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn b/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn new file mode 100644 index 0000000000000..ce295f31107f7 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/BUILD.gn @@ -0,0 +1,65 @@ +# 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. + +assert(is_fuchsia) + +import("//build/fuchsia/sdk.gni") +import("//flutter/tools/fuchsia/fuchsia_archive.gni") + +group("tests") { + testonly = true + deps = [ ":flutter-embedder-test" ] +} + +executable("flutter-embedder-test-bin") { + testonly = true + + output_name = "flutter-embedder-test" + + sources = [ + "color.cc", + "color.h", + "flutter-embedder-test.cc", + ] + + # This is needed for //third_party/googletest for linking zircon symbols. + libs = [ "$fuchsia_sdk_path/arch/$target_cpu/sysroot/lib/libzircon.so" ] + + deps = [ + "$fuchsia_sdk_root/fidl:fuchsia.logger", + "$fuchsia_sdk_root/fidl:fuchsia.tracing.provider", + "$fuchsia_sdk_root/fidl:fuchsia.ui.app", + "$fuchsia_sdk_root/fidl:fuchsia.ui.composition", + "$fuchsia_sdk_root/fidl:fuchsia.ui.observation.geometry", + "$fuchsia_sdk_root/fidl:fuchsia.ui.scenic", + "$fuchsia_sdk_root/fidl:fuchsia.ui.test.input", + "$fuchsia_sdk_root/fidl:fuchsia.ui.test.scene", + "$fuchsia_sdk_root/pkg:async", + "$fuchsia_sdk_root/pkg:async-loop-testing", + "$fuchsia_sdk_root/pkg:fidl_cpp", + "$fuchsia_sdk_root/pkg:scenic_cpp", + "$fuchsia_sdk_root/pkg:sys_component_cpp_testing", + "$fuchsia_sdk_root/pkg:zx", + "//flutter/fml", + "//third_party/googletest:gtest", + "//third_party/googletest:gtest_main", + ] +} + +fuchsia_test_archive("flutter-embedder-test") { + deps = [ + ":flutter-embedder-test-bin", + "child-view:package", + "parent-view:package", + + # "OOT" copies of the runners used by tests, to avoid conflicting with the + # runners in the base fuchsia image. + # TODO(fxbug.dev/106575): Fix this with subpackages. + "//flutter/shell/platform/fuchsia/flutter:oot_flutter_jit_runner", + ] + + binary = "$target_name" + + cml_file = rebase_path("meta/$target_name.cml") +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/BUILD.gn b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/BUILD.gn new file mode 100644 index 0000000000000..dedf77c3eb950 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/BUILD.gn @@ -0,0 +1,26 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/fuchsia/sdk.gni") +import("//flutter/tools/fuchsia/dart/dart_library.gni") +import("//flutter/tools/fuchsia/flutter/flutter_component.gni") +import("//flutter/tools/fuchsia/gn-sdk/package.gni") + +dart_library("lib") { + package_name = "child-view" + sources = [ "child_view.dart" ] +} + +flutter_component("component") { + main_package = "child-view" + component_name = "child-view" + main_dart = "child_view.dart" + manifest = rebase_path("meta/child-view.cml") + deps = [ ":lib" ] +} + +fuchsia_package("package") { + package_name = "child-view" + deps = [ ":component" ] +} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child_view2.dart b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/lib/child_view.dart similarity index 85% rename from shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child_view2.dart rename to shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/lib/child_view.dart index a36195526d497..5b71294b700d5 100644 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child_view2.dart +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/lib/child_view.dart @@ -4,10 +4,10 @@ import 'dart:ui'; -TestApp app; - void main(List args) { - app = TestApp(); + print('child-view: starting'); + + TestApp app = TestApp(); app.run(); } @@ -19,11 +19,15 @@ class TestApp { void run() { window.onPointerDataPacket = (PointerDataPacket packet) { - app.pointerDataPacket(packet); + this.pointerDataPacket(packet); + }; + window.onMetricsChanged = () { + window.scheduleFrame(); }; window.onBeginFrame = (Duration duration) { - app.beginFrame(duration); + this.beginFrame(duration); }; + window.scheduleFrame(); } @@ -46,7 +50,7 @@ class TestApp { void pointerDataPacket(PointerDataPacket packet) { for (final data in packet.data) { - if (data.change == PointerChange.up) { + if (data.change == PointerChange.down) { this._backgroundColor = _yellow; } } diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml new file mode 100644 index 0000000000000..9e33d6a3effe9 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/meta/child-view.cml @@ -0,0 +1,21 @@ +{ + include: [ "syslog/client.shard.cml" ], + program: { + data: "data/child-view", + + // Always use the jit runner for now. + // TODO(fxbug.dev/106577): Implement manifest merging build rules for V2 components. + runner: "flutter_jit_runner", + }, + capabilities: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + }, + ], + expose: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/pubspec.yaml b/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/pubspec.yaml similarity index 100% rename from shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/pubspec.yaml rename to shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/pubspec.yaml diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.cc b/shell/platform/fuchsia/flutter/tests/integration/embedder/color.cc similarity index 98% rename from shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.cc rename to shell/platform/fuchsia/flutter/tests/integration/embedder/color.cc index d723734f1a3ec..24fd675375247 100644 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.cc +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/color.cc @@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "color.h" + #include #include "flutter/fml/logging.h" -#include "src/ui/testing/views/color.h" namespace scenic { diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.h b/shell/platform/fuchsia/flutter/tests/integration/embedder/color.h similarity index 100% rename from shell/platform/fuchsia/flutter/integration_flutter_tests/fuchsia_testing/src/ui/testing/views/color.h rename to shell/platform/fuchsia/flutter/tests/integration/embedder/color.h diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc b/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc new file mode 100644 index 0000000000000..73f36e85ede8c --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/flutter-embedder-test.cc @@ -0,0 +1,602 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "flutter/fml/logging.h" +#include "gtest/gtest.h" + +#include "color.h" + +namespace flutter_embedder_test { +namespace { + +// Types imported for the realm_builder library. +using component_testing::ChildOptions; +using component_testing::ChildRef; +using component_testing::DirectoryContents; +using component_testing::ParentRef; +using component_testing::Protocol; +using component_testing::RealmRoot; +using component_testing::Route; +using component_testing::StartupMode; + +// The FIDL bindings for this service are not exposed in the Fuchsia SDK, so we +// must encode the name manually here. +constexpr auto kVulkanLoaderServiceName = "fuchsia.vulkan.loader.Loader"; + +constexpr auto kFlutterJitRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_flutter_jit_runner#meta/" + "flutter_jit_runner.cm"; +constexpr auto kFlutterJitProductRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_flutter_jit_product_runner#meta/" + "flutter_jit_product_runner.cm"; +constexpr auto kFlutterAotRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_flutter_aot_runner#meta/" + "flutter_aot_runner.cm"; +constexpr auto kFlutterAotProductRunnerUrl = + "fuchsia-pkg://fuchsia.com/oot_flutter_aot_product_runner#meta/" + "flutter_aot_product_runner.cm"; +constexpr char kChildViewUrl[] = + "fuchsia-pkg://fuchsia.com/child-view#meta/child-view.cm"; +constexpr char kParentViewUrl[] = + "fuchsia-pkg://fuchsia.com/parent-view#meta/parent-view.cm"; +static constexpr auto kTestUIStackUrl = + "fuchsia-pkg://fuchsia.com/test-ui-stack#meta/test-ui-stack.cm"; + +constexpr auto kFlutterRunnerEnvironment = "flutter_runner_env"; +constexpr auto kFlutterJitRunner = "flutter_jit_runner"; +constexpr auto kFlutterJitRunnerRef = ChildRef{kFlutterJitRunner}; +constexpr auto kFlutterJitProductRunner = "flutter_jit_product_runner"; +constexpr auto kFlutterJitProductRunnerRef = ChildRef{kFlutterJitProductRunner}; +constexpr auto kFlutterAotRunner = "flutter_aot_runner"; +constexpr auto kFlutterAotRunnerRef = ChildRef{kFlutterAotRunner}; +constexpr auto kFlutterAotProductRunner = "flutter_aot_product_runner"; +constexpr auto kFlutterAotProductRunnerRef = ChildRef{kFlutterAotProductRunner}; +constexpr auto kChildView = "child_view"; +constexpr auto kChildViewRef = ChildRef{kChildView}; +constexpr auto kParentView = "parent_view"; +constexpr auto kParentViewRef = ChildRef{kParentView}; +constexpr auto kTestUIStack = "ui"; +constexpr auto kTestUIStackRef = ChildRef{kTestUIStack}; + +constexpr scenic::Color kParentBackgroundColor = {0x00, 0x00, 0xFF, + 0xFF}; // Blue +constexpr scenic::Color kParentTappedColor = {0x00, 0x00, 0x00, 0xFF}; // Black +constexpr scenic::Color kChildBackgroundColor = {0xFF, 0x00, 0xFF, + 0xFF}; // Pink +constexpr scenic::Color kChildTappedColor = {0xFF, 0xFF, 0x00, 0xFF}; // Yellow + +// TODO(fxb/64201): Remove forced opacity colors when Flatland is enabled. +constexpr scenic::Color kOverlayBackgroundColor1 = { + 0x00, 0xFF, 0x0E, 0xFF}; // Green, blended with blue (FEMU local) +constexpr scenic::Color kOverlayBackgroundColor2 = { + 0x0E, 0xFF, 0x0E, 0xFF}; // Green, blended with pink (FEMU local) +constexpr scenic::Color kOverlayBackgroundColor3 = { + 0x00, 0xFF, 0x0D, 0xFF}; // Green, blended with blue (AEMU infra) +constexpr scenic::Color kOverlayBackgroundColor4 = { + 0x0D, 0xFF, 0x0D, 0xFF}; // Green, blended with pink (AEMU infra) +constexpr scenic::Color kOverlayBackgroundColor5 = { + 0x00, 0xFE, 0x0D, 0xFF}; // Green, blended with blue (NUC) +constexpr scenic::Color kOverlayBackgroundColor6 = { + 0x0D, 0xFF, 0x00, 0xFF}; // Green, blended with pink (NUC) + +static size_t OverlayPixelCount(std::map& histogram) { + return histogram[kOverlayBackgroundColor1] + + histogram[kOverlayBackgroundColor2] + + histogram[kOverlayBackgroundColor3] + + histogram[kOverlayBackgroundColor4] + + histogram[kOverlayBackgroundColor5] + + histogram[kOverlayBackgroundColor6]; +} + +// Timeout for Scenic's |TakeScreenshot| FIDL call. +constexpr zx::duration kScreenshotTimeout = zx::sec(10); +// Timeout to fail the test if it goes beyond this duration. +constexpr zx::duration kTestTimeout = zx::min(1); + +bool CheckViewExistsInSnapshot( + const fuchsia::ui::observation::geometry::ViewTreeSnapshot& snapshot, + zx_koid_t view_ref_koid) { + if (!snapshot.has_views()) { + return false; + } + + auto snapshot_count = + std::count_if(snapshot.views().begin(), snapshot.views().end(), + [view_ref_koid](const auto& view) { + return view.view_ref_koid() == view_ref_koid; + }); + + return snapshot_count > 0; +} + +bool CheckViewExistsInUpdates( + const std::vector& + updates, + zx_koid_t view_ref_koid) { + auto update_count = std::count_if( + updates.begin(), updates.end(), [view_ref_koid](auto& snapshot) { + return CheckViewExistsInSnapshot(snapshot, view_ref_koid); + }); + + return update_count > 0; +} + +} // namespace + +class FlutterEmbedderTest : public ::loop_fixture::RealLoop, + public ::testing::Test { + public: + FlutterEmbedderTest() + : realm_builder_(component_testing::RealmBuilder::Create()) { + FML_VLOG(-1) << "Setting up base realm"; + SetUpRealmBase(); + + // Post a "just in case" quit task, if the test hangs. + async::PostDelayedTask( + dispatcher(), + [] { + FML_LOG(FATAL) + << "\n\n>> Test did not complete in time, terminating. <<\n\n"; + }, + kTestTimeout); + } + + bool HasViewConnected( + const fuchsia::ui::observation::geometry::ViewTreeWatcherPtr& + view_tree_watcher, + std::optional& + watch_response, + zx_koid_t view_ref_koid); + + void LaunchParentViewInRealm( + const std::vector& component_args = {}); + + scenic::Screenshot TakeScreenshot(); + + bool TakeScreenshotUntil( + scenic::Color color, + fit::function)> callback = nullptr, + zx::duration timeout = kTestTimeout); + + // Simulates a tap at location (x, y). + void InjectTap(int32_t x, int32_t y); + + // Injects an input event, and posts a task to retry after + // `kTapRetryInterval`. + // + // We post the retry task because the first input event we send to Flutter may + // be lost. The reason the first event may be lost is that there is a race + // condition as the scene owner starts up. + // + // More specifically: in order for our app + // to receive the injected input, two things must be true before we inject + // touch input: + // * The Scenic root view must have been installed, and + // * The Input Pipeline must have received a viewport to inject touch into. + // + // The problem we have is that the `is_rendering` signal that we monitor only + // guarantees us the view is ready. If the viewport is not ready in Input + // Pipeline at that time, it will drop the touch event. + // + // TODO(fxbug.dev/96986): Improve synchronization and remove retry logic. + void TryInject(int32_t x, int32_t y); + + private: + fuchsia::ui::scenic::Scenic* scenic() { return scenic_.get(); } + + void SetUpRealmBase(); + + // Registers a fake touch screen device with an injection coordinate space + // spanning [-1000, 1000] on both axes. + void RegisterTouchScreen(); + + fuchsia::ui::scenic::ScenicPtr scenic_; + fuchsia::ui::test::input::RegistryPtr input_registry_; + fuchsia::ui::test::input::TouchScreenPtr fake_touchscreen_; + fuchsia::ui::test::scene::ControllerPtr scene_provider_; + fuchsia::ui::observation::geometry::ViewTreeWatcherPtr view_tree_watcher_; + + // Wrapped in optional since the view is not created until the middle of SetUp + component_testing::RealmBuilder realm_builder_; + std::unique_ptr realm_; + + // The typical latency on devices we've tested is ~60 msec. The retry interval + // is chosen to be a) Long enough that it's unlikely that we send a new tap + // while a previous tap is still being + // processed. That is, it should be far more likely that a new tap is sent + // because the first tap was lost, than because the system is just running + // slowly. + // b) Short enough that we don't slow down tryjobs. + // + // The first property is important to avoid skewing the latency metrics that + // we collect. For an explanation of why a tap might be lost, see the + // documentation for TryInject(). + static constexpr auto kTapRetryInterval = zx::sec(1); +}; + +void FlutterEmbedderTest::SetUpRealmBase() { + FML_LOG(INFO) << "Setting up realm base."; + + // First, add the flutter runner(s) as children. + realm_builder_.AddChild(kFlutterJitRunner, kFlutterJitRunnerUrl); + realm_builder_.AddChild(kFlutterJitProductRunner, + kFlutterJitProductRunnerUrl); + realm_builder_.AddChild(kFlutterAotRunner, kFlutterAotRunnerUrl); + realm_builder_.AddChild(kFlutterAotProductRunner, + kFlutterAotProductRunnerUrl); + + // Then, add an environment providing them. + fuchsia::component::decl::Environment flutter_runner_environment; + flutter_runner_environment.set_name(kFlutterRunnerEnvironment); + flutter_runner_environment.set_extends( + fuchsia::component::decl::EnvironmentExtends::REALM); + flutter_runner_environment.set_runners({}); + auto environment_runners = flutter_runner_environment.mutable_runners(); + fuchsia::component::decl::RunnerRegistration flutter_jit_runner_reg; + flutter_jit_runner_reg.set_source(fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = kFlutterJitRunner})); + flutter_jit_runner_reg.set_source_name(kFlutterJitRunner); + flutter_jit_runner_reg.set_target_name(kFlutterJitRunner); + environment_runners->push_back(std::move(flutter_jit_runner_reg)); + fuchsia::component::decl::RunnerRegistration flutter_jit_product_runner_reg; + flutter_jit_product_runner_reg.set_source( + fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = + kFlutterJitProductRunner})); + flutter_jit_product_runner_reg.set_source_name(kFlutterJitProductRunner); + flutter_jit_product_runner_reg.set_target_name(kFlutterJitProductRunner); + environment_runners->push_back(std::move(flutter_jit_product_runner_reg)); + fuchsia::component::decl::RunnerRegistration flutter_aot_runner_reg; + flutter_aot_runner_reg.set_source(fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = kFlutterAotRunner})); + flutter_aot_runner_reg.set_source_name(kFlutterAotRunner); + flutter_aot_runner_reg.set_target_name(kFlutterAotRunner); + environment_runners->push_back(std::move(flutter_aot_runner_reg)); + fuchsia::component::decl::RunnerRegistration flutter_aot_product_runner_reg; + flutter_aot_product_runner_reg.set_source( + fuchsia::component::decl::Ref::WithChild( + fuchsia::component::decl::ChildRef{.name = + kFlutterAotProductRunner})); + flutter_aot_product_runner_reg.set_source_name(kFlutterAotProductRunner); + flutter_aot_product_runner_reg.set_target_name(kFlutterAotProductRunner); + environment_runners->push_back(std::move(flutter_aot_product_runner_reg)); + auto realm_decl = realm_builder_.GetRealmDecl(); + if (!realm_decl.has_environments()) { + realm_decl.set_environments({}); + } + auto realm_environments = realm_decl.mutable_environments(); + realm_environments->push_back(std::move(flutter_runner_environment)); + realm_builder_.ReplaceRealmDecl(std::move(realm_decl)); + + // Add test UI stack component. + realm_builder_.AddChild(kTestUIStack, kTestUIStackUrl); + + // Add embedded parent and child components. + realm_builder_.AddChild(kChildView, kChildViewUrl, + ChildOptions{ + .environment = kFlutterRunnerEnvironment, + }); + realm_builder_.AddChild(kParentView, kParentViewUrl, + ChildOptions{ + .environment = kFlutterRunnerEnvironment, + }); + + // Route base system services to flutter runners. + realm_builder_.AddRoute( + Route{.capabilities = + { + Protocol{fuchsia::logger::LogSink::Name_}, + Protocol{fuchsia::sysmem::Allocator::Name_}, + Protocol{fuchsia::tracing::provider::Registry::Name_}, + Protocol{kVulkanLoaderServiceName}, + }, + .source = ParentRef{}, + .targets = {kFlutterJitRunnerRef, kFlutterJitProductRunnerRef, + kFlutterAotRunnerRef, kFlutterAotProductRunnerRef}}); + + // Route base system services to the test UI stack. + realm_builder_.AddRoute(Route{ + .capabilities = {Protocol{fuchsia::logger::LogSink::Name_}, + Protocol{fuchsia::sysmem::Allocator::Name_}, + Protocol{fuchsia::tracing::provider::Registry::Name_}, + Protocol{kVulkanLoaderServiceName}}, + .source = ParentRef{}, + .targets = {kTestUIStackRef}}); + + // Route UI capabilities from test UI stack to flutter runners. + realm_builder_.AddRoute(Route{ + .capabilities = {Protocol{fuchsia::ui::composition::Flatland::Name_}, + Protocol{fuchsia::ui::scenic::Scenic::Name_}}, + .source = kTestUIStackRef, + .targets = {kFlutterJitRunnerRef, kFlutterJitProductRunnerRef, + kFlutterAotRunnerRef, kFlutterAotProductRunnerRef}}); + + // Route test capabilities from test UI stack to test driver. + realm_builder_.AddRoute(Route{ + .capabilities = {Protocol{fuchsia::ui::test::input::Registry::Name_}, + Protocol{fuchsia::ui::test::scene::Controller::Name_}, + Protocol{fuchsia::ui::scenic::Scenic::Name_}}, + .source = kTestUIStackRef, + .targets = {ParentRef{}}}); + + // Route ViewProvider from child to parent, and parent to test. + realm_builder_.AddRoute( + Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}}, + .source = kParentViewRef, + .targets = {ParentRef()}}); + realm_builder_.AddRoute( + Route{.capabilities = {Protocol{fuchsia::ui::app::ViewProvider::Name_}}, + .source = kChildViewRef, + .targets = {kParentViewRef}}); +} + +// Checks whether the view with |view_ref_koid| has connected to the view tree. +// The response of a f.u.o.g.Provider.Watch call is stored in |watch_response| +// if it contains |view_ref_koid|. +bool FlutterEmbedderTest::HasViewConnected( + const fuchsia::ui::observation::geometry::ViewTreeWatcherPtr& + view_tree_watcher, + std::optional& + watch_response, + zx_koid_t view_ref_koid) { + std::optional watch_result; + view_tree_watcher->Watch( + [&watch_result](auto response) { watch_result = std::move(response); }); + FML_LOG(INFO) << "Waiting for view tree watch result"; + RunLoopUntil([&watch_result] { return watch_result.has_value(); }); + FML_LOG(INFO) << "Received for view tree watch result"; + if (CheckViewExistsInUpdates(watch_result->updates(), view_ref_koid)) { + watch_response = std::move(watch_result); + }; + return watch_response.has_value(); +} + +void FlutterEmbedderTest::LaunchParentViewInRealm( + const std::vector& component_args) { + FML_LOG(INFO) << "Launching parent-view"; + + if (!component_args.empty()) { + // Construct a args.csv file containing the specified comma-separated + // component args. + std::string csv; + for (const auto& arg : component_args) { + csv += arg + ','; + } + // Remove last comma. + csv.pop_back(); + + auto config_directory_contents = DirectoryContents(); + config_directory_contents.AddFile("args.csv", csv); + realm_builder_.RouteReadOnlyDirectory("config-data", {kParentViewRef}, + std::move(config_directory_contents)); + } + realm_ = std::make_unique(realm_builder_.Build()); + + // Register fake touch screen device. + RegisterTouchScreen(); + + // Instruct Test UI Stack to present parent-view's View. + std::optional view_ref_koid; + scene_provider_ = realm_->Connect(); + scene_provider_.set_error_handler( + [](auto) { FML_LOG(ERROR) << "Error from test scene provider"; }); + fuchsia::ui::test::scene::ControllerAttachClientViewRequest request; + request.set_view_provider(realm_->Connect()); + scene_provider_->RegisterViewTreeWatcher(view_tree_watcher_.NewRequest(), + []() {}); + scene_provider_->AttachClientView( + std::move(request), [&view_ref_koid](auto client_view_ref_koid) { + view_ref_koid = client_view_ref_koid; + }); + + FML_LOG(INFO) << "Waiting for client view ref koid"; + RunLoopUntil([&view_ref_koid] { return view_ref_koid.has_value(); }); + + // Wait for the client view to get attached to the view tree. + std::optional + watch_response; + FML_LOG(INFO) << "Waiting for client view to render; koid is " + << (view_ref_koid.has_value() ? view_ref_koid.value() : 0); + RunLoopUntil([this, &watch_response, &view_ref_koid] { + return HasViewConnected(view_tree_watcher_, watch_response, *view_ref_koid); + }); + FML_LOG(INFO) << "Client view has rendered"; + + scenic_ = realm_->Connect(); + FML_LOG(INFO) << "Launched parent-view"; +} + +scenic::Screenshot FlutterEmbedderTest::TakeScreenshot() { + FML_LOG(INFO) << "Taking screenshot... "; + fuchsia::ui::scenic::ScreenshotData screenshot_out; + scenic_->TakeScreenshot( + [this, &screenshot_out](fuchsia::ui::scenic::ScreenshotData screenshot, + bool status) { + EXPECT_TRUE(status) << "Failed to take screenshot"; + screenshot_out = std::move(screenshot); + QuitLoop(); + }); + EXPECT_FALSE(RunLoopWithTimeout(kScreenshotTimeout)) + << "Timed out waiting for screenshot."; + FML_LOG(INFO) << "Screenshot captured."; + + return scenic::Screenshot(screenshot_out); +} + +bool FlutterEmbedderTest::TakeScreenshotUntil( + scenic::Color color, + fit::function)> callback, + zx::duration timeout) { + return RunLoopWithTimeoutOrUntil( + [this, &callback, &color] { + auto screenshot = TakeScreenshot(); + auto histogram = screenshot.Histogram(); + + bool color_found = histogram[color] > 0; + if (color_found && callback != nullptr) { + callback(std::move(histogram)); + } + return color_found; + }, + timeout); +} + +void FlutterEmbedderTest::RegisterTouchScreen() { + FML_LOG(INFO) << "Registering fake touch screen"; + input_registry_ = realm_->Connect(); + input_registry_.set_error_handler( + [](auto) { FML_LOG(ERROR) << "Error from input helper"; }); + bool touchscreen_registered = false; + fuchsia::ui::test::input::RegistryRegisterTouchScreenRequest request; + request.set_device(fake_touchscreen_.NewRequest()); + input_registry_->RegisterTouchScreen( + std::move(request), + [&touchscreen_registered]() { touchscreen_registered = true; }); + RunLoopUntil([&touchscreen_registered] { return touchscreen_registered; }); + FML_LOG(INFO) << "Touchscreen registered"; +} + +void FlutterEmbedderTest::InjectTap(int32_t x, int32_t y) { + fuchsia::ui::test::input::TouchScreenSimulateTapRequest tap_request; + tap_request.mutable_tap_location()->x = x; + tap_request.mutable_tap_location()->y = y; + fake_touchscreen_->SimulateTap(std::move(tap_request), [x, y]() { + FML_LOG(INFO) << "Tap injected at (" << x << ", " << y << ")"; + }); +} + +void FlutterEmbedderTest::TryInject(int32_t x, int32_t y) { + InjectTap(x, y); + async::PostDelayedTask( + dispatcher(), [this, x, y] { TryInject(x, y); }, kTapRetryInterval); +} + +TEST_F(FlutterEmbedderTest, Embedding) { + LaunchParentViewInRealm(); + + // Take screenshot until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil( + kChildBackgroundColor, [](std::map histogram) { + // Expect parent and child background colors, with parent color > child + // color. + EXPECT_GT(histogram[kParentBackgroundColor], 0u); + EXPECT_GT(histogram[kChildBackgroundColor], 0u); + EXPECT_GT(histogram[kParentBackgroundColor], + histogram[kChildBackgroundColor]); + })); +} + +TEST_F(FlutterEmbedderTest, HittestEmbedding) { + LaunchParentViewInRealm(); + + // Take screenshot until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); + + // Simulate a tap at the center of the child view. + TryInject(/* x = */ 0, /* y = */ 0); + + // Take screenshot until we see the child-view's tapped color. + ASSERT_TRUE(TakeScreenshotUntil( + kChildTappedColor, [](std::map histogram) { + // Expect parent and child background colors, with parent color > child + // color. + EXPECT_GT(histogram[kParentBackgroundColor], 0u); + EXPECT_EQ(histogram[kChildBackgroundColor], 0u); + EXPECT_GT(histogram[kChildTappedColor], 0u); + EXPECT_GT(histogram[kParentBackgroundColor], + histogram[kChildTappedColor]); + })); +} + +TEST_F(FlutterEmbedderTest, HittestDisabledEmbedding) { + LaunchParentViewInRealm({"--no-hitTestable"}); + + // Take screenshots until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); + + // Simulate a tap at the center of the child view. + TryInject(/* x = */ 0, /* y = */ 0); + + // The parent-view should change color. + ASSERT_TRUE(TakeScreenshotUntil( + kParentTappedColor, [](std::map histogram) { + // Expect parent and child background colors, with parent color > child + // color. + EXPECT_EQ(histogram[kParentBackgroundColor], 0u); + EXPECT_GT(histogram[kParentTappedColor], 0u); + EXPECT_GT(histogram[kChildBackgroundColor], 0u); + EXPECT_EQ(histogram[kChildTappedColor], 0u); + EXPECT_GT(histogram[kParentTappedColor], + histogram[kChildBackgroundColor]); + })); +} + +TEST_F(FlutterEmbedderTest, EmbeddingWithOverlay) { + LaunchParentViewInRealm({"--showOverlay"}); + + // Take screenshot until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil( + kChildBackgroundColor, [](std::map histogram) { + // Expect parent, overlay and child background colors. + // With parent color > child color and overlay color > child color. + const size_t overlay_pixel_count = OverlayPixelCount(histogram); + EXPECT_GT(histogram[kParentBackgroundColor], 0u); + EXPECT_GT(overlay_pixel_count, 0u); + EXPECT_GT(histogram[kChildBackgroundColor], 0u); + EXPECT_GT(histogram[kParentBackgroundColor], + histogram[kChildBackgroundColor]); + EXPECT_GT(overlay_pixel_count, histogram[kChildBackgroundColor]); + })); +} + +TEST_F(FlutterEmbedderTest, HittestEmbeddingWithOverlay) { + LaunchParentViewInRealm({"--showOverlay"}); + + // Take screenshot until we see the child-view's embedded color. + ASSERT_TRUE(TakeScreenshotUntil(kChildBackgroundColor)); + + // The bottom-left corner of the overlay is at the center of the screen, + // which is at (0, 0) in the injection coordinate space. Inject a pointer + // event just outside the overlay's bounds, and ensure that it goes to the + // embedded view. + TryInject(/* x = */ -1, /* y = */ 1); + + // Take screenshot until we see the child-view's tapped color. + ASSERT_TRUE(TakeScreenshotUntil( + kChildTappedColor, [](std::map histogram) { + // Expect parent, overlay and child background colors. + // With parent color > child color and overlay color > child color. + const size_t overlay_pixel_count = OverlayPixelCount(histogram); + EXPECT_GT(histogram[kParentBackgroundColor], 0u); + EXPECT_GT(overlay_pixel_count, 0u); + EXPECT_EQ(histogram[kChildBackgroundColor], 0u); + EXPECT_GT(histogram[kChildTappedColor], 0u); + EXPECT_GT(histogram[kParentBackgroundColor], + histogram[kChildTappedColor]); + EXPECT_GT(overlay_pixel_count, histogram[kChildTappedColor]); + })); +} + +} // namespace flutter_embedder_test diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml b/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml new file mode 100644 index 0000000000000..b053b0a4cc24a --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/flutter-embedder-test.cml @@ -0,0 +1,27 @@ +{ + include: [ + "gtest_runner.shard.cml", + "sys/component/realm_builder_absolute.shard.cml", + + // This test needs both the vulkan facet and the hermetic-tier-2 facet, + // so we are forced to make it a system test. + "sys/testing/system-test.shard.cml", + ], + program: { + binary: "bin/app", + }, + offer: [ + { + // Offer capabilities needed by components in this test realm. + // Keep it minimal, describe only what's actually needed. + protocol: [ + "fuchsia.logger.LogSink", + "fuchsia.sysmem.Allocator", + "fuchsia.tracing.provider.Registry", + "fuchsia.vulkan.loader.Loader", + ], + from: "parent", + to: "#realm_builder", + }, + ], +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml b/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml new file mode 100644 index 0000000000000..4593cf2c66ad3 --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/meta/gtest_runner.shard.cml @@ -0,0 +1,14 @@ +{ + program: { + runner: "gtest_runner", + }, + capabilities: [ + { protocol: "fuchsia.test.Suite" }, + ], + expose: [ + { + protocol: "fuchsia.test.Suite", + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/BUILD.gn b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/BUILD.gn new file mode 100644 index 0000000000000..ceaf8299f4a1b --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/BUILD.gn @@ -0,0 +1,36 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/fuchsia/sdk.gni") +import("//flutter/tools/fuchsia/dart/dart_library.gni") +import("//flutter/tools/fuchsia/flutter/flutter_component.gni") +import("//flutter/tools/fuchsia/gn-sdk/package.gni") + +dart_library("lib") { + package_name = "parent-view" + sources = [ "parent_view.dart" ] + + deps = [ + "//flutter/shell/platform/fuchsia/dart:args", + "//flutter/shell/platform/fuchsia/dart:vector_math", + "//flutter/tools/fuchsia/dart:fuchsia_services", + "//flutter/tools/fuchsia/dart:zircon", + "//flutter/tools/fuchsia/fidl:fuchsia.sys", + "//flutter/tools/fuchsia/fidl:fuchsia.ui.app", + "//flutter/tools/fuchsia/fidl:fuchsia.ui.views", + ] +} + +flutter_component("component") { + main_package = "parent-view" + component_name = "parent-view" + main_dart = "parent_view.dart" + manifest = rebase_path("meta/parent-view.cml") + deps = [ ":lib" ] +} + +fuchsia_package("package") { + package_name = "parent-view" + deps = [ ":component" ] +} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart similarity index 71% rename from shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart rename to shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart index 6dcddd2d5c666..5fd521661150d 100644 --- a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent_view2.dart +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/lib/parent_view.dart @@ -4,42 +4,49 @@ import 'dart:convert'; import 'dart:typed_data'; +import 'dart:io'; import 'dart:ui'; -import 'package:vector_math/vector_math_64.dart' as vector_math_64; + import 'package:args/args.dart'; -import 'package:fidl_fuchsia_sys/fidl_async.dart'; import 'package:fidl_fuchsia_ui_app/fidl_async.dart'; import 'package:fidl_fuchsia_ui_views/fidl_async.dart'; import 'package:fuchsia_services/services.dart'; +import 'package:vector_math/vector_math_64.dart' as vector_math_64; import 'package:zircon/zircon.dart'; -// TODO(richkadel): To run the test serving the runner and test packages from -// the flutter/engine package server (via -// `//flutter/tools/fuchsia/devshell/serve.sh`), change `fuchsia.com` to -// `engine`. -const _kChildAppUrl = - 'fuchsia-pkg://fuchsia.com/child-view2#meta/child-view2.cmx'; - -TestApp app; +final _argsCsvFilePath = '/config/data/args.csv'; void main(List args) { + print('parent-view: starting'); + + args = args + _GetArgsFromConfigFile(); final parser = ArgParser() ..addFlag('showOverlay', defaultsTo: false) ..addFlag('hitTestable', defaultsTo: true) - ..addFlag('focusable', defaultsTo: true); + ..addFlag('focusable', defaultsTo: true) + ..addFlag('useFlatland', defaultsTo: false); final arguments = parser.parse(args); for (final option in arguments.options) { - print('parent-view2: $option: ${arguments[option]}'); + print('parent-view: $option: ${arguments[option]}'); } - final childViewToken = _launchApp(_kChildAppUrl); - - app = TestApp( - ChildView(childViewToken), - showOverlay: arguments['showOverlay'], - hitTestable: arguments['hitTestable'], - focusable: arguments['focusable'], - ); + TestApp app; + final useFlatland = arguments['useFlatland']; + if (useFlatland) { + app = TestApp( + ChildView(_launchFlatlandChildView()), + showOverlay: arguments['showOverlay'], + hitTestable: arguments['hitTestable'], + focusable: arguments['focusable'], + ); + } else { + app = TestApp( + ChildView.gfx(_launchGfxChildView()), + showOverlay: arguments['showOverlay'], + hitTestable: arguments['hitTestable'], + focusable: arguments['focusable'], + ); + } app.run(); } @@ -64,19 +71,24 @@ class TestApp { void run() { childView.create(hitTestable, focusable, (ByteData reply) { - // The child-view2 should be attached to Scenic now. - // Ready to build the scene. + // Set up window allbacks. window.onPointerDataPacket = (PointerDataPacket packet) { for (final data in packet.data) { - if (data.change == PointerChange.up) { + if (data.change == PointerChange.down) { this._backgroundColor = _black; } } window.scheduleFrame(); }; + window.onMetricsChanged = () { + window.scheduleFrame(); + }; window.onBeginFrame = (Duration duration) { - app.beginFrame(duration); + this.beginFrame(duration); }; + + // The child view should be attached to Scenic now. + // Ready to build the scene. window.scheduleFrame(); }); } @@ -149,45 +161,16 @@ class TestApp { } } -ViewHolderToken _launchApp(String componentUrl) { - final incoming = Incoming(); - final componentController = ComponentControllerProxy(); - - final launcher = LauncherProxy(); - Incoming.fromSvcPath() - ..connectToService(launcher) - ..close(); - launcher.createComponent( - LaunchInfo( - url: componentUrl, - directoryRequest: incoming.request().passChannel(), - ), - componentController.ctrl.request(), - ); - launcher.ctrl.close(); - - ViewProviderProxy viewProvider = ViewProviderProxy(); - incoming - ..connectToService(viewProvider) - ..close(); - - final viewTokens = EventPairPair(); - assert(viewTokens.status == ZX.OK); - final viewHolderToken = ViewHolderToken(value: viewTokens.first); - final viewToken = ViewToken(value: viewTokens.second); - - viewProvider.createView(viewToken.value, null, null); - viewProvider.ctrl.close(); - - return viewHolderToken; -} - class ChildView { - - final ViewHolderToken viewToken; + final ViewHolderToken viewHolderToken; + final ViewportCreationToken viewportCreationToken; final int viewId; - ChildView(this.viewToken) : viewId = viewToken.value.handle.handle { + ChildView(this.viewportCreationToken) : viewHolderToken = null, viewId = viewportCreationToken.value.handle.handle { + assert(viewId != null); + } + + ChildView.gfx(this.viewHolderToken) : viewportCreationToken = null, viewId = viewHolderToken.value.handle.handle { assert(viewId != null); } @@ -227,3 +210,49 @@ class ChildView { callback); } } + +ViewportCreationToken _launchFlatlandChildView() { + ViewProviderProxy viewProvider = ViewProviderProxy(); + Incoming.fromSvcPath() + ..connectToService(viewProvider) + ..close(); + + final viewTokens = ChannelPair(); + assert(viewTokens.status == ZX.OK); + final viewportCreationToken = ViewportCreationToken(value: viewTokens.first); + final viewCreationToken = ViewCreationToken(value: viewTokens.second); + + final createViewArgs = CreateView2Args(viewCreationToken: viewCreationToken); + viewProvider.createView2(createViewArgs); + viewProvider.ctrl.close(); + + return viewportCreationToken; +} + +ViewHolderToken _launchGfxChildView() { + ViewProviderProxy viewProvider = ViewProviderProxy(); + Incoming.fromSvcPath() + ..connectToService(viewProvider) + ..close(); + + final viewTokens = EventPairPair(); + assert(viewTokens.status == ZX.OK); + final viewHolderToken = ViewHolderToken(value: viewTokens.first); + final viewToken = ViewToken(value: viewTokens.second); + + viewProvider.createView(viewToken.value, null, null); + viewProvider.ctrl.close(); + + return viewHolderToken; +} + +List _GetArgsFromConfigFile() { + List args; + final f = File(_argsCsvFilePath); + if (!f.existsSync()) { + return List.empty(); + } + final fileContentCsv = f.readAsStringSync(); + args = fileContentCsv.split('\n'); + return args; +} diff --git a/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml new file mode 100644 index 0000000000000..aea9b8bc24dab --- /dev/null +++ b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/meta/parent-view.cml @@ -0,0 +1,33 @@ +{ + include: [ "syslog/client.shard.cml" ], + program: { + data: "data/parent-view", + + // Always use the jit runner for now. + // TODO(fxbug.dev/106577): Implement manifest merging build rules for V2 components. + runner: "flutter_jit_runner", + }, + capabilities: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + }, + ], + use: [ + { + protocol: [ + "fuchsia.ui.app.ViewProvider", + ], + }, + { + directory: "config-data", + rights: [ "r*" ], + path: "/config/data", + }, + ], + expose: [ + { + protocol: [ "fuchsia.ui.app.ViewProvider" ], + from: "self", + }, + ], +} diff --git a/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/pubspec.yaml b/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/pubspec.yaml similarity index 100% rename from shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/pubspec.yaml rename to shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/pubspec.yaml diff --git a/testing/fuchsia/test_suites.yaml b/testing/fuchsia/test_suites.yaml index 8dcbc8a9e2e1c..86630bdb73450 100644 --- a/testing/fuchsia/test_suites.yaml +++ b/testing/fuchsia/test_suites.yaml @@ -1,15 +1,13 @@ # This configuration file specifies several test suites with their package and # test command for femu_test.py. -# Legacy Component Framework v1 components. -- test_command: run-test-component fuchsia-pkg://fuchsia.com/flutter-embedder-test2#meta/flutter-embedder-test2.cmx - packages: - - flutter-embedder-test2-0.far - - gen/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/child-view2/child-view2/child-view2.far - - gen/flutter/shell/platform/fuchsia/flutter/integration_flutter_tests/embedder/parent-view2/parent-view2/parent-view2.far - - flutter_jit_runner-0.far - # v2 components. +- test_command: run-test-suite fuchsia-pkg://fuchsia.com/flutter-embedder-test#meta/flutter-embedder-test.cm + packages: + - flutter-embedder-test-0.far + - oot_flutter_jit_runner-0.far + - gen/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/child-view/child-view/child-view.far + - gen/flutter/shell/platform/fuchsia/flutter/tests/integration/embedder/parent-view/parent-view/parent-view.far - test_command: run-test-suite fuchsia-pkg://fuchsia.com/dart_runner_tests#meta/dart_runner_tests.cm package: dart_runner_tests-0.far - test_command: run-test-suite fuchsia-pkg://fuchsia.com/flutter_runner_tests#meta/flutter_runner_tests.cm diff --git a/tools/fuchsia/fuchsia_archive.gni b/tools/fuchsia/fuchsia_archive.gni index c0cc730973d64..a30d392c526e9 100644 --- a/tools/fuchsia/fuchsia_archive.gni +++ b/tools/fuchsia/fuchsia_archive.gni @@ -36,6 +36,8 @@ template("_compile_cml") { "--output", rebase_path(invoker.output, root_build_dir), "--includepath", + rebase_path("$fuchsia_sdk/pkg/", root_build_dir), + "--includepath", get_path_info(invoker.manifest, "dir"), "--includepath", rebase_path("//"), @@ -258,42 +260,66 @@ template("fuchsia_archive") { # cmx_file (optional): # A path to the .cmx file for the test archive. # If not defined, a generated .cml file for the test archive will be used instead. +# cml_file (optional): +# The path to the V2 component manifest (.cml file) for the test archive's component. +# Should include the file extension. +# If not defined, a generated .cml file for the test archive will be used instead. # libraries (optional): # Paths to .so libraries that should be dynamically linked to the binary. # resources (optional): # Files that should be placed into the `data/` directory of the archive. template("fuchsia_test_archive") { assert(defined(invoker.deps), "package must define deps") - - # Interpolate test_suite.cml template with the test suite's name. - test_suite = target_name - interpolate_cml_target = "${test_suite}_interpolate_cml" - generated_cml_file = "$root_out_dir/$test_suite.cml" - action(interpolate_cml_target) { - testonly = true - script = "//flutter/tools/fuchsia/interpolate_test_suite.py" - sources = [ "//flutter/testing/fuchsia/meta/test_suite.cml" ] - args = [ - "--input", - rebase_path("//flutter/testing/fuchsia/meta/test_suite.cml"), - "--test-suite", - test_suite, - "--output", - rebase_path(generated_cml_file), - ] - outputs = [ generated_cml_file ] + _deps = [] + if (defined(invoker.deps)) { + _deps += invoker.deps } - far_base_dir = "$root_out_dir/${target_name}_far" + if (defined(invoker.cml_file)) { + _far_base_dir = "$root_out_dir/${target_name}_far" + _cml_file_name = get_path_info(invoker.cml_file, "name") + _compile_cml_target = "${target_name}_${_cml_file_name}_compile_cml" - # Compile the resulting interpolated test suite's cml. - compile_test_suite_cml_target = "${test_suite}_test_suite_compile_cml" - _compile_cml(compile_test_suite_cml_target) { - testonly = true - deps = [ ":$interpolate_cml_target" ] + _compile_cml(_compile_cml_target) { + forward_variables_from(invoker, [ "testonly" ]) + + manifest = invoker.cml_file + output = "$_far_base_dir/meta/${_cml_file_name}.cm" + } + _deps += [ ":$_compile_cml_target" ] + } else { + # Interpolate test_suite.cml template with the test suite's name. + test_suite = target_name + interpolate_cml_target = "${test_suite}_interpolate_cml" + generated_cml_file = "$root_out_dir/$test_suite.cml" + action(interpolate_cml_target) { + testonly = true + script = "//flutter/tools/fuchsia/interpolate_test_suite.py" + sources = [ "//flutter/testing/fuchsia/meta/test_suite.cml" ] + args = [ + "--input", + rebase_path("//flutter/testing/fuchsia/meta/test_suite.cml"), + "--test-suite", + test_suite, + "--output", + rebase_path(generated_cml_file), + ] + outputs = [ generated_cml_file ] + } + + far_base_dir = "$root_out_dir/${target_name}_far" + + # Compile the resulting interpolated test suite's cml. + compile_test_suite_cml_target = "${test_suite}_test_suite_compile_cml" + _compile_cml(compile_test_suite_cml_target) { + testonly = true + deps = [ ":$interpolate_cml_target" ] + + manifest = generated_cml_file + output = "$far_base_dir/meta/${test_suite}.cm" + } - manifest = generated_cml_file - output = "$far_base_dir/meta/${test_suite}.cm" + _deps += [ ":$compile_test_suite_cml_target" ] } _fuchsia_archive(target_name) { @@ -309,15 +335,6 @@ template("fuchsia_test_archive") { libraries += invoker.libraries } - # TODO(fxbug.dev/79873): Only cfv2 components should be allowed after - # FakeScenic is available. - if (defined(invoker.cmx_file)) { - cmx_file = invoker.cmx_file - - # Don't include cml files. - deps = invoker.deps - } else { - deps = invoker.deps + [ ":$compile_test_suite_cml_target" ] - } + deps = _deps } } From 7fb83113616834b197d97b8052309a0bcc710bce Mon Sep 17 00:00:00 2001 From: Chris Bracken Date: Fri, 19 Aug 2022 18:38:49 -0700 Subject: [PATCH 443/558] [Windows] Set Platform.executable on engine start (#35560) When setting FlutterProjectArgs.command_line_argv prior to launching the engine, we were previously setting a placeholder value rather than the executable name. This resulted in Platform.executable (from dart:io) returning "placeholder" in application code. This updates the Windows implementation for consistency with macOS and guarantees that Platform.executable will return a reasonable value in Dart code. Note that this does not affect Platform.resolvedExecutable, which returns a full, resolved path, and is implemented in the Dart runtime itself. Previously the code: print(Platform.executable); print(Platform.resolvedExecutable); resulted in the following output on Windows: flutter: placeholder flutter: C:\path\to\project\build\windows\runner\Debug\project.exe after this patch, it results in: flutter: project.exe flutter: C:\path\to\project\build\windows\runner\Debug\project.exe Issue: https://github.com/flutter/flutter/issues/83921 --- shell/platform/windows/fixtures/main.dart | 9 +++++++ .../windows/flutter_windows_engine.cc | 25 +++++++++++++++---- .../platform/windows/flutter_windows_engine.h | 3 +++ .../flutter_windows_engine_unittests.cc | 5 ++++ .../windows/flutter_windows_unittests.cc | 24 ++++++++++++++++++ 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/shell/platform/windows/fixtures/main.dart b/shell/platform/windows/fixtures/main.dart index e2d76aa6171e7..57ba615d984a7 100644 --- a/shell/platform/windows/fixtures/main.dart +++ b/shell/platform/windows/fixtures/main.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:io' as io; import 'dart:ui' as ui; // Signals a waiting latch in the native test. @@ -10,6 +11,9 @@ void signal() native 'Signal'; // Signals a waiting latch in the native test, passing a boolean value. void signalBoolValue(bool value) native 'SignalBoolValue'; +// Signals a waiting latch in the native test, passing a string value. +void signalStringValue(String value) native 'SignalStringValue'; + // Signals a waiting latch in the native test, which returns a value to the fixture. bool signalBoolReturn() native 'SignalBoolReturn'; @@ -39,6 +43,11 @@ void verifyNativeFunctionWithReturn() { signalBoolValue(value); } +@pragma('vm:entry-point') +void readPlatformExecutable() { + signalStringValue(io.Platform.executable); +} + @pragma('vm:entry-point') void drawHelloWorld() { ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) { diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 6c3d728f7e4ff..9396a9e2c15bc 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -11,6 +11,7 @@ #include #include "flutter/fml/logging.h" +#include "flutter/fml/paths.h" #include "flutter/fml/platform/win/wstring_conversion.h" #include "flutter/shell/platform/common/client_wrapper/binary_messenger_impl.h" #include "flutter/shell/platform/common/path_utils.h" @@ -224,8 +225,9 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) { // FlutterProjectArgs is expecting a full argv, so when processing it for // flags the first item is treated as the executable and ignored. Add a dummy // value so that all provided arguments are used. + std::string executable_name = GetExecutableName(); + std::vector argv = {executable_name.c_str()}; std::vector switches = project_->GetSwitches(); - std::vector argv = {"placeholder"}; std::transform( switches.begin(), switches.end(), std::back_inserter(argv), [](const std::string& arg) -> const char* { return arg.c_str(); }); @@ -532,10 +534,9 @@ void FlutterWindowsEngine::SendSystemLocales() { // Convert the locale list to the locale pointer list that must be provided. std::vector flutter_locale_list; flutter_locale_list.reserve(flutter_locales.size()); - std::transform( - flutter_locales.begin(), flutter_locales.end(), - std::back_inserter(flutter_locale_list), - [](const auto& arg) -> const auto* { return &arg; }); + std::transform(flutter_locales.begin(), flutter_locales.end(), + std::back_inserter(flutter_locale_list), + [](const auto& arg) -> const auto* { return &arg; }); embedder_api_.UpdateLocales(engine_, flutter_locale_list.data(), flutter_locale_list.size()); } @@ -592,4 +593,18 @@ gfx::NativeViewAccessible FlutterWindowsEngine::GetNativeAccessibleFromId( return node_delegate->GetNativeViewAccessible(); } +std::string FlutterWindowsEngine::GetExecutableName() const { + std::pair result = fml::paths::GetExecutablePath(); + if (result.first) { + const std::string& executable_path = result.second; + size_t last_separator = executable_path.find_last_of("/\\"); + if (last_separator == std::string::npos || + last_separator == executable_path.size() - 1) { + return executable_path; + } + return executable_path.substr(last_separator + 1); + } + return "Flutter"; +} + } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index 3ead42238f616..700f7889a2ddf 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -220,6 +220,9 @@ class FlutterWindowsEngine { root_isolate_create_callback_ = callback; } + // Returns the executable name for this process or "Flutter" if unknown. + std::string GetExecutableName() const; + private: // Allows swapping out embedder_api_ calls in tests. friend class EngineModifier; diff --git a/shell/platform/windows/flutter_windows_engine_unittests.cc b/shell/platform/windows/flutter_windows_engine_unittests.cc index 87315efad58f5..1417fe48a3f0c 100644 --- a/shell/platform/windows/flutter_windows_engine_unittests.cc +++ b/shell/platform/windows/flutter_windows_engine_unittests.cc @@ -404,5 +404,10 @@ TEST(FlutterWindowsEngine, SetNextFrameCallback) { EXPECT_TRUE(called); } +TEST(FlutterWindowsEngine, GetExecutableName) { + std::unique_ptr engine = GetTestEngine(); + EXPECT_EQ(engine->GetExecutableName(), "flutter_windows_unittests.exe"); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_unittests.cc b/shell/platform/windows/flutter_windows_unittests.cc index 720c7b3fbc0a7..40cd9e32a3313 100644 --- a/shell/platform/windows/flutter_windows_unittests.cc +++ b/shell/platform/windows/flutter_windows_unittests.cc @@ -118,6 +118,30 @@ TEST_F(WindowsTest, VerifyNativeFunctionWithParameters) { EXPECT_TRUE(bool_value); } +// Verify that Platform.executable returns the executable name. +TEST_F(WindowsTest, PlatformExecutable) { + auto& context = GetContext(); + WindowsConfigBuilder builder(context); + builder.SetDartEntrypoint("readPlatformExecutable"); + + std::string executable_name; + fml::AutoResetWaitableEvent latch; + auto native_entry = CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + auto handle = Dart_GetNativeArgument(args, 0); + ASSERT_FALSE(Dart_IsError(handle)); + executable_name = tonic::DartConverter::FromDart(handle); + latch.Signal(); + }); + context.AddNativeFunction("SignalStringValue", native_entry); + + ViewControllerPtr controller{builder.Run()}; + ASSERT_NE(controller, nullptr); + + // Wait until signalStringValue has been called. + latch.Wait(); + EXPECT_EQ(executable_name, "flutter_windows_unittests.exe"); +} + // Verify that native functions that return values can be registered and // resolved. TEST_F(WindowsTest, VerifyNativeFunctionWithReturn) { From 98c567732402ebb0d4bade7b3bf2cbced15cb400 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Fri, 19 Aug 2022 22:38:28 -0400 Subject: [PATCH 444/558] Roll Dart SDK from 220698d69c17 to 1294984fe017 (1 revision) (#35564) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index bfb202d373d06..aaae081ebb48a 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '220698d69c1737184658dd513f567d795909f8f4', + 'dart_revision': '1294984fe017fb73436f6c242bef348caf000b1e', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 548492218a7cf..5e07b4afc3ca4 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 08d3ae27d4967d586a61824c57e6b876 +Signature: db11b54b3a25ad4da814f689d36f93af UNUSED LICENSES: From 835ba6b38df15d5397a1e6d4fa05cf81f0f37233 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Fri, 19 Aug 2022 22:30:19 -0700 Subject: [PATCH 445/558] MacOS framework was simplified to remove an internal zip. (#35563) --- build/archives/BUILD.gn | 6 ----- build/zip.py | 9 +++++++- shell/platform/darwin/macos/BUILD.gn | 33 ++++++++-------------------- 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/build/archives/BUILD.gn b/build/archives/BUILD.gn index 658ee2ce09308..81f2e537ea268 100644 --- a/build/archives/BUILD.gn +++ b/build/archives/BUILD.gn @@ -246,12 +246,6 @@ if (is_mac) { deps = [ "//flutter/lib/snapshot:create_macos_gen_snapshots" ] } - group("macos_flutter_framework") { - deps = [ - "//flutter/shell/platform/darwin/macos:macos_flutter_framework_archive", - ] - } - zip_bundle("archive_gen_snapshot") { deps = [ ":snapshot_entitlement_config", diff --git a/build/zip.py b/build/zip.py index 9b36dd2e537c1..dbcd18a433384 100755 --- a/build/zip.py +++ b/build/zip.py @@ -14,7 +14,14 @@ def _zip_dir(path, zip_file, prefix): path = path.rstrip('/\\') - for root, _, files in os.walk(path): + for root, directories, files in os.walk(path): + for directory in directories: + if os.path.islink(os.path.join(root, directory)): + add_symlink( + zip_file, + os.path.join(root, '%s/' % directory), + os.path.join(root.replace(path, prefix), directory), + ) for file in files: if os.path.islink(os.path.join(root, file)): add_symlink( diff --git a/shell/platform/darwin/macos/BUILD.gn b/shell/platform/darwin/macos/BUILD.gn index 0381e6feb8a08..d2f5b3df28619 100644 --- a/shell/platform/darwin/macos/BUILD.gn +++ b/shell/platform/darwin/macos/BUILD.gn @@ -325,8 +325,15 @@ if (build_glfw_shell) { } zip_bundle("zip_macos_flutter_framework") { - deps = [ ":_generate_symlinks" ] - output = "tmp/FlutterMacOS.framework.zip" + deps = [ + ":_generate_symlinks", + ":macos_framework_without_entitlement_config", + ] + prefix = "$full_platform_name-$flutter_runtime_mode/" + if (flutter_runtime_mode == "debug") { + prefix = "$full_platform_name/" + } + output = "${prefix}FlutterMacOS.framework.zip" visibility = [ ":*" ] files = [ { @@ -343,25 +350,3 @@ generated_file("macos_framework_without_entitlement_config") { deps = [ ":_generate_symlinks" ] } - -zip_bundle("macos_flutter_framework_archive") { - deps = [ - ":macos_framework_without_entitlement_config", - ":zip_macos_flutter_framework", - ] - prefix = "$full_platform_name-$flutter_runtime_mode/" - if (flutter_runtime_mode == "debug") { - prefix = "$full_platform_name/" - } - output = "${prefix}FlutterMacOS.framework.zip" - files = [ - { - source = "$root_out_dir/zip_archives/tmp/FlutterMacOS.framework.zip" - destination = "FlutterMacOS.framework.zip" - }, - { - source = "$target_gen_dir/framework_without_entitlements.txt" - destination = "without_entitlements.txt" - }, - ] -} From 1e63130d7b4e87c1957238901ed3d23b85708c1f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 20 Aug 2022 02:58:22 -0400 Subject: [PATCH 446/558] Roll Dart SDK from 1294984fe017 to 0ccc2c714dad (1 revision) (#35568) --- DEPS | 14 +++++++------- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/DEPS b/DEPS index aaae081ebb48a..b0ee86d4c7db2 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '1294984fe017fb73436f6c242bef348caf000b1e', + 'dart_revision': '0ccc2c714dadca0c88a882c6a4198978fb38861b', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -50,7 +50,7 @@ vars = { 'dart_pub_rev': 'ac7db6c07318efa4a8712110275eaf70f96a6d00', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': 'e00c0ea769e32821d91c0880da8eb736839a6e6d', - 'dart_webdev_rev': '1de398efc16a707ede884d629c1c0a7edea8b5fd', + 'dart_webdev_rev': 'a82a5a900e54584c53cdc0853e6ecf952f5c1d72', 'dart_webkit_inspection_protocol_rev': '57ebca4b97310a10774c59c0fb056d8f23bd5cee', 'dart_yaml_edit_rev': '01589b3ce447b03aed991db49f1ec6445ad5476d', 'dart_zlib_rev': '27c2f474b71d0d20764f86f60ef8b00da1a16cda', @@ -194,7 +194,7 @@ deps = { Var('dart_git') + '/convert.git@7145da14f9cd730e80fb4c6a10108fcfd205e8e7', 'src/third_party/dart/third_party/pkg/crypto': - Var('dart_git') + '/crypto.git@223e0a62c0f762fd2b510f753861445b52e14fc3', + Var('dart_git') + '/crypto.git@7cf89d35b3d90786d9f7f75211b3b3cd7e4d173f', 'src/third_party/dart/third_party/pkg/csslib': Var('dart_git') + '/csslib.git@ba2eb2d80530eedefadaade338a09c2dd60410f3', @@ -206,7 +206,7 @@ deps = { Var('dart_git') + '/dartdoc.git@b3d4aa002d36c28b0af114abd0997b8521c27b11', 'src/third_party/dart/third_party/pkg/ffi': - Var('dart_git') + '/ffi.git@18b2b549d55009ff594600b04705ff6161681e07', + Var('dart_git') + '/ffi.git@fb5f2667826c0900e551d19101052f84e35f41bf', 'src/third_party/dart/third_party/pkg/file': Var('dart_git') + '/external/github.com/google/file.dart@0132eeedea2933513bf230513a766a8baeab0c4f', @@ -221,7 +221,7 @@ deps = { Var('dart_git') + '/html.git@8243e967caad9932c13971af3b2a7c8f028383d5', 'src/third_party/dart/third_party/pkg/http': - Var('dart_git') + '/http.git@d54c4e005dfe150921d92fc6017e54358c3f23cc', + Var('dart_git') + '/http.git@b0585323f586d56359a8329cc532ad0ee7cbee91', 'src/third_party/dart/third_party/pkg/http_multi_server': Var('dart_git') + '/http_multi_server.git@20bf079c8955d1250a45afb9cb096472a724a551', @@ -299,7 +299,7 @@ deps = { Var('dart_git') + '/term_glyph.git@ec7cf7bb51ebb7d55760a1359f6697690dbc06ba', 'src/third_party/dart/third_party/pkg/test': - Var('dart_git') + '/test.git@aba7de5851ace64f1f887369ae9424582d9d4d7f', + Var('dart_git') + '/test.git@5f52c524cd10ba3dd9aa5614955c338d50b29d21', 'src/third_party/dart/third_party/pkg/test_reflective_loader': Var('dart_git') + '/test_reflective_loader.git@8d0de01bbe852fea1f8e33aba907abcba50a8a1e', @@ -314,7 +314,7 @@ deps = { Var('dart_git') + '/watcher.git' + '@' + Var('dart_watcher_rev'), 'src/third_party/dart/third_party/pkg/web_socket_channel': - Var('dart_git') + '/web_socket_channel.git@99dbdc5769e19b9eeaf69449a59079153c6a8b1f', + Var('dart_git') + '/web_socket_channel.git@4b46c0c4196a5e76c2b0e2589ed37de247d35938', 'src/third_party/dart/third_party/pkg/webdev': Var('dart_git') + '/webdev.git' + '@' + Var('dart_webdev_rev'), diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 5e07b4afc3ca4..43123ba9c8524 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: db11b54b3a25ad4da814f689d36f93af +Signature: eae701caa9f0488bb7cfc6cd080e32f0 UNUSED LICENSES: From 06900c486cee1a16f373812a9add855253f97006 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 20 Aug 2022 04:42:25 -0400 Subject: [PATCH 447/558] Roll Fuchsia Linux SDK from qkLLOLyDJFclyuGN7... to JcqRURLnM_MMMLoss... (#35569) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b0ee86d4c7db2..f8ca3746b5e2e 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'qkLLOLyDJFclyuGN7WP78QrAKS80W6F6H6WNl_K4pzIC' + 'version': 'JcqRURLnM_MMMLosspwpUXzH9GMkNtTtV8DUKPOwxR0C' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 2798bc67ee9b3..9b76c46627d02 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: b47424a813c87d11af55d4d1964cbe78 +Signature: 1a5767ec0f8f78114f5d82a490dde91e UNUSED LICENSES: From 0005149dca9b248663adcde4bdd7c6c915a76584 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 20 Aug 2022 06:54:16 -0400 Subject: [PATCH 448/558] Roll Dart SDK from 0ccc2c714dad to ddbdebabefca (1 revision) (#35571) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index f8ca3746b5e2e..0bd9f2cde4d92 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '0ccc2c714dadca0c88a882c6a4198978fb38861b', + 'dart_revision': 'ddbdebabefca45d094117481ff691a6353a8f441', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From ed37cbc666452674e705027a76505e121cb8d02e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 20 Aug 2022 07:00:21 -0400 Subject: [PATCH 449/558] Roll Skia from 00ddb61588a2 to b6a7a4a011b8 (1 revision) (#35570) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0bd9f2cde4d92..8210b257bb3bf 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': '00ddb61588a21b41192d36accead310f1ea2d8e6', + 'skia_revision': 'b6a7a4a011b81b9743dbf3c50e671e55feca81e6', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 064a27f160753..55140ab6f1a82 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 55e58e86363ba9d31e7e7fe54b83b354 +Signature: 6b6c12ab719cf7c8a049ce64e3ae582b UNUSED LICENSES: From d89aae21e9febc87c23d4f47b34321514da341f1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 20 Aug 2022 07:36:21 -0400 Subject: [PATCH 450/558] Roll Fuchsia Mac SDK from kTnpJXzVrlaAf7ayc... to GoVI4_nQlpH4f6Mho... (#35572) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 8210b257bb3bf..0e46fe36a54a2 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'kTnpJXzVrlaAf7aycDF3ql8314jLLTrqhWheqF9PQiUC' + 'version': 'GoVI4_nQlpH4f6MhogqMtnySlEG3BP5Q4nPf2XWOOF8C' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 00a48acb208dc1daa4155932596f4096ca46af75 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Sat, 20 Aug 2022 14:08:16 -0700 Subject: [PATCH 451/558] Update target used to generate mac flutter framework. (#35573) --- ci/builders/mac_host_engine.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/builders/mac_host_engine.json b/ci/builders/mac_host_engine.json index dd0bc3e9d978a..9f9c368f48d3f 100644 --- a/ci/builders/mac_host_engine.json +++ b/ci/builders/mac_host_engine.json @@ -36,7 +36,7 @@ "ninja": { "config": "host_debug", "targets": [ - "flutter/build/archives:macos_flutter_framework", + "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework", "flutter/build/archives:artifacts", "flutter/build/archives:dart_sdk_archive", "flutter/build/archives:flutter_web_sdk", @@ -78,7 +78,7 @@ "ninja": { "config": "host_profile", "targets": [ - "flutter/build/archives:macos_flutter_framework", + "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework", "flutter/build/archives:archive_gen_snapshot", "flutter/build/archives:artifacts", "flutter:unittests" @@ -133,7 +133,7 @@ "ninja": { "config": "host_release", "targets": [ - "flutter/build/archives:macos_flutter_framework", + "flutter/shell/platform/darwin/macos:zip_macos_flutter_framework", "flutter/build/archives:archive_gen_snapshot", "flutter/build/archives:artifacts", "flutter/tools/font-subset" From 8d7167a230b84f3cda3ef2f3e852681009c794de Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 20 Aug 2022 17:52:22 -0400 Subject: [PATCH 452/558] Roll Fuchsia Linux SDK from JcqRURLnM_MMMLoss... to dBgYmcOhwCMB3hr7w... (#35574) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0e46fe36a54a2..d51d3e96f2b8d 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'JcqRURLnM_MMMLosspwpUXzH9GMkNtTtV8DUKPOwxR0C' + 'version': 'dBgYmcOhwCMB3hr7w38ItoQtCCFsxuKYJTxf6pdW8ZIC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 9b76c46627d02..17ea94fa9c6e5 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 1a5767ec0f8f78114f5d82a490dde91e +Signature: 03e5ab0e6c292f091ad20751a8051492 UNUSED LICENSES: From 94c8b3ef5f388a16da4f9044dda37357157e39ae Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sat, 20 Aug 2022 14:56:45 -0700 Subject: [PATCH 453/558] Add Matrix GetDirectionScale (#35562) --- impeller/geometry/geometry_unittests.cc | 47 +++++++++++++++++++++++++ impeller/geometry/matrix.h | 16 +++++++-- impeller/geometry/vector.h | 14 +++++++- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 84eec3be14703..76f34073fdf9a 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -302,6 +302,53 @@ TEST(GeometryTest, MatrixMakePerspective) { } } +TEST(GeometryTest, MatrixGetBasisVectors) { + { + auto m = Matrix(); + Vector3 x = m.GetBasisX(); + Vector3 y = m.GetBasisY(); + Vector3 z = m.GetBasisZ(); + ASSERT_VECTOR3_NEAR(x, Vector3(1, 0, 0)); + ASSERT_VECTOR3_NEAR(y, Vector3(0, 1, 0)); + ASSERT_VECTOR3_NEAR(z, Vector3(0, 0, 1)); + } + + { + auto m = Matrix::MakeRotationZ(Radians{kPiOver2}) * + Matrix::MakeRotationX(Radians{kPiOver2}) * + Matrix::MakeScale(Vector3(2, 3, 4)); + Vector3 x = m.GetBasisX(); + Vector3 y = m.GetBasisY(); + Vector3 z = m.GetBasisZ(); + ASSERT_VECTOR3_NEAR(x, Vector3(0, 2, 0)); + ASSERT_VECTOR3_NEAR(y, Vector3(0, 0, 3)); + ASSERT_VECTOR3_NEAR(z, Vector3(4, 0, 0)); + } +} + +TEST(GeometryTest, MatrixGetDirectionScale) { + { + auto m = Matrix(); + Scalar result = m.GetDirectionScale(Vector3{1, 0, 0}); + ASSERT_FLOAT_EQ(result, 1); + } + + { + auto m = Matrix::MakeRotationX(Degrees{10}) * + Matrix::MakeRotationY(Degrees{83}) * + Matrix::MakeRotationZ(Degrees{172}); + Scalar result = m.GetDirectionScale(Vector3{0, 1, 0}); + ASSERT_FLOAT_EQ(result, 1); + } + + { + auto m = Matrix::MakeRotationZ(Radians{kPiOver2}) * + Matrix::MakeScale(Vector3(3, 4, 5)); + Scalar result = m.GetDirectionScale(Vector3{2, 0, 0}); + ASSERT_FLOAT_EQ(result, 8); + } +} + TEST(GeometryTest, QuaternionLerp) { auto q1 = Quaternion{{0.0, 0.0, 1.0}, 0.0}; auto q2 = Quaternion{{0.0, 0.0, 1.0}, kPiOver4}; diff --git a/impeller/geometry/matrix.h b/impeller/geometry/matrix.h index a3c300dda1830..8bdb250b61b56 100644 --- a/impeller/geometry/matrix.h +++ b/impeller/geometry/matrix.h @@ -236,10 +236,20 @@ struct Matrix { Scalar GetMaxBasisLength() const; + constexpr Vector3 GetBasisX() const { return Vector3(m[0], m[1], m[2]); } + + constexpr Vector3 GetBasisY() const { return Vector3(m[4], m[5], m[6]); } + + constexpr Vector3 GetBasisZ() const { return Vector3(m[8], m[9], m[10]); } + constexpr Vector3 GetScale() const { - return Vector3(Vector3(m[0], m[1], m[2]).Length(), - Vector3(m[4], m[5], m[6]).Length(), - Vector3(m[8], m[9], m[10]).Length()); + return Vector3(GetBasisX().Length(), GetBasisY().Length(), + GetBasisZ().Length()); + } + + constexpr Scalar GetDirectionScale(Vector3 direction) const { + return 1.0 / (this->Invert() * direction.Normalize()).Length() * + direction.Length(); } constexpr bool IsAffine() const { diff --git a/impeller/geometry/vector.h b/impeller/geometry/vector.h index ad59f91d89edc..b1621f0147a1b 100644 --- a/impeller/geometry/vector.h +++ b/impeller/geometry/vector.h @@ -41,7 +41,7 @@ struct Vector3 { * * @return the calculated length. */ - Scalar Length() const { return sqrt(x * x + y * y + z * z); } + constexpr Scalar Length() const { return sqrt(x * x + y * y + z * z); } constexpr Vector3 Normalize() const { const auto len = Length(); @@ -130,6 +130,18 @@ struct Vector3 { std::string ToString() const; }; +// RHS algebraic operations with arithmetic types. + +template >> +constexpr Vector3 operator*(U s, const Vector3& p) { + return p * s; +} + +template >> +constexpr Vector3 operator/(U s, const Vector3& p) { + return {static_cast(s) / p.x, static_cast(s) / p.y}; +} + struct Vector4 { union { struct { From e87ddd9819f43714ca98e83b99e48f66681643f6 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sat, 20 Aug 2022 20:30:24 -0400 Subject: [PATCH 454/558] Roll Fuchsia Mac SDK from GoVI4_nQlpH4f6Mho... to UQaQdrX4762yWqfoO... (#35575) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index d51d3e96f2b8d..00432c12e92d1 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'GoVI4_nQlpH4f6MhogqMtnySlEG3BP5Q4nPf2XWOOF8C' + 'version': 'UQaQdrX4762yWqfoOaSqoChQtyGmjLqqhHbDVTZORSIC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 9d831cd8ed594bb109e47a40c551388bdf487fb8 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 21 Aug 2022 05:36:23 -0400 Subject: [PATCH 455/558] Roll Dart SDK from ddbdebabefca to 372a3305d597 (1 revision) (#35578) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 00432c12e92d1..f30ef30744896 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'ddbdebabefca45d094117481ff691a6353a8f441', + 'dart_revision': '372a3305d597356fec033feac78a7d4d9faea244', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 30411d1931c8b4a19382bf7a6c4dcb5d17e79af6 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 21 Aug 2022 06:50:20 -0400 Subject: [PATCH 456/558] Roll Skia from b6a7a4a011b8 to 9f08d3ebfdda (1 revision) (#35580) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f30ef30744896..c644f04efc63b 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': 'b6a7a4a011b81b9743dbf3c50e671e55feca81e6', + 'skia_revision': '9f08d3ebfddaabc05434f70b9e50d86a01ca4924', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 55140ab6f1a82..f9d6db8042bd8 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 6b6c12ab719cf7c8a049ce64e3ae582b +Signature: 381ecc3c9712a5c1381a57eb55fa7f87 UNUSED LICENSES: From 3b0c87fa9f28d1be49d96dd138c4f0b098e8c662 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 21 Aug 2022 07:04:28 -0400 Subject: [PATCH 457/558] Roll Fuchsia Linux SDK from dBgYmcOhwCMB3hr7w... to cNcNAFqNDK7PQ8vbI... (#35581) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c644f04efc63b..9ee3356f6b449 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'dBgYmcOhwCMB3hr7w38ItoQtCCFsxuKYJTxf6pdW8ZIC' + 'version': 'cNcNAFqNDK7PQ8vbIFMfm0JjXco_6GuDb6oULH20i4sC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 17ea94fa9c6e5..6e5fb0d72b837 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 03e5ab0e6c292f091ad20751a8051492 +Signature: 6cf2bc1567ec247281c0a0288d327aa6 UNUSED LICENSES: From d030ae1a5a67ebe4c55f0e50bf1d1b1f35c56019 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 21 Aug 2022 09:18:21 -0400 Subject: [PATCH 458/558] Roll Fuchsia Mac SDK from UQaQdrX4762yWqfoO... to pQagFNtqMQ1Yh9nvs... (#35582) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 9ee3356f6b449..fcccb1da3e96b 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'UQaQdrX4762yWqfoOaSqoChQtyGmjLqqhHbDVTZORSIC' + 'version': 'pQagFNtqMQ1Yh9nvsKrLypCB4XCQQEVNRbK1a-cco60C' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From bd89852694fe08b12467c74a17bc6b7c5cb30563 Mon Sep 17 00:00:00 2001 From: Casey Hillers Date: Sun, 21 Aug 2022 21:42:30 +0200 Subject: [PATCH 459/558] Revert "Make ShaderMaskLayer code builder aware" (#35588) --- flow/layers/shader_mask_layer.cc | 33 +++++++--------------- flow/layers/shader_mask_layer_unittests.cc | 13 ++++----- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/flow/layers/shader_mask_layer.cc b/flow/layers/shader_mask_layer.cc index 9a99a807ea2fe..b7dd47e48d99e 100644 --- a/flow/layers/shader_mask_layer.cc +++ b/flow/layers/shader_mask_layer.cc @@ -54,32 +54,19 @@ void ShaderMaskLayer::Paint(PaintContext& context) const { return; } } - auto shader_rect = SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()); - if (context.leaf_nodes_builder) { - context.builder_multiplexer->saveLayer(&paint_bounds(), - cache_paint.dl_paint()); - PaintChildren(context); + Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( + context, paint_bounds(), cache_paint.sk_paint()); + PaintChildren(context); - DlPaint dl_paint; - dl_paint.setBlendMode(blend_mode_); - if (shader_) { - dl_paint.setColorSource(shader_.get()); - } - context.leaf_nodes_builder->translate(mask_rect_.left(), mask_rect_.top()); - context.leaf_nodes_builder->drawRect(shader_rect, dl_paint); - } else { - Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create( - context, paint_bounds(), cache_paint.sk_paint()); - PaintChildren(context); - SkPaint paint; - paint.setBlendMode(ToSk(blend_mode_)); - if (shader_) { - paint.setShader(shader_->skia_object()); - } - context.leaf_nodes_canvas->translate(mask_rect_.left(), mask_rect_.top()); - context.leaf_nodes_canvas->drawRect(shader_rect, paint); + SkPaint paint; + paint.setBlendMode(ToSk(blend_mode_)); + if (shader_) { + paint.setShader(shader_->skia_object()); } + context.leaf_nodes_canvas->translate(mask_rect_.left(), mask_rect_.top()); + context.leaf_nodes_canvas->drawRect( + SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()), paint); } } // namespace flutter diff --git a/flow/layers/shader_mask_layer_unittests.cc b/flow/layers/shader_mask_layer_unittests.cc index c4f863ac01eaa..5f6c38b76a0f1 100644 --- a/flow/layers/shader_mask_layer_unittests.cc +++ b/flow/layers/shader_mask_layer_unittests.cc @@ -373,18 +373,17 @@ TEST_F(ShaderMaskLayerTest, OpacityInheritance) { { expected_builder.translate(offset.fX, offset.fY); /* ShaderMaskLayer::Paint() */ { - DlPaint sl_paint; - sl_paint.setColor(opacity_alpha << 24); - expected_builder.saveLayer(&child_path.getBounds(), &sl_paint); + expected_builder.setColor(opacity_alpha << 24); + expected_builder.saveLayer(&child_path.getBounds(), true); { /* child layer paint */ { - expected_builder.drawPath(child_path, - DlPaint().setColor(0xFF000000)); + expected_builder.setColor(0xFF000000); + expected_builder.drawPath(child_path); } expected_builder.translate(mask_rect.fLeft, mask_rect.fTop); + expected_builder.setBlendMode(DlBlendMode::kSrc); expected_builder.drawRect( - SkRect::MakeWH(mask_rect.width(), mask_rect.height()), - DlPaint().setBlendMode(DlBlendMode::kSrc)); + SkRect::MakeWH(mask_rect.width(), mask_rect.height())); } expected_builder.restore(); } From 4d2188ddf73edad5ee8f0aaad8fc9ab42cac51f9 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sun, 21 Aug 2022 15:38:49 -0700 Subject: [PATCH 460/558] Include array before flatbuffers in blobcat (#35579) --- impeller/blobcat/blob_library.cc | 1 + impeller/blobcat/blob_writer.cc | 1 + 2 files changed, 2 insertions(+) diff --git a/impeller/blobcat/blob_library.cc b/impeller/blobcat/blob_library.cc index 12c0730721127..8282f2cb475df 100644 --- a/impeller/blobcat/blob_library.cc +++ b/impeller/blobcat/blob_library.cc @@ -4,6 +4,7 @@ #include "impeller/blobcat/blob_library.h" +#include #include #include "impeller/base/validation.h" diff --git a/impeller/blobcat/blob_writer.cc b/impeller/blobcat/blob_writer.cc index abba520b261c1..cb242041cffbb 100644 --- a/impeller/blobcat/blob_writer.cc +++ b/impeller/blobcat/blob_writer.cc @@ -4,6 +4,7 @@ #include "impeller/blobcat/blob_writer.h" +#include #include #include From a77a0ce7a5e149b6f893dcdb43a73969482dc194 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sun, 21 Aug 2022 15:39:05 -0700 Subject: [PATCH 461/558] Support binding vector3 (#35583) --- impeller/renderer/backend/gles/buffer_bindings_gles.cc | 7 +++++++ impeller/renderer/backend/gles/proc_table_gles.h | 1 + 2 files changed, 8 insertions(+) diff --git a/impeller/renderer/backend/gles/buffer_bindings_gles.cc b/impeller/renderer/backend/gles/buffer_bindings_gles.cc index 32896f631f34c..5119b5cc09df6 100644 --- a/impeller/renderer/backend/gles/buffer_bindings_gles.cc +++ b/impeller/renderer/backend/gles/buffer_bindings_gles.cc @@ -234,6 +234,13 @@ bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl, buffer_ptr + member.offset) // data ); continue; + case sizeof(Vector3): + gl.Uniform3fv(location->second, // location + 1u, // count + reinterpret_cast( + buffer_ptr + member.offset) // data + ); + continue; case sizeof(Vector2): gl.Uniform2fv(location->second, // location 1u, // count diff --git a/impeller/renderer/backend/gles/proc_table_gles.h b/impeller/renderer/backend/gles/proc_table_gles.h index ee98d44e3cf09..fc113e3697af0 100644 --- a/impeller/renderer/backend/gles/proc_table_gles.h +++ b/impeller/renderer/backend/gles/proc_table_gles.h @@ -157,6 +157,7 @@ struct GLProc { PROC(Uniform1fv); \ PROC(Uniform1i); \ PROC(Uniform2fv); \ + PROC(Uniform3fv); \ PROC(Uniform4fv); \ PROC(UniformMatrix4fv); \ PROC(UseProgram); \ From ebee9c3fb865a83581f074ba66231983fb00c552 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 21 Aug 2022 20:14:35 -0400 Subject: [PATCH 462/558] Roll Fuchsia Linux SDK from cNcNAFqNDK7PQ8vbI... to jYCCNbFJSRKIW7iSb... (#35590) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index fcccb1da3e96b..ae38eb3195d18 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'cNcNAFqNDK7PQ8vbIFMfm0JjXco_6GuDb6oULH20i4sC' + 'version': 'jYCCNbFJSRKIW7iSb3sDaFLgR7ZtPsdIDR8uP-Q1nfMC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 6e5fb0d72b837..3299a9ed0c8de 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 6cf2bc1567ec247281c0a0288d327aa6 +Signature: 62cd53680df67f0fff0105c2631be37c UNUSED LICENSES: From d311584c791d0f00086a431fe9a491dc0eff3a8c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Sun, 21 Aug 2022 22:14:24 -0400 Subject: [PATCH 463/558] Roll Fuchsia Mac SDK from pQagFNtqMQ1Yh9nvs... to 2okocUbyhYrU7It7M... (#35591) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index ae38eb3195d18..29cc33e0ed403 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'pQagFNtqMQ1Yh9nvsKrLypCB4XCQQEVNRbK1a-cco60C' + 'version': '2okocUbyhYrU7It7MDLQMF6G7No6Jkx6HvcoxICtD_sC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 7295b1ee87652e787af426964bc75f1f799bfc17 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 01:54:25 -0400 Subject: [PATCH 464/558] Roll Skia from 9f08d3ebfdda to 16bd61533ccf (1 revision) (#35593) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 29cc33e0ed403..95de305f5933b 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': '9f08d3ebfddaabc05434f70b9e50d86a01ca4924', + 'skia_revision': '16bd61533ccfa10bd949491c78f7d0cac13da5fa', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f9d6db8042bd8..10fe108ba29ed 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 381ecc3c9712a5c1381a57eb55fa7f87 +Signature: 972d64a15818977715273f1d8c75ea5d UNUSED LICENSES: From 482f967fa6b2512a791433565fdca21afdc003fe Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 03:04:22 -0400 Subject: [PATCH 465/558] Roll Skia from 16bd61533ccf to 27ccebd5bef4 (1 revision) (#35594) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 95de305f5933b..028800752ea0a 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': '16bd61533ccfa10bd949491c78f7d0cac13da5fa', + 'skia_revision': '27ccebd5bef495f51a61160ade5366ed59755e35', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 10fe108ba29ed..3d563c49cc735 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 972d64a15818977715273f1d8c75ea5d +Signature: 37219febc8ac40b6c8333e678c38b37d UNUSED LICENSES: From b9d670aaddcf8a825c5a45b067909af2363a66df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Aug 2022 09:20:05 +0000 Subject: [PATCH 466/558] Bump github/codeql-action from 2.1.18 to 2.1.19 (#35595) --- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index cd49ffe55f5c2..01fcff07b68cd 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -57,6 +57,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@2ca79b6fa8d3ec278944088b4aa5f46912db5d63 + uses: github/codeql-action/upload-sarif@f5d217be74900c6ac8fbbe53f3c10376ba4e64da with: sarif_file: results.sarif From 5f732d4e4e7a345ae793f560e318cfe846419725 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 06:18:22 -0400 Subject: [PATCH 467/558] Roll Dart SDK from 372a3305d597 to cfae94ab2b2d (1 revision) (#35596) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 028800752ea0a..4e6ccfae76a08 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '372a3305d597356fec033feac78a7d4d9faea244', + 'dart_revision': 'cfae94ab2b2d71a4d144622269c85beff4faa580', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 43123ba9c8524..c366613a365af 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: eae701caa9f0488bb7cfc6cd080e32f0 +Signature: d47b3da7922c2e807ea6d8e9e4fdd2d5 UNUSED LICENSES: From 00bb6056cb802e39b8696d93b66d8d280971b459 Mon Sep 17 00:00:00 2001 From: Casey Hillers Date: Mon, 22 Aug 2022 12:26:09 +0200 Subject: [PATCH 468/558] Revert "Include TextureViews in the output of Scene.toImage[Sync]" (#35587) --- flow/layers/layer_tree.cc | 14 +++---- flow/layers/layer_tree.h | 6 +-- lib/ui/compositing.dart | 1 - lib/ui/compositing/scene.cc | 39 ++++++------------ lib/ui/compositing/scene.h | 25 ++++------- .../display_list_deferred_image_gpu.cc | 41 +------------------ .../display_list_deferred_image_gpu.h | 21 +--------- lib/ui/painting/picture.cc | 35 +++------------- lib/ui/painting/picture.h | 12 ------ lib/ui/snapshot_delegate.h | 3 -- runtime/runtime_delegate.h | 2 +- shell/common/animator.cc | 2 +- shell/common/animator.h | 2 +- shell/common/animator_unittests.cc | 4 +- shell/common/engine.cc | 2 +- shell/common/engine.h | 2 +- shell/common/engine_unittests.cc | 2 +- shell/common/pipeline.h | 4 +- shell/common/rasterizer.cc | 8 +--- shell/common/rasterizer.h | 9 ++-- shell/common/rasterizer_unittests.cc | 26 ++++++------ shell/common/shell_test.cc | 2 +- testing/dart/compositing_test.dart | 22 ---------- 23 files changed, 64 insertions(+), 220 deletions(-) diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 3b4907b5336bf..de7573ef4ac39 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -171,10 +171,7 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, } } -sk_sp LayerTree::Flatten( - const SkRect& bounds, - std::shared_ptr texture_registry, - GrDirectContext* gr_context) { +sk_sp LayerTree::Flatten(const SkRect& bounds) { TRACE_EVENT0("flutter", "LayerTree::Flatten"); DisplayListCanvasRecorder builder(bounds); @@ -182,14 +179,13 @@ sk_sp LayerTree::Flatten( MutatorsStack unused_stack; const FixedRefreshRateStopwatch unused_stopwatch; SkMatrix root_surface_transformation; - // No root surface transformation. So assume identity. root_surface_transformation.reset(); PrerollContext preroll_context{ // clang-format off .raster_cache = nullptr, - .gr_context = gr_context, + .gr_context = nullptr, .view_embedder = nullptr, .mutators_stack = unused_stack, .dst_color_space = nullptr, @@ -197,7 +193,7 @@ sk_sp LayerTree::Flatten( .surface_needs_readback = false, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = texture_registry, + .texture_registry = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_ // clang-format on @@ -213,12 +209,12 @@ sk_sp LayerTree::Flatten( // clang-format off .internal_nodes_canvas = &internal_nodes_canvas, .leaf_nodes_canvas = &builder, - .gr_context = gr_context, + .gr_context = nullptr, .dst_color_space = nullptr, .view_embedder = nullptr, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = texture_registry, + .texture_registry = nullptr, .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_, diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index 167500400b758..c7daa5f809e9f 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -8,7 +8,6 @@ #include #include -#include "flutter/common/graphics/texture.h" #include "flutter/flow/compositor_context.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" @@ -42,10 +41,7 @@ class LayerTree { void Paint(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache = false) const; - sk_sp Flatten( - const SkRect& bounds, - std::shared_ptr texture_registry = nullptr, - GrDirectContext* gr_context = nullptr); + sk_sp Flatten(const SkRect& bounds); Layer* root_layer() const { return root_layer_.get(); } diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index 384d1b500ccb3..528fc027c043a 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -38,7 +38,6 @@ class Scene extends NativeFieldWrapperClass1 { external String? _toImageSync(int width, int height, _Image outImage); /// Creates a raster image representation of the current state of the scene. - /// /// This is a slow operation that is performed on a background thread. /// /// Callers must dispose the [Image] when they are done with it. If the result diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 5a8601b90effe..734a67ef2481c 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -5,7 +5,6 @@ #include "flutter/lib/ui/compositing/scene.h" #include "flutter/fml/trace_event.h" -#include "flutter/lib/ui/painting/display_list_deferred_image_gpu.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/picture.h" #include "flutter/lib/ui/ui_dart_state.h" @@ -43,7 +42,7 @@ Scene::Scene(std::shared_ptr rootLayer, ->get_window(0) ->viewport_metrics(); - layer_tree_ = std::make_shared( + layer_tree_ = std::make_unique( SkISize::Make(viewport_metrics.physical_width, viewport_metrics.physical_height), static_cast(viewport_metrics.device_pixel_ratio)); @@ -70,7 +69,12 @@ Dart_Handle Scene::toImageSync(uint32_t width, return tonic::ToDart("Scene did not contain a layer tree."); } - Scene::RasterizeToImage(width, height, raw_image_handle); + auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height)); + if (!picture) { + return tonic::ToDart("Could not flatten scene into a layer tree."); + } + + Picture::RasterizeToImageSync(picture, width, height, raw_image_handle); return Dart_Null(); } @@ -83,32 +87,15 @@ Dart_Handle Scene::toImage(uint32_t width, return tonic::ToDart("Scene did not contain a layer tree."); } - return Picture::RasterizeLayerTreeToImage(std::move(layer_tree_), width, - height, raw_image_callback); -} - -void Scene::RasterizeToImage(uint32_t width, - uint32_t height, - Dart_Handle raw_image_handle) { - auto* dart_state = UIDartState::Current(); - if (!dart_state) { - return; + auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height)); + if (!picture) { + return tonic::ToDart("Could not flatten scene into a layer tree."); } - auto unref_queue = dart_state->GetSkiaUnrefQueue(); - auto snapshot_delegate = dart_state->GetSnapshotDelegate(); - auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); - - auto image = CanvasImage::Create(); - const SkImageInfo image_info = SkImageInfo::Make( - width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType); - auto dl_image = DlDeferredImageGPU::MakeFromLayerTree( - image_info, std::move(layer_tree_), std::move(snapshot_delegate), - std::move(raster_task_runner), std::move(unref_queue)); - image->set_image(dl_image); - image->AssociateWithDartWrapper(raw_image_handle); + + return Picture::RasterizeToImage(picture, width, height, raw_image_callback); } -std::shared_ptr Scene::takeLayerTree() { +std::unique_ptr Scene::takeLayerTree() { return std::move(layer_tree_); } diff --git a/lib/ui/compositing/scene.h b/lib/ui/compositing/scene.h index aca797836fcb1..1cf95aad4ec43 100644 --- a/lib/ui/compositing/scene.h +++ b/lib/ui/compositing/scene.h @@ -26,7 +26,7 @@ class Scene : public RefCountedDartWrappable { bool checkerboardRasterCacheImages, bool checkerboardOffscreenLayers); - std::shared_ptr takeLayerTree(); + std::unique_ptr takeLayerTree(); Dart_Handle toImageSync(uint32_t width, uint32_t height, @@ -34,26 +34,17 @@ class Scene : public RefCountedDartWrappable { Dart_Handle toImage(uint32_t width, uint32_t height, - Dart_Handle raw_image_handle); + Dart_Handle image_callback); void dispose(); private: - Scene(std::shared_ptr rootLayer, - uint32_t rasterizerTracingThreshold, - bool checkerboardRasterCacheImages, - bool checkerboardOffscreenLayers); - - void RasterizeToImage(uint32_t width, - uint32_t height, - Dart_Handle raw_image_handle); - - // This is a shared_ptr to support flattening the layer tree from the UI - // thread onto the raster thread - allowing access to the texture registry - // required to render TextureLayers. - // - // No longer valid after calling `takeLayerTree`. - std::shared_ptr layer_tree_; + explicit Scene(std::shared_ptr rootLayer, + uint32_t rasterizerTracingThreshold, + bool checkerboardRasterCacheImages, + bool checkerboardOffscreenLayers); + + std::unique_ptr layer_tree_; }; } // namespace flutter diff --git a/lib/ui/painting/display_list_deferred_image_gpu.cc b/lib/ui/painting/display_list_deferred_image_gpu.cc index 4ea7ad7ab1666..beeb0ccf80404 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.cc +++ b/lib/ui/painting/display_list_deferred_image_gpu.cc @@ -22,19 +22,6 @@ sk_sp DlDeferredImageGPU::Make( raster_task_runner)); } -sk_sp DlDeferredImageGPU::MakeFromLayerTree( - const SkImageInfo& image_info, - std::shared_ptr layer_tree, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue) { - return sk_sp(new DlDeferredImageGPU( - ImageWrapper::MakeFromLayerTree( - image_info, std::move(layer_tree), std::move(snapshot_delegate), - raster_task_runner, std::move(unref_queue)), - raster_task_runner)); -} - DlDeferredImageGPU::DlDeferredImageGPU( std::shared_ptr image_wrapper, fml::RefPtr raster_task_runner) @@ -105,20 +92,6 @@ DlDeferredImageGPU::ImageWrapper::Make( return wrapper; } -std::shared_ptr -DlDeferredImageGPU::ImageWrapper::MakeFromLayerTree( - const SkImageInfo& image_info, - std::shared_ptr layer_tree, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue) { - auto wrapper = std::shared_ptr( - new ImageWrapper(image_info, nullptr, std::move(snapshot_delegate), - std::move(raster_task_runner), std::move(unref_queue))); - wrapper->SnapshotDisplayList(std::move(layer_tree)); - return wrapper; -} - DlDeferredImageGPU::ImageWrapper::ImageWrapper( const SkImageInfo& image_info, sk_sp display_list, @@ -158,11 +131,9 @@ bool DlDeferredImageGPU::ImageWrapper::isTextureBacked() const { return texture_.isValid(); } -void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList( - std::shared_ptr layer_tree) { +void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { fml::TaskRunner::RunNowOrPostTask( - raster_task_runner_, - [weak_this = weak_from_this(), layer_tree = std::move(layer_tree)]() { + raster_task_runner_, [weak_this = weak_from_this()]() { auto wrapper = weak_this.lock(); if (!wrapper) { return; @@ -171,14 +142,6 @@ void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList( if (!snapshot_delegate) { return; } - if (layer_tree) { - auto display_list = - layer_tree->Flatten(SkRect::MakeWH(wrapper->image_info_.width(), - wrapper->image_info_.height()), - snapshot_delegate.get()->GetTextureRegistry(), - snapshot_delegate.get()->GetGrContext()); - wrapper->display_list_ = std::move(display_list); - } auto result = snapshot_delegate->MakeGpuImage(wrapper->display_list_, wrapper->image_info_); if (result->texture.isValid()) { diff --git a/lib/ui/painting/display_list_deferred_image_gpu.h b/lib/ui/painting/display_list_deferred_image_gpu.h index 5f04eb25d0765..429dcd873a101 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.h +++ b/lib/ui/painting/display_list_deferred_image_gpu.h @@ -11,7 +11,6 @@ #include "flutter/common/graphics/texture.h" #include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_image.h" -#include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/fml/macros.h" #include "flutter/fml/memory/weak_ptr.h" @@ -29,13 +28,6 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); - static sk_sp MakeFromLayerTree( - const SkImageInfo& image_info, - std::shared_ptr layer_tree, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue); - // |DlImage| ~DlDeferredImageGPU() override; @@ -81,13 +73,6 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); - static std::shared_ptr MakeFromLayerTree( - const SkImageInfo& image_info, - std::shared_ptr layer_tree, - fml::WeakPtr snapshot_delegate, - fml::RefPtr raster_task_runner, - fml::RefPtr unref_queue); - const SkImageInfo image_info() const { return image_info_; } const GrBackendTexture& texture() const { return texture_; } bool isTextureBacked() const; @@ -118,11 +103,7 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); - // If a layer tree is provided, it will be flattened during the raster - // thread task spwaned by this method. After being flattened into a display - // list, the image wrapper will be updated to hold this display list and the - // layer tree can be dropped. - void SnapshotDisplayList(std::shared_ptr layer_tree = nullptr); + void SnapshotDisplayList(); // |ContextListener| void OnGrContextCreated() override; diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 849b5cc634c35..4d5411d1830f6 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -95,21 +95,11 @@ Dart_Handle Picture::RasterizeToImage(sk_sp display_list, Dart_Handle raw_image_callback) { return RasterizeToImage( [display_list](SkCanvas* canvas) { display_list->RenderTo(canvas); }, - nullptr, width, height, raw_image_callback); -} - -Dart_Handle Picture::RasterizeLayerTreeToImage( - std::shared_ptr layer_tree, - uint32_t width, - uint32_t height, - Dart_Handle raw_image_callback) { - return RasterizeToImage(nullptr, std::move(layer_tree), width, height, - raw_image_callback); + width, height, raw_image_callback); } Dart_Handle Picture::RasterizeToImage( std::function draw_callback, - std::shared_ptr layer_tree, uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { @@ -168,25 +158,10 @@ Dart_Handle Picture::RasterizeToImage( // Kick things off on the raster rask runner. fml::TaskRunner::RunNowOrPostTask( - raster_task_runner, - [ui_task_runner, snapshot_delegate, draw_callback, picture_bounds, - ui_task, layer_tree = std::move(layer_tree)] { - sk_sp raster_image; - if (layer_tree) { - auto display_list = layer_tree->Flatten( - SkRect::MakeWH(picture_bounds.width(), picture_bounds.height()), - snapshot_delegate.get()->GetTextureRegistry(), - snapshot_delegate.get()->GetGrContext()); - - raster_image = snapshot_delegate->MakeRasterSnapshot( - [display_list](SkCanvas* canvas) { - display_list->RenderTo(canvas); - }, - picture_bounds); - } else { - raster_image = snapshot_delegate->MakeRasterSnapshot(draw_callback, - picture_bounds); - } + raster_task_runner, [ui_task_runner, snapshot_delegate, draw_callback, + picture_bounds, ui_task] { + sk_sp raster_image = snapshot_delegate->MakeRasterSnapshot( + draw_callback, picture_bounds); fml::TaskRunner::RunNowOrPostTask( ui_task_runner, diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index 77fda55884c3d..1cb390a182138 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -6,7 +6,6 @@ #define FLUTTER_LIB_UI_PAINTING_PICTURE_H_ #include "flutter/display_list/display_list.h" -#include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/image.h" @@ -52,19 +51,8 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); - static Dart_Handle RasterizeLayerTreeToImage( - std::shared_ptr layer_tree, - uint32_t width, - uint32_t height, - Dart_Handle raw_image_callback); - - // Callers may provide either a draw_callback (which should reference a - // display list) or a layer tree. If a layer tree is provided, it will be - // flattened on the raster thread. In this case the draw callback will be - // ignored. static Dart_Handle RasterizeToImage( std::function draw_callback, - std::shared_ptr layer_tree, uint32_t width, uint32_t height, Dart_Handle raw_image_callback); diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 3b59ffed9fb23..4158d28701cbb 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -13,7 +13,6 @@ #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkPromiseImageTexture.h" #include "third_party/skia/include/gpu/GrContextThreadSafeProxy.h" -#include "third_party/skia/include/gpu/GrDirectContext.h" namespace flutter { @@ -53,8 +52,6 @@ class SnapshotDelegate { /// virtual std::shared_ptr GetTextureRegistry() = 0; - virtual GrDirectContext* GetGrContext() = 0; - virtual std::unique_ptr MakeGpuImage( sk_sp display_list, const SkImageInfo& image_info) = 0; diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index ad680677338e0..540e47dd09ba4 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -24,7 +24,7 @@ class RuntimeDelegate { virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0; - virtual void Render(std::shared_ptr layer_tree) = 0; + virtual void Render(std::unique_ptr layer_tree) = 0; virtual void UpdateSemantics(SemanticsNodeUpdates update, CustomAccessibilityActionUpdates actions) = 0; diff --git a/shell/common/animator.cc b/shell/common/animator.cc index d8614dc22f69c..31bd0cdfb5eb5 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -144,7 +144,7 @@ void Animator::BeginFrame( } } -void Animator::Render(std::shared_ptr layer_tree) { +void Animator::Render(std::unique_ptr layer_tree) { has_rendered_ = true; last_layer_tree_size_ = layer_tree->frame_size(); diff --git a/shell/common/animator.h b/shell/common/animator.h index 6550452ba481e..d822935307ac8 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -54,7 +54,7 @@ class Animator final { void RequestFrame(bool regenerate_layer_tree = true); - void Render(std::shared_ptr layer_tree); + void Render(std::unique_ptr layer_tree); const std::weak_ptr GetVsyncWaiter() const; diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc index 91c2bad1b033f..628d7eb9afbc0 100644 --- a/shell/common/animator_unittests.cc +++ b/shell/common/animator_unittests.cc @@ -157,7 +157,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyIdleBeforeRender) { [&] { ASSERT_FALSE(delegate.notify_idle_called_); auto layer_tree = - std::make_shared(SkISize::Make(600, 800), 1.0); + std::make_unique(SkISize::Make(600, 800), 1.0); animator->Render(std::move(layer_tree)); task_runners.GetPlatformTaskRunner()->PostTask(flush_vsync_task); }, @@ -240,7 +240,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyDelegateIfPipelineIsNotEmpty) { PostTaskSync(task_runners.GetUITaskRunner(), [&] { auto layer_tree = - std::make_shared(SkISize::Make(600, 800), 1.0); + std::make_unique(SkISize::Make(600, 800), 1.0); animator->Render(std::move(layer_tree)); }); } diff --git a/shell/common/engine.cc b/shell/common/engine.cc index c2cbc9f512b98..9a0e5d03e4883 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -439,7 +439,7 @@ void Engine::ScheduleFrame(bool regenerate_layer_tree) { animator_->RequestFrame(regenerate_layer_tree); } -void Engine::Render(std::shared_ptr layer_tree) { +void Engine::Render(std::unique_ptr layer_tree) { if (!layer_tree) { return; } diff --git a/shell/common/engine.h b/shell/common/engine.h index 04b968f106c41..491ec4f0e5fe3 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -879,7 +879,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { std::string DefaultRouteName() override; // |RuntimeDelegate| - void Render(std::shared_ptr layer_tree) override; + void Render(std::unique_ptr layer_tree) override; // |RuntimeDelegate| void UpdateSemantics(SemanticsNodeUpdates update, diff --git a/shell/common/engine_unittests.cc b/shell/common/engine_unittests.cc index 6dfc93c555c36..62674947f9e87 100644 --- a/shell/common/engine_unittests.cc +++ b/shell/common/engine_unittests.cc @@ -48,7 +48,7 @@ class MockRuntimeDelegate : public RuntimeDelegate { public: MOCK_METHOD0(DefaultRouteName, std::string()); MOCK_METHOD1(ScheduleFrame, void(bool)); - MOCK_METHOD1(Render, void(std::shared_ptr)); + MOCK_METHOD1(Render, void(std::unique_ptr)); MOCK_METHOD2(UpdateSemantics, void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates)); MOCK_METHOD1(HandlePlatformMessage, void(std::unique_ptr)); diff --git a/shell/common/pipeline.h b/shell/common/pipeline.h index f9546d0816125..35f90f39f2c6a 100644 --- a/shell/common/pipeline.h +++ b/shell/common/pipeline.h @@ -222,11 +222,11 @@ class Pipeline { }; struct LayerTreeItem { - LayerTreeItem(std::shared_ptr layer_tree, + LayerTreeItem(std::unique_ptr layer_tree, std::unique_ptr frame_timings_recorder) : layer_tree(std::move(layer_tree)), frame_timings_recorder(std::move(frame_timings_recorder)) {} - std::shared_ptr layer_tree; + std::unique_ptr layer_tree; std::unique_ptr frame_timings_recorder; }; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 6e0b22d1ff1df..d3ecb11fee8ec 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -145,10 +145,6 @@ std::shared_ptr Rasterizer::GetTextureRegistry() { return compositor_context_->texture_registry(); } -GrDirectContext* Rasterizer::GetGrContext() { - return surface_->GetContext(); -} - flutter::LayerTree* Rasterizer::GetLastLayerTree() { return last_layer_tree_.get(); } @@ -185,7 +181,7 @@ RasterStatus Rasterizer::Draw(std::shared_ptr pipeline, RasterStatus raster_status = RasterStatus::kFailed; LayerTreePipeline::Consumer consumer = [&](std::unique_ptr item) { - std::shared_ptr layer_tree = std::move(item->layer_tree); + std::unique_ptr layer_tree = std::move(item->layer_tree); std::unique_ptr frame_timings_recorder = std::move(item->frame_timings_recorder); if (discard_callback(*layer_tree.get())) { @@ -492,7 +488,7 @@ fml::Milliseconds Rasterizer::GetFrameBudget() const { RasterStatus Rasterizer::DoDraw( std::unique_ptr frame_timings_recorder, - std::shared_ptr layer_tree) { + std::unique_ptr layer_tree) { TRACE_EVENT_WITH_FRAME_NUMBER(frame_timings_recorder, "flutter", "Rasterizer::DoDraw"); FML_DCHECK(delegate_.GetTaskRunners() diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 7052b664e1791..2f90ed5b1fe66 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -26,7 +26,6 @@ #include "flutter/shell/common/pipeline.h" #include "flutter/shell/common/snapshot_surface_producer.h" #include "third_party/skia/include/core/SkImage.h" -#include "third_party/skia/include/gpu/GrDirectContext.h" namespace flutter { @@ -214,8 +213,6 @@ class Rasterizer final : public SnapshotDelegate, std::unique_ptr frame_timings_recorder); // |SnapshotDelegate| - GrDirectContext* GetGrContext() override; - std::shared_ptr GetTextureRegistry() override; using LayerTreeDiscardCallback = std::function; @@ -499,7 +496,7 @@ class Rasterizer final : public SnapshotDelegate, RasterStatus DoDraw( std::unique_ptr frame_timings_recorder, - std::shared_ptr layer_tree); + std::unique_ptr layer_tree); RasterStatus DrawToSurface(FrameTimingsRecorder& frame_timings_recorder, flutter::LayerTree& layer_tree); @@ -518,11 +515,11 @@ class Rasterizer final : public SnapshotDelegate, std::unique_ptr snapshot_surface_producer_; std::unique_ptr compositor_context_; // This is the last successfully rasterized layer tree. - std::shared_ptr last_layer_tree_; + std::unique_ptr last_layer_tree_; // Set when we need attempt to rasterize the layer tree again. This layer_tree // has not successfully rasterized. This can happen due to the change in the // thread configuration. This will be inserted to the front of the pipeline. - std::shared_ptr resubmitted_layer_tree_; + std::unique_ptr resubmitted_layer_tree_; std::unique_ptr resubmitted_recorder_; fml::closure next_frame_callback_; bool user_override_resource_cache_bytes_; diff --git a/shell/common/rasterizer_unittests.cc b/shell/common/rasterizer_unittests.cc index af14fcc1675cf..45232840bf2b1 100644 --- a/shell/common/rasterizer_unittests.cc +++ b/shell/common/rasterizer_unittests.cc @@ -176,7 +176,7 @@ TEST(RasterizerTest, fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -238,7 +238,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -306,7 +306,7 @@ TEST( rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -376,7 +376,7 @@ TEST(RasterizerTest, rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -423,7 +423,7 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) { fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -476,7 +476,7 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) { fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -573,7 +573,7 @@ TEST(RasterizerTest, fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -627,7 +627,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -681,7 +681,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -734,7 +734,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -811,7 +811,7 @@ TEST(RasterizerTest, auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = - std::make_shared(/*frame_size=*/SkISize(), + std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i])); @@ -972,7 +972,7 @@ TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) { auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = - std::make_shared(/*frame_size=*/SkISize(), + std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i])); @@ -1045,7 +1045,7 @@ TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) { thread_host.raster_thread->GetTaskRunner()->PostTask([&] { rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(first_timestamp)); diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index eca345058787f..27f6b0f65f527 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -197,7 +197,7 @@ void ShellTest::PumpOneFrame(Shell* shell, fml::WeakPtr runtime_delegate = shell->weak_engine_; shell->GetTaskRunners().GetUITaskRunner()->PostTask( [&latch, runtime_delegate, &builder, viewport_metrics]() { - auto layer_tree = std::make_shared( + auto layer_tree = std::make_unique( SkISize::Make(viewport_metrics.physical_width, viewport_metrics.physical_height), static_cast(viewport_metrics.device_pixel_ratio)); diff --git a/testing/dart/compositing_test.dart b/testing/dart/compositing_test.dart index 01320919a52dd..10c70978d22b5 100644 --- a/testing/dart/compositing_test.dart +++ b/testing/dart/compositing_test.dart @@ -36,28 +36,6 @@ void main() { expect(data.buffer.asUint8List()[3], 0xFF); }); - test('Scene.toImageSync succeeds with texture layer', () async { - final SceneBuilder builder = SceneBuilder(); - builder.pushOffset(10, 10); - builder.addTexture(0, width: 10, height: 10); - - final Scene scene = builder.build(); - final Image image = scene.toImageSync(10, 10); - scene.dispose(); - - expect(image.width, 10); - expect(image.height, 10); - - final ByteData? data = await image.toByteData(); - - expect(data, isNotNull); - expect(data!.lengthInBytes, 10 * 10 * 4); - expect(data.buffer.asUint8List()[0], 0); - expect(data.buffer.asUint8List()[1], 0); - expect(data.buffer.asUint8List()[2], 0); - expect(data.buffer.asUint8List()[3], 0); - }); - test('addPicture with disposed picture does not crash', () { bool assertsEnabled = false; assert(() { From e70ba6a3a32d9f8602fedba008b77067ebc29729 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 09:22:31 -0400 Subject: [PATCH 469/558] Roll Fuchsia Linux SDK from jYCCNbFJSRKIW7iSb... to i7HhHxamwTC16efZ2... (#35598) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 4e6ccfae76a08..bfe430cb8e3d0 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'jYCCNbFJSRKIW7iSb3sDaFLgR7ZtPsdIDR8uP-Q1nfMC' + 'version': 'i7HhHxamwTC16efZ2HEccS4fabVfP0wTOc2-U1coVQwC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 3299a9ed0c8de..3bbc4a732edca 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: 62cd53680df67f0fff0105c2631be37c +Signature: d4354d9ee2ed56bfd15e7ea752056758 UNUSED LICENSES: From 0d182ddb0d1d73e2a389ba3545db465525d8f781 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 10:15:21 -0400 Subject: [PATCH 470/558] Roll Dart SDK from cfae94ab2b2d to 7cbd8dc183c0 (1 revision) (#35599) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index bfe430cb8e3d0..862c06128a82c 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'cfae94ab2b2d71a4d144622269c85beff4faa580', + 'dart_revision': '7cbd8dc183c04b61127eff684e5e4dfea2456623', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 60707621bf9b87fd54b3e27aaa9aeb88a4760ccf Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 10:39:32 -0400 Subject: [PATCH 471/558] Roll Skia from 27ccebd5bef4 to 95321396c690 (1 revision) (#35600) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 862c06128a82c..aa9f8b1974929 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': '27ccebd5bef495f51a61160ade5366ed59755e35', + 'skia_revision': '95321396c690624fc4c39a68e3348a1360597570', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 3d563c49cc735..3654fbb05b4c2 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 37219febc8ac40b6c8333e678c38b37d +Signature: 8983c9167477056ea1e432a0165c49bf UNUSED LICENSES: From 8ae76c349f945ec808477f6c2afd842c9a7cde03 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Mon, 22 Aug 2022 08:16:46 -0700 Subject: [PATCH 472/558] Write link content rather than source path (#35577) --- build/zip.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/zip.py b/build/zip.py index dbcd18a433384..a6ce362d77f90 100755 --- a/build/zip.py +++ b/build/zip.py @@ -6,10 +6,10 @@ import argparse import json -import zipfile import os import stat import sys +import zipfile def _zip_dir(path, zip_file, prefix): @@ -19,7 +19,7 @@ def _zip_dir(path, zip_file, prefix): if os.path.islink(os.path.join(root, directory)): add_symlink( zip_file, - os.path.join(root, '%s/' % directory), + os.path.join(root, directory), os.path.join(root.replace(path, prefix), directory), ) for file in files: @@ -50,7 +50,7 @@ def add_symlink(zip_file, source, target): | stat.S_IWGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH ) zip_info.external_attr = unix_st_mode << 16 - zip_file.writestr(zip_info, source) + zip_file.writestr(zip_info, os.readlink(source)) def main(args): From ca7acb34c5bc4304e972d8ffcf4542f66b5467ff Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 11:49:16 -0400 Subject: [PATCH 473/558] Roll Skia from 95321396c690 to 90198e0c0a4e (2 revisions) (#35604) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 41 ++++++++++++++++++++++++++++++-- sky/packages/sky_engine/LICENSE | 32 +++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index aa9f8b1974929..4689ed24ba8b1 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': '95321396c690624fc4c39a68e3348a1360597570', + 'skia_revision': '90198e0c0a4e57479e6ef50cce8f4005b95d804e', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 3654fbb05b4c2..503204ab750ef 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 8983c9167477056ea1e432a0165c49bf +Signature: 4488819230e684648be4af3027178c68 UNUSED LICENSES: @@ -6474,6 +6474,43 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== +==================================================================================================== +LIBRARY: skia +ORIGIN: ../../../third_party/skia/fuzz/oss_fuzz/FuzzCOLRv1.cpp + ../../../third_party/skia/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../third_party/skia/fuzz/oss_fuzz/FuzzCOLRv1.cpp +---------------------------------------------------------------------------------------------------- +Copyright 2022 Google, LLC + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +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. +==================================================================================================== + ==================================================================================================== LIBRARY: skia ORIGIN: ../../../third_party/skia/fuzz/oss_fuzz/FuzzDDLThreading.cpp + ../../../third_party/skia/LICENSE @@ -7994,4 +8031,4 @@ Materials are furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Materials. ==================================================================================================== -Total license count: 68 +Total license count: 69 diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index 0d79c7f510f5c..0056073125a97 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -15469,6 +15469,38 @@ skia Copyright 2022 Google LLC. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +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. +-------------------------------------------------------------------------------- +skia + +Copyright 2022 Google, LLC + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 38d2213d99ac6ef187824eecd9aaf592df97e69b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 12:19:11 -0400 Subject: [PATCH 474/558] Roll Fuchsia Mac SDK from 2okocUbyhYrU7It7M... to kZJxkRRI82W2CW_nM... (#35605) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 4689ed24ba8b1..b66d71d99a87f 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': '2okocUbyhYrU7It7MDLQMF6G7No6Jkx6HvcoxICtD_sC' + 'version': 'kZJxkRRI82W2CW_nMUOVsrVaVrQIM1yi-d06o_5_ACQC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From af499f35f0420b1e0b3b0ca105b40261fb3be2b4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 12:53:05 -0400 Subject: [PATCH 475/558] Roll Skia from 90198e0c0a4e to b4de358a0159 (2 revisions) (#35606) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index b66d71d99a87f..08cd7b1f231d4 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': '90198e0c0a4e57479e6ef50cce8f4005b95d804e', + 'skia_revision': 'b4de358a01593cc7bfb5d3206d6cb76f6f8ec269', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 9513c34aabcdac36c35872d105f0cbf010b96a06 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Mon, 22 Aug 2022 19:23:38 +0200 Subject: [PATCH 476/558] Ensure raster cache doesn't bleed over to adjacent physical pixels (#35602) * Ensure raster cache doesn't bleed over to adjacent physical pixels * Only clip if necessary * Add tests * Reformat * Only save/restore when necessary --- flow/raster_cache.cc | 15 ++++++++ flow/raster_cache_unittests.cc | 62 ++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index 8a4e46d58d695..9b6e72d43c2c8 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -47,8 +47,23 @@ void RasterCacheResult::draw(SkCanvas& canvas, const SkPaint* paint) const { #endif canvas.resetMatrix(); flow_.Step(); + + bool exceeds_bounds = bounds.fLeft + image_->dimensions().width() > + SkScalarCeilToScalar(bounds.fRight) || + bounds.fTop + image_->dimensions().height() > + SkScalarCeilToScalar(bounds.fBottom); + + // Make sure raster cache doesn't bleed to physical pixels outside of + // original bounds. https://github.com/flutter/flutter/issues/110002 + if (exceeds_bounds) { + canvas.save(); + canvas.clipRect(SkRect::Make(bounds.roundOut())); + } canvas.drawImage(image_, bounds.fLeft, bounds.fTop, SkSamplingOptions(), paint); + if (exceeds_bounds) { + canvas.restore(); + } } RasterCache::RasterCache(size_t access_threshold, diff --git a/flow/raster_cache_unittests.cc b/flow/raster_cache_unittests.cc index afd00392afa1d..9a72da8e698ff 100644 --- a/flow/raster_cache_unittests.cc +++ b/flow/raster_cache_unittests.cc @@ -787,5 +787,67 @@ TEST_F(RasterCacheTest, RasterCacheKeyID_LayerChildrenIds) { ASSERT_EQ(ids, expected_ids); } +TEST_F(RasterCacheTest, RasterCacheBleedingNoClipNeeded) { + SkImageInfo info = + SkImageInfo::MakeN32(40, 40, SkAlphaType::kOpaque_SkAlphaType); + + auto image = SkImage::MakeRasterData( + info, SkData::MakeUninitialized(40 * 40 * 4), 40 * 4); + auto canvas = MockCanvas(); + canvas.setMatrix(SkMatrix::Scale(2, 2)); + // Drawing cached image does not exceeds physical pixels of the original + // bounds and does not need to be clipped. + auto cache_result = + RasterCacheResult(image, SkRect::MakeXYWH(100.3, 100.3, 20, 20), ""); + auto paint = SkPaint(); + cache_result.draw(canvas, &paint); + + EXPECT_EQ(canvas.draw_calls(), + std::vector({ + MockCanvas::DrawCall{ + 0, MockCanvas::SetMatrixData{SkM44::Scale(2, 2)}}, + MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, + MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkM44()}}, + MockCanvas::DrawCall{ + 1, MockCanvas::DrawImageData{image, 200.6, 200.6, + SkSamplingOptions(), paint}}, + MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}, + })); +} + +TEST_F(RasterCacheTest, RasterCacheBleedingClipNeeded) { + SkImageInfo info = + SkImageInfo::MakeN32(40, 40, SkAlphaType::kOpaque_SkAlphaType); + + auto image = SkImage::MakeRasterData( + info, SkData::MakeUninitialized(40 * 40 * 4), 40 * 4); + auto canvas = MockCanvas(); + canvas.setMatrix(SkMatrix::Scale(2, 2)); + + auto cache_result = + RasterCacheResult(image, SkRect::MakeXYWH(100.3, 100.3, 19.6, 19.6), ""); + auto paint = SkPaint(); + cache_result.draw(canvas, &paint); + + EXPECT_EQ( + canvas.draw_calls(), + std::vector({ + MockCanvas::DrawCall{0, + MockCanvas::SetMatrixData{SkM44::Scale(2, 2)}}, + MockCanvas::DrawCall{0, MockCanvas::SaveData{1}}, + MockCanvas::DrawCall{1, MockCanvas::SetMatrixData{SkM44()}}, + MockCanvas::DrawCall{1, MockCanvas::SaveData{2}}, + MockCanvas::DrawCall{ + 2, MockCanvas::ClipRectData{SkRect::MakeLTRB(200, 200, 240, 240), + SkClipOp::kIntersect, + MockCanvas::kHard_ClipEdgeStyle}}, + MockCanvas::DrawCall{ + 2, MockCanvas::DrawImageData{image, 200.6, 200.6, + SkSamplingOptions(), paint}}, + MockCanvas::DrawCall{2, MockCanvas::RestoreData{1}}, + MockCanvas::DrawCall{1, MockCanvas::RestoreData{0}}, + })); +} + } // namespace testing } // namespace flutter From 0fd04455fd7772af4631685f0f2071123f9b2e3c Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 22 Aug 2022 10:52:11 -0700 Subject: [PATCH 477/558] deprecate pushPhysicalLayer (#35566) --- lib/ui/compositing.dart | 4 ++++ lib/web_ui/lib/compositing.dart | 4 ++++ testing/dart/compositing_test.dart | 1 + 3 files changed, 9 insertions(+) diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index 528fc027c043a..e38066aa77703 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -625,6 +625,10 @@ class SceneBuilder extends NativeFieldWrapperClass1 { /// {@macro dart.ui.sceneBuilder.oldLayerVsRetained} /// /// See [pop] for details about the operation stack, and [Clip] for different clip modes. + @Deprecated( + 'Use a clip and canvas operations directly (See RenderPhysicalModel). ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) PhysicalShapeEngineLayer pushPhysicalShape({ required Path path, required double elevation, diff --git a/lib/web_ui/lib/compositing.dart b/lib/web_ui/lib/compositing.dart index 96c51cbeeecf4..349ad272d4b3d 100644 --- a/lib/web_ui/lib/compositing.dart +++ b/lib/web_ui/lib/compositing.dart @@ -89,6 +89,10 @@ abstract class SceneBuilder { ShaderMaskEngineLayer? oldLayer, FilterQuality filterQuality = FilterQuality.low, }); + @Deprecated( + 'Use a clip and canvas operations directly (See RenderPhysicalModel). ' + 'This feature was deprecated after v3.1.0-0.0.pre.', + ) PhysicalShapeEngineLayer pushPhysicalShape({ required Path path, required double elevation, diff --git a/testing/dart/compositing_test.dart b/testing/dart/compositing_test.dart index 10c70978d22b5..99c95cf89db4f 100644 --- a/testing/dart/compositing_test.dart +++ b/testing/dart/compositing_test.dart @@ -382,6 +382,7 @@ void main() { ); }); testNoSharing((SceneBuilder builder, EngineLayer? oldLayer) { + // ignore: deprecated_member_use return builder.pushPhysicalShape(path: Path(), color: const Color.fromARGB(0, 0, 0, 0), oldLayer: oldLayer as PhysicalShapeEngineLayer?, elevation: 0.0); }); testNoSharing((SceneBuilder builder, EngineLayer? oldLayer) { From 75d7843ecb80b67d2a68c94b92066741866202b8 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Mon, 22 Aug 2022 11:26:22 -0700 Subject: [PATCH 478/558] Adjust rules for analyze_snapshot (#35585) --- lib/snapshot/BUILD.gn | 4 +++ shell/platform/android/BUILD.gn | 64 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/lib/snapshot/BUILD.gn b/lib/snapshot/BUILD.gn index 2c05b6cc4ffde..618640efe53be 100644 --- a/lib/snapshot/BUILD.gn +++ b/lib/snapshot/BUILD.gn @@ -20,6 +20,10 @@ group("generate_snapshot_bins") { if (host_os == "mac" && target_os == "mac") { deps += [ ":create_macos_gen_snapshots" ] } + if (target_cpu == "x64" || target_cpu == "arm64") { + deps += + [ "//third_party/dart/runtime/bin:analyze_snapshot($host_toolchain)" ] + } } compiled_action("generate_snapshot_bin") { diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index edb78d40445d9..3a91161dc23ee 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -646,6 +646,70 @@ if (target_cpu != "x86") { } } +if (target_cpu == "x64" || target_cpu == "arm64") { + zip_bundle("analyze_snapshot") { + deps = + [ "//third_party/dart/runtime/bin:analyze_snapshot($host_toolchain)" ] + + analyze_snapshot_bin = "analyze_snapshot" + analyze_snapshot_out_dir = + get_label_info( + "//third_party/dart/runtime/bin:analyze_snapshot($host_toolchain)", + "root_out_dir") + analyze_snapshot_path = + rebase_path("$analyze_snapshot_out_dir/$analyze_snapshot_bin") + + if (host_os == "linux") { + output = "$android_zip_archive_dir/analyze-snapshot-linux-x64.zip" + } else if (host_os == "mac") { + output = "$android_zip_archive_dir/analyze-snapshot-darwin-x64.zip" + } else if (host_os == "win") { + output = "$android_zip_archive_dir/analyze-snapshot-windows-x64.zip" + analyze_snapshot_bin = "analyze-snapshot.exe" + analyze_snapshot_path = rebase_path("$root_out_dir/$analyze_snapshot_bin") + } + + files = [ + { + source = analyze_snapshot_path + destination = analyze_snapshot_bin + }, + ] + } + + # TODO(godofredoc): Remove analyze_snapshot and rename new_analyze_snapshot when v2 migration is complete. + # BUG: https://github.com/flutter/flutter/issues/105351 + zip_bundle("new_analyze_snapshot") { + deps = + [ "//third_party/dart/runtime/bin:analyze_snapshot($host_toolchain)" ] + + analyze_snapshot_bin = "analyze_snapshot" + analyze_snapshot_out_dir = + get_label_info( + "//third_party/dart/runtime/bin:analyze_snapshot($host_toolchain)", + "root_out_dir") + analyze_snapshot_path = + rebase_path("$analyze_snapshot_out_dir/$analyze_snapshot_bin") + + if (host_os == "linux") { + output = "$android_zip_archive_dir/$full_platform_name-$flutter_runtime_mode/analyze-snapshot-linux-x64.zip" + } else if (host_os == "mac") { + output = "$android_zip_archive_dir/$full_platform_name-$flutter_runtime_mode/analyze-snapshot-darwin-x64.zip" + } else if (host_os == "win") { + output = "$android_zip_archive_dir/$full_platform_name-$flutter_runtime_mode/analyze-snapshot-windows-x64.zip" + analyze_snapshot_bin = "analyze-snapshot.exe" + analyze_snapshot_path = rebase_path("$root_out_dir/$analyze_snapshot_bin") + } + + files = [ + { + source = analyze_snapshot_path + destination = analyze_snapshot_bin + }, + ] + } +} + group("android") { deps = [ ":android_javadoc", From 0c023bac7e8ff70b7a74f64aa170eac0efca904e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 14:57:05 -0400 Subject: [PATCH 479/558] Roll Dart SDK from 7cbd8dc183c0 to 31310f2db06b (1 revision) (#35610) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 08cd7b1f231d4..6157c2c0466a9 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '7cbd8dc183c04b61127eff684e5e4dfea2456623', + 'dart_revision': '31310f2db06bff139d9efc69dbdc7c1e82345faf', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 7252c6406b2c4f77efd9439a7dcba2f3d9071436 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 15:18:16 -0400 Subject: [PATCH 480/558] Roll Skia from b4de358a0159 to 12449e09e422 (1 revision) (#35612) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6157c2c0466a9..422df6df9e99e 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': 'b4de358a01593cc7bfb5d3206d6cb76f6f8ec269', + 'skia_revision': '12449e09e422956c22ae3e8559c8de7a219397a8', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 503204ab750ef..87354baac882a 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 4488819230e684648be4af3027178c68 +Signature: 5473182ef27e9b08a337cf49ad51fbac UNUSED LICENSES: From c889963026ccd09b16a3a0ff15e70f0a29137cc4 Mon Sep 17 00:00:00 2001 From: yaakovschectman <109111084+yaakovschectman@users.noreply.github.com> Date: Mon, 22 Aug 2022 16:01:02 -0400 Subject: [PATCH 481/558] Include checkbox in check state update (#35557) * Include checkbox in check state update * Windows test for checkbox native state * Reformat to appease linux_unopt test * More format hoops * Update accessibility_bridge_unittests.cc * Update flutter_windows_view_unittests.cc --- shell/platform/common/accessibility_bridge.cc | 3 +- .../common/accessibility_bridge_unittests.cc | 31 +++++++ .../windows/flutter_windows_view_unittests.cc | 90 +++++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/shell/platform/common/accessibility_bridge.cc b/shell/platform/common/accessibility_bridge.cc index ab2468e331cfa..576edfac6e6eb 100644 --- a/shell/platform/common/accessibility_bridge.cc +++ b/shell/platform/common/accessibility_bridge.cc @@ -375,7 +375,8 @@ void AccessibilityBridge::SetIntAttributesFromFlutterUpdate( node_data.AddIntAttribute(ax::mojom::IntAttribute::kTextSelStart, sel_start); node_data.AddIntAttribute(ax::mojom::IntAttribute::kTextSelEnd, sel_end); - if (node_data.role == ax::mojom::Role::kRadioButton) { + if (node_data.role == ax::mojom::Role::kRadioButton || + node_data.role == ax::mojom::Role::kCheckBox) { node_data.AddIntAttribute( ax::mojom::IntAttribute::kCheckedState, static_cast( diff --git a/shell/platform/common/accessibility_bridge_unittests.cc b/shell/platform/common/accessibility_bridge_unittests.cc index 38e038266628d..41834b107a44b 100644 --- a/shell/platform/common/accessibility_bridge_unittests.cc +++ b/shell/platform/common/accessibility_bridge_unittests.cc @@ -337,5 +337,36 @@ TEST(AccessibilityBridgeTest, SliderHasSliderRole) { EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kSlider); } +// Ensure that checkboxes have their checked status set apropriately +// Previously, only Radios could have this flag updated +// Resulted in the issue seen at +// https://github.com/flutter/flutter/issues/96218 +// As this fix involved code run on all platforms, it is included here. +TEST(AccessibilityBridgeTest, CanSetCheckboxChecked) { + std::shared_ptr bridge = + std::make_shared( + std::make_unique()); + FlutterSemanticsNode root; + root.id = 0; + root.label = "root"; + root.hint = ""; + root.value = ""; + root.increased_value = ""; + root.decreased_value = ""; + root.child_count = 0; + root.custom_accessibility_actions_count = 0; + root.flags = static_cast( + FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState | + FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked); + bridge->AddFlutterSemanticsNodeUpdate(&root); + + bridge->CommitUpdates(); + + auto root_node = bridge->GetFlutterPlatformNodeDelegateFromID(0).lock(); + EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox); + EXPECT_EQ(root_node->GetData().GetCheckedState(), + ax::mojom::CheckedState::kTrue); +} + } // namespace testing } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc index 9513322daa2b7..d6830d69081d2 100644 --- a/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/shell/platform/windows/flutter_windows_view_unittests.cc @@ -597,5 +597,95 @@ TEST(FlutterWindowsViewTest, WindowRepaintTests) { EXPECT_TRUE(schedule_frame_called); } +// Ensure that checkboxes have their checked status set apropriately +// Previously, only Radios could have this flag updated +// Resulted in the issue seen at +// https://github.com/flutter/flutter/issues/96218 +// This test ensures that the native state of Checkboxes on Windows, +// specifically, is updated as desired. +TEST(FlutterWindowsViewTest, CheckboxNativeState) { + std::unique_ptr engine = GetTestEngine(); + EngineModifier modifier(engine.get()); + modifier.embedder_api().UpdateSemanticsEnabled = + [](FLUTTER_API_SYMBOL(FlutterEngine) engine, bool enabled) { + return kSuccess; + }; + + auto window_binding_handler = + std::make_unique<::testing::NiceMock>(); + FlutterWindowsView view(std::move(window_binding_handler)); + view.SetEngine(std::move(engine)); + + // Enable semantics to instantiate accessibility bridge. + view.OnUpdateSemanticsEnabled(true); + + auto bridge = view.GetEngine()->accessibility_bridge().lock(); + ASSERT_TRUE(bridge); + + FlutterSemanticsNode root{sizeof(FlutterSemanticsNode), 0}; + root.id = 0; + root.label = "root"; + root.hint = ""; + root.value = ""; + root.increased_value = ""; + root.decreased_value = ""; + root.child_count = 0; + root.custom_accessibility_actions_count = 0; + root.flags = static_cast( + FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState | + FlutterSemanticsFlag::kFlutterSemanticsFlagIsChecked); + bridge->AddFlutterSemanticsNodeUpdate(&root); + + bridge->CommitUpdates(); + + auto root_node = bridge + ->GetFlutterPlatformNodeDelegateFromID( + AccessibilityBridge::kRootNodeId) + .lock(); + EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox); + EXPECT_EQ(root_node->GetData().GetCheckedState(), + ax::mojom::CheckedState::kTrue); + + // Get the IAccessible for the root node. + IAccessible* native_view = root_node->GetNativeViewAccessible(); + ASSERT_TRUE(native_view != nullptr); + + // Look up against the node itself (not one of its children) + VARIANT varchild = {}; + varchild.vt = VT_I4; + + // Verify the checkbox is checked. + varchild.lVal = CHILDID_SELF; + VARIANT native_state = {}; + ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state))); + EXPECT_TRUE(native_state.lVal & STATE_SYSTEM_CHECKED); + + // Test unchecked too + root.flags = static_cast( + FlutterSemanticsFlag::kFlutterSemanticsFlagHasCheckedState); + bridge->AddFlutterSemanticsNodeUpdate(&root); + bridge->CommitUpdates(); + root_node = bridge + ->GetFlutterPlatformNodeDelegateFromID( + AccessibilityBridge::kRootNodeId) + .lock(); + EXPECT_EQ(root_node->GetData().role, ax::mojom::Role::kCheckBox); + EXPECT_EQ(root_node->GetData().GetCheckedState(), + ax::mojom::CheckedState::kFalse); + + // Get the IAccessible for the root node. + native_view = root_node->GetNativeViewAccessible(); + + // Look up against the node itself (not one of its children) + varchild = {}; + varchild.vt = VT_I4; + + // Verify the checkbox is checked. + varchild.lVal = CHILDID_SELF; + native_state = {}; + ASSERT_TRUE(SUCCEEDED(native_view->get_accState(varchild, &native_state))); + EXPECT_FALSE(native_state.lVal & STATE_SYSTEM_CHECKED); +} + } // namespace testing } // namespace flutter From cd119976dcc943dba362d5e99cdfe448521722ce Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 16:30:02 -0400 Subject: [PATCH 482/558] Roll Skia from 12449e09e422 to fc260b97046d (5 revisions) (#35613) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 422df6df9e99e..5179062446d77 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': '12449e09e422956c22ae3e8559c8de7a219397a8', + 'skia_revision': 'fc260b97046d28a82403248ddd561f7cc396ed58', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 87354baac882a..d767cbe97a5c4 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 5473182ef27e9b08a337cf49ad51fbac +Signature: 8c4256b87ac673917115a3339cde0873 UNUSED LICENSES: @@ -825,6 +825,7 @@ FILE: ../../../third_party/skia/include/private/BUILD.bazel FILE: ../../../third_party/skia/include/private/chromium/BUILD.bazel FILE: ../../../third_party/skia/include/private/gpu/BUILD.bazel FILE: ../../../third_party/skia/include/private/gpu/ganesh/BUILD.bazel +FILE: ../../../third_party/skia/include/private/gpu/vk/BUILD.bazel FILE: ../../../third_party/skia/include/sksl/BUILD.bazel FILE: ../../../third_party/skia/include/svg/BUILD.bazel FILE: ../../../third_party/skia/include/utils/BUILD.bazel @@ -3483,12 +3484,12 @@ FILE: ../../../third_party/skia/include/effects/SkTrimPathEffect.h FILE: ../../../third_party/skia/include/gpu/GrBackendDrawableInfo.h FILE: ../../../third_party/skia/include/gpu/GrDriverBugWorkarounds.h FILE: ../../../third_party/skia/include/gpu/vk/GrVkMemoryAllocator.h -FILE: ../../../third_party/skia/include/gpu/vk/GrVkVulkan.h FILE: ../../../third_party/skia/include/ports/SkFontMgr_fuchsia.h FILE: ../../../third_party/skia/include/private/SkMacros.h FILE: ../../../third_party/skia/include/private/SkSafe32.h FILE: ../../../third_party/skia/include/private/SkTo.h FILE: ../../../third_party/skia/include/private/gpu/ganesh/GrVkTypesPriv.h +FILE: ../../../third_party/skia/include/private/gpu/vk/SkiaVulkan.h FILE: ../../../third_party/skia/include/utils/SkAnimCodecPlayer.h FILE: ../../../third_party/skia/include/utils/SkTextUtils.h FILE: ../../../third_party/skia/modules/skcms/skcms.cc @@ -5574,6 +5575,8 @@ FILE: ../../../third_party/skia/src/gpu/graphite/ImageUtils.h FILE: ../../../third_party/skia/src/gpu/graphite/Log.h FILE: ../../../third_party/skia/src/gpu/graphite/PaintParams.cpp FILE: ../../../third_party/skia/src/gpu/graphite/PaintParams.h +FILE: ../../../third_party/skia/src/gpu/graphite/PietRenderTask.cpp +FILE: ../../../third_party/skia/src/gpu/graphite/PietRenderTask.h FILE: ../../../third_party/skia/src/gpu/graphite/QueueManager.cpp FILE: ../../../third_party/skia/src/gpu/graphite/QueueManager.h FILE: ../../../third_party/skia/src/gpu/graphite/RecorderPriv.h From 258c580a83c640686c6c64f58a6c9ff424d981ba Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 19:24:29 -0400 Subject: [PATCH 483/558] Roll Dart SDK from 31310f2db06b to 744430878593 (1 revision) (#35616) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 5179062446d77..4637ce3b59da4 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '31310f2db06bff139d9efc69dbdc7c1e82345faf', + 'dart_revision': '744430878593ea6bf130712fe2557c434399cc38', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index c366613a365af..47dee475fe15c 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: d47b3da7922c2e807ea6d8e9e4fdd2d5 +Signature: 0e240be838d32639b8bb4dc3fe2c4cce UNUSED LICENSES: @@ -10735,6 +10735,8 @@ FILE: ../../../third_party/dart/runtime/bin/thread_absl.cc FILE: ../../../third_party/dart/runtime/bin/thread_absl.h FILE: ../../../third_party/dart/runtime/platform/mach_o.h FILE: ../../../third_party/dart/runtime/platform/pe.h +FILE: ../../../third_party/dart/runtime/vm/compiler/backend/il_serializer.cc +FILE: ../../../third_party/dart/runtime/vm/compiler/backend/il_serializer.h 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/instructions.cc From ca48808d06f377f2a8a028834b4bbd2e5fbe23a6 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 19:48:21 -0400 Subject: [PATCH 484/558] Roll Skia from fc260b97046d to 26566799d0c3 (2 revisions) (#35617) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 4637ce3b59da4..fc28726696880 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': 'fc260b97046d28a82403248ddd561f7cc396ed58', + 'skia_revision': '26566799d0c30082c53301655d1d374b7e858c1a', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index d767cbe97a5c4..cd89970c8cd5a 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 8c4256b87ac673917115a3339cde0873 +Signature: 53d25d67c63c570162cbc26dd12870af UNUSED LICENSES: From ad9af346115d6d7fe3e9cf278f4cafa070ce2548 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 22 Aug 2022 19:16:06 -0700 Subject: [PATCH 485/558] Include TextureLayer in contents of toImageSync (#35608) --- flow/layers/layer_tree.cc | 14 ++++--- flow/layers/layer_tree.h | 6 ++- lib/ui/compositing.dart | 1 + lib/ui/compositing/scene.cc | 39 ++++++++++++------ lib/ui/compositing/scene.h | 25 +++++++---- .../display_list_deferred_image_gpu.cc | 41 ++++++++++++++++++- .../display_list_deferred_image_gpu.h | 21 +++++++++- lib/ui/painting/picture.cc | 35 +++++++++++++--- lib/ui/painting/picture.h | 12 ++++++ lib/ui/snapshot_delegate.h | 3 ++ runtime/runtime_delegate.h | 2 +- shell/common/animator.cc | 2 +- shell/common/animator.h | 2 +- shell/common/animator_unittests.cc | 4 +- shell/common/engine.cc | 2 +- shell/common/engine.h | 2 +- shell/common/engine_unittests.cc | 2 +- shell/common/pipeline.h | 4 +- shell/common/rasterizer.cc | 8 +++- shell/common/rasterizer.h | 9 ++-- shell/common/rasterizer_unittests.cc | 26 ++++++------ shell/common/shell_test.cc | 2 +- testing/dart/compositing_test.dart | 22 ++++++++++ 23 files changed, 220 insertions(+), 64 deletions(-) diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index de7573ef4ac39..3b4907b5336bf 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -171,7 +171,10 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, } } -sk_sp LayerTree::Flatten(const SkRect& bounds) { +sk_sp LayerTree::Flatten( + const SkRect& bounds, + std::shared_ptr texture_registry, + GrDirectContext* gr_context) { TRACE_EVENT0("flutter", "LayerTree::Flatten"); DisplayListCanvasRecorder builder(bounds); @@ -179,13 +182,14 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { MutatorsStack unused_stack; const FixedRefreshRateStopwatch unused_stopwatch; SkMatrix root_surface_transformation; + // No root surface transformation. So assume identity. root_surface_transformation.reset(); PrerollContext preroll_context{ // clang-format off .raster_cache = nullptr, - .gr_context = nullptr, + .gr_context = gr_context, .view_embedder = nullptr, .mutators_stack = unused_stack, .dst_color_space = nullptr, @@ -193,7 +197,7 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .surface_needs_readback = false, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = nullptr, + .texture_registry = texture_registry, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_ // clang-format on @@ -209,12 +213,12 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { // clang-format off .internal_nodes_canvas = &internal_nodes_canvas, .leaf_nodes_canvas = &builder, - .gr_context = nullptr, + .gr_context = gr_context, .dst_color_space = nullptr, .view_embedder = nullptr, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, - .texture_registry = nullptr, + .texture_registry = texture_registry, .raster_cache = nullptr, .checkerboard_offscreen_layers = false, .frame_device_pixel_ratio = device_pixel_ratio_, diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index c7daa5f809e9f..167500400b758 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -8,6 +8,7 @@ #include #include +#include "flutter/common/graphics/texture.h" #include "flutter/flow/compositor_context.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" @@ -41,7 +42,10 @@ class LayerTree { void Paint(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache = false) const; - sk_sp Flatten(const SkRect& bounds); + sk_sp Flatten( + const SkRect& bounds, + std::shared_ptr texture_registry = nullptr, + GrDirectContext* gr_context = nullptr); Layer* root_layer() const { return root_layer_.get(); } diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index e38066aa77703..843be9631a0e5 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -38,6 +38,7 @@ class Scene extends NativeFieldWrapperClass1 { external String? _toImageSync(int width, int height, _Image outImage); /// Creates a raster image representation of the current state of the scene. + /// /// This is a slow operation that is performed on a background thread. /// /// Callers must dispose the [Image] when they are done with it. If the result diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 734a67ef2481c..5a8601b90effe 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -5,6 +5,7 @@ #include "flutter/lib/ui/compositing/scene.h" #include "flutter/fml/trace_event.h" +#include "flutter/lib/ui/painting/display_list_deferred_image_gpu.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/picture.h" #include "flutter/lib/ui/ui_dart_state.h" @@ -42,7 +43,7 @@ Scene::Scene(std::shared_ptr rootLayer, ->get_window(0) ->viewport_metrics(); - layer_tree_ = std::make_unique( + layer_tree_ = std::make_shared( SkISize::Make(viewport_metrics.physical_width, viewport_metrics.physical_height), static_cast(viewport_metrics.device_pixel_ratio)); @@ -69,12 +70,7 @@ Dart_Handle Scene::toImageSync(uint32_t width, return tonic::ToDart("Scene did not contain a layer tree."); } - auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height)); - if (!picture) { - return tonic::ToDart("Could not flatten scene into a layer tree."); - } - - Picture::RasterizeToImageSync(picture, width, height, raw_image_handle); + Scene::RasterizeToImage(width, height, raw_image_handle); return Dart_Null(); } @@ -87,15 +83,32 @@ Dart_Handle Scene::toImage(uint32_t width, return tonic::ToDart("Scene did not contain a layer tree."); } - auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height)); - if (!picture) { - return tonic::ToDart("Could not flatten scene into a layer tree."); - } + return Picture::RasterizeLayerTreeToImage(std::move(layer_tree_), width, + height, raw_image_callback); +} - return Picture::RasterizeToImage(picture, width, height, raw_image_callback); +void Scene::RasterizeToImage(uint32_t width, + uint32_t height, + Dart_Handle raw_image_handle) { + auto* dart_state = UIDartState::Current(); + if (!dart_state) { + return; + } + auto unref_queue = dart_state->GetSkiaUnrefQueue(); + auto snapshot_delegate = dart_state->GetSnapshotDelegate(); + auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner(); + + auto image = CanvasImage::Create(); + const SkImageInfo image_info = SkImageInfo::Make( + width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType); + auto dl_image = DlDeferredImageGPU::MakeFromLayerTree( + image_info, std::move(layer_tree_), std::move(snapshot_delegate), + std::move(raster_task_runner), std::move(unref_queue)); + image->set_image(dl_image); + image->AssociateWithDartWrapper(raw_image_handle); } -std::unique_ptr Scene::takeLayerTree() { +std::shared_ptr Scene::takeLayerTree() { return std::move(layer_tree_); } diff --git a/lib/ui/compositing/scene.h b/lib/ui/compositing/scene.h index 1cf95aad4ec43..aca797836fcb1 100644 --- a/lib/ui/compositing/scene.h +++ b/lib/ui/compositing/scene.h @@ -26,7 +26,7 @@ class Scene : public RefCountedDartWrappable { bool checkerboardRasterCacheImages, bool checkerboardOffscreenLayers); - std::unique_ptr takeLayerTree(); + std::shared_ptr takeLayerTree(); Dart_Handle toImageSync(uint32_t width, uint32_t height, @@ -34,17 +34,26 @@ class Scene : public RefCountedDartWrappable { Dart_Handle toImage(uint32_t width, uint32_t height, - Dart_Handle image_callback); + Dart_Handle raw_image_handle); void dispose(); private: - explicit Scene(std::shared_ptr rootLayer, - uint32_t rasterizerTracingThreshold, - bool checkerboardRasterCacheImages, - bool checkerboardOffscreenLayers); - - std::unique_ptr layer_tree_; + Scene(std::shared_ptr rootLayer, + uint32_t rasterizerTracingThreshold, + bool checkerboardRasterCacheImages, + bool checkerboardOffscreenLayers); + + void RasterizeToImage(uint32_t width, + uint32_t height, + Dart_Handle raw_image_handle); + + // This is a shared_ptr to support flattening the layer tree from the UI + // thread onto the raster thread - allowing access to the texture registry + // required to render TextureLayers. + // + // No longer valid after calling `takeLayerTree`. + std::shared_ptr layer_tree_; }; } // namespace flutter diff --git a/lib/ui/painting/display_list_deferred_image_gpu.cc b/lib/ui/painting/display_list_deferred_image_gpu.cc index beeb0ccf80404..14391c2128a74 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.cc +++ b/lib/ui/painting/display_list_deferred_image_gpu.cc @@ -22,6 +22,19 @@ sk_sp DlDeferredImageGPU::Make( raster_task_runner)); } +sk_sp DlDeferredImageGPU::MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + return sk_sp(new DlDeferredImageGPU( + ImageWrapper::MakeFromLayerTree( + image_info, std::move(layer_tree), std::move(snapshot_delegate), + raster_task_runner, std::move(unref_queue)), + raster_task_runner)); +} + DlDeferredImageGPU::DlDeferredImageGPU( std::shared_ptr image_wrapper, fml::RefPtr raster_task_runner) @@ -92,6 +105,20 @@ DlDeferredImageGPU::ImageWrapper::Make( return wrapper; } +std::shared_ptr +DlDeferredImageGPU::ImageWrapper::MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + auto wrapper = std::shared_ptr( + new ImageWrapper(image_info, nullptr, std::move(snapshot_delegate), + std::move(raster_task_runner), std::move(unref_queue))); + wrapper->SnapshotDisplayList(std::move(layer_tree)); + return wrapper; +} + DlDeferredImageGPU::ImageWrapper::ImageWrapper( const SkImageInfo& image_info, sk_sp display_list, @@ -131,9 +158,11 @@ bool DlDeferredImageGPU::ImageWrapper::isTextureBacked() const { return texture_.isValid(); } -void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { +void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList( + std::shared_ptr layer_tree) { fml::TaskRunner::RunNowOrPostTask( - raster_task_runner_, [weak_this = weak_from_this()]() { + raster_task_runner_, + [weak_this = weak_from_this(), layer_tree = std::move(layer_tree)]() { auto wrapper = weak_this.lock(); if (!wrapper) { return; @@ -142,6 +171,14 @@ void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { if (!snapshot_delegate) { return; } + if (layer_tree) { + auto display_list = + layer_tree->Flatten(SkRect::MakeWH(wrapper->image_info_.width(), + wrapper->image_info_.height()), + snapshot_delegate->GetTextureRegistry(), + snapshot_delegate->GetGrContext()); + wrapper->display_list_ = std::move(display_list); + } auto result = snapshot_delegate->MakeGpuImage(wrapper->display_list_, wrapper->image_info_); if (result->texture.isValid()) { diff --git a/lib/ui/painting/display_list_deferred_image_gpu.h b/lib/ui/painting/display_list_deferred_image_gpu.h index 429dcd873a101..5f04eb25d0765 100644 --- a/lib/ui/painting/display_list_deferred_image_gpu.h +++ b/lib/ui/painting/display_list_deferred_image_gpu.h @@ -11,6 +11,7 @@ #include "flutter/common/graphics/texture.h" #include "flutter/display_list/display_list.h" #include "flutter/display_list/display_list_image.h" +#include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/fml/macros.h" #include "flutter/fml/memory/weak_ptr.h" @@ -28,6 +29,13 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); + static sk_sp MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + // |DlImage| ~DlDeferredImageGPU() override; @@ -73,6 +81,13 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); + static std::shared_ptr MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + const SkImageInfo image_info() const { return image_info_; } const GrBackendTexture& texture() const { return texture_; } bool isTextureBacked() const; @@ -103,7 +118,11 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); - void SnapshotDisplayList(); + // If a layer tree is provided, it will be flattened during the raster + // thread task spwaned by this method. After being flattened into a display + // list, the image wrapper will be updated to hold this display list and the + // layer tree can be dropped. + void SnapshotDisplayList(std::shared_ptr layer_tree = nullptr); // |ContextListener| void OnGrContextCreated() override; diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 4d5411d1830f6..c79c5c08a3688 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -95,11 +95,21 @@ Dart_Handle Picture::RasterizeToImage(sk_sp display_list, Dart_Handle raw_image_callback) { return RasterizeToImage( [display_list](SkCanvas* canvas) { display_list->RenderTo(canvas); }, - width, height, raw_image_callback); + nullptr, width, height, raw_image_callback); +} + +Dart_Handle Picture::RasterizeLayerTreeToImage( + std::shared_ptr layer_tree, + uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback) { + return RasterizeToImage(nullptr, std::move(layer_tree), width, height, + raw_image_callback); } Dart_Handle Picture::RasterizeToImage( std::function draw_callback, + std::shared_ptr layer_tree, uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { @@ -158,10 +168,25 @@ Dart_Handle Picture::RasterizeToImage( // Kick things off on the raster rask runner. fml::TaskRunner::RunNowOrPostTask( - raster_task_runner, [ui_task_runner, snapshot_delegate, draw_callback, - picture_bounds, ui_task] { - sk_sp raster_image = snapshot_delegate->MakeRasterSnapshot( - draw_callback, picture_bounds); + raster_task_runner, + [ui_task_runner, snapshot_delegate, draw_callback, picture_bounds, + ui_task, layer_tree = std::move(layer_tree)] { + sk_sp raster_image; + if (layer_tree) { + auto display_list = layer_tree->Flatten( + SkRect::MakeWH(picture_bounds.width(), picture_bounds.height()), + snapshot_delegate->GetTextureRegistry(), + snapshot_delegate->GetGrContext()); + + raster_image = snapshot_delegate->MakeRasterSnapshot( + [display_list](SkCanvas* canvas) { + display_list->RenderTo(canvas); + }, + picture_bounds); + } else { + raster_image = snapshot_delegate->MakeRasterSnapshot(draw_callback, + picture_bounds); + } fml::TaskRunner::RunNowOrPostTask( ui_task_runner, diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index 1cb390a182138..77fda55884c3d 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -6,6 +6,7 @@ #define FLUTTER_LIB_UI_PAINTING_PICTURE_H_ #include "flutter/display_list/display_list.h" +#include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/skia_gpu_object.h" #include "flutter/lib/ui/dart_wrapper.h" #include "flutter/lib/ui/painting/image.h" @@ -51,8 +52,19 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + static Dart_Handle RasterizeLayerTreeToImage( + std::shared_ptr layer_tree, + uint32_t width, + uint32_t height, + Dart_Handle raw_image_callback); + + // Callers may provide either a draw_callback (which should reference a + // display list) or a layer tree. If a layer tree is provided, it will be + // flattened on the raster thread. In this case the draw callback will be + // ignored. static Dart_Handle RasterizeToImage( std::function draw_callback, + std::shared_ptr layer_tree, uint32_t width, uint32_t height, Dart_Handle raw_image_callback); diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h index 4158d28701cbb..3b59ffed9fb23 100644 --- a/lib/ui/snapshot_delegate.h +++ b/lib/ui/snapshot_delegate.h @@ -13,6 +13,7 @@ #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkPromiseImageTexture.h" #include "third_party/skia/include/gpu/GrContextThreadSafeProxy.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" namespace flutter { @@ -52,6 +53,8 @@ class SnapshotDelegate { /// virtual std::shared_ptr GetTextureRegistry() = 0; + virtual GrDirectContext* GetGrContext() = 0; + virtual std::unique_ptr MakeGpuImage( sk_sp display_list, const SkImageInfo& image_info) = 0; diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index 540e47dd09ba4..ad680677338e0 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -24,7 +24,7 @@ class RuntimeDelegate { virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0; - virtual void Render(std::unique_ptr layer_tree) = 0; + virtual void Render(std::shared_ptr layer_tree) = 0; virtual void UpdateSemantics(SemanticsNodeUpdates update, CustomAccessibilityActionUpdates actions) = 0; diff --git a/shell/common/animator.cc b/shell/common/animator.cc index 31bd0cdfb5eb5..d8614dc22f69c 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -144,7 +144,7 @@ void Animator::BeginFrame( } } -void Animator::Render(std::unique_ptr layer_tree) { +void Animator::Render(std::shared_ptr layer_tree) { has_rendered_ = true; last_layer_tree_size_ = layer_tree->frame_size(); diff --git a/shell/common/animator.h b/shell/common/animator.h index d822935307ac8..6550452ba481e 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -54,7 +54,7 @@ class Animator final { void RequestFrame(bool regenerate_layer_tree = true); - void Render(std::unique_ptr layer_tree); + void Render(std::shared_ptr layer_tree); const std::weak_ptr GetVsyncWaiter() const; diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc index 628d7eb9afbc0..91c2bad1b033f 100644 --- a/shell/common/animator_unittests.cc +++ b/shell/common/animator_unittests.cc @@ -157,7 +157,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyIdleBeforeRender) { [&] { ASSERT_FALSE(delegate.notify_idle_called_); auto layer_tree = - std::make_unique(SkISize::Make(600, 800), 1.0); + std::make_shared(SkISize::Make(600, 800), 1.0); animator->Render(std::move(layer_tree)); task_runners.GetPlatformTaskRunner()->PostTask(flush_vsync_task); }, @@ -240,7 +240,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyDelegateIfPipelineIsNotEmpty) { PostTaskSync(task_runners.GetUITaskRunner(), [&] { auto layer_tree = - std::make_unique(SkISize::Make(600, 800), 1.0); + std::make_shared(SkISize::Make(600, 800), 1.0); animator->Render(std::move(layer_tree)); }); } diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 9a0e5d03e4883..c2cbc9f512b98 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -439,7 +439,7 @@ void Engine::ScheduleFrame(bool regenerate_layer_tree) { animator_->RequestFrame(regenerate_layer_tree); } -void Engine::Render(std::unique_ptr layer_tree) { +void Engine::Render(std::shared_ptr layer_tree) { if (!layer_tree) { return; } diff --git a/shell/common/engine.h b/shell/common/engine.h index 491ec4f0e5fe3..04b968f106c41 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -879,7 +879,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { std::string DefaultRouteName() override; // |RuntimeDelegate| - void Render(std::unique_ptr layer_tree) override; + void Render(std::shared_ptr layer_tree) override; // |RuntimeDelegate| void UpdateSemantics(SemanticsNodeUpdates update, diff --git a/shell/common/engine_unittests.cc b/shell/common/engine_unittests.cc index 62674947f9e87..6dfc93c555c36 100644 --- a/shell/common/engine_unittests.cc +++ b/shell/common/engine_unittests.cc @@ -48,7 +48,7 @@ class MockRuntimeDelegate : public RuntimeDelegate { public: MOCK_METHOD0(DefaultRouteName, std::string()); MOCK_METHOD1(ScheduleFrame, void(bool)); - MOCK_METHOD1(Render, void(std::unique_ptr)); + MOCK_METHOD1(Render, void(std::shared_ptr)); MOCK_METHOD2(UpdateSemantics, void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates)); MOCK_METHOD1(HandlePlatformMessage, void(std::unique_ptr)); diff --git a/shell/common/pipeline.h b/shell/common/pipeline.h index 35f90f39f2c6a..f9546d0816125 100644 --- a/shell/common/pipeline.h +++ b/shell/common/pipeline.h @@ -222,11 +222,11 @@ class Pipeline { }; struct LayerTreeItem { - LayerTreeItem(std::unique_ptr layer_tree, + LayerTreeItem(std::shared_ptr layer_tree, std::unique_ptr frame_timings_recorder) : layer_tree(std::move(layer_tree)), frame_timings_recorder(std::move(frame_timings_recorder)) {} - std::unique_ptr layer_tree; + std::shared_ptr layer_tree; std::unique_ptr frame_timings_recorder; }; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index d3ecb11fee8ec..f9d10fd3e2240 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -145,6 +145,10 @@ std::shared_ptr Rasterizer::GetTextureRegistry() { return compositor_context_->texture_registry(); } +GrDirectContext* Rasterizer::GetGrContext() { + return surface_ ? surface_->GetContext() : nullptr; +} + flutter::LayerTree* Rasterizer::GetLastLayerTree() { return last_layer_tree_.get(); } @@ -181,7 +185,7 @@ RasterStatus Rasterizer::Draw(std::shared_ptr pipeline, RasterStatus raster_status = RasterStatus::kFailed; LayerTreePipeline::Consumer consumer = [&](std::unique_ptr item) { - std::unique_ptr layer_tree = std::move(item->layer_tree); + std::shared_ptr layer_tree = std::move(item->layer_tree); std::unique_ptr frame_timings_recorder = std::move(item->frame_timings_recorder); if (discard_callback(*layer_tree.get())) { @@ -488,7 +492,7 @@ fml::Milliseconds Rasterizer::GetFrameBudget() const { RasterStatus Rasterizer::DoDraw( std::unique_ptr frame_timings_recorder, - std::unique_ptr layer_tree) { + std::shared_ptr layer_tree) { TRACE_EVENT_WITH_FRAME_NUMBER(frame_timings_recorder, "flutter", "Rasterizer::DoDraw"); FML_DCHECK(delegate_.GetTaskRunners() diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 2f90ed5b1fe66..7052b664e1791 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -26,6 +26,7 @@ #include "flutter/shell/common/pipeline.h" #include "flutter/shell/common/snapshot_surface_producer.h" #include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/gpu/GrDirectContext.h" namespace flutter { @@ -213,6 +214,8 @@ class Rasterizer final : public SnapshotDelegate, std::unique_ptr frame_timings_recorder); // |SnapshotDelegate| + GrDirectContext* GetGrContext() override; + std::shared_ptr GetTextureRegistry() override; using LayerTreeDiscardCallback = std::function; @@ -496,7 +499,7 @@ class Rasterizer final : public SnapshotDelegate, RasterStatus DoDraw( std::unique_ptr frame_timings_recorder, - std::unique_ptr layer_tree); + std::shared_ptr layer_tree); RasterStatus DrawToSurface(FrameTimingsRecorder& frame_timings_recorder, flutter::LayerTree& layer_tree); @@ -515,11 +518,11 @@ class Rasterizer final : public SnapshotDelegate, std::unique_ptr snapshot_surface_producer_; std::unique_ptr compositor_context_; // This is the last successfully rasterized layer tree. - std::unique_ptr last_layer_tree_; + std::shared_ptr last_layer_tree_; // Set when we need attempt to rasterize the layer tree again. This layer_tree // has not successfully rasterized. This can happen due to the change in the // thread configuration. This will be inserted to the front of the pipeline. - std::unique_ptr resubmitted_layer_tree_; + std::shared_ptr resubmitted_layer_tree_; std::unique_ptr resubmitted_recorder_; fml::closure next_frame_callback_; bool user_override_resource_cache_bytes_; diff --git a/shell/common/rasterizer_unittests.cc b/shell/common/rasterizer_unittests.cc index 45232840bf2b1..af14fcc1675cf 100644 --- a/shell/common/rasterizer_unittests.cc +++ b/shell/common/rasterizer_unittests.cc @@ -176,7 +176,7 @@ TEST(RasterizerTest, fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -238,7 +238,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -306,7 +306,7 @@ TEST( rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -376,7 +376,7 @@ TEST(RasterizerTest, rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -423,7 +423,7 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) { fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -476,7 +476,7 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) { fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -573,7 +573,7 @@ TEST(RasterizerTest, fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -627,7 +627,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -681,7 +681,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -734,7 +734,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -811,7 +811,7 @@ TEST(RasterizerTest, auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = - std::make_unique(/*frame_size=*/SkISize(), + std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i])); @@ -972,7 +972,7 @@ TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) { auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = - std::make_unique(/*frame_size=*/SkISize(), + std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i])); @@ -1045,7 +1045,7 @@ TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) { thread_host.raster_thread->GetTaskRunner()->PostTask([&] { rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(first_timestamp)); diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index 27f6b0f65f527..eca345058787f 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -197,7 +197,7 @@ void ShellTest::PumpOneFrame(Shell* shell, fml::WeakPtr runtime_delegate = shell->weak_engine_; shell->GetTaskRunners().GetUITaskRunner()->PostTask( [&latch, runtime_delegate, &builder, viewport_metrics]() { - auto layer_tree = std::make_unique( + auto layer_tree = std::make_shared( SkISize::Make(viewport_metrics.physical_width, viewport_metrics.physical_height), static_cast(viewport_metrics.device_pixel_ratio)); diff --git a/testing/dart/compositing_test.dart b/testing/dart/compositing_test.dart index 99c95cf89db4f..cb65eb0ed44fe 100644 --- a/testing/dart/compositing_test.dart +++ b/testing/dart/compositing_test.dart @@ -36,6 +36,28 @@ void main() { expect(data.buffer.asUint8List()[3], 0xFF); }); + test('Scene.toImageSync succeeds with texture layer', () async { + final SceneBuilder builder = SceneBuilder(); + builder.pushOffset(10, 10); + builder.addTexture(0, width: 10, height: 10); + + final Scene scene = builder.build(); + final Image image = scene.toImageSync(10, 10); + scene.dispose(); + + expect(image.width, 10); + expect(image.height, 10); + + final ByteData? data = await image.toByteData(); + + expect(data, isNotNull); + expect(data!.lengthInBytes, 10 * 10 * 4); + expect(data.buffer.asUint8List()[0], 0); + expect(data.buffer.asUint8List()[1], 0); + expect(data.buffer.asUint8List()[2], 0); + expect(data.buffer.asUint8List()[3], 0); + }); + test('addPicture with disposed picture does not crash', () { bool assertsEnabled = false; assert(() { From 388340cfbf78a1173707c5b3dfaef2de9a69664f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 22:35:05 -0400 Subject: [PATCH 486/558] Roll Fuchsia Linux SDK from i7HhHxamwTC16efZ2... to 8N2zrCMhImBEPCtuC... (#35620) --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index fc28726696880..30561beb34bbc 100644 --- a/DEPS +++ b/DEPS @@ -674,7 +674,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'i7HhHxamwTC16efZ2HEccS4fabVfP0wTOc2-U1coVQwC' + 'version': '8N2zrCMhImBEPCtuCFCohtRIJRw1UxWRKIee5kvj5JMC' } ], 'condition': 'host_os == "linux" and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 3bbc4a732edca..9fb23e4a550a3 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: d4354d9ee2ed56bfd15e7ea752056758 +Signature: 6e8c8027dce5590b0915f65a18ff891f UNUSED LICENSES: From 6e315dd06ef475eb222c2402f8eac5114806af23 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 22 Aug 2022 23:07:23 -0400 Subject: [PATCH 487/558] Roll Skia from 26566799d0c3 to e38ad41e26b0 (1 revision) (#35621) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 30561beb34bbc..9e0ad70c98f86 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': '26566799d0c30082c53301655d1d374b7e858c1a', + 'skia_revision': 'e38ad41e26b0543bc0acea308068e31bfaf7574d', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index cd89970c8cd5a..b5a7bb5b49c7c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 53d25d67c63c570162cbc26dd12870af +Signature: 884ff17654ffb1f69253147a819d1689 UNUSED LICENSES: From 6138a016206388a70114fde29cd6c0a988620ee3 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 01:17:22 -0400 Subject: [PATCH 488/558] Roll Fuchsia Mac SDK from kZJxkRRI82W2CW_nM... to JocShsJvXYeSVjgvW... (#35625) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 9e0ad70c98f86..e80263ff32324 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'kZJxkRRI82W2CW_nMUOVsrVaVrQIM1yi-d06o_5_ACQC' + 'version': 'JocShsJvXYeSVjgvWtf8jbf-5Bkf5raVk7uNvChR1TkC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From a928e90da9324bdcd0a3da0481f494fe292c19e5 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 01:59:16 -0400 Subject: [PATCH 489/558] Roll Skia from e38ad41e26b0 to 7cb2672d04de (1 revision) (#35626) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e80263ff32324..e68ac9f5e21e2 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': 'e38ad41e26b0543bc0acea308068e31bfaf7574d', + 'skia_revision': '7cb2672d04def0c1b342db287a415e65644473ae', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index b5a7bb5b49c7c..c9a54d6fdc950 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 884ff17654ffb1f69253147a819d1689 +Signature: c334457ce301f3afe3f28fce07daa6c4 UNUSED LICENSES: From 11f1b5a17b56a9564a945c56859e65d81a6190b4 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 22 Aug 2022 23:17:37 -0700 Subject: [PATCH 490/558] [Impeller] Apply effects to layers (#35615) --- impeller/aiks/aiks_unittests.cc | 26 ++++++++++++++++ impeller/aiks/paint.cc | 19 +++++++----- impeller/aiks/paint.h | 22 ++++++++----- impeller/aiks/paint_pass_delegate.cc | 6 ++-- impeller/aiks/paint_pass_delegate.h | 3 +- .../display_list/display_list_dispatcher.cc | 19 +++++------- .../contents/filters/blend_filter_contents.cc | 1 + .../contents/filters/blend_filter_contents.h | 1 + .../border_mask_blur_filter_contents.cc | 11 ++++--- .../border_mask_blur_filter_contents.h | 7 +++-- .../filters/color_matrix_filter_contents.cc | 1 + .../filters/color_matrix_filter_contents.h | 1 + .../contents/filters/filter_contents.cc | 31 +++++++++++++------ .../entity/contents/filters/filter_contents.h | 18 ++++++++--- .../filters/gaussian_blur_filter_contents.cc | 22 +++++++------ .../filters/gaussian_blur_filter_contents.h | 7 +++-- .../filters/linear_to_srgb_filter_contents.cc | 1 + .../filters/linear_to_srgb_filter_contents.h | 1 + .../filters/srgb_to_linear_filter_contents.cc | 1 + .../filters/srgb_to_linear_filter_contents.h | 1 + impeller/entity/entity_pass.cc | 10 +++--- impeller/entity/entity_pass.h | 5 +-- impeller/entity/entity_pass_delegate.cc | 3 +- impeller/entity/entity_pass_delegate.h | 3 +- impeller/entity/entity_unittests.cc | 3 +- 25 files changed, 150 insertions(+), 73 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 7176d08f39f5c..8e8c52e2f81ca 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -1227,5 +1227,31 @@ TEST_P(AiksTest, CanRenderClippedLayers) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, SaveLayerFiltersScaleWithTransform) { + Canvas canvas; + canvas.Scale(GetContentScale()); + canvas.Translate(Vector2(100, 100)); + + auto texture = std::make_shared(CreateTextureForFixture("boston.jpg")); + auto draw_image_layer = [&canvas, &texture](Paint paint) { + canvas.SaveLayer(paint); + canvas.DrawImage(texture, {}, Paint{}); + canvas.Restore(); + }; + + Paint effect_paint; + effect_paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kNormal, + .sigma = Sigma{6}, + }; + draw_image_layer(effect_paint); + + canvas.Translate(Vector2(300, 300)); + canvas.Scale(Vector2(3, 3)); + draw_image_layer(effect_paint); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 0a6704de9147f..1702cb9f72b3c 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -42,17 +42,18 @@ std::shared_ptr Paint::CreateContentsForEntity(Path path, std::shared_ptr Paint::WithFilters( std::shared_ptr input, - std::optional is_solid_color) const { + std::optional is_solid_color, + const Matrix& effect_transform) const { bool is_solid_color_val = is_solid_color.value_or(!color_source); if (mask_blur_descriptor.has_value()) { - input = mask_blur_descriptor->CreateMaskBlur(FilterInput::Make(input), - is_solid_color_val); + input = mask_blur_descriptor->CreateMaskBlur( + FilterInput::Make(input), is_solid_color_val, effect_transform); } if (image_filter.has_value()) { const ImageFilterProc& filter = image_filter.value(); - input = filter(FilterInput::Make(input)); + input = filter(FilterInput::Make(input), effect_transform); } if (color_filter.has_value()) { @@ -65,12 +66,14 @@ std::shared_ptr Paint::WithFilters( std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( FilterInput::Ref input, - bool is_solid_color) const { + bool is_solid_color, + const Matrix& effect_transform) const { if (is_solid_color) { - return FilterContents::MakeGaussianBlur(input, sigma, sigma, style, - Entity::TileMode::kDecal); + return FilterContents::MakeGaussianBlur( + input, sigma, sigma, style, Entity::TileMode::kDecal, effect_transform); } - return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style); + return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style, + effect_transform); } } // namespace impeller diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index ba01221e3b3f9..02da68de57f87 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -19,12 +19,15 @@ namespace impeller { struct Paint { - using ImageFilterProc = + using ImageFilterProc = std::function( + FilterInput::Ref, + const Matrix& effect_transform)>; + using ColorFilterProc = std::function(FilterInput::Ref)>; - using ColorFilterProc = ImageFilterProc; - using MaskFilterProc = - std::function(FilterInput::Ref, - bool is_solid_color)>; + using MaskFilterProc = std::function( + FilterInput::Ref, + bool is_solid_color, + const Matrix& effect_transform)>; using ColorSourceProc = std::function()>; enum class Style { @@ -36,8 +39,10 @@ struct Paint { FilterContents::BlurStyle style; Sigma sigma; - std::shared_ptr CreateMaskBlur(FilterInput::Ref input, - bool is_solid_color) const; + std::shared_ptr CreateMaskBlur( + FilterInput::Ref input, + bool is_solid_color, + const Matrix& effect_matrix) const; }; Color color = Color::Black(); @@ -67,7 +72,8 @@ struct Paint { /// original contents is returned. std::shared_ptr WithFilters( std::shared_ptr input, - std::optional is_solid_color = std::nullopt) const; + std::optional is_solid_color = std::nullopt, + const Matrix& effect_transform = Matrix()) const; std::shared_ptr CreateContentsForEntity(Path path = {}, bool cover = false) const; diff --git a/impeller/aiks/paint_pass_delegate.cc b/impeller/aiks/paint_pass_delegate.cc index 146549f604daf..453da016714bf 100644 --- a/impeller/aiks/paint_pass_delegate.cc +++ b/impeller/aiks/paint_pass_delegate.cc @@ -33,12 +33,14 @@ bool PaintPassDelegate::CanCollapseIntoParentPass() { // |EntityPassDelgate| std::shared_ptr PaintPassDelegate::CreateContentsForSubpassTarget( - std::shared_ptr target) { + std::shared_ptr target, + const Matrix& effect_transform) { auto contents = TextureContents::MakeRect(Rect::MakeSize(target->GetSize())); contents->SetTexture(target); contents->SetSourceRect(Rect::MakeSize(target->GetSize())); contents->SetOpacity(paint_.color.alpha); - return contents; + + return paint_.WithFilters(std::move(contents), false, effect_transform); } } // namespace impeller diff --git a/impeller/aiks/paint_pass_delegate.h b/impeller/aiks/paint_pass_delegate.h index dcd94d16d8258..128f7b6abb14a 100644 --- a/impeller/aiks/paint_pass_delegate.h +++ b/impeller/aiks/paint_pass_delegate.h @@ -30,7 +30,8 @@ class PaintPassDelegate final : public EntityPassDelegate { // |EntityPassDelgate| std::shared_ptr CreateContentsForSubpassTarget( - std::shared_ptr target) override; + std::shared_ptr target, + const Matrix& effect_transform) override; private: const Paint paint_; diff --git a/impeller/display_list/display_list_dispatcher.cc b/impeller/display_list/display_list_dispatcher.cc index 8cdc086523f0e..378c960fe01c0 100644 --- a/impeller/display_list/display_list_dispatcher.cc +++ b/impeller/display_list/display_list_dispatcher.cc @@ -513,8 +513,7 @@ void DisplayListDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) { } static std::optional ToImageFilterProc( - const flutter::DlImageFilter* filter, - const Vector2& effect_scale = {1, 1}) { + const flutter::DlImageFilter* filter) { if (filter == nullptr) { return std::nullopt; } @@ -522,16 +521,15 @@ static std::optional ToImageFilterProc( switch (filter->type()) { case flutter::DlImageFilterType::kBlur: { auto blur = filter->asBlur(); - Vector2 scaled_blur = - Vector2(blur->sigma_x(), blur->sigma_y()) * effect_scale; - auto sigma_x = Sigma(scaled_blur.x); - auto sigma_y = Sigma(scaled_blur.y); + auto sigma_x = Sigma(blur->sigma_x()); + auto sigma_y = Sigma(blur->sigma_y()); auto tile_mode = ToTileMode(blur->tile_mode()); - return [sigma_x, sigma_y, tile_mode](FilterInput::Ref input) { + return [sigma_x, sigma_y, tile_mode](FilterInput::Ref input, + const Matrix& effect_transform) { return FilterContents::MakeGaussianBlur( input, sigma_x, sigma_y, FilterContents::BlurStyle::kNormal, - tile_mode); + tile_mode, effect_transform); }; break; @@ -578,10 +576,7 @@ void DisplayListDispatcher::saveLayer(const SkRect* bounds, const flutter::SaveLayerOptions options, const flutter::DlImageFilter* backdrop) { auto paint = options.renders_with_attributes() ? paint_ : Paint{}; - auto scale = canvas_.GetCurrentTransformation().GetScale(); - canvas_.SaveLayer( - paint, ToRect(bounds), - ToImageFilterProc(backdrop, Vector2::MakeXY(scale.x, scale.y))); + canvas_.SaveLayer(paint, ToRect(bounds), ToImageFilterProc(backdrop)); } // |flutter::Dispatcher| diff --git a/impeller/entity/contents/filters/blend_filter_contents.cc b/impeller/entity/contents/filters/blend_filter_contents.cc index 2a8e647fee3b3..bc115086d291c 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.cc +++ b/impeller/entity/contents/filters/blend_filter_contents.cc @@ -309,6 +309,7 @@ std::optional BlendFilterContents::RenderFilter( const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const { if (inputs.empty()) { return std::nullopt; diff --git a/impeller/entity/contents/filters/blend_filter_contents.h b/impeller/entity/contents/filters/blend_filter_contents.h index 22ec3040364b8..b0010f2db717e 100644 --- a/impeller/entity/contents/filters/blend_filter_contents.h +++ b/impeller/entity/contents/filters/blend_filter_contents.h @@ -33,6 +33,7 @@ class BlendFilterContents : public FilterContents { std::optional RenderFilter(const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const override; Entity::BlendMode blend_mode_ = Entity::BlendMode::kSourceOver; diff --git a/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc b/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc index 4cbf8c11d07f5..619f457a4e563 100644 --- a/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc @@ -51,6 +51,7 @@ std::optional BorderMaskBlurFilterContents::RenderFilter( const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const { using VS = BorderMaskBlurPipeline::VertexShader; using FS = BorderMaskBlurPipeline::FragmentShader; @@ -101,8 +102,9 @@ std::optional BorderMaskBlurFilterContents::RenderFilter( VS::FrameInfo frame_info; frame_info.mvp = Matrix::MakeOrthographic(ISize(1, 1)); - frame_info.sigma_uv = Vector2(sigma_x_.sigma, sigma_y_.sigma).Abs() / - input_snapshot->texture->GetSize(); + + auto sigma = effect_transform * Vector2(sigma_x_.sigma, sigma_y_.sigma); + frame_info.sigma_uv = sigma.Abs() / input_snapshot->texture->GetSize(); frame_info.src_factor = src_color_factor_; frame_info.inner_blur_factor = inner_blur_factor_; frame_info.outer_blur_factor = outer_blur_factor_; @@ -127,7 +129,8 @@ std::optional BorderMaskBlurFilterContents::RenderFilter( std::optional BorderMaskBlurFilterContents::GetFilterCoverage( const FilterInput::Vector& inputs, - const Entity& entity) const { + const Entity& entity, + const Matrix& effect_transform) const { if (inputs.empty()) { return std::nullopt; } @@ -136,7 +139,7 @@ std::optional BorderMaskBlurFilterContents::GetFilterCoverage( if (!coverage.has_value()) { return std::nullopt; } - auto transform = inputs[0]->GetTransform(entity); + auto transform = inputs[0]->GetTransform(entity) * effect_transform; auto transformed_blur_vector = transform.TransformDirection(Vector2(Radius{sigma_x_}.radius, 0)).Abs() + transform.TransformDirection(Vector2(0, Radius{sigma_y_}.radius)).Abs(); diff --git a/impeller/entity/contents/filters/border_mask_blur_filter_contents.h b/impeller/entity/contents/filters/border_mask_blur_filter_contents.h index 407c7b9d52319..9d971f5a11fdf 100644 --- a/impeller/entity/contents/filters/border_mask_blur_filter_contents.h +++ b/impeller/entity/contents/filters/border_mask_blur_filter_contents.h @@ -22,8 +22,10 @@ class BorderMaskBlurFilterContents final : public FilterContents { void SetBlurStyle(BlurStyle blur_style); // |FilterContents| - std::optional GetFilterCoverage(const FilterInput::Vector& inputs, - const Entity& entity) const override; + std::optional GetFilterCoverage( + const FilterInput::Vector& inputs, + const Entity& entity, + const Matrix& effect_transform) const override; private: // |FilterContents| @@ -31,6 +33,7 @@ class BorderMaskBlurFilterContents final : public FilterContents { const FilterInput::Vector& input_textures, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const override; Sigma sigma_x_; diff --git a/impeller/entity/contents/filters/color_matrix_filter_contents.cc b/impeller/entity/contents/filters/color_matrix_filter_contents.cc index 3280e98df1d4a..78409bad759fd 100644 --- a/impeller/entity/contents/filters/color_matrix_filter_contents.cc +++ b/impeller/entity/contents/filters/color_matrix_filter_contents.cc @@ -27,6 +27,7 @@ std::optional ColorMatrixFilterContents::RenderFilter( const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const { using VS = ColorMatrixColorFilterPipeline::VertexShader; using FS = ColorMatrixColorFilterPipeline::FragmentShader; diff --git a/impeller/entity/contents/filters/color_matrix_filter_contents.h b/impeller/entity/contents/filters/color_matrix_filter_contents.h index e2448566d895c..b725249019106 100644 --- a/impeller/entity/contents/filters/color_matrix_filter_contents.h +++ b/impeller/entity/contents/filters/color_matrix_filter_contents.h @@ -28,6 +28,7 @@ class ColorMatrixFilterContents final : public FilterContents { const FilterInput::Vector& input_textures, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const override; ColorMatrix matrix_; diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index 694c56ef952ca..10e3601ea0212 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -78,7 +78,8 @@ std::shared_ptr FilterContents::MakeDirectionalGaussianBlur( Vector2 direction, BlurStyle blur_style, Entity::TileMode tile_mode, - FilterInput::Ref source_override) { + FilterInput::Ref source_override, + const Matrix& effect_transform) { auto blur = std::make_shared(); blur->SetInputs({input}); blur->SetSigma(sigma); @@ -86,6 +87,7 @@ std::shared_ptr FilterContents::MakeDirectionalGaussianBlur( blur->SetBlurStyle(blur_style); blur->SetTileMode(tile_mode); blur->SetSourceOverride(source_override); + blur->SetEffectTransform(effect_transform); return blur; } @@ -94,12 +96,14 @@ std::shared_ptr FilterContents::MakeGaussianBlur( Sigma sigma_x, Sigma sigma_y, BlurStyle blur_style, - Entity::TileMode tile_mode) { + Entity::TileMode tile_mode, + const Matrix& effect_transform) { auto x_blur = MakeDirectionalGaussianBlur(input, sigma_x, Point(1, 0), - BlurStyle::kNormal, tile_mode); - auto y_blur = - MakeDirectionalGaussianBlur(FilterInput::Make(x_blur), sigma_y, - Point(0, 1), blur_style, tile_mode, input); + BlurStyle::kNormal, tile_mode, + nullptr, effect_transform); + auto y_blur = MakeDirectionalGaussianBlur(FilterInput::Make(x_blur), sigma_y, + Point(0, 1), blur_style, tile_mode, + input, effect_transform); return y_blur; } @@ -107,11 +111,13 @@ std::shared_ptr FilterContents::MakeBorderMaskBlur( FilterInput::Ref input, Sigma sigma_x, Sigma sigma_y, - BlurStyle blur_style) { + BlurStyle blur_style, + const Matrix& effect_transform) { auto filter = std::make_shared(); filter->SetInputs({input}); filter->SetSigma(sigma_x, sigma_y); filter->SetBlurStyle(blur_style); + filter->SetEffectTransform(effect_transform); return filter; } @@ -150,6 +156,10 @@ void FilterContents::SetCoverageCrop(std::optional coverage_crop) { coverage_crop_ = coverage_crop; } +void FilterContents::SetEffectTransform(Matrix effect_transform) { + effect_transform_ = effect_transform.Basis(); +} + bool FilterContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { @@ -183,7 +193,7 @@ bool FilterContents::Render(const ContentContext& renderer, std::optional FilterContents::GetLocalCoverage( const Entity& local_entity) const { - auto coverage = GetFilterCoverage(inputs_, local_entity); + auto coverage = GetFilterCoverage(inputs_, local_entity, effect_transform_); if (coverage_crop_.has_value() && coverage.has_value()) { coverage = coverage->Intersection(coverage_crop_.value()); } @@ -201,7 +211,8 @@ std::optional FilterContents::GetCoverage(const Entity& entity) const { std::optional FilterContents::GetFilterCoverage( const FilterInput::Vector& inputs, - const Entity& entity) const { + const Entity& entity, + const Matrix& effect_transform) const { // The default coverage of FilterContents is just the union of its inputs' // coverage. FilterContents implementations may choose to adjust this // coverage depending on the use case. @@ -238,7 +249,7 @@ std::optional FilterContents::RenderToSnapshot( } return RenderFilter(inputs_, renderer, entity_with_local_transform, - coverage.value()); + effect_transform_, coverage.value()); } Matrix FilterContents::GetLocalTransform() const { diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 1ee7a5813aef0..87333aed8f4f2 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -47,20 +47,23 @@ class FilterContents : public Contents { Vector2 direction, BlurStyle blur_style = BlurStyle::kNormal, Entity::TileMode tile_mode = Entity::TileMode::kDecal, - FilterInput::Ref alpha_mask = nullptr); + FilterInput::Ref alpha_mask = nullptr, + const Matrix& effect_transform = Matrix()); static std::shared_ptr MakeGaussianBlur( FilterInput::Ref input, Sigma sigma_x, Sigma sigma_y, BlurStyle blur_style = BlurStyle::kNormal, - Entity::TileMode tile_mode = Entity::TileMode::kDecal); + Entity::TileMode tile_mode = Entity::TileMode::kDecal, + const Matrix& effect_transform = Matrix()); static std::shared_ptr MakeBorderMaskBlur( FilterInput::Ref input, Sigma sigma_x, Sigma sigma_y, - BlurStyle blur_style = BlurStyle::kNormal); + BlurStyle blur_style = BlurStyle::kNormal, + const Matrix& effect_transform = Matrix()); static std::shared_ptr MakeColorMatrix( FilterInput::Ref input, @@ -86,6 +89,10 @@ class FilterContents : public Contents { /// @brief Screen space bounds to use for cropping the filter output. void SetCoverageCrop(std::optional coverage_crop); + /// @brief Sets the transform which gets appended to the effect of this + /// filter. Note that this is in addition to the entity's transform. + void SetEffectTransform(Matrix effect_transform); + // |Contents| bool Render(const ContentContext& renderer, const Entity& entity, @@ -105,19 +112,22 @@ class FilterContents : public Contents { private: virtual std::optional GetFilterCoverage( const FilterInput::Vector& inputs, - const Entity& entity) const; + const Entity& entity, + const Matrix& effect_transform) const; /// @brief Converts zero or more filter inputs into a new texture. virtual std::optional RenderFilter( const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const = 0; std::optional GetLocalCoverage(const Entity& local_entity) const; FilterInput::Vector inputs_; std::optional coverage_crop_; + Matrix effect_transform_; FML_DISALLOW_COPY_AND_ASSIGN(FilterContents); }; diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index a9f2ceed5ba9f..adbcf754a28c6 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -7,6 +7,7 @@ #include #include +#include "impeller/base/strings.h" #include "impeller/base/validation.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/contents/filters/filter_contents.h" @@ -79,6 +80,7 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const { using VS = GaussianBlurPipeline::VertexShader; using FS = GaussianBlurPipeline::FragmentShader; @@ -104,8 +106,9 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( auto radius = Radius{blur_sigma_}.radius; + auto transform = entity.GetTransformation() * effect_transform; auto transformed_blur_radius = - entity.GetTransformation().TransformDirection(blur_direction_ * radius); + transform.TransformDirection(blur_direction_ * radius); auto transformed_blur_radius_length = transformed_blur_radius.GetLength(); @@ -176,9 +179,9 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( frag_info.alpha_mask_sampler_y_coord_scale = source_snapshot->texture->GetYCoordScale(); - auto radius = Radius{transformed_blur_radius_length}; - frag_info.blur_sigma = Sigma{radius}.sigma; - frag_info.blur_radius = radius.radius; + auto r = Radius{transformed_blur_radius_length}; + frag_info.blur_sigma = Sigma{r}.sigma; + frag_info.blur_radius = r.radius; // The blur direction is in input UV space. frag_info.blur_direction = @@ -191,7 +194,8 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( frag_info.texture_size = Point(input_snapshot->GetCoverage().value().size); Command cmd; - cmd.label = "Gaussian Blur Filter"; + cmd.label = SPrintF("Gaussian Blur Filter (Radius=%.2f)", + transformed_blur_radius_length); auto options = OptionsFromPass(pass); options.blend_mode = Entity::BlendMode::kSource; cmd.pipeline = renderer.GetGaussianBlurPipeline(options); @@ -236,7 +240,8 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( std::optional DirectionalGaussianBlurFilterContents::GetFilterCoverage( const FilterInput::Vector& inputs, - const Entity& entity) const { + const Entity& entity, + const Matrix& effect_transform) const { if (inputs.empty()) { return std::nullopt; } @@ -246,10 +251,9 @@ std::optional DirectionalGaussianBlurFilterContents::GetFilterCoverage( return std::nullopt; } + auto transform = inputs[0]->GetTransform(entity) * effect_transform; auto transformed_blur_vector = - inputs[0] - ->GetTransform(entity) - .TransformDirection(blur_direction_ * Radius{blur_sigma_}.radius) + transform.TransformDirection(blur_direction_ * Radius{blur_sigma_}.radius) .Abs(); auto extent = coverage->size + transformed_blur_vector * 2; return Rect(coverage->origin - transformed_blur_vector, diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index a7eed40b1806b..1e2ec6b3ab544 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h @@ -28,8 +28,10 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents { void SetSourceOverride(FilterInput::Ref alpha_mask); // |FilterContents| - std::optional GetFilterCoverage(const FilterInput::Vector& inputs, - const Entity& entity) const override; + std::optional GetFilterCoverage( + const FilterInput::Vector& inputs, + const Entity& entity, + const Matrix& effect_transform) const override; private: // |FilterContents| @@ -37,6 +39,7 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents { const FilterInput::Vector& input_textures, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const override; Sigma blur_sigma_; Vector2 blur_direction_; diff --git a/impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc b/impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc index ff9b65087b7a4..3d7ffdae9cf83 100644 --- a/impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc +++ b/impeller/entity/contents/filters/linear_to_srgb_filter_contents.cc @@ -21,6 +21,7 @@ std::optional LinearToSrgbFilterContents::RenderFilter( const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const { if (inputs.empty()) { return std::nullopt; diff --git a/impeller/entity/contents/filters/linear_to_srgb_filter_contents.h b/impeller/entity/contents/filters/linear_to_srgb_filter_contents.h index ec1424c2573da..271ac250ca711 100644 --- a/impeller/entity/contents/filters/linear_to_srgb_filter_contents.h +++ b/impeller/entity/contents/filters/linear_to_srgb_filter_contents.h @@ -21,6 +21,7 @@ class LinearToSrgbFilterContents final : public FilterContents { const FilterInput::Vector& input_textures, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const override; FML_DISALLOW_COPY_AND_ASSIGN(LinearToSrgbFilterContents); diff --git a/impeller/entity/contents/filters/srgb_to_linear_filter_contents.cc b/impeller/entity/contents/filters/srgb_to_linear_filter_contents.cc index bef5543d24a37..3c3a5fa1befbb 100644 --- a/impeller/entity/contents/filters/srgb_to_linear_filter_contents.cc +++ b/impeller/entity/contents/filters/srgb_to_linear_filter_contents.cc @@ -21,6 +21,7 @@ std::optional SrgbToLinearFilterContents::RenderFilter( const FilterInput::Vector& inputs, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const { if (inputs.empty()) { return std::nullopt; diff --git a/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h b/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h index 099aced7bffd5..11d0dc762cffa 100644 --- a/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h +++ b/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h @@ -21,6 +21,7 @@ class SrgbToLinearFilterContents final : public FilterContents { const FilterInput::Vector& input_textures, const ContentContext& renderer, const Entity& entity, + const Matrix& effect_transform, const Rect& coverage) const override; FML_DISALLOW_COPY_AND_ASSIGN(SrgbToLinearFilterContents); diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 832dfe8273404..be4dc731182ac 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -240,7 +240,8 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( auto texture = pass_context.GetTexture(); // Render the backdrop texture before any of the pass elements. const auto& proc = subpass->backdrop_filter_proc_.value(); - backdrop_contents = proc(FilterInput::Make(std::move(texture))); + backdrop_contents = + proc(FilterInput::Make(std::move(texture)), subpass->xformation_); // The subpass will need to read from the current pass texture when // rendering the backdrop, so if there's an active pass, end it prior to @@ -304,7 +305,8 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( } auto offscreen_texture_contents = - subpass->delegate_->CreateContentsForSubpassTarget(subpass_texture); + subpass->delegate_->CreateContentsForSubpassTarget( + subpass_texture, subpass->xformation_); if (!offscreen_texture_contents) { // This is an error because the subpass delegate said the pass couldn't @@ -329,10 +331,6 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( element_entity.SetContents(std::move(offscreen_texture_contents)); element_entity.SetStencilDepth(subpass->stencil_depth_); element_entity.SetBlendMode(subpass->blend_mode_); - // Once we have filters being applied for SaveLayer, some special sauce - // may be needed here (or in PaintPassDelegate) to ensure the filter - // parameters are transformed by the `xformation_` matrix, while - // continuing to apply only the subpass offset to the offscreen texture. element_entity.SetTransformation( Matrix::MakeTranslation(Vector3(subpass_coverage->origin - position))); } else { diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index 7ec177f68f5c8..16f6a25842f57 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -25,8 +25,9 @@ class ContentContext; class EntityPass { public: using Element = std::variant>; - using BackdropFilterProc = - std::function(FilterInput::Ref)>; + using BackdropFilterProc = std::function( + FilterInput::Ref, + const Matrix& effect_transform)>; EntityPass(); diff --git a/impeller/entity/entity_pass_delegate.cc b/impeller/entity/entity_pass_delegate.cc index 00963048a6e9e..529c8698f68bd 100644 --- a/impeller/entity/entity_pass_delegate.cc +++ b/impeller/entity/entity_pass_delegate.cc @@ -28,7 +28,8 @@ class DefaultEntityPassDelegate final : public EntityPassDelegate { // |EntityPassDelegate| std::shared_ptr CreateContentsForSubpassTarget( - std::shared_ptr target) override { + std::shared_ptr target, + const Matrix& effect_transform) override { // Not possible since this pass always collapses into its parent. FML_UNREACHABLE(); } diff --git a/impeller/entity/entity_pass_delegate.h b/impeller/entity/entity_pass_delegate.h index 19dd4f01f8fdc..28f485c1237f7 100644 --- a/impeller/entity/entity_pass_delegate.h +++ b/impeller/entity/entity_pass_delegate.h @@ -27,7 +27,8 @@ class EntityPassDelegate { virtual bool CanCollapseIntoParentPass() = 0; virtual std::shared_ptr CreateContentsForSubpassTarget( - std::shared_ptr target) = 0; + std::shared_ptr target, + const Matrix& effect_transform) = 0; private: FML_DISALLOW_COPY_AND_ASSIGN(EntityPassDelegate); diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index 76c62dc976fa7..ad5a67c816b13 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -61,7 +61,8 @@ class TestPassDelegate final : public EntityPassDelegate { // |EntityPassDelgate| std::shared_ptr CreateContentsForSubpassTarget( - std::shared_ptr target) override { + std::shared_ptr target, + const Matrix& transform) override { return nullptr; } From d40c48f50bb2d233e9921f049445daaeccab8520 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 02:49:10 -0400 Subject: [PATCH 491/558] Roll Dart SDK from 744430878593 to e078774a275e (2 revisions) (#35627) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index e68ac9f5e21e2..0d3c6bbb424cd 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '744430878593ea6bf130712fe2557c434399cc38', + 'dart_revision': 'e078774a275ea8d9d3b1b111d2db098bf48fa428', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -46,7 +46,7 @@ vars = { 'dart_clock_rev': '2507a228773c5e877fc9e3330080b234aad965c0', 'dart_collection_rev': '414ffa1bc8ba18bd608bbf916d95715311d89ac1', 'dart_devtools_rev': 'd131d19091f6b89ac89486bd92440a25a523e8b0', - 'dart_protobuf_rev': '9cf05f6e9f53d88b4b6c1f6f1accec09bcd5cca7', + 'dart_protobuf_rev': '8337a7910fef805214e5aae35a98abd481d87a18', 'dart_pub_rev': 'ac7db6c07318efa4a8712110275eaf70f96a6d00', 'dart_root_certificates_rev': '692f6d6488af68e0121317a9c2c9eb393eb0ee50', 'dart_watcher_rev': 'e00c0ea769e32821d91c0880da8eb736839a6e6d', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 47dee475fe15c..09ca18d7bf089 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 0e240be838d32639b8bb4dc3fe2c4cce +Signature: 4ee683d18ebd990bfec031fe69992fc1 UNUSED LICENSES: From 9e2a8313acbc7db2689b3e3b9c84f3b774885dc4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 03:11:04 -0400 Subject: [PATCH 492/558] Roll Skia from 7cb2672d04de to ec632aa9654c (2 revisions) (#35628) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0d3c6bbb424cd..72047c6e90da4 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': '7cb2672d04def0c1b342db287a415e65644473ae', + 'skia_revision': 'ec632aa9654cd3e103873fdd47cc7ef44d00e533', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index c9a54d6fdc950..3252bd12e7a14 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: c334457ce301f3afe3f28fce07daa6c4 +Signature: 14903463b8fdad4a9a064b2a1771af1c UNUSED LICENSES: From d9cb4b27880376b97f90ecbddeec8a8e248d0097 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 05:11:21 -0400 Subject: [PATCH 493/558] Roll Skia from ec632aa9654c to 1c7777d47b15 (1 revision) (#35629) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 72047c6e90da4..6682e98cfe006 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': 'ec632aa9654cd3e103873fdd47cc7ef44d00e533', + 'skia_revision': '1c7777d47b1575e5c020c346e5d3f80860639830', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 3252bd12e7a14..ca6ec8e048b36 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 14903463b8fdad4a9a064b2a1771af1c +Signature: d368565dfb12ebabd204af8abb16766f UNUSED LICENSES: From 8c29591b89a36095ad5c769f342e46e87db75edb Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 07:16:39 -0400 Subject: [PATCH 494/558] Roll Dart SDK from e078774a275e to 03506589f2d0 (1 revision) (#35630) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6682e98cfe006..24ca9b02c8f2a 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'e078774a275ea8d9d3b1b111d2db098bf48fa428', + 'dart_revision': '03506589f2d0d0b0e87b376959ec0578441b4bee', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 09ca18d7bf089..317a33d2edd1d 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 4ee683d18ebd990bfec031fe69992fc1 +Signature: 17bdface7e5781ab2d5bf4b03c081d8b UNUSED LICENSES: From c9d0a012817d5521d9cc1ffa032806c975370024 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 09:08:04 -0400 Subject: [PATCH 495/558] Roll Skia from 1c7777d47b15 to b91dbe274717 (1 revision) (#35631) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 24ca9b02c8f2a..77f12a8f04cf2 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': '1c7777d47b1575e5c020c346e5d3f80860639830', + 'skia_revision': 'b91dbe27471709e4f2f49c263cd0ce6a8fb40926', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index ca6ec8e048b36..6c42c506c0098 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d368565dfb12ebabd204af8abb16766f +Signature: b1f131b413b43b41079328ef527becb3 UNUSED LICENSES: From 94f97c3373d2b583ff7383ca7219475ebb7c16ef Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 10:19:17 -0400 Subject: [PATCH 496/558] Roll Skia from b91dbe274717 to 94602de608e0 (4 revisions) (#35634) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 77f12a8f04cf2..b69c378646ac5 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': 'b91dbe27471709e4f2f49c263cd0ce6a8fb40926', + 'skia_revision': '94602de608e0e5f4f9c55698a52c9317a29e413f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 6c42c506c0098..171af86d47d22 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b1f131b413b43b41079328ef527becb3 +Signature: a45b8bc6436fa6766000c5270c869d83 UNUSED LICENSES: From 6ec08c50e3fea1497ba7ea434fafccf3a22eafa7 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 11:31:09 -0400 Subject: [PATCH 497/558] Roll Skia from 94602de608e0 to 8c32b0148770 (7 revisions) (#35636) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b69c378646ac5..cfac412874ab8 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': '94602de608e0e5f4f9c55698a52c9317a29e413f', + 'skia_revision': '8c32b0148770ed29edc93c193d67b02ea8086a67', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 171af86d47d22..145b1c4056944 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: a45b8bc6436fa6766000c5270c869d83 +Signature: eae82dadf40480dc7ff289363104a661 UNUSED LICENSES: From 9195b7a2f8859a70488160ff56197d0a3dbf47dc Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 11:35:07 -0400 Subject: [PATCH 498/558] Roll Dart SDK from 03506589f2d0 to c064b9bacc4d (1 revision) (#35637) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index cfac412874ab8..2fafa22ca7b54 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '03506589f2d0d0b0e87b376959ec0578441b4bee', + 'dart_revision': 'c064b9bacc4d77fd9d7b34d2579bc222a05e3d4b', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -329,7 +329,7 @@ deps = { Var('dart_git') + '/yaml_edit.git' + '@' + Var('dart_yaml_edit_rev'), 'src/third_party/dart/tools/sdks': - {'packages': [{'version': 'version:2.18.0-271.0.dev', 'package': 'dart/dart-sdk/${{platform}}'}], 'dep_type': 'cipd'}, + {'packages': [{'version': 'version:2.18.0-271.7.beta', 'package': 'dart/dart-sdk/${{platform}}'}], 'dep_type': 'cipd'}, # WARNING: end of dart dependencies list that is cleaned up automatically - see create_updated_flutter_deps.py. diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 317a33d2edd1d..8122a31f3cf52 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 17bdface7e5781ab2d5bf4b03c081d8b +Signature: 3ea51e98d8621b5a61e172e21a7db59d UNUSED LICENSES: From f7ec70782a851efa457bf086f9970ef65261bc4e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 12:46:04 -0400 Subject: [PATCH 499/558] Roll Skia from 8c32b0148770 to a9a05d0bf0c5 (3 revisions) (#35639) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 2fafa22ca7b54..4c7186d7d5296 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': '8c32b0148770ed29edc93c193d67b02ea8086a67', + 'skia_revision': 'a9a05d0bf0c58279cde002d951fca45076b4f46b', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 145b1c4056944..5cc2112397a4c 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: eae82dadf40480dc7ff289363104a661 +Signature: e280f9c1e16928c270dc463392d72b76 UNUSED LICENSES: @@ -6604,6 +6604,8 @@ FILE: ../../../third_party/skia/gm/drawlines_with_local_matrix.cpp FILE: ../../../third_party/skia/gm/palette.cpp FILE: ../../../third_party/skia/include/core/SkOpenTypeSVGDecoder.h FILE: ../../../third_party/skia/modules/skottie/src/BlendModes.cpp +FILE: ../../../third_party/skia/modules/skottie/src/text/Font.cpp +FILE: ../../../third_party/skia/modules/skottie/src/text/Font.h FILE: ../../../third_party/skia/modules/skunicode/src/SkUnicode_client.cpp FILE: ../../../third_party/skia/modules/svg/include/SkSVGOpenTypeSVGDecoder.h FILE: ../../../third_party/skia/modules/svg/src/SkSVGOpenTypeSVGDecoder.cpp From 15cf53accf2f8756ec8a81666a4ee60fe8640bde Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 23 Aug 2022 10:56:31 -0700 Subject: [PATCH 500/558] Image shader dispose (#35640) --- lib/ui/dart_ui.cc | 1 + lib/ui/painting.dart | 35 +++++++++++++++++++ lib/ui/painting/image_shader.cc | 5 +++ lib/ui/painting/image_shader.h | 2 ++ lib/web_ui/lib/painting.dart | 6 +++- .../lib/src/engine/canvaskit/shader.dart | 21 +++++++++++ .../src/engine/html/shaders/image_shader.dart | 21 +++++++++++ lib/web_ui/test/canvaskit/shader_test.dart | 4 +++ .../drawing/draw_vertices_golden_test.dart | 4 +++ testing/dart/image_shader_test.dart | 26 ++++++++++++++ 10 files changed, 124 insertions(+), 1 deletion(-) diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index 61d35c5cd2a5c..c669b920576be 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -185,6 +185,7 @@ typedef CanvasPath Path; V(ImageFilter, initColorFilter, 2) \ V(ImageFilter, initComposeFilter, 3) \ V(ImageFilter, initMatrix, 3) \ + V(ImageShader, dispose, 1) \ V(ImageShader, initWithImage, 6) \ V(ImmutableBuffer, dispose, 1) \ V(ImmutableBuffer, length, 1) \ diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 90bb63654b396..95ff6d5009f20 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4050,6 +4050,41 @@ class ImageShader extends Shader { @FfiNative, Pointer, Int32, Int32, Int32, Handle)>('ImageShader::initWithImage') external String? _initWithImage(_Image image, int tmx, int tmy, int filterQualityIndex, Float64List matrix4); + + bool _debugDisposed = false; + + /// Whether [dispose] has been called. + /// + /// This must only be used when asserts are enabled. Otherwise, it will throw. + bool get debugDisposed { + late bool disposed; + assert(() { + disposed = _debugDisposed; + return true; + }()); + return disposed; + } + + /// Release the resources used by this object. The object is no longer usable + /// after this method is called. + /// + /// The underlying memory allocated by this object will be retained beyond + /// this call if it is still needed by another object that has not been + /// disposed. For example, an [Picture] that has not been disposed that + /// refers to this [ImageShader] may keep its underlying resources alive. + void dispose() { + assert(() { + assert(!_debugDisposed); + _debugDisposed = true; + return true; + }()); + _dispose(); + } + + /// This can't be a leaf call because the native function calls Dart API + /// (Dart_SetNativeInstanceField). + @FfiNative)>('ImageShader::dispose') + external void _dispose(); } /// An instance of [FragmentProgram] creates [Shader] objects (as used by [Paint.shader]) that run SPIR-V code. diff --git a/lib/ui/painting/image_shader.cc b/lib/ui/painting/image_shader.cc index c7416bc86652c..85d4740de5a73 100644 --- a/lib/ui/painting/image_shader.cc +++ b/lib/ui/painting/image_shader.cc @@ -69,6 +69,11 @@ int ImageShader::height() { return image_->height(); } +void ImageShader::dispose() { + image_.reset(); + ClearDartWrapper(); +} + ImageShader::ImageShader() = default; ImageShader::~ImageShader() = default; diff --git a/lib/ui/painting/image_shader.h b/lib/ui/painting/image_shader.h index 27fd3f72e3888..d130c5d53c390 100644 --- a/lib/ui/painting/image_shader.h +++ b/lib/ui/painting/image_shader.h @@ -35,6 +35,8 @@ class ImageShader : public Shader { int width(); int height(); + void dispose(); + private: ImageShader(); diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index 40bc7fb65e31c..c4f41803c0285 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -744,12 +744,16 @@ class Shadow { String toString() => 'TextShadow($color, $offset, $blurRadius)'; } -class ImageShader extends Shader { +abstract class ImageShader extends Shader { factory ImageShader(Image image, TileMode tmx, TileMode tmy, Float64List matrix4, { FilterQuality? filterQuality, }) => engine.useCanvasKit ? engine.CkImageShader(image, tmx, tmy, matrix4, filterQuality) : engine.EngineImageShader(image, tmx, tmy, matrix4, filterQuality); + + void dispose(); + + bool get debugDisposed; } class ImmutableBuffer { diff --git a/lib/web_ui/lib/src/engine/canvaskit/shader.dart b/lib/web_ui/lib/src/engine/canvaskit/shader.dart index 94ac8f22122af..febaacd811567 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/shader.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/shader.dart @@ -224,4 +224,25 @@ class CkImageShader extends CkShader implements ui.ImageShader { void delete() { rawSkiaObject?.delete(); } + + bool _disposed = false; + + @override + bool get debugDisposed { + late bool disposed; + assert(() { + disposed = _disposed; + return true; + }()); + return disposed; + } + + @override + void dispose() { + assert(() { + _disposed = true; + return true; + }()); + _image.dispose(); + } } diff --git a/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart b/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart index 63573eff49ec6..60cca92e3db03 100644 --- a/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart +++ b/lib/web_ui/lib/src/engine/html/shaders/image_shader.dart @@ -265,4 +265,25 @@ class EngineImageShader implements ui.ImageShader { gl.bindElementArrayBuffer(null); return context!.createPattern(bitmapImage!, 'no-repeat')!; } + + bool _disposed = false; + + @override + bool get debugDisposed { + late bool disposed; + assert(() { + disposed = _disposed; + return true; + }()); + return disposed; + } + + @override + void dispose() { + assert(() { + _disposed = true; + return true; + }()); + image.dispose(); + } } diff --git a/lib/web_ui/test/canvaskit/shader_test.dart b/lib/web_ui/test/canvaskit/shader_test.dart index 0c0dcda41845c..619cf9dd196c4 100644 --- a/lib/web_ui/test/canvaskit/shader_test.dart +++ b/lib/web_ui/test/canvaskit/shader_test.dart @@ -70,6 +70,10 @@ void testMain() { Float64List.fromList(Matrix4.diagonal3Values(1, 2, 3).storage), ) as CkImageShader; expect(imageShader, isA()); + + expect(imageShader.debugDisposed, false); + imageShader.dispose(); + expect(imageShader.debugDisposed, true); }); }); } diff --git a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart index bb981854e2f0b..7ba70b6e0925a 100644 --- a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart +++ b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart @@ -393,6 +393,10 @@ Future testMain() async { rc.drawVertices(vertices as SurfaceVertices, BlendMode.srcOver, paint); await checkScreenshot(rc, filename, maxDiffRatePercent: 1.0); + + expect(imgShader.debugDisposed, false); + imgShader.dispose(); + expect(imgShader.debugDisposed, true); } test('Should draw triangle with texture and indices', () async { diff --git a/testing/dart/image_shader_test.dart b/testing/dart/image_shader_test.dart index 25b8b2dafb4f5..ea174ac29fa8c 100644 --- a/testing/dart/image_shader_test.dart +++ b/testing/dart/image_shader_test.dart @@ -9,12 +9,28 @@ import 'package:litetest/litetest.dart'; import 'canvas_test.dart' show createImage, testCanvas; void main() { + bool assertsEnabled = false; + assert(() { + assertsEnabled = true; + return true; + }()); + test('Construct an ImageShader', () async { final Image image = await createImage(50, 50); final ImageShader shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Float64List(16)); final Paint paint = Paint()..shader=shader; const Rect rect = Rect.fromLTRB(0, 0, 100, 100); testCanvas((Canvas canvas) => canvas.drawRect(rect, paint)); + + if (assertsEnabled) { + expect(shader.debugDisposed, false); + } + shader.dispose(); + if (assertsEnabled) { + expect(shader.debugDisposed, true); + } + + image.dispose(); }); test('Construct an ImageShader - GPU image', () async { @@ -29,5 +45,15 @@ void main() { final Paint paint = Paint()..shader=shader; const Rect rect = Rect.fromLTRB(0, 0, 100, 100); testCanvas((Canvas canvas) => canvas.drawRect(rect, paint)); + + if (assertsEnabled) { + expect(shader.debugDisposed, false); + } + shader.dispose(); + if (assertsEnabled) { + expect(shader.debugDisposed, true); + } + + image.dispose(); }); } From ee3cd0d8a91de958f589f02a78f9fe16626cedca Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 14:00:23 -0400 Subject: [PATCH 501/558] Roll Skia from a9a05d0bf0c5 to 147232a3cebc (2 revisions) (#35641) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 4c7186d7d5296..7ac49e16c7256 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': 'a9a05d0bf0c58279cde002d951fca45076b4f46b', + 'skia_revision': '147232a3cebc39f7b6771425b39d44bb0aef51a8', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 5cc2112397a4c..0e93b84f871ed 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e280f9c1e16928c270dc463392d72b76 +Signature: b2c9d84c4dafbb5e1ff3fb52e8a2e9ed UNUSED LICENSES: From 5f53ee3b23cafd820368551695ab53ff58f064b7 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 23 Aug 2022 11:08:27 -0700 Subject: [PATCH 502/558] [Impeller] Use linear sampling for reads in the texture atlas (#35618) --- impeller/entity/contents/text_contents.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/impeller/entity/contents/text_contents.cc b/impeller/entity/contents/text_contents.cc index 17b5f9948ac6a..c082aabb4a1b3 100644 --- a/impeller/entity/contents/text_contents.cc +++ b/impeller/entity/contents/text_contents.cc @@ -9,7 +9,9 @@ #include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity.h" #include "impeller/geometry/path_builder.h" +#include "impeller/renderer/formats.h" #include "impeller/renderer/render_pass.h" +#include "impeller/renderer/sampler_descriptor.h" #include "impeller/renderer/sampler_library.h" #include "impeller/tessellator/tessellator.h" #include "impeller/typographer/glyph_atlas.h" @@ -93,11 +95,16 @@ bool TextContents::Render(const ContentContext& renderer, frame_info.text_color = ToVector(color_.Premultiply()); VS::BindFrameInfo(cmd, pass.GetTransientsBuffer().EmplaceUniform(frame_info)); + SamplerDescriptor sampler_desc; + sampler_desc.min_filter = MinMagFilter::kLinear; + sampler_desc.mag_filter = MinMagFilter::kLinear; + // Common fragment uniforms for all glyphs. FS::BindGlyphAtlasSampler( - cmd, // command - atlas->GetTexture(), // texture - renderer.GetContext()->GetSamplerLibrary()->GetSampler({}) // sampler + cmd, // command + atlas->GetTexture(), // texture + renderer.GetContext()->GetSamplerLibrary()->GetSampler( + sampler_desc) // sampler ); // Common vertex information for all glyphs. From 4ff7f7b9a88fec077aefd2f631cb3089901f7e2c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 14:13:29 -0400 Subject: [PATCH 503/558] Roll Fuchsia Mac SDK from JocShsJvXYeSVjgvW... to Es8SXkqDOYZ5dgYTq... (#35642) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 7ac49e16c7256..f68600ddac93d 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'JocShsJvXYeSVjgvWtf8jbf-5Bkf5raVk7uNvChR1TkC' + 'version': 'Es8SXkqDOYZ5dgYTq4UVERgHhIPYuo1vKJJUF55pnO4C' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 565cc861e77a9e8b434334c752a980b3e11b2f1b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 15:11:21 -0400 Subject: [PATCH 504/558] Roll Skia from 147232a3cebc to cc63d5dd13b6 (1 revision) (#35643) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f68600ddac93d..baba82f00c003 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': '147232a3cebc39f7b6771425b39d44bb0aef51a8', + 'skia_revision': 'cc63d5dd13b6c0db4c3e4a75ccc53286fb4a3d1a', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 0e93b84f871ed..e05d1e3a5a140 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: b2c9d84c4dafbb5e1ff3fb52e8a2e9ed +Signature: 63aa9d526132203ca42cccbd3aae86ed UNUSED LICENSES: From b4af69f027824dadab49ca8e4a0185a6cc3c498c Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 16:03:23 -0400 Subject: [PATCH 505/558] Roll Dart SDK from c064b9bacc4d to 3042d6196824 (1 revision) (#35644) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index baba82f00c003..178a6f5fe8b11 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'c064b9bacc4d77fd9d7b34d2579bc222a05e3d4b', + 'dart_revision': '3042d61968245f7ec65083b5f7c1cd0475666dfb', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 8122a31f3cf52..2bb5355035676 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 3ea51e98d8621b5a61e172e21a7db59d +Signature: 9f65c336c221de745d7cc056d049a51f UNUSED LICENSES: From 8cc02dc73e958faaef524c1cf65c9df40bfd461e Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 16:29:40 -0400 Subject: [PATCH 506/558] Roll Skia from cc63d5dd13b6 to a4744aa054cf (2 revisions) (#35645) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 178a6f5fe8b11..2228c9d48a954 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': 'cc63d5dd13b6c0db4c3e4a75ccc53286fb4a3d1a', + 'skia_revision': 'a4744aa054cf0b345d69b6d6ad2aa283430f6e28', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index e05d1e3a5a140..a126fc9811691 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 63aa9d526132203ca42cccbd3aae86ed +Signature: c6ce2be70f2ba6df923a785964de3bdf UNUSED LICENSES: From 9dee4b9e4b8f5a3786d8deb3938d48eff91061b7 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 18:08:20 -0400 Subject: [PATCH 507/558] Roll Skia from a4744aa054cf to fad2781bd328 (4 revisions) (#35647) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index 2228c9d48a954..261bf97c01c51 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': 'a4744aa054cf0b345d69b6d6ad2aa283430f6e28', + 'skia_revision': 'fad2781bd32864fafd34feecb1ff5605e95f2c73', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index a126fc9811691..101f2206c2520 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: c6ce2be70f2ba6df923a785964de3bdf +Signature: cb52130fe81571ba4985819c5a8983f7 UNUSED LICENSES: @@ -2513,7 +2513,6 @@ FILE: ../../../third_party/skia/include/gpu/graphite/Context.h FILE: ../../../third_party/skia/include/gpu/graphite/GraphiteTypes.h FILE: ../../../third_party/skia/include/gpu/graphite/Recorder.h FILE: ../../../third_party/skia/include/gpu/graphite/Recording.h -FILE: ../../../third_party/skia/include/gpu/graphite/SkStuff.h FILE: ../../../third_party/skia/include/gpu/graphite/TextureInfo.h FILE: ../../../third_party/skia/include/gpu/graphite/mtl/MtlBackendContext.h FILE: ../../../third_party/skia/include/gpu/graphite/mtl/MtlTypes.h @@ -2609,7 +2608,6 @@ FILE: ../../../third_party/skia/src/gpu/graphite/ResourceProvider.h FILE: ../../../third_party/skia/src/gpu/graphite/ResourceTypes.h FILE: ../../../third_party/skia/src/gpu/graphite/SharedContext.cpp FILE: ../../../third_party/skia/src/gpu/graphite/SharedContext.h -FILE: ../../../third_party/skia/src/gpu/graphite/SkStuff.cpp FILE: ../../../third_party/skia/src/gpu/graphite/Surface_Graphite.cpp FILE: ../../../third_party/skia/src/gpu/graphite/Surface_Graphite.h FILE: ../../../third_party/skia/src/gpu/graphite/Task.cpp From 68beed75a3f7f18dd54e87269f05c5329338af4a Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Tue, 23 Aug 2022 15:49:46 -0700 Subject: [PATCH 508/558] Refactor - Create `Renderer` interface for CanvasKit/HTML switching (#35502) --- ci/licenses_golden/licenses_flutter | 5 +- lib/web_ui/lib/canvas.dart | 50 +-- lib/web_ui/lib/compositing.dart | 10 +- lib/web_ui/lib/painting.dart | 173 +++----- lib/web_ui/lib/path.dart | 26 +- lib/web_ui/lib/src/engine.dart | 5 +- .../src/engine/canvaskit/canvaskit_api.dart | 48 +++ .../src/engine/canvaskit/embedded_views.dart | 24 +- .../src/engine/canvaskit/font_fallbacks.dart | 15 +- .../lib/src/engine/canvaskit/fonts.dart | 10 +- .../src/engine/canvaskit/initialization.dart | 121 ------ .../lib/src/engine/canvaskit/renderer.dart | 379 ++++++++++++++++++ .../lib/src/engine/canvaskit/shader.dart | 6 - .../engine/canvaskit/skia_object_cache.dart | 9 +- .../lib/src/engine/canvaskit/surface.dart | 4 +- lib/web_ui/lib/src/engine/canvaskit/text.dart | 4 +- lib/web_ui/lib/src/engine/embedder.dart | 13 +- lib/web_ui/lib/src/engine/fonts.dart | 15 + lib/web_ui/lib/src/engine/html/renderer.dart | 336 ++++++++++++++++ lib/web_ui/lib/src/engine/initialization.dart | 47 +-- .../lib/src/engine/platform_dispatcher.dart | 36 +- lib/web_ui/lib/src/engine/renderer.dart | 210 ++++++++++ .../lib/src/engine/text/font_collection.dart | 14 +- lib/web_ui/lib/text.dart | 178 +++----- .../backdrop_filter_golden_test.dart | 3 +- .../test/canvaskit/canvas_golden_test.dart | 12 +- .../test/canvaskit/canvaskit_api_test.dart | 4 +- .../canvaskit/color_filter_golden_test.dart | 4 +- lib/web_ui/test/canvaskit/common.dart | 6 +- .../test/canvaskit/embedded_views_test.dart | 118 ++---- .../canvaskit/fallback_fonts_golden_test.dart | 26 +- .../test/canvaskit/hot_restart_test.dart | 4 +- .../test/canvaskit/image_golden_test.dart | 12 +- lib/web_ui/test/canvaskit/layer_test.dart | 5 +- .../linear_gradient_golden_test.dart | 4 +- lib/web_ui/test/canvaskit/path_test.dart | 2 +- .../canvaskit/shader_mask_golden_test.dart | 4 +- .../canvaskit/skia_font_collection_test.dart | 2 +- .../canvaskit/skia_objects_cache_test.dart | 2 +- .../canvaskit/sweep_gradient_golden_test.dart | 4 +- lib/web_ui/test/canvaskit/vertices_test.dart | 2 +- .../test/engine/image_to_byte_data_test.dart | 4 +- .../html/canvas_clip_path_golden_test.dart | 4 +- .../test/html/canvas_context_golden_test.dart | 4 +- .../test/html/canvas_reuse_golden_test.dart | 4 +- .../backdrop_filter_golden_test.dart | 4 +- .../compositing/canvas_blend_golden_test.dart | 4 +- .../canvas_image_blend_mode_golden_test.dart | 4 +- .../canvas_mask_filter_golden_test.dart | 4 +- .../compositing/color_filter_golden_test.dart | 4 +- .../compositing/compositing_golden_test.dart | 4 +- .../dom_mask_filter_golden_test.dart | 4 +- .../canvas_draw_color_golden_test.dart | 4 +- .../canvas_draw_picture_golden_test.dart | 4 +- .../drawing/draw_vertices_golden_test.dart | 4 +- .../test/html/paragraph/text_scuba.dart | 4 +- .../test/html/path_metrics_golden_test.dart | 4 +- .../test/html/path_transform_golden_test.dart | 4 +- lib/web_ui/test/html/screenshot.dart | 4 +- .../shaders/image_shader_golden_test.dart | 4 +- .../shaders/linear_gradient_golden_test.dart | 4 +- .../shaders/radial_gradient_golden_test.dart | 4 +- .../html/shaders/shader_mask_golden_test.dart | 4 +- .../web_engine_tester/lib/golden_tester.dart | 8 +- 64 files changed, 1316 insertions(+), 732 deletions(-) delete mode 100644 lib/web_ui/lib/src/engine/canvaskit/initialization.dart create mode 100644 lib/web_ui/lib/src/engine/canvaskit/renderer.dart create mode 100644 lib/web_ui/lib/src/engine/fonts.dart create mode 100644 lib/web_ui/lib/src/engine/html/renderer.dart create mode 100644 lib/web_ui/lib/src/engine/renderer.dart diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index c78b93d5c0076..93b67b395ffd5 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1145,7 +1145,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image_wasm_codecs.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image_web_codecs.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/initialization.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.dart @@ -1160,6 +1159,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/picture_recorder.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/platform_message.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/raster_cache.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/rasterizer.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/shader.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -1175,6 +1175,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/dom.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/embedder.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/engine_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/font_change_util.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/fonts.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/frame_reference.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/host_node.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/backdrop_filter.dart @@ -1203,6 +1204,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/picture.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/platform_view.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/recording_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/render_vertices.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/scene.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/scene_builder.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/shader_mask.dart @@ -1237,6 +1239,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/plugins.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/pointer_binding.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/pointer_converter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/profiler.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/rrect_renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/safe_browser_api.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/semantics.dart diff --git a/lib/web_ui/lib/canvas.dart b/lib/web_ui/lib/canvas.dart index c9359b6930781..1bcb8173c594e 100644 --- a/lib/web_ui/lib/canvas.dart +++ b/lib/web_ui/lib/canvas.dart @@ -29,21 +29,11 @@ class Vertices { List? colors, List? indices, }) { - if (engine.useCanvasKit) { - return engine.CkVertices( - mode, - positions, - textureCoordinates: textureCoordinates, - colors: colors, - indices: indices, - ); - } - return engine.SurfaceVertices( - mode, + return engine.renderer.createVertices(mode, positions, + textureCoordinates: textureCoordinates, colors: colors, - indices: indices, - ); + indices: indices); } factory Vertices.raw( VertexMode mode, @@ -52,45 +42,23 @@ class Vertices { Int32List? colors, Uint16List? indices, }) { - if (engine.useCanvasKit) { - return engine.CkVertices.raw( - mode, - positions, - textureCoordinates: textureCoordinates, - colors: colors, - indices: indices, - ); - } - return engine.SurfaceVertices.raw( - mode, + return engine.renderer.createVerticesRaw(mode, positions, + textureCoordinates: textureCoordinates, colors: colors, - indices: indices, - ); + indices: indices); } } abstract class PictureRecorder { - factory PictureRecorder() { - if (engine.useCanvasKit) { - return engine.CkPictureRecorder(); - } else { - return engine.EnginePictureRecorder(); - } - } + factory PictureRecorder() => engine.renderer.createPictureRecorder(); bool get isRecording; Picture endRecording(); } abstract class Canvas { - factory Canvas(PictureRecorder recorder, [Rect? cullRect]) { - if (engine.useCanvasKit) { - return engine.CanvasKitCanvas(recorder, cullRect); - } else { - return engine.SurfaceCanvas( - recorder as engine.EnginePictureRecorder, cullRect); - } - } + factory Canvas(PictureRecorder recorder, [Rect? cullRect]) => + engine.renderer.createCanvas(recorder, cullRect); void save(); void saveLayer(Rect? bounds, Paint paint); void restore(); diff --git a/lib/web_ui/lib/compositing.dart b/lib/web_ui/lib/compositing.dart index 349ad272d4b3d..11154ad6608e9 100644 --- a/lib/web_ui/lib/compositing.dart +++ b/lib/web_ui/lib/compositing.dart @@ -33,13 +33,9 @@ abstract class ShaderMaskEngineLayer implements EngineLayer {} abstract class PhysicalShapeEngineLayer implements EngineLayer {} abstract class SceneBuilder { - factory SceneBuilder() { - if (engine.useCanvasKit) { - return engine.LayerSceneBuilder(); - } else { - return engine.SurfaceSceneBuilder(); - } - } + factory SceneBuilder() => + engine.renderer.createSceneBuilder(); + OffsetEngineLayer pushOffset( double dx, double dy, { diff --git a/lib/web_ui/lib/painting.dart b/lib/web_ui/lib/painting.dart index c4f41803c0285..0edd2faeb0dbd 100644 --- a/lib/web_ui/lib/painting.dart +++ b/lib/web_ui/lib/painting.dart @@ -232,7 +232,7 @@ enum Clip { } abstract class Paint { - factory Paint() => engine.useCanvasKit ? engine.CkPaint() : engine.SurfacePaint(); + factory Paint() => engine.renderer.createPaint(); static bool enableDithering = false; BlendMode get blendMode; set blendMode(BlendMode value); @@ -282,10 +282,13 @@ abstract class Gradient extends Shader { Float64List? matrix4, ]) { final Float32List? matrix = matrix4 == null ? null : engine.toMatrix32(matrix4); - return engine.useCanvasKit - ? engine.CkGradientLinear( - from, to, colors, colorStops, tileMode, matrix) - : engine.GradientLinear(from, to, colors, colorStops, tileMode, matrix); + return engine.renderer.createLinearGradient( + from, + to, + colors, + colorStops, + tileMode, + matrix); } factory Gradient.radial( @@ -303,17 +306,13 @@ abstract class Gradient extends Shader { // If focal == center and the focal radius is 0.0, it's still a regular radial gradient final Float32List? matrix32 = matrix4 != null ? engine.toMatrix32(matrix4) : null; if (focal == null || (focal == center && focalRadius == 0.0)) { - return engine.useCanvasKit - ? engine.CkGradientRadial(center, radius, colors, colorStops, tileMode, matrix32) - : engine.GradientRadial(center, radius, colors, colorStops, tileMode, matrix32); + return engine.renderer.createRadialGradient( + center, radius, colors, colorStops, tileMode, matrix32); } else { assert(center != Offset.zero || focal != Offset.zero); // will result in exception(s) in Skia side - return engine.useCanvasKit - ? engine.CkGradientConical( - focal, focalRadius, center, radius, colors, colorStops, tileMode, matrix32) - : engine.GradientConical( - focal, focalRadius, center, radius, colors, colorStops, tileMode, matrix32); + return engine.renderer.createConicalGradient( + focal, focalRadius, center, radius, colors, colorStops, tileMode, matrix32); } } factory Gradient.sweep( @@ -324,11 +323,14 @@ abstract class Gradient extends Shader { double startAngle = 0.0, double endAngle = math.pi * 2, Float64List? matrix4, - ]) => engine.useCanvasKit - ? engine.CkGradientSweep(center, colors, colorStops, tileMode, startAngle, - endAngle, matrix4 != null ? engine.toMatrix32(matrix4) : null) - : engine.GradientSweep(center, colors, colorStops, tileMode, startAngle, - endAngle, matrix4 != null ? engine.toMatrix32(matrix4) : null); + ]) => engine.renderer.createSweepGradient( + center, + colors, + colorStops, + tileMode, + startAngle, + endAngle, + matrix4 != null ? engine.toMatrix32(matrix4) : null); } abstract class Image { @@ -398,45 +400,31 @@ enum FilterQuality { } class ImageFilter { - factory ImageFilter.blur({double sigmaX = 0.0, double sigmaY = 0.0, TileMode tileMode = TileMode.clamp}) { - if (engine.useCanvasKit) { - return engine.CkImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode); - } - // TODO(ferhat): implement TileMode. - return engine.EngineImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode); - } + factory ImageFilter.blur({ + double sigmaX = 0.0, + double sigmaY = 0.0, + TileMode tileMode = TileMode.clamp + }) => engine.renderer.createBlurImageFilter( + sigmaX: sigmaX, + sigmaY: sigmaY, + tileMode: tileMode + ); - // ignore: avoid_unused_constructor_parameters - factory ImageFilter.dilate({ double radiusX = 0.0, double radiusY = 0.0 }) { - // TODO(fzyzcjy): implement dilate. https://github.com/flutter/flutter/issues/101085 - throw UnimplementedError( - 'ImageFilter.dilate not implemented for web platform.'); - } + factory ImageFilter.dilate({ double radiusX = 0.0, double radiusY = 0.0 }) => + engine.renderer.createDilateImageFilter(radiusX: radiusX, radiusY: radiusY); - // ignore: avoid_unused_constructor_parameters - factory ImageFilter.erode({ double radiusX = 0.0, double radiusY = 0.0 }) { - // TODO(fzyzcjy): implement erode. https://github.com/flutter/flutter/issues/101085 - throw UnimplementedError( - 'ImageFilter.erode not implemented for web platform.'); - } + factory ImageFilter.erode({ double radiusX = 0.0, double radiusY = 0.0 }) => + engine.renderer.createErodeImageFilter(radiusX: radiusX, radiusY: radiusY); factory ImageFilter.matrix(Float64List matrix4, {FilterQuality filterQuality = FilterQuality.low}) { if (matrix4.length != 16) { throw ArgumentError('"matrix4" must have 16 entries.'); } - if (engine.useCanvasKit) { - return engine.CkImageFilter.matrix(matrix: matrix4, filterQuality: filterQuality); - } - // TODO(yjbanov): implement FilterQuality. - return engine.EngineImageFilter.matrix(matrix: matrix4, filterQuality: filterQuality); + return engine.renderer.createMatrixImageFilter(matrix4, filterQuality: filterQuality); } - // TODO(ferhat): add implementation and remove the "ignore". - // ignore: avoid_unused_constructor_parameters - ImageFilter.compose({required ImageFilter outer, required ImageFilter inner}) { - throw UnimplementedError( - 'ImageFilter.compose not implemented for web platform.'); - } + factory ImageFilter.compose({required ImageFilter outer, required ImageFilter inner}) => + engine.renderer.composeImageFilters(outer: outer, inner: inner); } enum ImageByteFormat { @@ -477,48 +465,26 @@ Future instantiateImageCodec( int? targetWidth, int? targetHeight, bool allowUpscaling = true, -}) async { - if (engine.useCanvasKit) { - return engine.skiaInstantiateImageCodec(list, targetWidth, targetHeight); - } else { - final engine.DomBlob blob = engine.createDomBlob([list.buffer]); - return engine.HtmlBlobCodec(blob); - } -} +}) => engine.renderer.instantiateImageCodec( + list, + targetWidth: targetWidth, + targetHeight: targetHeight, + allowUpscaling: allowUpscaling); Future instantiateImageCodecFromBuffer( ImmutableBuffer buffer, { int? targetWidth, int? targetHeight, bool allowUpscaling = true, -}) async { - if (engine.useCanvasKit) { - return engine.skiaInstantiateImageCodec(buffer._list!, targetWidth, targetHeight); - } else { - final engine.DomBlob blob = engine.createDomBlob([buffer._list!.buffer]); - return engine.HtmlBlobCodec(blob); - } -} +}) => engine.renderer.instantiateImageCodec( + buffer._list!, + targetWidth: targetWidth, + targetHeight: targetHeight, + allowUpscaling: allowUpscaling); Future webOnlyInstantiateImageCodecFromUrl(Uri uri, - {engine.WebOnlyImageCodecChunkCallback? chunkCallback}) { - if (engine.useCanvasKit) { - return engine.skiaInstantiateWebImageCodec( - uri.toString(), chunkCallback); - } else { - return engine.futurize((engine.Callback callback) => - _instantiateImageCodecFromUrl(uri, chunkCallback, callback)); - } -} - -String? _instantiateImageCodecFromUrl( - Uri uri, - engine.WebOnlyImageCodecChunkCallback? chunkCallback, - engine.Callback callback, -) { - callback(engine.HtmlCodec(uri.toString(), chunkCallback: chunkCallback)); - return null; -} + {engine.WebOnlyImageCodecChunkCallback? chunkCallback}) => + engine.renderer.instantiateImageCodecFromUrl(uri, chunkCallback: chunkCallback); void decodeImageFromList(Uint8List list, ImageDecoderCallback callback) { _decodeImageFromListAsync(list, callback); @@ -535,7 +501,7 @@ Future _decodeImageFromListAsync(Uint8List list, ImageDecoderCallback call // The `pixels` should be the scanlined raw pixels, 4 bytes per pixel, from left // to right, then from top to down. The order of the 4 bytes of pixels is // decided by `format`. -Future _createBmp( +Future createBmp( Uint8List pixels, int width, int height, @@ -624,31 +590,16 @@ void decodeImageFromPixels( int? targetWidth, int? targetHeight, bool allowUpscaling = true, -}) { - if (engine.useCanvasKit) { - engine.skiaDecodeImageFromPixels( - pixels, - width, - height, - format, - callback, - rowBytes: rowBytes, - targetWidth: targetWidth, - targetHeight: targetHeight, - allowUpscaling: allowUpscaling, - ); - return; - } - - void executeCallback(Codec codec) { - codec.getNextFrame().then((FrameInfo frameInfo) { - callback(frameInfo.image); - }); - } - _createBmp(pixels, width, height, rowBytes ?? width, format).then( - executeCallback); - -} +}) => engine.renderer.decodeImageFromPixels( + pixels, + width, + height, + format, + callback, + rowBytes: rowBytes, + targetWidth: targetWidth, + targetHeight: targetHeight, + allowUpscaling: allowUpscaling); class Shadow { const Shadow({ @@ -747,9 +698,7 @@ class Shadow { abstract class ImageShader extends Shader { factory ImageShader(Image image, TileMode tmx, TileMode tmy, Float64List matrix4, { FilterQuality? filterQuality, - }) => engine.useCanvasKit - ? engine.CkImageShader(image, tmx, tmy, matrix4, filterQuality) - : engine.EngineImageShader(image, tmx, tmy, matrix4, filterQuality); + }) => engine.renderer.createImageShader(image, tmx, tmy, matrix4, filterQuality); void dispose(); @@ -839,7 +788,7 @@ class ImageDescriptor { ); } - return _createBmp(_data!, width, height, _rowBytes ?? width, _format!); + return createBmp(_data!, width, height, _rowBytes ?? width, _format!); } } diff --git a/lib/web_ui/lib/path.dart b/lib/web_ui/lib/path.dart index c609b82d109ba..47b80ecd084cc 100644 --- a/lib/web_ui/lib/path.dart +++ b/lib/web_ui/lib/path.dart @@ -7,20 +7,8 @@ part of ui; // For documentation see https://github.com/flutter/engine/blob/main/lib/ui/painting.dart abstract class Path { - factory Path() { - if (engine.useCanvasKit) { - return engine.CkPath(); - } else { - return engine.SurfacePath(); - } - } - factory Path.from(Path source) { - if (engine.useCanvasKit) { - return engine.CkPath.from(source as engine.CkPath); - } else { - return engine.SurfacePath.from(source as engine.SurfacePath); - } - } + factory Path() => engine.renderer.createPath(); + factory Path.from(Path source) => engine.renderer.copyPath(source); PathFillType get fillType; set fillType(PathFillType value); void moveTo(double x, double y); @@ -62,14 +50,8 @@ abstract class Path { Path transform(Float64List matrix4); // see https://skia.org/user/api/SkPath_Reference#SkPath_getBounds Rect getBounds(); - static Path combine(PathOperation operation, Path path1, Path path2) { - assert(path1 != null); - assert(path2 != null); - if (engine.useCanvasKit) { - return engine.CkPath.combine(operation, path1, path2); - } - throw UnimplementedError(); - } + static Path combine(PathOperation operation, Path path1, Path path2) => + engine.renderer.combinePaths(operation, path1, path2); PathMetrics computeMetrics({bool forceClosed = false}); } diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 166f78ffac659..32b4fd13e479f 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -32,7 +32,6 @@ export 'engine/canvaskit/image.dart'; export 'engine/canvaskit/image_filter.dart'; export 'engine/canvaskit/image_wasm_codecs.dart'; export 'engine/canvaskit/image_web_codecs.dart'; -export 'engine/canvaskit/initialization.dart'; export 'engine/canvaskit/interval_tree.dart'; export 'engine/canvaskit/layer.dart'; export 'engine/canvaskit/layer_scene_builder.dart'; @@ -46,6 +45,7 @@ export 'engine/canvaskit/picture.dart'; export 'engine/canvaskit/picture_recorder.dart'; export 'engine/canvaskit/raster_cache.dart'; export 'engine/canvaskit/rasterizer.dart'; +export 'engine/canvaskit/renderer.dart'; export 'engine/canvaskit/shader.dart'; export 'engine/canvaskit/skia_object_cache.dart'; export 'engine/canvaskit/surface.dart'; @@ -60,6 +60,7 @@ export 'engine/dom.dart'; export 'engine/embedder.dart'; export 'engine/engine_canvas.dart'; export 'engine/font_change_util.dart'; +export 'engine/fonts.dart'; export 'engine/frame_reference.dart'; export 'engine/host_node.dart'; export 'engine/html/backdrop_filter.dart'; @@ -88,6 +89,7 @@ export 'engine/html/picture.dart'; export 'engine/html/platform_view.dart'; export 'engine/html/recording_canvas.dart'; export 'engine/html/render_vertices.dart'; +export 'engine/html/renderer.dart'; export 'engine/html/scene.dart'; export 'engine/html/scene_builder.dart'; export 'engine/html/shader_mask.dart'; @@ -121,6 +123,7 @@ export 'engine/plugins.dart'; export 'engine/pointer_binding.dart'; export 'engine/pointer_converter.dart'; export 'engine/profiler.dart'; +export 'engine/renderer.dart'; export 'engine/rrect_renderer.dart'; export 'engine/safe_browser_api.dart'; export 'engine/semantics/accessibility.dart'; 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 c9b4135b804bf..32dd0dbc2e365 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -17,7 +17,9 @@ import 'dart:typed_data'; import 'package:js/js.dart'; import 'package:ui/ui.dart' as ui; +import '../configuration.dart'; import '../dom.dart'; +import '../initialization.dart'; import '../profiler.dart'; /// Entrypoint into the CanvasKit API. @@ -2612,3 +2614,49 @@ void patchCanvasKitModule(DomHTMLScriptElement canvasKitScript) { } domDocument.head!.appendChild(canvasKitScript); } + +String get canvasKitBuildUrl => + configuration.canvasKitBaseUrl + (kProfileMode ? 'profiling/' : ''); +String get canvasKitJavaScriptBindingsUrl => + '${canvasKitBuildUrl}canvaskit.js'; +String canvasKitWasmModuleUrl(String canvasKitBase, String file) => + canvasKitBase + file; + +/// Download and initialize the CanvasKit module. +/// +/// Downloads the CanvasKit JavaScript, then calls `CanvasKitInit` to download +/// and intialize the CanvasKit wasm. +Future downloadCanvasKit() async { + await _downloadCanvasKitJs(); + final Completer canvasKitInitCompleter = Completer(); + final CanvasKitInitPromise canvasKitInitPromise = + CanvasKitInit(CanvasKitInitOptions( + locateFile: allowInterop((String file, String unusedBase) => + canvasKitWasmModuleUrl(canvasKitBuildUrl, file)), + )); + canvasKitInitPromise.then(allowInterop((CanvasKit ck) { + canvasKitInitCompleter.complete(ck); + })); + return canvasKitInitCompleter.future; +} + +/// Downloads the CanvasKit JavaScript file at [canvasKitBase]. +Future _downloadCanvasKitJs() { + final String canvasKitJavaScriptUrl = canvasKitJavaScriptBindingsUrl; + + final DomHTMLScriptElement canvasKitScript = createDomHTMLScriptElement(); + canvasKitScript.src = canvasKitJavaScriptUrl; + + final Completer canvasKitLoadCompleter = Completer(); + late DomEventListener callback; + void loadEventHandler(DomEvent _) { + canvasKitLoadCompleter.complete(); + canvasKitScript.removeEventListener('load', callback); + } + callback = allowInterop(loadEventHandler); + canvasKitScript.addEventListener('load', callback); + + patchCanvasKitModule(canvasKitScript); + + return canvasKitLoadCompleter.future; +} diff --git a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart index 8390316ec90bd..9e1f48e8bb189 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart @@ -15,9 +15,9 @@ import '../vector_math.dart'; import '../window.dart'; import 'canvas.dart'; import 'embedded_views_diff.dart'; -import 'initialization.dart'; import 'path.dart'; import 'picture_recorder.dart'; +import 'renderer.dart'; import 'surface.dart'; import 'surface_factory.dart'; @@ -28,6 +28,8 @@ class HtmlViewEmbedder { /// The [HtmlViewEmbedder] singleton. static HtmlViewEmbedder instance = HtmlViewEmbedder._(); + DomElement get skiaSceneHost => CanvasKitRenderer.instance.sceneHost!; + /// Force the view embedder to disable overlays. /// /// This should never be used outside of tests. @@ -270,7 +272,7 @@ class HtmlViewEmbedder { // If the chain was previously attached, attach it to the same position. if (headClipViewWasAttached) { - skiaSceneHost!.insertBefore(head, headClipViewNextSibling); + skiaSceneHost.insertBefore(head, headClipViewNextSibling); } return head; } @@ -408,7 +410,7 @@ class HtmlViewEmbedder { } _svgPathDefs = kSvgResourceHeader.cloneNode(false) as SVGElement; _svgPathDefs!.append(createSVGDefsElement()..id = 'sk_path_defs'); - skiaSceneHost!.append(_svgPathDefs!); + skiaSceneHost.append(_svgPathDefs!); } void submitFrame() { @@ -476,18 +478,18 @@ class HtmlViewEmbedder { } if (diffResult.addToBeginning) { final DomElement platformViewRoot = _viewClipChains[viewId]!.root; - skiaSceneHost!.insertBefore(platformViewRoot, elementToInsertBefore); + skiaSceneHost.insertBefore(platformViewRoot, elementToInsertBefore); final Surface? overlay = _overlays[viewId]; if (overlay != null) { - skiaSceneHost! + skiaSceneHost .insertBefore(overlay.htmlElement, elementToInsertBefore); } } else { final DomElement platformViewRoot = _viewClipChains[viewId]!.root; - skiaSceneHost!.append(platformViewRoot); + skiaSceneHost.append(platformViewRoot); final Surface? overlay = _overlays[viewId]; if (overlay != null) { - skiaSceneHost!.append(overlay.htmlElement); + skiaSceneHost.append(overlay.htmlElement); } } } @@ -500,11 +502,11 @@ class HtmlViewEmbedder { if (!overlayElement.isConnected!) { // This overlay wasn't added to the DOM. if (i == _compositionOrder.length - 1) { - skiaSceneHost!.append(overlayElement); + skiaSceneHost.append(overlayElement); } else { final int nextView = _compositionOrder[i + 1]; final DomElement nextElement = _viewClipChains[nextView]!.root; - skiaSceneHost!.insertBefore(overlayElement, nextElement); + skiaSceneHost.insertBefore(overlayElement, nextElement); } } } @@ -524,9 +526,9 @@ class HtmlViewEmbedder { final DomElement platformViewRoot = _viewClipChains[viewId]!.root; final Surface? overlay = _overlays[viewId]; - skiaSceneHost!.append(platformViewRoot); + skiaSceneHost.append(platformViewRoot); if (overlay != null) { - skiaSceneHost!.append(overlay.htmlElement); + skiaSceneHost.append(overlay.htmlElement); } _activeCompositionOrder.add(viewId); unusedViews.remove(viewId); diff --git a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart index 40a915f44876c..2473dfdae5021 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart @@ -6,13 +6,14 @@ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; +import 'package:ui/src/engine/canvaskit/renderer.dart'; + import '../dom.dart'; import '../font_change_util.dart'; -import '../platform_dispatcher.dart'; +import '../renderer.dart'; import '../util.dart'; import 'canvaskit_api.dart'; import 'fonts.dart'; -import 'initialization.dart'; import 'interval_tree.dart'; /// Global static font fallback data. @@ -120,7 +121,7 @@ class FontFallbackData { final List fonts = []; for (final String font in fontFamilies) { final List? typefacesForFamily = - skiaFontCollection.familyToFontMap[font]; + CanvasKitRenderer.instance.fontCollection.familyToFontMap[font]; if (typefacesForFamily != null) { fonts.addAll(typefacesForFamily); } @@ -146,9 +147,7 @@ class FontFallbackData { _codeUnitsToCheckAgainstFallbackFonts.addAll(missingCodeUnits); if (!_scheduledCodeUnitCheck) { _scheduledCodeUnitCheck = true; - // ignore: invalid_use_of_visible_for_testing_member - EnginePlatformDispatcher.instance.rasterizer! - .addPostFrameCallback(_ensureFallbackFonts); + CanvasKitRenderer.instance.rasterizer.addPostFrameCallback(_ensureFallbackFonts); } } } @@ -173,7 +172,7 @@ class FontFallbackData { for (final String font in globalFontFallbacks) { final List? fontsForFamily = - skiaFontCollection.familyToFontMap[font]; + CanvasKitRenderer.instance.fontCollection.familyToFontMap[font]; if (fontsForFamily == null) { printWarning('A fallback font was registered but we ' 'cannot retrieve the typeface for it.'); @@ -917,7 +916,7 @@ class FallbackFontDownloadQueue { final Uint8List bytes = downloadedData[url]!; FontFallbackData.instance.registerFallbackFont(subset.family, bytes); if (pendingSubsets.isEmpty) { - _fontsLoading = skiaFontCollection.ensureFontsLoaded(); + _fontsLoading = renderer.fontCollection.ensureFontsLoaded(); try { await _fontsLoading; } finally { diff --git a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart index 4f8d156e00d9d..07b51ded8276b 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/fonts.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/fonts.dart @@ -7,6 +7,7 @@ import 'dart:typed_data'; import '../assets.dart'; import '../dom.dart'; +import '../fonts.dart'; import '../util.dart'; import 'canvaskit_api.dart'; import 'font_fallbacks.dart'; @@ -23,7 +24,7 @@ const String _robotoUrl = const String _ahemUrl = '/assets/fonts/ahem.ttf'; /// Manages the fonts used in the Skia-based backend. -class SkiaFontCollection { +class SkiaFontCollection implements FontCollection { final Set _registeredFontFamilies = {}; /// Fonts that started the download process. @@ -50,6 +51,7 @@ class SkiaFontCollection { final Map> familyToFontMap = >{}; + @override Future ensureFontsLoaded() async { await _loadFonts(); @@ -91,6 +93,7 @@ class SkiaFontCollection { _pendingFonts.clear(); } + @override Future loadFontFromList(Uint8List list, {String? fontFamily}) async { if (fontFamily == null) { fontFamily = _readActualFamilyName(list); @@ -112,6 +115,7 @@ class SkiaFontCollection { } /// Loads fonts from `FontManifest.json`. + @override Future registerFonts(AssetManager assetManager) async { ByteData byteData; @@ -164,6 +168,7 @@ class SkiaFontCollection { /// `FontManifest.json` has higher priority than the default test font URLs. /// This allows customizing test environments where fonts are loaded from /// different URLs. + @override void debugRegisterTestFonts() { if (!_isFontFamilyRegistered('Ahem')) { _registerFont(_ahemUrl, 'Ahem'); @@ -218,6 +223,9 @@ class SkiaFontCollection { SkFontMgr? skFontMgr; TypefaceFontProvider? fontProvider; + + @override + void clear() {} } /// Represents a font that has been registered. diff --git a/lib/web_ui/lib/src/engine/canvaskit/initialization.dart b/lib/web_ui/lib/src/engine/canvaskit/initialization.dart deleted file mode 100644 index 9e673ab183606..0000000000000 --- a/lib/web_ui/lib/src/engine/canvaskit/initialization.dart +++ /dev/null @@ -1,121 +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. -library canvaskit_initialization; - -import 'dart:async'; - -import '../../engine.dart' show kProfileMode; -import '../browser_detection.dart'; -import '../configuration.dart'; -import '../dom.dart'; -import '../safe_browser_api.dart'; -import 'canvaskit_api.dart'; -import 'fonts.dart'; -import 'util.dart'; - -/// Whether to use CanvasKit as the rendering backend. -final bool useCanvasKit = FlutterConfiguration.flutterWebAutoDetect - ? _hasCanvasKit - : FlutterConfiguration.useSkia; - -/// Returns true if CanvasKit is used. -/// -/// Otherwise, returns false. -final bool _hasCanvasKit = _detectCanvasKit(); - -bool _detectCanvasKit() { - if (requestedRendererType != null) { - return requestedRendererType! == 'canvaskit'; - } - // If requestedRendererType is not specified, use CanvasKit for desktop and - // html for mobile. - return isDesktop; -} - -String get canvasKitBuildUrl => - configuration.canvasKitBaseUrl + (kProfileMode ? 'profiling/' : ''); -String get canvasKitJavaScriptBindingsUrl => - '${canvasKitBuildUrl}canvaskit.js'; -String canvasKitWasmModuleUrl(String canvasKitBase, String file) => - canvasKitBase + file; - -/// Downloads CanvasKit and instantiates its WASM module. -/// -/// Uses a cached implemenation if it exists. Otherwise downloads CanvasKit. -/// Assigns the global [canvasKit] object. -/// -/// Does not put any UI onto the page. It is therefore safe to call this -/// function while the page is showing non-Flutter UI, such as a loading -/// indicator or a splash screen. -/// -/// See also: -/// -/// * `initializeEngineUi`, which puts UI elements on the page. -Future initializeCanvasKit({String? canvasKitBase}) async { - if (windowFlutterCanvasKit != null) { - canvasKit = windowFlutterCanvasKit!; - } else if (useH5vccCanvasKit) { - if (h5vcc?.canvasKit == null) { - throw CanvasKitError('H5vcc CanvasKit implementation not found.'); - } - canvasKit = h5vcc!.canvasKit!; - windowFlutterCanvasKit = canvasKit; - } else { - canvasKit = await downloadCanvasKit(canvasKitBase: canvasKitBase); - windowFlutterCanvasKit = canvasKit; - } -} - -/// Download and initialize the CanvasKit module. -/// -/// Downloads the CanvasKit JavaScript, then calls `CanvasKitInit` to download -/// and intialize the CanvasKit wasm. -Future downloadCanvasKit({String? canvasKitBase}) async { - await _downloadCanvasKitJs(canvasKitBase: canvasKitBase); - final Completer canvasKitInitCompleter = Completer(); - final CanvasKitInitPromise canvasKitInitPromise = - CanvasKitInit(CanvasKitInitOptions( - locateFile: allowInterop((String file, String unusedBase) => - canvasKitWasmModuleUrl(canvasKitBase ?? canvasKitBuildUrl, file)), - )); - canvasKitInitPromise.then(allowInterop((CanvasKit ck) { - canvasKitInitCompleter.complete(ck); - })); - return canvasKitInitCompleter.future; -} - -/// Downloads the CanvasKit JavaScript file at [canvasKitBase]. -Future _downloadCanvasKitJs({String? canvasKitBase}) { - final String canvasKitJavaScriptUrl = canvasKitBase != null - ? '${canvasKitBase}canvaskit.js' - : canvasKitJavaScriptBindingsUrl; - - final DomHTMLScriptElement canvasKitScript = createDomHTMLScriptElement(); - canvasKitScript.src = canvasKitJavaScriptUrl; - - final Completer canvasKitLoadCompleter = Completer(); - late DomEventListener callback; - void loadEventHandler(DomEvent _) { - canvasKitLoadCompleter.complete(); - canvasKitScript.removeEventListener('load', callback); - } - callback = allowInterop(loadEventHandler); - canvasKitScript.addEventListener('load', callback); - - patchCanvasKitModule(canvasKitScript); - - return canvasKitLoadCompleter.future; -} - -/// The Skia font collection. -SkiaFontCollection get skiaFontCollection => _skiaFontCollection!; -SkiaFontCollection? _skiaFontCollection; - -/// Initializes [skiaFontCollection]. -void ensureSkiaFontCollectionInitialized() { - _skiaFontCollection ??= SkiaFontCollection(); -} - -/// The scene host, where the root canvas and overlay canvases are added to. -DomElement? skiaSceneHost; diff --git a/lib/web_ui/lib/src/engine/canvaskit/renderer.dart b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart new file mode 100644 index 0000000000000..0ebf6848e8615 --- /dev/null +++ b/lib/web_ui/lib/src/engine/canvaskit/renderer.dart @@ -0,0 +1,379 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:ui/ui.dart' as ui; + +import '../dom.dart'; +import '../embedder.dart'; +import '../html_image_codec.dart'; +import '../profiler.dart'; +import '../renderer.dart'; +import 'canvaskit_api.dart'; +import 'canvaskit_canvas.dart'; +import 'fonts.dart'; +import 'image.dart'; +import 'image_filter.dart'; +import 'layer_scene_builder.dart'; +import 'painting.dart'; +import 'path.dart'; +import 'picture_recorder.dart'; +import 'rasterizer.dart'; +import 'shader.dart'; +import 'text.dart'; +import 'util.dart'; +import 'vertices.dart'; + +class CanvasKitRenderer implements Renderer { + static CanvasKitRenderer get instance => _instance; + static late CanvasKitRenderer _instance; + + @override + String get rendererTag => 'canvaskit'; + + late final SkiaFontCollection _fontCollection = SkiaFontCollection(); + + @override + SkiaFontCollection get fontCollection => _fontCollection; + + /// The scene host, where the root canvas and overlay canvases are added to. + DomElement? _sceneHost; + DomElement? get sceneHost => _sceneHost; + + late Rasterizer rasterizer = Rasterizer(); + + set resourceCacheMaxBytes(int bytes) => rasterizer.setSkiaResourceCacheMaxBytes(bytes); + + @override + Future initialize() async { + if (windowFlutterCanvasKit != null) { + canvasKit = windowFlutterCanvasKit!; + } else if (useH5vccCanvasKit) { + if (h5vcc?.canvasKit == null) { + throw CanvasKitError('H5vcc CanvasKit implementation not found.'); + } + canvasKit = h5vcc!.canvasKit!; + windowFlutterCanvasKit = canvasKit; + } else { + canvasKit = await downloadCanvasKit(); + windowFlutterCanvasKit = canvasKit; + } + + _instance = this; + } + + @override + void reset(FlutterViewEmbedder embedder) { + // CanvasKit uses a static scene element that never gets replaced, so it's + // added eagerly during initialization here and never touched, unless the + // system is reset due to hot restart or in a test. + _sceneHost = createDomElement('flt-scene'); + embedder.addSceneToSceneHost(_sceneHost); + } + + @override + ui.Paint createPaint() => CkPaint(); + + @override + ui.Vertices createVertices( + ui.VertexMode mode, + List positions, { + List? textureCoordinates, + List? colors, + List? indices, + }) => CkVertices( + mode, + positions, + textureCoordinates: textureCoordinates, + colors: colors, + indices: indices); + + @override + ui.Vertices createVerticesRaw( + ui.VertexMode mode, + Float32List positions, { + Float32List? textureCoordinates, + Int32List? colors, + Uint16List? indices, + }) => CkVertices.raw( + mode, + positions, + textureCoordinates: textureCoordinates, + colors: colors, + indices: indices); + + @override + ui.Canvas createCanvas(ui.PictureRecorder recorder, [ui.Rect? cullRect]) => + CanvasKitCanvas(recorder, cullRect); + + @override + ui.Gradient createLinearGradient( + ui.Offset from, + ui.Offset to, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4 + ]) => CkGradientLinear(from, to, colors, colorStops, tileMode, matrix4); + + @override + ui.Gradient createRadialGradient( + ui.Offset center, + double radius, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4, + ui.Offset? focal, + double focalRadius = 0.0, + ]) => CkGradientRadial(center, radius, colors, colorStops, tileMode, matrix4); + + @override + ui.Gradient createConicalGradient( + ui.Offset focal, + double focalRadius, + ui.Offset center, + double radius, + List colors, + [List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix] + ) => CkGradientConical( + focal, + focalRadius, + center, + radius, + colors, + colorStops, + tileMode, + matrix); + + @override + ui.Gradient createSweepGradient( + ui.Offset center, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + double startAngle = 0.0, + double endAngle = math.pi * 2, + Float32List? matrix4 + ]) => CkGradientSweep(center, colors, colorStops, tileMode, startAngle, endAngle, matrix4); + + @override + ui.PictureRecorder createPictureRecorder() => CkPictureRecorder(); + + @override + ui.SceneBuilder createSceneBuilder() => LayerSceneBuilder(); + + @override + ui.ImageFilter createBlurImageFilter({ + double sigmaX = 0.0, + double sigmaY = 0.0, + ui.TileMode tileMode = ui.TileMode.clamp + }) => CkImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode); + + @override + ui.ImageFilter createDilateImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + // TODO(fzyzcjy): implement dilate. https://github.com/flutter/flutter/issues/101085 + throw UnimplementedError('ImageFilter.dilate not implemented for CanvasKit.'); + } + + @override + ui.ImageFilter createErodeImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + // TODO(fzyzcjy): implement erode. https://github.com/flutter/flutter/issues/101085 + throw UnimplementedError('ImageFilter.erode not implemented for CanvasKit.'); + } + + @override + ui.ImageFilter createMatrixImageFilter( + Float64List matrix4, { + ui.FilterQuality filterQuality = ui.FilterQuality.low + }) => CkImageFilter.matrix(matrix: matrix4, filterQuality: filterQuality); + + @override + ui.ImageFilter composeImageFilters({required ui.ImageFilter outer, required ui.ImageFilter inner}) { + // TODO(ferhat): add implementation + throw UnimplementedError('ImageFilter.compose not implemented for CanvasKit.'); + } + + @override + Future instantiateImageCodec( + Uint8List list, { + int? targetWidth, + int? targetHeight, + bool allowUpscaling = true + }) async => skiaInstantiateImageCodec( + list, + targetWidth, + targetHeight); + + @override + Future instantiateImageCodecFromUrl( + Uri uri, { + WebOnlyImageCodecChunkCallback? chunkCallback + }) => skiaInstantiateWebImageCodec(uri.toString(), chunkCallback); + + @override + void decodeImageFromPixels( + Uint8List pixels, + int width, + int height, + ui.PixelFormat format, + ui.ImageDecoderCallback callback, { + int? rowBytes, + int? targetWidth, + int? targetHeight, + bool allowUpscaling = true + }) => skiaDecodeImageFromPixels( + pixels, + width, + height, + format, + callback, + rowBytes: rowBytes, + targetWidth: targetWidth, + targetHeight: targetHeight, + allowUpscaling: allowUpscaling + ); + + @override + ui.ImageShader createImageShader( + ui.Image image, + ui.TileMode tmx, + ui.TileMode tmy, + Float64List matrix4, + ui.FilterQuality? filterQuality + ) => CkImageShader(image, tmx, tmy, matrix4, filterQuality); + + @override + ui.Path createPath() => CkPath(); + + @override + ui.Path copyPath(ui.Path src) => CkPath.from(src as CkPath); + + @override + ui.Path combinePaths(ui.PathOperation op, ui.Path path1, ui.Path path2) => + CkPath.combine(op, path1, path2); + + @override + ui.TextStyle createTextStyle({ + ui.Color? color, + ui.TextDecoration? decoration, + ui.Color? decorationColor, + ui.TextDecorationStyle? decorationStyle, + double? decorationThickness, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + ui.TextBaseline? textBaseline, + String? fontFamily, + List? fontFamilyFallback, + double? fontSize, + double? letterSpacing, + double? wordSpacing, + double? height, + ui.TextLeadingDistribution? leadingDistribution, + ui.Locale? locale, + ui.Paint? background, + ui.Paint? foreground, + List? shadows, + List? fontFeatures, + List? fontVariations + }) => CkTextStyle( + color: color, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fontWeight: fontWeight, + fontStyle: fontStyle, + textBaseline: textBaseline, + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontSize: fontSize, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + height: height, + leadingDistribution: leadingDistribution, + locale: locale, + background: background as CkPaint?, + foreground: foreground as CkPaint?, + shadows: shadows, + fontFeatures: fontFeatures, + ); + + @override + ui.ParagraphStyle createParagraphStyle({ + ui.TextAlign? textAlign, + ui.TextDirection? textDirection, + int? maxLines, + String? fontFamily, + double? fontSize, + double? height, + ui.TextHeightBehavior? textHeightBehavior, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + ui.StrutStyle? strutStyle, + String? ellipsis, + ui.Locale? locale + }) => CkParagraphStyle( + textAlign: textAlign, + textDirection: textDirection, + maxLines: maxLines, + fontFamily: fontFamily, + fontSize: fontSize, + height: height, + textHeightBehavior: textHeightBehavior, + fontWeight: fontWeight, + fontStyle: fontStyle, + strutStyle: strutStyle, + ellipsis: ellipsis, + locale: locale, + ); + + @override + ui.StrutStyle createStrutStyle({ + String? fontFamily, + List? fontFamilyFallback, + double? fontSize, + double? height, + ui.TextLeadingDistribution? leadingDistribution, + double? leading, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + bool? forceStrutHeight + }) => CkStrutStyle( + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontSize: fontSize, + height: height, + leadingDistribution: leadingDistribution, + leading: leading, + fontWeight: fontWeight, + fontStyle: fontStyle, + forceStrutHeight: forceStrutHeight, + ); + + @override + ui.ParagraphBuilder createParagraphBuilder(ui.ParagraphStyle style) => + CkParagraphBuilder(style); + + @override + void renderScene(ui.Scene scene) { + // "Build finish" and "raster start" happen back-to-back because we + // render on the same thread, so there's no overhead from hopping to + // another thread. + // + // CanvasKit works differently from the HTML renderer in that in HTML + // we update the DOM in SceneBuilder.build, which is these function calls + // here are CanvasKit-only. + frameTimingsOnBuildFinish(); + frameTimingsOnRasterStart(); + + rasterizer.draw((scene as LayerScene).layerTree); + frameTimingsOnRasterFinish(); + } +} diff --git a/lib/web_ui/lib/src/engine/canvaskit/shader.dart b/lib/web_ui/lib/src/engine/canvaskit/shader.dart index febaacd811567..531a251da5744 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/shader.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/shader.dart @@ -11,7 +11,6 @@ import '../util.dart'; import '../validators.dart'; import 'canvaskit_api.dart'; import 'image.dart'; -import 'initialization.dart'; import 'skia_object_cache.dart'; abstract class CkShader extends ManagedSkiaObject @@ -95,8 +94,6 @@ class CkGradientLinear extends CkShader implements ui.Gradient { @override SkShader createDefault() { - assert(useCanvasKit); - return canvasKit.Shader.MakeLinearGradient( toSkPoint(from), toSkPoint(to), @@ -124,8 +121,6 @@ class CkGradientRadial extends CkShader implements ui.Gradient { @override SkShader createDefault() { - assert(useCanvasKit); - return canvasKit.Shader.MakeRadialGradient( toSkPoint(center), radius, @@ -156,7 +151,6 @@ class CkGradientConical extends CkShader implements ui.Gradient { @override SkShader createDefault() { - assert(useCanvasKit); return canvasKit.Shader.MakeTwoPointConicalGradient( toSkPoint(focal), focalRadius, diff --git a/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart b/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart index 7ec5e1aef9262..21debea93cfb9 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/skia_object_cache.dart @@ -6,9 +6,10 @@ import 'dart:collection'; import 'package:meta/meta.dart'; -import '../../engine.dart' show EnginePlatformDispatcher, Instrumentation; +import '../../engine.dart' show Instrumentation; import '../util.dart'; import 'canvaskit_api.dart'; +import 'renderer.dart'; /// A cache of Skia objects whose memory Flutter manages. /// @@ -533,11 +534,7 @@ class SkiaObjects { if (_addedCleanupCallback) { return; } - // This method is @visibleForTesting but we're getting a warning about - // using a @visibleForTesting member. - // ignore: invalid_use_of_visible_for_testing_member - EnginePlatformDispatcher.instance.rasterizer! - .addPostFrameCallback(postFrameCleanUp); + CanvasKitRenderer.instance.rasterizer.addPostFrameCallback(postFrameCleanUp); _addedCleanupCallback = true; } diff --git a/lib/web_ui/lib/src/engine/canvaskit/surface.dart b/lib/web_ui/lib/src/engine/canvaskit/surface.dart index 144aab63eb37f..7e859ba394864 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/surface.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/surface.dart @@ -13,7 +13,7 @@ import '../util.dart'; import '../window.dart'; import 'canvas.dart'; import 'canvaskit_api.dart'; -import 'initialization.dart'; +import 'renderer.dart'; import 'surface_factory.dart'; import 'util.dart'; @@ -131,7 +131,7 @@ class Surface { void addToScene() { if (!_addedToScene) { - skiaSceneHost!.prepend(htmlElement); + CanvasKitRenderer.instance.sceneHost!.prepend(htmlElement); } _addedToScene = true; } diff --git a/lib/web_ui/lib/src/engine/canvaskit/text.dart b/lib/web_ui/lib/src/engine/canvaskit/text.dart index 1722f77c389c8..01ee84fc7bd30 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/text.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/text.dart @@ -11,8 +11,8 @@ import '../safe_browser_api.dart'; import '../util.dart'; import 'canvaskit_api.dart'; import 'font_fallbacks.dart'; -import 'initialization.dart'; import 'painting.dart'; +import 'renderer.dart'; import 'skia_object_cache.dart'; import 'util.dart'; @@ -843,7 +843,7 @@ class CkParagraphBuilder implements ui.ParagraphBuilder { _styleStack = [], _paragraphBuilder = canvasKit.ParagraphBuilder.MakeFromFontProvider( style.skParagraphStyle, - skiaFontCollection.fontProvider, + CanvasKitRenderer.instance.fontCollection.fontProvider, ) { _styleStack.add(_style.getTextStyle()); } diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart index ef6107e3a6023..ff65ba564948f 100644 --- a/lib/web_ui/lib/src/engine/embedder.dart +++ b/lib/web_ui/lib/src/engine/embedder.dart @@ -6,9 +6,8 @@ import 'dart:async'; import 'package:ui/ui.dart' as ui; -import '../engine.dart' show buildMode, registerHotRestartListener; +import '../engine.dart' show buildMode, registerHotRestartListener, renderer; import 'browser_detection.dart'; -import 'canvaskit/initialization.dart'; import 'configuration.dart'; import 'dom.dart'; import 'host_node.dart'; @@ -199,7 +198,7 @@ class FlutterViewEmbedder { bodyElement.setAttribute( 'flt-renderer', - '${useCanvasKit ? 'canvaskit' : 'html'} (${FlutterConfiguration.flutterWebAutoDetect ? 'auto-selected' : 'requested explicitly'})', + '${renderer.rendererTag} (${FlutterConfiguration.flutterWebAutoDetect ? 'auto-selected' : 'requested explicitly'})', ); bodyElement.setAttribute('flt-build-mode', buildMode); @@ -287,13 +286,7 @@ class FlutterViewEmbedder { _sceneHostElement = domDocument.createElement('flt-scene-host') ..style.pointerEvents = 'none'; - /// CanvasKit uses a static scene element that never gets replaced, so it's - /// added eagerly during initialization here and never touched, unless the - /// system is reset due to hot restart or in a test. - if (useCanvasKit) { - skiaSceneHost = createDomElement('flt-scene'); - addSceneToSceneHost(skiaSceneHost); - } + renderer.reset(this); final DomElement semanticsHostElement = domDocument.createElement('flt-semantics-host'); diff --git a/lib/web_ui/lib/src/engine/fonts.dart b/lib/web_ui/lib/src/engine/fonts.dart new file mode 100644 index 0000000000000..0dd6c816c8357 --- /dev/null +++ b/lib/web_ui/lib/src/engine/fonts.dart @@ -0,0 +1,15 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; + +import 'assets.dart'; + +abstract class FontCollection { + Future loadFontFromList(Uint8List list, {String? fontFamily}); + Future ensureFontsLoaded(); + Future registerFonts(AssetManager assetManager); + void debugRegisterTestFonts(); + void clear(); +} diff --git a/lib/web_ui/lib/src/engine/html/renderer.dart b/lib/web_ui/lib/src/engine/html/renderer.dart new file mode 100644 index 0000000000000..70b69908c26a2 --- /dev/null +++ b/lib/web_ui/lib/src/engine/html/renderer.dart @@ -0,0 +1,336 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; + +class HtmlRenderer implements Renderer { + static HtmlRenderer get instance => _instance; + static late HtmlRenderer _instance; + + @override + String get rendererTag => 'html'; + + late final HtmlFontCollection _fontCollection = HtmlFontCollection(); + + late FlutterViewEmbedder _viewEmbedder; + + @override + HtmlFontCollection get fontCollection => _fontCollection; + + @override + void initialize() { + scheduleMicrotask(() { + // Access [lineLookup] to force the lazy unpacking of line break data + // now. Removing this line won't break anything. It's just an optimization + // to make the unpacking happen while we are waiting for network requests. + lineLookup; + }); + + _instance = this; + } + + @override + void reset(FlutterViewEmbedder embedder) { + _viewEmbedder = embedder; + } + + @override + ui.Paint createPaint() => SurfacePaint(); + + @override + ui.Vertices createVertices( + ui.VertexMode mode, + List positions, { + List? textureCoordinates, + List? colors, + List? indices, + }) => SurfaceVertices( + mode, + positions, + colors: colors, + indices: indices); + + @override + ui.Vertices createVerticesRaw( + ui.VertexMode mode, + Float32List positions, { + Float32List? textureCoordinates, + Int32List? colors, + Uint16List? indices, + }) => SurfaceVertices.raw( + mode, + positions, + colors: colors, + indices: indices); + + @override + ui.Canvas createCanvas(ui.PictureRecorder recorder, [ui.Rect? cullRect]) => + SurfaceCanvas(recorder as EnginePictureRecorder, cullRect); + + @override + ui.Gradient createLinearGradient( + ui.Offset from, + ui.Offset to, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4 + ]) => GradientLinear(from, to, colors, colorStops, tileMode, matrix4); + + @override + ui.Gradient createRadialGradient( + ui.Offset center, + double radius, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4, + ui.Offset? focal, + double focalRadius = 0.0, + ]) => GradientRadial(center, radius, colors, colorStops, tileMode, matrix4); + + @override + ui.Gradient createConicalGradient( + ui.Offset focal, + double focalRadius, + ui.Offset center, + double radius, + List colors, + [List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix + ]) => GradientConical( + focal, + focalRadius, + center, + radius, + colors, + colorStops, + tileMode, + matrix); + + @override + ui.Gradient createSweepGradient( + ui.Offset center, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + double startAngle = 0.0, + double endAngle = math.pi * 2, + Float32List? matrix4 + ]) => GradientSweep(center, colors, colorStops, tileMode, startAngle, endAngle, matrix4); + + @override + ui.PictureRecorder createPictureRecorder() => EnginePictureRecorder(); + + @override + ui.SceneBuilder createSceneBuilder() => SurfaceSceneBuilder(); + + // TODO(ferhat): implement TileMode. + @override + ui.ImageFilter createBlurImageFilter({ + double sigmaX = 0.0, + double sigmaY = 0.0, + ui.TileMode tileMode = ui.TileMode.clamp + }) => EngineImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode); + + @override + ui.ImageFilter createDilateImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + // TODO(fzyzcjy): implement dilate. https://github.com/flutter/flutter/issues/101085 + throw UnimplementedError('ImageFilter.dilate not implemented for HTML renderer.'); + } + + @override + ui.ImageFilter createErodeImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + // TODO(fzyzcjy): implement erode. https://github.com/flutter/flutter/issues/101085 + throw UnimplementedError('ImageFilter.erode not implemented for HTML renderer.'); + } + + @override + ui.ImageFilter createMatrixImageFilter( + Float64List matrix4, { + ui.FilterQuality filterQuality = ui.FilterQuality.low + }) => EngineImageFilter.matrix(matrix: matrix4, filterQuality: filterQuality); + + @override + ui.ImageFilter composeImageFilters({required ui.ImageFilter outer, required ui.ImageFilter inner}) { + // TODO(ferhat): add implementation and remove the "ignore". + // ignore: avoid_unused_constructor_parameters + throw UnimplementedError('ImageFilter.erode not implemented for HTML renderer.'); + } + + @override + Future instantiateImageCodec( + Uint8List list, { + int? targetWidth, + int? targetHeight, + bool allowUpscaling = true}) async { + final DomBlob blob = createDomBlob([list.buffer]); + return HtmlBlobCodec(blob); + } + + @override + Future instantiateImageCodecFromUrl( + Uri uri, { + WebOnlyImageCodecChunkCallback? chunkCallback}) { + return futurize((Callback callback) { + callback(HtmlCodec(uri.toString(), chunkCallback: chunkCallback)); + return null; + }); + } + + @override + void decodeImageFromPixels( + Uint8List pixels, + int width, + int height, + ui.PixelFormat format, + ui.ImageDecoderCallback callback, { + int? rowBytes, + int? targetWidth, + int? targetHeight, + bool allowUpscaling = true + }) { + void executeCallback(ui.Codec codec) { + codec.getNextFrame().then((ui.FrameInfo frameInfo) { + callback(frameInfo.image); + }); + } + ui.createBmp(pixels, width, height, rowBytes ?? width, format).then( + executeCallback); + } + + @override + ui.ImageShader createImageShader( + ui.Image image, + ui.TileMode tmx, + ui.TileMode tmy, + Float64List matrix4, + ui.FilterQuality? filterQuality + ) => EngineImageShader(image, tmx, tmy, matrix4, filterQuality); + + @override + ui.Path createPath() => SurfacePath(); + + @override + ui.Path copyPath(ui.Path src) => SurfacePath.from(src as SurfacePath); + + @override + ui.Path combinePaths(ui.PathOperation op, ui.Path path1, ui.Path path2) { + throw UnimplementedError('combinePaths not implemented in HTML renderer.'); + } + + @override + ui.TextStyle createTextStyle({ + ui.Color? color, + ui.TextDecoration? decoration, + ui.Color? decorationColor, + ui.TextDecorationStyle? decorationStyle, + double? decorationThickness, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + ui.TextBaseline? textBaseline, + String? fontFamily, + List? fontFamilyFallback, + double? fontSize, + double? letterSpacing, + double? wordSpacing, + double? height, + ui.TextLeadingDistribution? leadingDistribution, + ui.Locale? locale, + ui.Paint? background, + ui.Paint? foreground, + List? shadows, + List? fontFeatures, + List? fontVariations + }) => EngineTextStyle( + color: color, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fontWeight: fontWeight, + fontStyle: fontStyle, + textBaseline: textBaseline, + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontSize: fontSize, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + height: height, + locale: locale, + background: background, + foreground: foreground, + shadows: shadows, + fontFeatures: fontFeatures, + fontVariations: fontVariations, + ); + + @override + ui.ParagraphStyle createParagraphStyle({ + ui.TextAlign? textAlign, + ui.TextDirection? textDirection, + int? maxLines, + String? fontFamily, + double? fontSize, + double? height, + ui.TextHeightBehavior? textHeightBehavior, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + ui.StrutStyle? strutStyle, + String? ellipsis, + ui.Locale? locale + }) => EngineParagraphStyle( + textAlign: textAlign, + textDirection: textDirection, + maxLines: maxLines, + fontFamily: fontFamily, + fontSize: fontSize, + height: height, + textHeightBehavior: textHeightBehavior, + fontWeight: fontWeight, + fontStyle: fontStyle, + strutStyle: strutStyle, + ellipsis: ellipsis, + locale: locale, + ); + + @override + ui.StrutStyle createStrutStyle({ + String? fontFamily, + List? fontFamilyFallback, + double? fontSize, + double? height, + ui.TextLeadingDistribution? leadingDistribution, + double? leading, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + bool? forceStrutHeight + }) => EngineStrutStyle( + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontSize: fontSize, + height: height, + leadingDistribution: leadingDistribution, + leading: leading, + fontWeight: fontWeight, + fontStyle: fontStyle, + forceStrutHeight: forceStrutHeight, + ); + + @override + ui.ParagraphBuilder createParagraphBuilder(ui.ParagraphStyle style) => + CanvasParagraphBuilder(style as EngineParagraphStyle); + + @override + void renderScene(ui.Scene scene) { + _viewEmbedder.addSceneToSceneHost((scene as SurfaceScene).webOnlyRootElement); + frameTimingsOnRasterFinish(); + } +} diff --git a/lib/web_ui/lib/src/engine/initialization.dart b/lib/web_ui/lib/src/engine/initialization.dart index 1257c677f8ab9..682f1e13c9b75 100644 --- a/lib/web_ui/lib/src/engine/initialization.dart +++ b/lib/web_ui/lib/src/engine/initialization.dart @@ -7,7 +7,6 @@ import 'dart:developer' as developer; import 'package:ui/src/engine/assets.dart'; import 'package:ui/src/engine/browser_detection.dart'; -import 'package:ui/src/engine/canvaskit/initialization.dart'; import 'package:ui/src/engine/embedder.dart'; import 'package:ui/src/engine/keyboard.dart'; import 'package:ui/src/engine/mouse_cursor.dart'; @@ -15,9 +14,8 @@ import 'package:ui/src/engine/navigation.dart'; import 'package:ui/src/engine/platform_dispatcher.dart'; import 'package:ui/src/engine/platform_views/content_manager.dart'; import 'package:ui/src/engine/profiler.dart'; +import 'package:ui/src/engine/renderer.dart'; import 'package:ui/src/engine/safe_browser_api.dart'; -import 'package:ui/src/engine/text/font_collection.dart'; -import 'package:ui/src/engine/text/line_break_properties.dart'; import 'package:ui/src/engine/window.dart'; import 'package:ui/ui.dart' as ui; @@ -141,15 +139,6 @@ Future initializeEngineServices({ } _initializationState = DebugEngineInitializationState.initializingServices; - if (!useCanvasKit) { - scheduleMicrotask(() { - // Access [lineLookup] to force the lazy unpacking of line break data - // now. Removing this line won't break anything. It's just an optimization - // to make the unpacking happen while we are waiting for network requests. - lineLookup; - }); - } - // Setup the hook that allows users to customize URL strategy before running // the app. _addUrlStrategyListener(); @@ -215,19 +204,11 @@ Future initializeEngineServices({ } }; - // This needs to be after `initializeEngine` because that is where the - // canvaskit script is added to the page. - if (useCanvasKit) { - await initializeCanvasKit(); - } + await renderer.initialize(); assetManager ??= const AssetManager(); await _setAssetManager(assetManager); - if (useCanvasKit) { - await skiaFontCollection.ensureFontsLoaded(); - } else { - await _fontCollection!.ensureFontsLoaded(); - } + await renderer.fontCollection.ensureFontsLoaded(); _initializationState = DebugEngineInitializationState.initializedServices; } @@ -262,9 +243,6 @@ Future initializeEngineUi() async { AssetManager get assetManager => _assetManager!; AssetManager? _assetManager; -FontCollection get fontCollection => _fontCollection!; -FontCollection? _fontCollection; - Future _setAssetManager(AssetManager assetManager) async { assert(assetManager != null, 'Cannot set assetManager to null'); if (assetManager == _assetManager) { @@ -273,27 +251,14 @@ Future _setAssetManager(AssetManager assetManager) async { _assetManager = assetManager; - if (useCanvasKit) { - ensureSkiaFontCollectionInitialized(); - } else { - _fontCollection ??= FontCollection(); - _fontCollection!.clear(); - } + renderer.fontCollection.clear(); if (_assetManager != null) { - if (useCanvasKit) { - await skiaFontCollection.registerFonts(_assetManager!); - } else { - await _fontCollection!.registerFonts(_assetManager!); - } + await renderer.fontCollection.registerFonts(assetManager); } if (ui.debugEmulateFlutterTesterEnvironment) { - if (useCanvasKit) { - skiaFontCollection.debugRegisterTestFonts(); - } else { - _fontCollection!.debugRegisterTestFonts(); - } + renderer.fontCollection.debugRegisterTestFonts(); } } diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index e195aec769295..311be4fa5e391 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -6,21 +6,17 @@ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; -import 'package:meta/meta.dart'; +import 'package:ui/src/engine/canvaskit/renderer.dart'; +import 'package:ui/src/engine/renderer.dart'; import 'package:ui/ui.dart' as ui; import '../engine.dart' show platformViewManager, registerHotRestartListener; -import 'canvaskit/initialization.dart'; -import 'canvaskit/layer_scene_builder.dart'; -import 'canvaskit/rasterizer.dart'; import 'clipboard.dart'; import 'dom.dart'; import 'embedder.dart'; -import 'html/scene.dart'; import 'mouse_cursor.dart'; import 'platform_views/message_handler.dart'; import 'plugins.dart'; -import 'profiler.dart'; import 'safe_browser_api.dart'; import 'semantics.dart'; import 'services.dart'; @@ -433,15 +429,13 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { final MethodCall decoded = codec.decodeMethodCall(data); switch (decoded.method) { case 'Skia.setResourceCacheMaxBytes': - if (useCanvasKit) { - // If we're in CanvasKit mode, we must also have a rasterizer. - assert(rasterizer != null); + if (renderer is CanvasKitRenderer) { assert( decoded.arguments is int, 'Argument to Skia.setResourceCacheMaxBytes must be an int, but was ${decoded.arguments.runtimeType}', ); final int cacheSizeInBytes = decoded.arguments as int; - rasterizer!.setSkiaResourceCacheMaxBytes(cacheSizeInBytes); + CanvasKitRenderer.instance.resourceCacheMaxBytes = cacheSizeInBytes; } // Also respond in HTML mode. Otherwise, apps would have to detect @@ -651,24 +645,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { /// painting. @override void render(ui.Scene scene, [ui.FlutterView? view]) { - if (useCanvasKit) { - // "Build finish" and "raster start" happen back-to-back because we - // render on the same thread, so there's no overhead from hopping to - // another thread. - // - // CanvasKit works differently from the HTML renderer in that in HTML - // we update the DOM in SceneBuilder.build, which is these function calls - // here are CanvasKit-only. - frameTimingsOnBuildFinish(); - frameTimingsOnRasterStart(); - - final LayerScene layerScene = scene as LayerScene; - rasterizer!.draw(layerScene.layerTree); - } else { - final SurfaceScene surfaceScene = scene as SurfaceScene; - flutterViewEmbedder.addSceneToSceneHost(surfaceScene.webOnlyRootElement); - } - frameTimingsOnRasterFinish(); + renderer.renderScene(scene); } /// Additional accessibility features that may be enabled by the platform. @@ -1144,9 +1121,6 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { /// to set [locationStrategy] in `lib/initialization.dart`. String? _defaultRouteName; - @visibleForTesting - late Rasterizer? rasterizer = useCanvasKit ? Rasterizer() : null; - /// In Flutter, platform messages are exchanged between threads so the /// messages and responses have to be exchanged asynchronously. We simulate /// that by adding a zero-length delay to the reply. diff --git a/lib/web_ui/lib/src/engine/renderer.dart b/lib/web_ui/lib/src/engine/renderer.dart new file mode 100644 index 0000000000000..e66d77f2d264b --- /dev/null +++ b/lib/web_ui/lib/src/engine/renderer.dart @@ -0,0 +1,210 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:ui/ui.dart' as ui; + +import 'browser_detection.dart'; +import 'canvaskit/renderer.dart'; +import 'configuration.dart'; +import 'embedder.dart'; +import 'fonts.dart'; +import 'html/renderer.dart'; +import 'html_image_codec.dart'; + +final Renderer _renderer = Renderer._internal(); +Renderer get renderer => _renderer; + +/// This class is an abstraction over the rendering backend for the web engine. +/// Which backend is selected is based off of the `--web-renderer` command-line +/// argument passed to the flutter tool. It provides many of the rendering +/// primitives of the dart:ui library, as well as other backend-specific pieces +/// of functionality needed by the rest of the generic web engine code. +abstract class Renderer { + factory Renderer._internal() { + bool useCanvasKit; + if (FlutterConfiguration.flutterWebAutoDetect) { + if (requestedRendererType != null) { + useCanvasKit = requestedRendererType == 'canvaskit'; + } else { + // If requestedRendererType is not specified, use CanvasKit for desktop and + // html for mobile. + useCanvasKit = isDesktop; + } + } else { + useCanvasKit = FlutterConfiguration.useSkia; + } + + return useCanvasKit ? CanvasKitRenderer() : HtmlRenderer(); + } + + String get rendererTag; + FontCollection get fontCollection; + + FutureOr initialize(); + void reset(FlutterViewEmbedder embedder); + + ui.Paint createPaint(); + + ui.Vertices createVertices( + ui.VertexMode mode, + List positions, { + List? textureCoordinates, + List? colors, + List? indices, + }); + ui.Vertices createVerticesRaw( + ui.VertexMode mode, + Float32List positions, { + Float32List? textureCoordinates, + Int32List? colors, + Uint16List? indices, + }); + + ui.PictureRecorder createPictureRecorder(); + ui.Canvas createCanvas(ui.PictureRecorder recorder, [ui.Rect? cullRect]); + ui.SceneBuilder createSceneBuilder(); + + ui.Gradient createLinearGradient( + ui.Offset from, + ui.Offset to, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4, + ]); + ui.Gradient createRadialGradient( + ui.Offset center, + double radius, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix4, + ]); + ui.Gradient createConicalGradient( + ui.Offset focal, + double focalRadius, + ui.Offset center, + double radius, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + Float32List? matrix, + ]); + ui.Gradient createSweepGradient( + ui.Offset center, + List colors, [ + List? colorStops, + ui.TileMode tileMode = ui.TileMode.clamp, + double startAngle = 0.0, + double endAngle = math.pi * 2, + Float32List? matrix4, + ]); + + ui.ImageFilter createBlurImageFilter({ + double sigmaX = 0.0, + double sigmaY = 0.0, + ui.TileMode tileMode = ui.TileMode.clamp}); + ui.ImageFilter createDilateImageFilter({ double radiusX = 0.0, double radiusY = 0.0}); + ui.ImageFilter createErodeImageFilter({ double radiusX = 0.0, double radiusY = 0.0}); + ui.ImageFilter createMatrixImageFilter( + Float64List matrix4, { + ui.FilterQuality filterQuality = ui.FilterQuality.low + }); + ui.ImageFilter composeImageFilters({required ui.ImageFilter outer, required ui.ImageFilter inner}); + + Future instantiateImageCodec( + Uint8List list, { + int? targetWidth, + int? targetHeight, + bool allowUpscaling = true, + }); + + Future instantiateImageCodecFromUrl( + Uri uri, { + WebOnlyImageCodecChunkCallback? chunkCallback, + }); + + void decodeImageFromPixels( + Uint8List pixels, + int width, + int height, + ui.PixelFormat format, + ui.ImageDecoderCallback callback, { + int? rowBytes, + int? targetWidth, + int? targetHeight, + bool allowUpscaling = true + }); + + ui.ImageShader createImageShader( + ui.Image image, + ui.TileMode tmx, + ui.TileMode tmy, + Float64List matrix4, + ui.FilterQuality? filterQuality, + ); + + ui.Path createPath(); + ui.Path copyPath(ui.Path src); + ui.Path combinePaths(ui.PathOperation op, ui.Path path1, ui.Path path2); + + ui.TextStyle createTextStyle({ + ui.Color? color, + ui.TextDecoration? decoration, + ui.Color? decorationColor, + ui.TextDecorationStyle? decorationStyle, + double? decorationThickness, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + ui.TextBaseline? textBaseline, + String? fontFamily, + List? fontFamilyFallback, + double? fontSize, + double? letterSpacing, + double? wordSpacing, + double? height, + ui.TextLeadingDistribution? leadingDistribution, + ui.Locale? locale, + ui.Paint? background, + ui.Paint? foreground, + List? shadows, + List? fontFeatures, + List? fontVariations, + }); + + ui.ParagraphStyle createParagraphStyle({ + ui.TextAlign? textAlign, + ui.TextDirection? textDirection, + int? maxLines, + String? fontFamily, + double? fontSize, + double? height, + ui.TextHeightBehavior? textHeightBehavior, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + ui.StrutStyle? strutStyle, + String? ellipsis, + ui.Locale? locale, + }); + + ui.StrutStyle createStrutStyle({ + String? fontFamily, + List? fontFamilyFallback, + double? fontSize, + double? height, + ui.TextLeadingDistribution? leadingDistribution, + double? leading, + ui.FontWeight? fontWeight, + ui.FontStyle? fontStyle, + bool? forceStrutHeight, + }); + + ui.ParagraphBuilder createParagraphBuilder(ui.ParagraphStyle style); + + void renderScene(ui.Scene scene); +} diff --git a/lib/web_ui/lib/src/engine/text/font_collection.dart b/lib/web_ui/lib/src/engine/text/font_collection.dart index 8eda9e38319ad..864d0f9d99660 100644 --- a/lib/web_ui/lib/src/engine/text/font_collection.dart +++ b/lib/web_ui/lib/src/engine/text/font_collection.dart @@ -6,6 +6,8 @@ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; +import 'package:ui/src/engine/fonts.dart'; + import '../assets.dart'; import '../browser_detection.dart'; import '../dom.dart'; @@ -26,12 +28,13 @@ const String robotoVariableTestFontUrl = '/assets/fonts/RobotoSlab-VariableFont_ /// [registerFonts] with it to register fonts declared in the /// font manifest. If test fonts are enabled, then call /// [registerTestFonts] as well. -class FontCollection { +class HtmlFontCollection implements FontCollection { FontManager? _assetFontManager; FontManager? _testFontManager; /// Reads the font manifest using the [assetManager] and registers all of the /// fonts declared within. + @override Future registerFonts(AssetManager assetManager) async { ByteData byteData; @@ -78,11 +81,16 @@ class FontCollection { } } - Future loadFontFromList(Uint8List list, {required String fontFamily}) { + @override + Future loadFontFromList(Uint8List list, {String? fontFamily}) { + if (fontFamily == null) { + throw AssertionError('Font family must be provided to HtmlFontCollection.'); + } return _assetFontManager!._loadFontFaceBytes(fontFamily, list); } /// Registers fonts that are used by tests. + @override void debugRegisterTestFonts() { _testFontManager = FontManager(); _testFontManager!.registerAsset( @@ -95,12 +103,14 @@ class FontCollection { /// Returns a [Future] that completes when the registered fonts are loaded /// and ready to be used. + @override Future ensureFontsLoaded() async { await _assetFontManager?.ensureFontsLoaded(); await _testFontManager?.ensureFontsLoaded(); } /// Unregister all fonts that have been registered. + @override void clear() { _assetFontManager = null; _testFontManager = null; diff --git a/lib/web_ui/lib/text.dart b/lib/web_ui/lib/text.dart index 30e0ed35de273..1712155ad91c3 100644 --- a/lib/web_ui/lib/text.dart +++ b/lib/web_ui/lib/text.dart @@ -342,55 +342,29 @@ abstract class TextStyle { List? shadows, List? fontFeatures, List? fontVariations, - }) { - if (engine.useCanvasKit) { - return engine.CkTextStyle( - color: color, - decoration: decoration, - decorationColor: decorationColor, - decorationStyle: decorationStyle, - decorationThickness: decorationThickness, - fontWeight: fontWeight, - fontStyle: fontStyle, - textBaseline: textBaseline, - fontFamily: fontFamily, - fontFamilyFallback: fontFamilyFallback, - fontSize: fontSize, - letterSpacing: letterSpacing, - wordSpacing: wordSpacing, - height: height, - leadingDistribution: leadingDistribution, - locale: locale, - background: background as engine.CkPaint?, - foreground: foreground as engine.CkPaint?, - shadows: shadows, - fontFeatures: fontFeatures, - ); - } else { - return engine.EngineTextStyle( - color: color, - decoration: decoration, - decorationColor: decorationColor, - decorationStyle: decorationStyle, - decorationThickness: decorationThickness, - fontWeight: fontWeight, - fontStyle: fontStyle, - textBaseline: textBaseline, - fontFamily: fontFamily, - fontFamilyFallback: fontFamilyFallback, - fontSize: fontSize, - letterSpacing: letterSpacing, - wordSpacing: wordSpacing, - height: height, - locale: locale, - background: background, - foreground: foreground, - shadows: shadows, - fontFeatures: fontFeatures, - fontVariations: fontVariations, - ); - } - } + }) => engine.renderer.createTextStyle( + color: color, + decoration: decoration, + decorationColor: decorationColor, + decorationStyle: decorationStyle, + decorationThickness: decorationThickness, + fontWeight: fontWeight, + fontStyle: fontStyle, + textBaseline: textBaseline, + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontSize: fontSize, + letterSpacing: letterSpacing, + wordSpacing: wordSpacing, + height: height, + leadingDistribution: leadingDistribution, + locale: locale, + background: background, + foreground: foreground, + shadows: shadows, + fontFeatures: fontFeatures, + fontVariations: fontVariations, + ); } abstract class ParagraphStyle { @@ -408,39 +382,20 @@ abstract class ParagraphStyle { StrutStyle? strutStyle, String? ellipsis, Locale? locale, - }) { - if (engine.useCanvasKit) { - return engine.CkParagraphStyle( - textAlign: textAlign, - textDirection: textDirection, - maxLines: maxLines, - fontFamily: fontFamily, - fontSize: fontSize, - height: height, - textHeightBehavior: textHeightBehavior, - fontWeight: fontWeight, - fontStyle: fontStyle, - strutStyle: strutStyle, - ellipsis: ellipsis, - locale: locale, - ); - } else { - return engine.EngineParagraphStyle( - textAlign: textAlign, - textDirection: textDirection, - maxLines: maxLines, - fontFamily: fontFamily, - fontSize: fontSize, - height: height, - textHeightBehavior: textHeightBehavior, - fontWeight: fontWeight, - fontStyle: fontStyle, - strutStyle: strutStyle, - ellipsis: ellipsis, - locale: locale, - ); - } - } + }) => engine.renderer.createParagraphStyle( + textAlign: textAlign, + textDirection: textDirection, + maxLines: maxLines, + fontFamily: fontFamily, + fontSize: fontSize, + height: height, + textHeightBehavior: textHeightBehavior, + fontWeight: fontWeight, + fontStyle: fontStyle, + strutStyle: strutStyle, + ellipsis: ellipsis, + locale: locale, + ); } abstract class StrutStyle { @@ -489,33 +444,17 @@ abstract class StrutStyle { FontWeight? fontWeight, FontStyle? fontStyle, bool? forceStrutHeight, - }) { - if (engine.useCanvasKit) { - return engine.CkStrutStyle( - fontFamily: fontFamily, - fontFamilyFallback: fontFamilyFallback, - fontSize: fontSize, - height: height, - leadingDistribution: leadingDistribution, - leading: leading, - fontWeight: fontWeight, - fontStyle: fontStyle, - forceStrutHeight: forceStrutHeight, - ); - } else { - return engine.EngineStrutStyle( - fontFamily: fontFamily, - fontFamilyFallback: fontFamilyFallback, - fontSize: fontSize, - height: height, - leadingDistribution: leadingDistribution, - leading: leading, - fontWeight: fontWeight, - fontStyle: fontStyle, - forceStrutHeight: forceStrutHeight, - ); - } - } + }) => engine.renderer.createStrutStyle( + fontFamily: fontFamily, + fontFamilyFallback: fontFamilyFallback, + fontSize: fontSize, + height: height, + leadingDistribution: leadingDistribution, + leading: leading, + fontWeight: fontWeight, + fontStyle: fontStyle, + forceStrutHeight: forceStrutHeight, + ); } // The order of this enum must match the order of the values in TextDirection.h's TextDirection. @@ -734,12 +673,8 @@ abstract class Paragraph { } abstract class ParagraphBuilder { - factory ParagraphBuilder(ParagraphStyle style) { - if (engine.useCanvasKit) { - return engine.CkParagraphBuilder(style); - } - return engine.CanvasParagraphBuilder(style as engine.EngineParagraphStyle); - } + factory ParagraphBuilder(ParagraphStyle style) => + engine.renderer.createParagraphBuilder(style); void pushStyle(TextStyle style); void pop(); void addText(String text); @@ -756,14 +691,7 @@ abstract class ParagraphBuilder { }); } -Future loadFontFromList(Uint8List list, {String? fontFamily}) { - if (engine.useCanvasKit) { - return engine.skiaFontCollection - .loadFontFromList(list, fontFamily: fontFamily) - .then((_) => engine.sendFontChangeMessage()); - } else { - return engine.fontCollection - .loadFontFromList(list, fontFamily: fontFamily!) - .then((_) => engine.sendFontChangeMessage()); - } +Future loadFontFromList(Uint8List list, {String? fontFamily}) async { + await engine.renderer.fontCollection.loadFontFromList(list, fontFamily: fontFamily); + engine.sendFontChangeMessage(); } diff --git a/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart b/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart index 67d4b003a5b1c..ca1d16f6c6826 100644 --- a/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart +++ b/lib/web_ui/test/canvaskit/backdrop_filter_golden_test.dart @@ -49,8 +49,7 @@ void testMain() { builder.pushOffset(0, 0); builder.addPicture(ui.Offset.zero, checkerboard); builder.pushBackdropFilter(ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10)); - EnginePlatformDispatcher.instance.rasterizer! - .draw(builder.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(builder.build().layerTree); await matchGoldenFile('canvaskit_backdropfilter_blur_edges.png', region: region); }); diff --git a/lib/web_ui/test/canvaskit/canvas_golden_test.dart b/lib/web_ui/test/canvaskit/canvas_golden_test.dart index 77a3a57eb7fc5..3c093f7d6a5f9 100644 --- a/lib/web_ui/test/canvaskit/canvas_golden_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_golden_test.dart @@ -219,9 +219,7 @@ void testMain() { // Render again, this time with the shadow bounds. final LayerTree layerTree = buildTestScene(paintShadowBounds: true); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - dispatcher.rasterizer!.draw(layerTree); + CanvasKitRenderer.instance.rasterizer.draw(layerTree); await matchGoldenFile('canvaskit_shadow_bounds.png', region: region); }); @@ -802,14 +800,14 @@ void testMain() { builder.pushOffset(0, 0); builder.addPicture(ui.Offset.zero, picture); final LayerTree layerTree = builder.build().layerTree; - EnginePlatformDispatcher.instance.rasterizer!.draw(layerTree); + CanvasKitRenderer.instance.rasterizer.draw(layerTree); // Now draw an empty layer tree and confirm that the red rectangle is // no longer drawn. final LayerSceneBuilder emptySceneBuilder = LayerSceneBuilder(); emptySceneBuilder.pushOffset(0, 0); final LayerTree emptyLayerTree = emptySceneBuilder.build().layerTree; - EnginePlatformDispatcher.instance.rasterizer!.draw(emptyLayerTree); + CanvasKitRenderer.instance.rasterizer.draw(emptyLayerTree); await matchGoldenFile('canvaskit_empty_scene.png', region: const ui.Rect.fromLTRB(0, 0, 100, 100)); @@ -1340,7 +1338,7 @@ Future generatePictureWhenFontsStable( PictureGenerator generator) async { CkPicture picture = generator(); // Fallback fonts start downloading as a post-frame callback. - EnginePlatformDispatcher.instance.rasterizer!.debugRunPostFrameCallbacks(); + CanvasKitRenderer.instance.rasterizer.debugRunPostFrameCallbacks(); // Font downloading begins asynchronously so we inject a timer before checking the download queue. await Future.delayed(Duration.zero); while (notoDownloadQueue.isPending || @@ -1348,7 +1346,7 @@ Future generatePictureWhenFontsStable( await notoDownloadQueue.debugWhenIdle(); await notoDownloadQueue.downloader.debugWhenIdle(); picture = generator(); - EnginePlatformDispatcher.instance.rasterizer!.debugRunPostFrameCallbacks(); + CanvasKitRenderer.instance.rasterizer.debugRunPostFrameCallbacks(); // Dummy timer for the same reason as above. await Future.delayed(Duration.zero); } diff --git a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart index eae7a3bee5730..551c9fadcba7a 100644 --- a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart +++ b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart @@ -1490,7 +1490,7 @@ void _paragraphTests() { final SkParagraphStyle paragraphStyle = canvasKit.ParagraphStyle(props); final SkParagraphBuilder builder = canvasKit.ParagraphBuilder.Make( paragraphStyle, - skiaFontCollection.skFontMgr, + CanvasKitRenderer.instance.fontCollection.skFontMgr, ); builder.addText('Hello'); @@ -1587,7 +1587,7 @@ void _paragraphTests() { final SkParagraphBuilder builder = canvasKit.ParagraphBuilder.MakeFromFontProvider( paragraphStyle, - skiaFontCollection.fontProvider, + CanvasKitRenderer.instance.fontCollection.fontProvider, ); builder.addText('hello'); diff --git a/lib/web_ui/test/canvaskit/color_filter_golden_test.dart b/lib/web_ui/test/canvaskit/color_filter_golden_test.dart index 9833ee1fd577c..4a5fd312e672e 100644 --- a/lib/web_ui/test/canvaskit/color_filter_golden_test.dart +++ b/lib/web_ui/test/canvaskit/color_filter_golden_test.dart @@ -19,9 +19,7 @@ const ui.Rect region = ui.Rect.fromLTRB(0, 0, 500, 250); Future matchSceneGolden(String goldenFile, LayerScene scene, {bool write = false}) async { - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - dispatcher.rasterizer!.draw(scene.layerTree); + CanvasKitRenderer.instance.rasterizer.draw(scene.layerTree); await matchGoldenFile(goldenFile, region: region, write: write); } diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index 9b3275f4da4dc..bbf0db785858b 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -21,7 +21,7 @@ const MethodCodec codec = StandardMethodCodec(); /// Common test setup for all CanvasKit unit-tests. void setUpCanvasKitTest() { setUpAll(() async { - expect(useCanvasKit, true, reason: 'This test must run in CanvasKit mode.'); + expect(renderer, isA(), reason: 'This test must run in CanvasKit mode.'); debugResetBrowserSupportsFinalizationRegistry(); await initializeEngine(assetManager: WebOnlyMockAssetManager()); }); @@ -180,12 +180,10 @@ class TestCollector implements Collector { /// layers. Future matchPictureGolden(String goldenFile, CkPicture picture, {required ui.Rect region, bool write = false}) async { - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPicture(ui.Offset.zero, picture); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); await matchGoldenFile(goldenFile, region: region, maxDiffRatePercent: 0.0, write: write); } diff --git a/lib/web_ui/test/canvaskit/embedded_views_test.dart b/lib/web_ui/test/canvaskit/embedded_views_test.dart index 61ce23a724830..7cdb18c0120dd 100644 --- a/lib/web_ui/test/canvaskit/embedded_views_test.dart +++ b/lib/web_ui/test/canvaskit/embedded_views_test.dart @@ -24,18 +24,17 @@ void testMain() { }); test('embeds interactive platform views', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; ui.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(0, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); // The platform view is now split in two parts. The contents live // as a child of the glassPane, and the slot lives in the glassPane @@ -60,20 +59,19 @@ void testMain() { }); test('clips platform views with RRects', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; ui.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.pushClipRRect( ui.RRect.fromLTRBR(0, 0, 10, 10, const ui.Radius.circular(3))); sb.addPlatformView(0, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); expect( flutterViewEmbedder.sceneElement! @@ -100,14 +98,13 @@ void testMain() { }); test('correctly transforms platform views', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; ui.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); final Matrix4 scaleMatrix = Matrix4.identity() @@ -116,7 +113,7 @@ void testMain() { sb.pushTransform(scaleMatrix.toFloat64()); sb.pushOffset(3, 3); sb.addPlatformView(0, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); // Transformations happen on the slot element. final DomElement slotHost = flutterViewEmbedder.sceneElement! @@ -138,11 +135,9 @@ void testMain() { ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; final LayerSceneBuilder sb = LayerSceneBuilder(); sb.addPlatformView(0, offset: const ui.Offset(3, 4), width: 5, height: 6); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); final DomElement slotHost = flutterViewEmbedder.sceneElement! .querySelector('flt-platform-view-slot')!; @@ -178,15 +173,13 @@ void testMain() { ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(3, 3); sb.pushClipRect(ui.Rect.largest); sb.pushOffset(6, 6); sb.addPlatformView(0, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); // Transformations happen on the slot element. DomElement slotHost = flutterViewEmbedder.sceneElement! @@ -207,7 +200,7 @@ void testMain() { sb.pushClipRect(ui.Rect.largest); sb.pushOffset(9, 9); sb.addPlatformView(0, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); // Transformations happen on the slot element. slotHost = flutterViewEmbedder.sceneElement! @@ -231,14 +224,12 @@ void testMain() { ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(1, 1); sb.pushOffset(2, 2); sb.pushOffset(3, 3); sb.addPlatformView(0, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); // Transformations happen on the slot element. final DomElement slotHost = flutterViewEmbedder.sceneElement! @@ -258,8 +249,6 @@ void testMain() { ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(3, 3); sb.pushClipRect(ui.Rect.largest); @@ -267,7 +256,7 @@ void testMain() { sb.pushClipRect(ui.Rect.largest); sb.pushOffset(9, 9); sb.addPlatformView(0, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); // Transformations happen on the slot element. final DomElement slotHost = flutterViewEmbedder.sceneElement! @@ -302,9 +291,6 @@ void testMain() { platformViewIds.add(i); } - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - void renderTestScene({required int viewCount}) { final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); @@ -312,7 +298,7 @@ void testMain() { sb.addPicture(ui.Offset.zero, testPicture); sb.addPlatformView(i, width: 10, height: 10); } - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); } // Frame 1: @@ -458,9 +444,6 @@ void testMain() { platformViewIds.add(i); } - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - void renderTestScene(List views) { final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); @@ -468,7 +451,7 @@ void testMain() { sb.addPicture(ui.Offset.zero, testPicture); sb.addPlatformView(view, width: 10, height: 10); } - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); } // Frame 1: @@ -586,13 +569,10 @@ void testMain() { ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(0, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -609,7 +589,7 @@ void testMain() { sb = LayerSceneBuilder(); sb.pushOffset(0, 0); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, @@ -623,19 +603,17 @@ void testMain() { }); test('removed the DOM node of an unrendered platform view', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; ui.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(0, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -653,7 +631,7 @@ void testMain() { sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(1, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -669,7 +647,7 @@ void testMain() { // the platform view. sb = LayerSceneBuilder(); sb.pushOffset(0, 0); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, ]); @@ -685,22 +663,20 @@ void testMain() { test( 'removes old SVG clip definitions from the DOM when the view is recomposited', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; ui.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'test-view', ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - void renderTestScene() { final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.pushClipRRect( ui.RRect.fromLTRBR(0, 0, 10, 10, const ui.Radius.circular(3))); sb.addPlatformView(0, width: 10, height: 10); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); } final DomNode skPathDefs = flutterViewEmbedder.sceneElement! @@ -722,28 +698,27 @@ void testMain() { test('does not crash when a prerolled platform view is not composited', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; ui.platformViewRegistry.registerViewFactory( 'test-platform-view', (int viewId) => createDomHTMLDivElement()..id = 'view-0', ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.pushClipRect(ui.Rect.zero); sb.addPlatformView(0, width: 10, height: 10); sb.pop(); // The below line should not throw an error. - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, ]); }); test('does not crash when overlays are disabled', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; HtmlViewEmbedder.debugDisableOverlays = true; ui.platformViewRegistry.registerViewFactory( 'test-platform-view', @@ -751,15 +726,12 @@ void testMain() { ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(0, width: 10, height: 10); sb.pop(); // The below line should not throw an error. - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -768,6 +740,7 @@ void testMain() { }); test('works correctly with max overlays == 2', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; debugSetConfiguration(FlutterConfiguration( JsFlutterConfiguration()..canvasKitMaximumSurfaces = 2)); SurfaceFactory.instance.debugClear(); @@ -782,15 +755,12 @@ void testMain() { await createPlatformView(0, 'test-platform-view'); await createPlatformView(1, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(0, width: 10, height: 10); sb.pop(); // The below line should not throw an error. - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, @@ -804,7 +774,7 @@ void testMain() { sb.addPlatformView(0, width: 10, height: 10); sb.pop(); // The below line should not throw an error. - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, @@ -820,6 +790,7 @@ void testMain() { test( 'correctly renders when overlays are disabled and a subset ' 'of views is used', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; HtmlViewEmbedder.debugDisableOverlays = true; ui.platformViewRegistry.registerViewFactory( 'test-platform-view', @@ -828,16 +799,13 @@ void testMain() { await createPlatformView(0, 'test-platform-view'); await createPlatformView(1, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPlatformView(0, width: 10, height: 10); sb.addPlatformView(1, width: 10, height: 10); sb.pop(); // The below line should not throw an error. - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -849,7 +817,7 @@ void testMain() { sb.addPlatformView(1, width: 10, height: 10); sb.pop(); // The below line should not throw an error. - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -859,6 +827,7 @@ void testMain() { }); test('does not create overlays for invisible platform views', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; ui.platformViewRegistry.registerViewFactory( 'test-visible-view', (int viewId) => @@ -877,9 +846,6 @@ void testMain() { await createPlatformView(5, 'test-invisible-view'); await createPlatformView(6, 'test-invisible-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - expect(platformViewManager.isInvisible(0), isFalse); expect(platformViewManager.isInvisible(1), isTrue); @@ -887,7 +853,7 @@ void testMain() { sb.pushOffset(0, 0); sb.addPlatformView(1, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -899,7 +865,7 @@ void testMain() { sb.addPlatformView(0, width: 10, height: 10); sb.addPlatformView(1, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -913,7 +879,7 @@ void testMain() { sb.addPlatformView(1, width: 10, height: 10); sb.addPlatformView(2, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -930,7 +896,7 @@ void testMain() { sb.addPlatformView(2, width: 10, height: 10); sb.addPlatformView(3, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -949,7 +915,7 @@ void testMain() { sb.addPlatformView(3, width: 10, height: 10); sb.addPlatformView(4, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -970,7 +936,7 @@ void testMain() { sb.addPlatformView(4, width: 10, height: 10); sb.addPlatformView(5, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -993,7 +959,7 @@ void testMain() { sb.addPlatformView(5, width: 10, height: 10); sb.addPlatformView(6, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -1015,7 +981,7 @@ void testMain() { sb.addPlatformView(5, width: 10, height: 10); sb.addPlatformView(6, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -1033,7 +999,7 @@ void testMain() { sb.addPlatformView(3, width: 10, height: 10); sb.addPlatformView(4, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, @@ -1050,7 +1016,7 @@ void testMain() { sb.addPlatformView(2, width: 10, height: 10); sb.addPlatformView(1, width: 10, height: 10); sb.pop(); - dispatcher.rasterizer!.draw(sb.build().layerTree); + rasterizer.draw(sb.build().layerTree); _expectSceneMatches(<_EmbeddedViewMarker>[ _overlay, _platformView, diff --git a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart index ed1293b813e23..b8ff69a560516 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -43,6 +43,7 @@ void testMain() { }); test('will download Noto Naskh Arabic if Arabic text is added', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; TestDownloader.mockDownloads[ 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = ''' @@ -65,8 +66,7 @@ void testMain() { ); pb.addText('مرحبا'); - EnginePlatformDispatcher.instance.rasterizer! - .debugRunPostFrameCallbacks(); + rasterizer.debugRunPostFrameCallbacks(); await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, @@ -96,6 +96,7 @@ void testMain() { test('will put the Noto Emoji font before other fallback fonts in the list', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; TestDownloader.mockDownloads[ 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'] = ''' @@ -127,8 +128,7 @@ void testMain() { ); pb.addText('مرحبا'); - EnginePlatformDispatcher.instance.rasterizer! - .debugRunPostFrameCallbacks(); + rasterizer.debugRunPostFrameCallbacks(); await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, @@ -143,8 +143,7 @@ void testMain() { final CkParagraph paragraph = pb.build(); paragraph.layout(const ui.ParagraphConstraints(width: 1000)); - EnginePlatformDispatcher.instance.rasterizer! - .debugRunPostFrameCallbacks(); + rasterizer.debugRunPostFrameCallbacks(); await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, [ @@ -156,6 +155,7 @@ void testMain() { test('will download Noto Emojis and Noto Symbols if no matching Noto Font', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; TestDownloader.mockDownloads[ 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'] = ''' @@ -174,8 +174,7 @@ void testMain() { ); pb.addText('Hello 😊'); - EnginePlatformDispatcher.instance.rasterizer! - .debugRunPostFrameCallbacks(); + rasterizer.debugRunPostFrameCallbacks(); await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, @@ -205,6 +204,7 @@ void testMain() { test('will gracefully fail if we cannot parse the Google Fonts CSS', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; TestDownloader.mockDownloads[ 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = 'invalid CSS... this should cause our parser to fail'; @@ -219,8 +219,7 @@ void testMain() { pb.addText('مرحبا'); // Flush microtasks and test that we didn't start any downloads. - EnginePlatformDispatcher.instance.rasterizer! - .debugRunPostFrameCallbacks(); + rasterizer.debugRunPostFrameCallbacks(); await Future.delayed(Duration.zero); expect(notoDownloadQueue.isPending, isFalse); @@ -233,14 +232,14 @@ void testMain() { test( 'Can find fonts for two adjacent unmatched code units from different fonts', () async { + final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; final LoggingDownloader loggingDownloader = LoggingDownloader(NotoDownloader()); notoDownloadQueue.downloader = loggingDownloader; // Try rendering text that requires fallback fonts, initially before the fonts are loaded. CkParagraphBuilder(CkParagraphStyle()).addText('ヽಠ'); - EnginePlatformDispatcher.instance.rasterizer! - .debugRunPostFrameCallbacks(); + rasterizer.debugRunPostFrameCallbacks(); await notoDownloadQueue.downloader.debugWhenIdle(); expect( loggingDownloader.log, @@ -257,8 +256,7 @@ void testMain() { // Do the same thing but this time with loaded fonts. loggingDownloader.log.clear(); CkParagraphBuilder(CkParagraphStyle()).addText('ヽಠ'); - EnginePlatformDispatcher.instance.rasterizer! - .debugRunPostFrameCallbacks(); + rasterizer.debugRunPostFrameCallbacks(); await notoDownloadQueue.downloader.debugWhenIdle(); expect(loggingDownloader.log, isEmpty); }); diff --git a/lib/web_ui/test/canvaskit/hot_restart_test.dart b/lib/web_ui/test/canvaskit/hot_restart_test.dart index 4923c3b6e8951..b032f532e31b7 100644 --- a/lib/web_ui/test/canvaskit/hot_restart_test.dart +++ b/lib/web_ui/test/canvaskit/hot_restart_test.dart @@ -15,14 +15,14 @@ void testMain() { expect(windowFlutterCanvasKit, isNull); // First initialization should make CanvasKit available through `window`. - await initializeCanvasKit(); + await renderer.initialize(); expect(windowFlutterCanvasKit, isNotNull); // Remember the initial instance. final CanvasKit firstCanvasKitInstance = windowFlutterCanvasKit!; // Try to load CanvasKit again. - await initializeCanvasKit(); + await renderer.initialize(); // Should find the existing instance and reuse it. expect(firstCanvasKitInstance, windowFlutterCanvasKit); diff --git a/lib/web_ui/test/canvaskit/image_golden_test.dart b/lib/web_ui/test/canvaskit/image_golden_test.dart index 19528b2370e79..215af2fceb165 100644 --- a/lib/web_ui/test/canvaskit/image_golden_test.dart +++ b/lib/web_ui/test/canvaskit/image_golden_test.dart @@ -510,8 +510,7 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { canvas.drawImage(snapshot, ui.Offset.zero, CkPaint()); sb.addPicture(ui.Offset.zero, recorder.endRecording()); - final EnginePlatformDispatcher dispatcher = ui.window.platformDispatcher as EnginePlatformDispatcher; - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); await matchGoldenFile( 'canvaskit_read_back_decoded_image_$mode.png', region: const ui.Rect.fromLTRB(0, 0, 150, 150), @@ -536,9 +535,6 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { ); await createPlatformView(0, 'test-platform-view'); - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - final ui.Codec codec = await ui.instantiateImageCodec(k4x4PngImage); final CkImage image = (await codec.getNextFrame()).image as CkImage; @@ -566,7 +562,7 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { canvas.drawParagraph(makeSimpleText('2'), const ui.Offset(2, 2)); sb.addPicture(ui.Offset.zero, recorder.endRecording()); } - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); await matchGoldenFile( 'canvaskit_cross_gl_context_image_$mode.png', region: const ui.Rect.fromLTRB(0, 0, 100, 100), @@ -611,9 +607,7 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) { canvas.restore(); sb.addPicture(ui.Offset.zero, recorder.endRecording()); } - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); await matchGoldenFile( 'canvaskit_picture_texture_toimage', region: const ui.Rect.fromLTRB(0, 0, 128, 128), diff --git a/lib/web_ui/test/canvaskit/layer_test.dart b/lib/web_ui/test/canvaskit/layer_test.dart index 8a1fdcaaf8c52..b4bc7d866b953 100644 --- a/lib/web_ui/test/canvaskit/layer_test.dart +++ b/lib/web_ui/test/canvaskit/layer_test.dart @@ -21,9 +21,6 @@ void testMain() { // Regression test for https://github.com/flutter/flutter/issues/63715 test('TransformLayer prerolls correctly', () async { - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - final CkPicture picture = paintPicture(const ui.Rect.fromLTRB(0, 0, 60, 60), (CkCanvas canvas) { canvas.drawRect(const ui.Rect.fromLTRB(0, 0, 60, 60), @@ -42,7 +39,7 @@ void testMain() { sb.addPicture(ui.Offset.zero, picture); final LayerTree layerTree = sb.build().layerTree; - dispatcher.rasterizer!.draw(layerTree); + CanvasKitRenderer.instance.rasterizer.draw(layerTree); final ClipRectEngineLayer clipRect = layerTree.rootLayer.debugLayers.single as ClipRectEngineLayer; expect(clipRect.paintBounds, const ui.Rect.fromLTRB(15, 15, 30, 30)); diff --git a/lib/web_ui/test/canvaskit/linear_gradient_golden_test.dart b/lib/web_ui/test/canvaskit/linear_gradient_golden_test.dart index 9cca66b39db3f..71d7351a5c6ee 100644 --- a/lib/web_ui/test/canvaskit/linear_gradient_golden_test.dart +++ b/lib/web_ui/test/canvaskit/linear_gradient_golden_test.dart @@ -21,12 +21,10 @@ const ui.Rect region = ui.Rect.fromLTRB(0, 0, 500, 250); Future matchPictureGolden(String goldenFile, CkPicture picture, {bool write = false}) async { - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPicture(ui.Offset.zero, picture); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); await matchGoldenFile(goldenFile, region: region, write: write); } diff --git a/lib/web_ui/test/canvaskit/path_test.dart b/lib/web_ui/test/canvaskit/path_test.dart index febfbf89b63ff..c6e3985b75923 100644 --- a/lib/web_ui/test/canvaskit/path_test.dart +++ b/lib/web_ui/test/canvaskit/path_test.dart @@ -19,7 +19,7 @@ void testMain() { setUpCanvasKitTest(); test('Using CanvasKit', () { - expect(useCanvasKit, isTrue); + expect(renderer is CanvasKitRenderer, isTrue); }); test(CkPathMetrics, () { diff --git a/lib/web_ui/test/canvaskit/shader_mask_golden_test.dart b/lib/web_ui/test/canvaskit/shader_mask_golden_test.dart index 3b7481496242a..d4effcbdd5c6a 100644 --- a/lib/web_ui/test/canvaskit/shader_mask_golden_test.dart +++ b/lib/web_ui/test/canvaskit/shader_mask_golden_test.dart @@ -20,9 +20,7 @@ const ui.Rect region = ui.Rect.fromLTRB(0, 0, 500, 250); Future matchSceneGolden(String goldenFile, LayerScene scene, {bool write = false}) async { - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; - dispatcher.rasterizer!.draw(scene.layerTree); + CanvasKitRenderer.instance.rasterizer.draw(scene.layerTree); await matchGoldenFile(goldenFile, region: region, write: write); } diff --git a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart index 8d667d8af12ec..9f6aac9a4c926 100644 --- a/lib/web_ui/test/canvaskit/skia_font_collection_test.dart +++ b/lib/web_ui/test/canvaskit/skia_font_collection_test.dart @@ -20,7 +20,7 @@ void testMain() { setUpAll(() async { ensureFlutterViewEmbedderInitialized(); - await initializeCanvasKit(); + await renderer.initialize(); oldPrintWarning = printWarning; printWarning = (String warning) { warnings.add(warning); diff --git a/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart b/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart index 68e2e92458b7b..b58fe26cc8b30 100644 --- a/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart +++ b/lib/web_ui/test/canvaskit/skia_objects_cache_test.dart @@ -38,7 +38,7 @@ void _tests() { group(ManagedSkiaObject, () { test('implements create, cache, delete, resurrect, delete lifecycle', () { final FakeRasterizer fakeRasterizer = FakeRasterizer(); - EnginePlatformDispatcher.instance.rasterizer = fakeRasterizer; + CanvasKitRenderer.instance.rasterizer = fakeRasterizer; // Trigger first create final TestSkiaObject testObject = TestSkiaObject(); diff --git a/lib/web_ui/test/canvaskit/sweep_gradient_golden_test.dart b/lib/web_ui/test/canvaskit/sweep_gradient_golden_test.dart index ee90f20da1b4d..cfd351dbb8e6f 100644 --- a/lib/web_ui/test/canvaskit/sweep_gradient_golden_test.dart +++ b/lib/web_ui/test/canvaskit/sweep_gradient_golden_test.dart @@ -21,12 +21,10 @@ const ui.Rect region = ui.Rect.fromLTRB(0, 0, 500, 250); Future matchPictureGolden(String goldenFile, CkPicture picture, {bool write = false}) async { - final EnginePlatformDispatcher dispatcher = - ui.window.platformDispatcher as EnginePlatformDispatcher; final LayerSceneBuilder sb = LayerSceneBuilder(); sb.pushOffset(0, 0); sb.addPicture(ui.Offset.zero, picture); - dispatcher.rasterizer!.draw(sb.build().layerTree); + CanvasKitRenderer.instance.rasterizer.draw(sb.build().layerTree); await matchGoldenFile(goldenFile, region: region, write: write); } diff --git a/lib/web_ui/test/canvaskit/vertices_test.dart b/lib/web_ui/test/canvaskit/vertices_test.dart index 5b871ff1b89b2..dc0c0110f3556 100644 --- a/lib/web_ui/test/canvaskit/vertices_test.dart +++ b/lib/web_ui/test/canvaskit/vertices_test.dart @@ -59,7 +59,7 @@ void testMain() { final LayerSceneBuilder builder = LayerSceneBuilder(); builder.pushOffset(0, 0); builder.addPicture(ui.Offset.zero, verticesPicture); - EnginePlatformDispatcher.instance.rasterizer! + CanvasKitRenderer.instance.rasterizer .draw(builder.build().layerTree); await matchGoldenFile('canvaskit_vertices_antialiased.png', region: region); }, skip: isSafari); diff --git a/lib/web_ui/test/engine/image_to_byte_data_test.dart b/lib/web_ui/test/engine/image_to_byte_data_test.dart index 56d94e56dca71..991c3e80c8853 100644 --- a/lib/web_ui/test/engine/image_to_byte_data_test.dart +++ b/lib/web_ui/test/engine/image_to_byte_data_test.dart @@ -16,8 +16,8 @@ void main() { Future testMain() async { setUpAll(() async { await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); Future createTestImageByColor(Color color) async { diff --git a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart index d31b314908210..e98fde4ec8e66 100644 --- a/lib/web_ui/test/html/canvas_clip_path_golden_test.dart +++ b/lib/web_ui/test/html/canvas_clip_path_golden_test.dart @@ -23,8 +23,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - engine.fontCollection.debugRegisterTestFonts(); - await engine.fontCollection.ensureFontsLoaded(); + engine.renderer.fontCollection.debugRegisterTestFonts(); + await engine.renderer.fontCollection.ensureFontsLoaded(); }); // Regression test for https://github.com/flutter/flutter/issues/48683 diff --git a/lib/web_ui/test/html/canvas_context_golden_test.dart b/lib/web_ui/test/html/canvas_context_golden_test.dart index bb26e08a00d06..6cdf7003564b6 100644 --- a/lib/web_ui/test/html/canvas_context_golden_test.dart +++ b/lib/web_ui/test/html/canvas_context_golden_test.dart @@ -53,8 +53,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - engine.fontCollection.debugRegisterTestFonts(); - await engine.fontCollection.ensureFontsLoaded(); + engine.renderer.fontCollection.debugRegisterTestFonts(); + await engine.renderer.fontCollection.ensureFontsLoaded(); }); // Regression test for https://github.com/flutter/flutter/issues/49429 diff --git a/lib/web_ui/test/html/canvas_reuse_golden_test.dart b/lib/web_ui/test/html/canvas_reuse_golden_test.dart index a14ded8c8a62f..b0b3b6606d81b 100644 --- a/lib/web_ui/test/html/canvas_reuse_golden_test.dart +++ b/lib/web_ui/test/html/canvas_reuse_golden_test.dart @@ -25,8 +25,8 @@ Future testMain() async { setUp(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); // Regression test for https://github.com/flutter/flutter/issues/51514 diff --git a/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart b/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart index 36f654dbeceb9..734f26f308221 100644 --- a/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/backdrop_filter_golden_test.dart @@ -16,8 +16,8 @@ void main() { Future testMain() async { setUpAll(() async { await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); setUp(() async { diff --git a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart index f5c2d9a60f3dc..74b54110fff1e 100644 --- a/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_blend_golden_test.dart @@ -20,8 +20,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); test('Blend circles with difference and color', () async { 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 d7810f3be3d78..ae2baaea12fbd 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 @@ -24,8 +24,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); const Color red = Color(0xFFFF0000); diff --git a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart index 8c593c4fcbf29..24ab2bf8156c6 100644 --- a/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/canvas_mask_filter_golden_test.dart @@ -20,8 +20,8 @@ Future testMain() async { setUpAll(() async { ui.debugEmulateFlutterTesterEnvironment = true; await ui.webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); tearDown(() { diff --git a/lib/web_ui/test/html/compositing/color_filter_golden_test.dart b/lib/web_ui/test/html/compositing/color_filter_golden_test.dart index df768f3f129b7..094d06a768c6a 100644 --- a/lib/web_ui/test/html/compositing/color_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/color_filter_golden_test.dart @@ -20,8 +20,8 @@ void main() { Future testMain() async { setUpAll(() async { await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); setUp(() async { diff --git a/lib/web_ui/test/html/compositing/compositing_golden_test.dart b/lib/web_ui/test/html/compositing/compositing_golden_test.dart index 761a1243fba50..5f81799bdf9be 100644 --- a/lib/web_ui/test/html/compositing/compositing_golden_test.dart +++ b/lib/web_ui/test/html/compositing/compositing_golden_test.dart @@ -21,8 +21,8 @@ void main() { Future testMain() async { setUpAll(() async { await ui.webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); setUp(() async { diff --git a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart index ca29e4efbc42a..fb0ed2b01eedf 100644 --- a/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart +++ b/lib/web_ui/test/html/compositing/dom_mask_filter_golden_test.dart @@ -20,8 +20,8 @@ Future testMain() async { setUp(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); test('Should blur rectangles based on sigma.', () async { diff --git a/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart index b79a6dd9bb433..8201c2e808a6f 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_color_golden_test.dart @@ -18,8 +18,8 @@ Future testMain() async { debugShowClipLayers = true; SurfaceSceneBuilder.debugForgetFrameScene(); await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); tearDown(() { diff --git a/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart b/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart index ae5330f39159b..c304c21c4033f 100644 --- a/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart +++ b/lib/web_ui/test/html/drawing/canvas_draw_picture_golden_test.dart @@ -21,8 +21,8 @@ Future testMain() async { setUpAll(() async { debugShowClipLayers = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); setUp(() async { diff --git a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart index 7ba70b6e0925a..8bb1d8de0d74e 100644 --- a/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart +++ b/lib/web_ui/test/html/drawing/draw_vertices_golden_test.dart @@ -60,8 +60,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); setUp(() { diff --git a/lib/web_ui/test/html/paragraph/text_scuba.dart b/lib/web_ui/test/html/paragraph/text_scuba.dart index 765ce121e1b59..bdbaa03822b59 100644 --- a/lib/web_ui/test/html/paragraph/text_scuba.dart +++ b/lib/web_ui/test/html/paragraph/text_scuba.dart @@ -134,7 +134,7 @@ CanvasParagraph paragraph( void setUpStableTestFonts() { setUpAll(() async { await ui.webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); } diff --git a/lib/web_ui/test/html/path_metrics_golden_test.dart b/lib/web_ui/test/html/path_metrics_golden_test.dart index 0ee1464beaf55..7caeb31235315 100644 --- a/lib/web_ui/test/html/path_metrics_golden_test.dart +++ b/lib/web_ui/test/html/path_metrics_golden_test.dart @@ -52,8 +52,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); test('Should calculate tangent on line', () async { diff --git a/lib/web_ui/test/html/path_transform_golden_test.dart b/lib/web_ui/test/html/path_transform_golden_test.dart index f0b322b90d4e1..1b173b67b5bce 100644 --- a/lib/web_ui/test/html/path_transform_golden_test.dart +++ b/lib/web_ui/test/html/path_transform_golden_test.dart @@ -51,8 +51,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); test('Should draw transformed line.', () async { diff --git a/lib/web_ui/test/html/screenshot.dart b/lib/web_ui/test/html/screenshot.dart index a99bc89f14530..b3c3f294a90f7 100644 --- a/lib/web_ui/test/html/screenshot.dart +++ b/lib/web_ui/test/html/screenshot.dart @@ -70,7 +70,7 @@ Future sceneScreenshot(SurfaceSceneBuilder sceneBuilder, String fileName, void setUpStableTestFonts() { setUpAll(() async { await ui.webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); } diff --git a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart index 212f580c51882..55a5276c829de 100644 --- a/lib/web_ui/test/html/shaders/image_shader_golden_test.dart +++ b/lib/web_ui/test/html/shaders/image_shader_golden_test.dart @@ -27,8 +27,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); void drawShapes(RecordingCanvas rc, SurfacePaint paint, Rect shaderRect) { diff --git a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart index d9ab10bc06180..df62522299fa8 100644 --- a/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/linear_gradient_golden_test.dart @@ -25,8 +25,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); test('Should draw linear gradient using rectangle.', () async { diff --git a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart index c0f18d55e1cad..e8324b12a2ab2 100644 --- a/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart +++ b/lib/web_ui/test/html/shaders/radial_gradient_golden_test.dart @@ -17,8 +17,8 @@ Future testMain() async { setUpAll(() async { debugEmulateFlutterTesterEnvironment = true; await webOnlyInitializePlatform(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); Future testGradient(String fileName, Shader shader, diff --git a/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart b/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart index 717adc1266936..2fcceba1fc939 100644 --- a/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart +++ b/lib/web_ui/test/html/shaders/shader_mask_golden_test.dart @@ -41,8 +41,8 @@ Future testMain() async { scene.remove(); } initWebGl(); - fontCollection.debugRegisterTestFonts(); - await fontCollection.ensureFontsLoaded(); + renderer.fontCollection.debugRegisterTestFonts(); + await renderer.fontCollection.ensureFontsLoaded(); }); /// Should render the picture unmodified. diff --git a/web_sdk/web_engine_tester/lib/golden_tester.dart b/web_sdk/web_engine_tester/lib/golden_tester.dart index 732866637ec64..09ce5212e2b9a 100644 --- a/web_sdk/web_engine_tester/lib/golden_tester.dart +++ b/web_sdk/web_engine_tester/lib/golden_tester.dart @@ -7,7 +7,7 @@ import 'dart:convert'; import 'package:test/test.dart'; // ignore: implementation_imports -import 'package:ui/src/engine.dart' show OperatingSystem, operatingSystem, useCanvasKit; +import 'package:ui/src/engine.dart' show OperatingSystem, operatingSystem, renderer; // ignore: implementation_imports import 'package:ui/src/engine/dom.dart'; import 'package:ui/ui.dart'; @@ -64,7 +64,11 @@ Future matchGoldenFile(String filename, 'height': region.height }, 'pixelComparison': pixelComparison.toString(), - 'isCanvaskitTest': useCanvasKit, + // We use the renderer tag here rather than `renderer is CanvasKitRenderer` + // because these unit tests operate on the post-transformed (sdk_rewriter) + // sdk where the internal classes like `CanvasKitRenderer` are no longer + // visible. + 'isCanvaskitTest': renderer.rendererTag == 'canvaskit', }; // Chrome on macOS renders slightly differently from Linux, so allow it an From 2ecccf195ec71cb4a03c9e168897bb54076ce1b5 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Tue, 23 Aug 2022 16:28:14 -0700 Subject: [PATCH 509/558] [Impeller] Enforce a minimum stroke width (#35576) --- .../display_list/display_list_unittests.cc | 34 +++++++++++++++++++ .../entity/contents/solid_stroke_contents.cc | 16 +++++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/impeller/display_list/display_list_unittests.cc b/impeller/display_list/display_list_unittests.cc index b887c22e49bae..c29a999cc6c12 100644 --- a/impeller/display_list/display_list_unittests.cc +++ b/impeller/display_list/display_list_unittests.cc @@ -521,5 +521,39 @@ TEST_P(DisplayListTest, CanDrawShadow) { ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); } +TEST_P(DisplayListTest, CanDrawZeroWidthLine) { + flutter::DisplayListBuilder builder; + std::vector caps = { + flutter::DlStrokeCap::kButt, + flutter::DlStrokeCap::kRound, + flutter::DlStrokeCap::kSquare, + }; + flutter::DlPaint paint = // + flutter::DlPaint() // + .setColor(flutter::DlColor::kWhite()) // + .setDrawStyle(flutter::DlDrawStyle::kStroke) // + .setStrokeWidth(0); + flutter::DlPaint outline_paint = // + flutter::DlPaint() // + .setColor(flutter::DlColor::kYellow()) // + .setDrawStyle(flutter::DlDrawStyle::kStroke) // + .setStrokeCap(flutter::DlStrokeCap::kSquare) // + .setStrokeWidth(1); + SkPath path = SkPath().addPoly({{150, 50}, {160, 50}}, false); + for (auto cap : caps) { + paint.setStrokeCap(cap); + builder.drawLine({50, 50}, {60, 50}, paint); + builder.drawRect({45, 45, 65, 55}, outline_paint); + builder.drawLine({100, 50}, {100, 50}, paint); + if (cap != flutter::DlStrokeCap::kButt) { + builder.drawRect({95, 45, 105, 55}, outline_paint); + } + builder.drawPath(path, paint); + builder.drawRect(path.getBounds().makeOutset(5, 5), outline_paint); + builder.translate(0, 150); + } + ASSERT_TRUE(OpenPlaygroundHere(builder.Build())); +} + } // namespace testing } // namespace impeller diff --git a/impeller/entity/contents/solid_stroke_contents.cc b/impeller/entity/contents/solid_stroke_contents.cc index 326b90f342805..357498ad18cc3 100644 --- a/impeller/entity/contents/solid_stroke_contents.cc +++ b/impeller/entity/contents/solid_stroke_contents.cc @@ -52,8 +52,13 @@ std::optional SolidStrokeContents::GetCoverage( if (join_ == Join::kMiter) { max_radius = std::max(max_radius, miter_limit_ * 0.5f); } + Scalar determinant = entity.GetTransformation().GetDeterminant(); + if (determinant == 0) { + return std::nullopt; + } + Scalar min_size = 1.0f / sqrt(std::abs(determinant)); Vector2 max_radius_xy = entity.GetTransformation().TransformDirection( - Vector2(max_radius, max_radius) * stroke_size_); + Vector2(max_radius, max_radius) * std::max(stroke_size_, min_size)); return Rect(path_coverage.origin - max_radius_xy, Size(path_coverage.size.width + max_radius_xy.x * 2, @@ -182,7 +187,7 @@ static VertexBuffer CreateSolidStrokeVertices( bool SolidStrokeContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - if (stroke_size_ <= 0.0) { + if (stroke_size_ < 0.0) { return true; } @@ -192,7 +197,12 @@ bool SolidStrokeContents::Render(const ContentContext& renderer, VS::VertInfo vert_info; vert_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) * entity.GetTransformation(); - vert_info.size = stroke_size_; + Scalar determinant = entity.GetTransformation().GetDeterminant(); + if (determinant == 0) { + return true; + } + Scalar min_size = 1.0f / sqrt(std::abs(determinant)); + vert_info.size = std::max(stroke_size_, min_size); FS::FragInfo frag_info; frag_info.color = color_.Premultiply(); From d1ac8d84ec706ca41f27924a27e357f9174bec39 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam <58529443+srujzs@users.noreply.github.com> Date: Tue, 23 Aug 2022 16:49:19 -0700 Subject: [PATCH 510/558] Move extension to TypefaceFontProvider instead of SkFontMgr (#35381) --- lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 32dd0dbc2e365..6fdcc06831c93 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/canvaskit_api.dart @@ -2113,7 +2113,7 @@ class TypefaceFontProvider extends SkFontMgr { external factory TypefaceFontProvider(); } -extension TypefaceFontProviderExtension on SkFontMgr { +extension TypefaceFontProviderExtension on TypefaceFontProvider { external void registerFont(Uint8List font, String family); } From 55b46a70abda349a9cbd610037d0153fe69d54a6 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 20:11:03 -0400 Subject: [PATCH 511/558] Roll Skia from fad2781bd328 to 6cec033662c7 (3 revisions) (#35649) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 261bf97c01c51..73580fa80043c 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': 'fad2781bd32864fafd34feecb1ff5605e95f2c73', + 'skia_revision': '6cec033662c7d8a36287d644cefbe519c75d1c07', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 101f2206c2520..acdc01cf5b893 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: cb52130fe81571ba4985819c5a8983f7 +Signature: 38fcb61f9829ff4621df57cb85cd8463 UNUSED LICENSES: @@ -5625,6 +5625,8 @@ FILE: ../../../third_party/skia/src/gpu/tessellate/FixedCountBufferUtils.h FILE: ../../../third_party/skia/src/gpu/tessellate/LinearTolerances.h FILE: ../../../third_party/skia/src/shaders/SkEmptyShader.cpp FILE: ../../../third_party/skia/src/shaders/gradients/SkGradientShaderBase.cpp +FILE: ../../../third_party/skia/src/sksl/SkSLModuleLoader.cpp +FILE: ../../../third_party/skia/src/sksl/SkSLModuleLoader.h FILE: ../../../third_party/skia/src/sksl/analysis/SkSLFinalizationChecks.cpp FILE: ../../../third_party/skia/src/sksl/analysis/SkSLIsSameExpressionTree.cpp FILE: ../../../third_party/skia/src/sksl/analysis/SkSLIsTrivialExpression.cpp From de4ef8c6f379285d49c785d69f4825765c5d0b6f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 20:23:09 -0400 Subject: [PATCH 512/558] Roll Dart SDK from 3042d6196824 to 9be467274ae4 (1 revision) (#35650) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 73580fa80043c..dd130c77b6b77 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '3042d61968245f7ec65083b5f7c1cd0475666dfb', + 'dart_revision': '9be467274ae4677c83643b3fdb8993242deacd6d', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 2bb5355035676..2605516948b0f 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 9f65c336c221de745d7cc056d049a51f +Signature: 4f50b1892f0f65856019ac283dfc46c4 UNUSED LICENSES: From 7d0afb03e363421a65c29d4ca00fc64962663d0a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 22:16:21 -0400 Subject: [PATCH 513/558] Roll Clang Windows from 60d276923902 to 41d4067d0b7c (#35655) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index dd130c77b6b77..e2bb1d41fcc41 100644 --- a/DEPS +++ b/DEPS @@ -650,7 +650,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/clang/windows-amd64', - 'version': 'git_revision:60d276923902051192eba692e5312e605c9d9f65' + 'version': 'git_revision:41d4067d0b7c3c955b8b6cda328bcb46e268bd6a' } ], 'condition': 'download_windows_deps', From bab44fee834c89a2c4a46c09219266a01acedf9b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 23 Aug 2022 22:18:12 -0400 Subject: [PATCH 514/558] Roll Clang Linux from 60d276923902 to 41d4067d0b7c (#35654) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e2bb1d41fcc41..ab668f8551cb8 100644 --- a/DEPS +++ b/DEPS @@ -628,7 +628,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/third_party/clang/linux-amd64', - 'version': 'git_revision:60d276923902051192eba692e5312e605c9d9f65' + 'version': 'git_revision:41d4067d0b7c3c955b8b6cda328bcb46e268bd6a' } ], 'condition': 'host_os == "linux" and host_cpu == "x64"', From 59a61b2300ea432d702b0ce115bda96e761c54f9 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 23 Aug 2022 19:24:57 -0700 Subject: [PATCH 515/558] [Impeller] Fix Gaussian blur jittering. (#35652) * Fix Gaussian blur jittering. Converting the scaled texutre width to an ISize snaps it down. This accounts for the extra snapping in the scale transform. Also fixes a bug where small blur radius values which would result in a single turn of the shader sampling would produce no output. Updates an existing test to use smaller sigma range to make jitter more apparent on changing the imgui slider. * Update gaussian_blur_filter_contents.cc --- .../filters/gaussian_blur_filter_contents.cc | 21 +++++++++++++------ impeller/entity/entity_unittests.cc | 4 ++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index adbcf754a28c6..ea350055d2f01 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -112,6 +112,12 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( auto transformed_blur_radius_length = transformed_blur_radius.GetLength(); + // If the radius length is < .5, the shader will take at most 1 sample, + // resulting in no blur. + if (transformed_blur_radius_length < .5) { + return input_snapshot.value(); // No blur to render. + } + // A matrix that rotates the snapshot space such that the blur direction is // +X. auto texture_rotate = Matrix::MakeRotationZ( @@ -216,11 +222,11 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( }; Scalar x_scale = - std::min(1.0, 1.0 / std::ceil(std::log2(transformed_blur_radius_length))); - auto out_texture = - renderer.MakeSubpass(ISize(pass_texture_rect.size.width * x_scale, - pass_texture_rect.size.height), - callback); + 1.0 / + std::ceil(std::log2(std::max(2.0f, transformed_blur_radius_length))); + auto scaled_texture_width = pass_texture_rect.size.width * x_scale; + auto out_texture = renderer.MakeSubpass( + ISize(scaled_texture_width, pass_texture_rect.size.height), callback); if (!out_texture) { return std::nullopt; } @@ -234,7 +240,10 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( .texture = out_texture, .transform = texture_rotate.Invert() * Matrix::MakeTranslation(pass_texture_rect.origin) * - Matrix::MakeScale(Vector2(1 / x_scale, 1)), + Matrix::MakeScale(Vector2( + (1 / x_scale) * (scaled_texture_width / + std::floor(scaled_texture_width)), + 1)), .sampler_descriptor = sampler_desc}; } diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc index ad5a67c816b13..4c79890f77f57 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -864,7 +864,7 @@ TEST_P(EntityTest, GaussianBlurFilter) { static Color input_color = Color::Black(); static int selected_blur_type = 0; static int selected_pass_variation = 0; - static float blur_amount[2] = {20, 20}; + static float blur_amount[2] = {10, 10}; static int selected_blur_style = 0; static int selected_tile_mode = 3; static Color cover_color(1, 0, 0, 0.2); @@ -894,7 +894,7 @@ TEST_P(EntityTest, GaussianBlurFilter) { pass_variation_names, sizeof(pass_variation_names) / sizeof(char*)); } - ImGui::SliderFloat2("Sigma", blur_amount, 0, 200); + ImGui::SliderFloat2("Sigma", blur_amount, 0, 10); ImGui::Combo("Blur style", &selected_blur_style, blur_style_names, sizeof(blur_style_names) / sizeof(char*)); ImGui::Combo("Tile mode", &selected_tile_mode, tile_mode_names, From 55c461f28697b2e724d194dbb1a235e0767b48c7 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 23 Aug 2022 21:29:19 -0700 Subject: [PATCH 516/558] [Impeller] Use MSAA attachments for offscreen passes (#35648) --- impeller/entity/contents/content_context.cc | 7 +- impeller/entity/entity_pass.cc | 51 +++++++--- impeller/entity/inline_pass_context.cc | 3 +- .../renderer/backend/gles/context_gles.cc | 5 + impeller/renderer/backend/gles/context_gles.h | 3 + impeller/renderer/backend/metal/context_mtl.h | 3 + .../renderer/backend/metal/context_mtl.mm | 5 + impeller/renderer/backend/metal/formats_mtl.h | 4 + .../renderer/backend/metal/render_pass_mtl.mm | 14 +-- .../renderer/backend/vulkan/context_vk.cc | 4 + impeller/renderer/backend/vulkan/context_vk.h | 3 + impeller/renderer/backend/vulkan/formats_vk.h | 1 + impeller/renderer/context.h | 2 + impeller/renderer/formats.h | 2 + impeller/renderer/render_target.cc | 97 ++++++++++++++++++- impeller/renderer/render_target.h | 12 +++ 16 files changed, 189 insertions(+), 27 deletions(-) diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 7dd30168df53e..707a3bf5a79a3 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -245,7 +245,12 @@ std::shared_ptr ContentContext::MakeSubpass( SubpassCallback subpass_callback) const { auto context = GetContext(); - auto subpass_target = RenderTarget::CreateOffscreen(*context, texture_size); + RenderTarget subpass_target; + if (context->SupportsOffscreenMSAA()) { + subpass_target = RenderTarget::CreateOffscreenMSAA(*context, texture_size); + } else { + subpass_target = RenderTarget::CreateOffscreen(*context, texture_size); + } auto subpass_texture = subpass_target.GetRenderTargetTexture(); if (!subpass_texture) { return nullptr; diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index be4dc731182ac..953cb4052e114 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -144,11 +144,18 @@ EntityPass* EntityPass::AddSubpass(std::unique_ptr pass) { bool EntityPass::Render(ContentContext& renderer, RenderTarget render_target) const { if (reads_from_pass_texture_) { - auto offscreen_target = RenderTarget::CreateOffscreen( - *renderer.GetContext(), render_target.GetRenderTargetSize(), - "EntityPass", // - StorageMode::kDevicePrivate, LoadAction::kClear, StoreAction::kStore, - StorageMode::kDevicePrivate, LoadAction::kClear, StoreAction::kStore); + auto offscreen_target = RenderTarget::CreateOffscreenMSAA( + *renderer.GetContext(), // context + render_target.GetRenderTargetSize(), // size + "EntityPass", // label + StorageMode::kDevicePrivate, // color_storage_mode + StorageMode::kDevicePrivate, // color_resolve_storage_mode + LoadAction::kClear, // color_load_action + StoreAction::kStoreAndMultisampleResolve, // color_store_action + StorageMode::kDevicePrivate, // stencil_storage_mode + LoadAction::kClear, // stencil_load_action + StoreAction::kStore // stencil_store_action + ); if (!OnRender(renderer, offscreen_target.GetRenderTargetSize(), offscreen_target, Point(), Point(), 0)) { return false; @@ -285,17 +292,31 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( RenderTarget subpass_target; if (subpass->reads_from_pass_texture_) { - subpass_target = RenderTarget::CreateOffscreen( - *renderer.GetContext(), ISize::Ceil(subpass_coverage->size), - "EntityPass", StorageMode::kDevicePrivate, LoadAction::kClear, - StoreAction::kStore, StorageMode::kDevicePrivate, LoadAction::kClear, - StoreAction::kStore); + subpass_target = RenderTarget::CreateOffscreenMSAA( + *renderer.GetContext(), // context + ISize::Ceil(subpass_coverage->size), // size + "EntityPass", // label + StorageMode::kDevicePrivate, // color_storage_mode + StorageMode::kDevicePrivate, // color_resolve_storage_mode + LoadAction::kClear, // color_load_action + StoreAction::kStoreAndMultisampleResolve, // color_store_action + StorageMode::kDevicePrivate, // stencil_storage_mode + LoadAction::kClear, // stencil_load_action + StoreAction::kStore // stencil_store_action + ); } else { - subpass_target = RenderTarget::CreateOffscreen( - *renderer.GetContext(), ISize::Ceil(subpass_coverage->size), - "EntityPass", StorageMode::kDevicePrivate, LoadAction::kClear, - StoreAction::kStore, StorageMode::kDeviceTransient, - LoadAction::kClear, StoreAction::kDontCare); + subpass_target = RenderTarget::CreateOffscreenMSAA( + *renderer.GetContext(), // context + ISize::Ceil(subpass_coverage->size), // size + "EntityPass", // label + StorageMode::kDevicePrivate, // color_storage_mode + StorageMode::kDevicePrivate, // color_resolve_storage_mode + LoadAction::kClear, // color_load_action + StoreAction::kStoreAndMultisampleResolve, // color_store_action + StorageMode::kDeviceTransient, // stencil_storage_mode + LoadAction::kClear, // stencil_load_action + StoreAction::kDontCare // stencil_store_action + ); } auto subpass_texture = subpass_target.GetRenderTargetTexture(); diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc index 26661e8d8155a..485d91d99df31 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -29,8 +29,7 @@ std::shared_ptr InlinePassContext::GetTexture() { if (!IsValid()) { return nullptr; } - auto color0 = render_target_.GetColorAttachments().find(0)->second; - return color0.resolve_texture ? color0.resolve_texture : color0.texture; + return render_target_.GetRenderTargetTexture(); } bool InlinePassContext::EndPass() { diff --git a/impeller/renderer/backend/gles/context_gles.cc b/impeller/renderer/backend/gles/context_gles.cc index 7ff2339498613..49f454f542cb3 100644 --- a/impeller/renderer/backend/gles/context_gles.cc +++ b/impeller/renderer/backend/gles/context_gles.cc @@ -132,4 +132,9 @@ bool ContextGLES::HasThreadingRestrictions() const { return true; } +// |Context| +bool ContextGLES::SupportsOffscreenMSAA() const { + return false; +} + } // namespace impeller diff --git a/impeller/renderer/backend/gles/context_gles.h b/impeller/renderer/backend/gles/context_gles.h index 7c7246dc796b6..405f31d1b168b 100644 --- a/impeller/renderer/backend/gles/context_gles.h +++ b/impeller/renderer/backend/gles/context_gles.h @@ -69,6 +69,9 @@ class ContextGLES final : public Context, // |Context| bool HasThreadingRestrictions() const override; + // |Context| + bool SupportsOffscreenMSAA() 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 45368a26ac737..98f6c9139a118 100644 --- a/impeller/renderer/backend/metal/context_mtl.h +++ b/impeller/renderer/backend/metal/context_mtl.h @@ -68,6 +68,9 @@ class ContextMTL final : public Context, // |Context| std::shared_ptr GetWorkQueue() const override; + // |Context| + bool SupportsOffscreenMSAA() 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 b3a8d7ea5c805..8cc908a8d06f8 100644 --- a/impeller/renderer/backend/metal/context_mtl.mm +++ b/impeller/renderer/backend/metal/context_mtl.mm @@ -232,4 +232,9 @@ return device_; } +// |Context| +bool ContextMTL::SupportsOffscreenMSAA() const { + return true; +} + } // namespace impeller diff --git a/impeller/renderer/backend/metal/formats_mtl.h b/impeller/renderer/backend/metal/formats_mtl.h index ef9bdc31fe0fc..c9857f9a3b108 100644 --- a/impeller/renderer/backend/metal/formats_mtl.h +++ b/impeller/renderer/backend/metal/formats_mtl.h @@ -247,6 +247,8 @@ constexpr MTLStoreAction ToMTLStoreAction(StoreAction action) { return MTLStoreActionStore; case StoreAction::kMultisampleResolve: return MTLStoreActionMultisampleResolve; + case StoreAction::kStoreAndMultisampleResolve: + return MTLStoreActionStoreAndMultisampleResolve; } return MTLStoreActionDontCare; } @@ -259,6 +261,8 @@ constexpr StoreAction FromMTLStoreAction(MTLStoreAction action) { return StoreAction::kStore; case MTLStoreActionMultisampleResolve: return StoreAction::kMultisampleResolve; + case MTLStoreActionStoreAndMultisampleResolve: + return StoreAction::kStoreAndMultisampleResolve; default: break; } diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 8827498924559..c277bbb50569b 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -22,17 +22,19 @@ static bool ConfigureResolveTextureAttachment( const Attachment& desc, MTLRenderPassAttachmentDescriptor* attachment) { - if (desc.store_action == StoreAction::kMultisampleResolve && - !desc.resolve_texture) { + bool needs_resolve = + desc.store_action == StoreAction::kMultisampleResolve || + desc.store_action == StoreAction::kStoreAndMultisampleResolve; + + if (needs_resolve && !desc.resolve_texture) { VALIDATION_LOG << "Resolve store action specified on attachment but no " "resolve texture was specified."; return false; } - if (desc.resolve_texture && - desc.store_action != StoreAction::kMultisampleResolve) { - VALIDATION_LOG << "Resolve store action specified but there was no " - "resolve attachment."; + if (desc.resolve_texture && !needs_resolve) { + VALIDATION_LOG << "A resolve texture was specified even though the store " + "action doesn't require it."; return false; } diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index e5ff5257373af..77bf5533afdd1 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -501,4 +501,8 @@ void ContextVK::SetupSwapchain(vk::UniqueSurfaceKHR surface) { }); } +bool ContextVK::SupportsOffscreenMSAA() const { + return true; +} + } // namespace impeller diff --git a/impeller/renderer/backend/vulkan/context_vk.h b/impeller/renderer/backend/vulkan/context_vk.h index f8a4ce6211318..ab63afd0610d2 100644 --- a/impeller/renderer/backend/vulkan/context_vk.h +++ b/impeller/renderer/backend/vulkan/context_vk.h @@ -109,6 +109,9 @@ class ContextVK final : public Context, public BackendCast { // |Context| std::shared_ptr GetWorkQueue() const override; + // |Context| + bool SupportsOffscreenMSAA() const override; + FML_DISALLOW_COPY_AND_ASSIGN(ContextVK); }; diff --git a/impeller/renderer/backend/vulkan/formats_vk.h b/impeller/renderer/backend/vulkan/formats_vk.h index c603dfd222665..00cd5efa3cf56 100644 --- a/impeller/renderer/backend/vulkan/formats_vk.h +++ b/impeller/renderer/backend/vulkan/formats_vk.h @@ -283,6 +283,7 @@ constexpr vk::AttachmentStoreOp ToVKAttachmentStoreOp( case StoreAction::kDontCare: return vk::AttachmentStoreOp::eDontCare; case StoreAction::kMultisampleResolve: + case StoreAction::kStoreAndMultisampleResolve: // TODO (kaushikiska): vulkan doesn't support multisample resolve. return vk::AttachmentStoreOp::eDontCare; } diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index 7f13fce9ac684..6db6d7bc994de 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -41,6 +41,8 @@ class Context : public std::enable_shared_from_this { virtual bool HasThreadingRestrictions() const; + virtual bool SupportsOffscreenMSAA() const = 0; + protected: Context(); diff --git a/impeller/renderer/formats.h b/impeller/renderer/formats.h index 65509c6a3ae15..0e8ce849a23c4 100644 --- a/impeller/renderer/formats.h +++ b/impeller/renderer/formats.h @@ -99,6 +99,7 @@ enum class StoreAction { kDontCare, kStore, kMultisampleResolve, + kStoreAndMultisampleResolve, }; constexpr bool CanClearAttachment(LoadAction action) { @@ -115,6 +116,7 @@ constexpr bool CanClearAttachment(LoadAction action) { constexpr bool CanDiscardAttachmentWhenDone(StoreAction action) { switch (action) { case StoreAction::kStore: + case StoreAction::kStoreAndMultisampleResolve: return false; case StoreAction::kDontCare: case StoreAction::kMultisampleResolve: diff --git a/impeller/renderer/render_target.cc b/impeller/renderer/render_target.cc index 1ec8c9d914173..da74b6a3c2041 100644 --- a/impeller/renderer/render_target.cc +++ b/impeller/renderer/render_target.cc @@ -136,7 +136,8 @@ std::shared_ptr RenderTarget::GetRenderTargetTexture() const { if (found == colors_.end()) { return nullptr; } - return found->second.texture; + return found->second.resolve_texture ? found->second.resolve_texture + : found->second.texture; } RenderTarget& RenderTarget::SetColorAttachment(ColorAttachment attachment, @@ -211,7 +212,7 @@ RenderTarget RenderTarget::CreateOffscreen(const Context& context, return {}; } - color0.texture->SetLabel(SPrintF("%sColorTexture", label.c_str())); + color0.texture->SetLabel(SPrintF("%s Color Texture", label.c_str())); StencilAttachment stencil0; stencil0.load_action = stencil_load_action; @@ -224,7 +225,97 @@ RenderTarget RenderTarget::CreateOffscreen(const Context& context, return {}; } - stencil0.texture->SetLabel(SPrintF("%sStencilTexture", label.c_str())); + stencil0.texture->SetLabel(SPrintF("%s Stencil Texture", label.c_str())); + + RenderTarget target; + target.SetColorAttachment(std::move(color0), 0u); + target.SetStencilAttachment(std::move(stencil0)); + + return target; +} + +RenderTarget RenderTarget::CreateOffscreenMSAA( + const Context& context, + ISize size, + std::string label, + StorageMode color_storage_mode, + StorageMode color_resolve_storage_mode, + LoadAction color_load_action, + StoreAction color_store_action, + StorageMode stencil_storage_mode, + LoadAction stencil_load_action, + StoreAction stencil_store_action) { + if (size.IsEmpty()) { + return {}; + } + + // Create MSAA color texture. + + TextureDescriptor color0_tex_desc; + color0_tex_desc.type = TextureType::kTexture2DMultisample; + color0_tex_desc.sample_count = SampleCount::kCount4; + color0_tex_desc.format = PixelFormat::kDefaultColor; + color0_tex_desc.size = size; + color0_tex_desc.usage = static_cast(TextureUsage::kRenderTarget) | + static_cast(TextureUsage::kShaderRead); + + auto color0_msaa_tex = context.GetResourceAllocator()->CreateTexture( + color_storage_mode, color0_tex_desc); + if (!color0_msaa_tex) { + VALIDATION_LOG << "Could not create multisample color texture."; + return {}; + } + color0_msaa_tex->SetLabel( + SPrintF("%s Color Texture (Multisample)", label.c_str())); + + // Create color resolve texture. + + TextureDescriptor color0_resolve_tex_desc; + color0_resolve_tex_desc.format = PixelFormat::kDefaultColor; + color0_resolve_tex_desc.size = size; + color0_resolve_tex_desc.usage = + static_cast(TextureUsage::kRenderTarget) | + static_cast(TextureUsage::kShaderRead); + + auto color0_resolve_tex = context.GetResourceAllocator()->CreateTexture( + color_resolve_storage_mode, color0_resolve_tex_desc); + if (!color0_resolve_tex) { + VALIDATION_LOG << "Could not create color texture."; + return {}; + } + color0_resolve_tex->SetLabel(SPrintF("%s Color Texture", label.c_str())); + + // Color attachment. + + ColorAttachment color0; + color0.clear_color = Color::BlackTransparent(); + color0.load_action = color_load_action; + color0.store_action = color_store_action; + color0.texture = color0_msaa_tex; + color0.resolve_texture = color0_resolve_tex; + + // Create MSAA stencil texture. + + TextureDescriptor stencil_tex0; + stencil_tex0.type = TextureType::kTexture2DMultisample; + stencil_tex0.sample_count = SampleCount::kCount4; + stencil_tex0.format = PixelFormat::kDefaultStencil; + stencil_tex0.size = size; + stencil_tex0.usage = + static_cast(TextureUsage::kRenderTarget); + + StencilAttachment stencil0; + stencil0.load_action = stencil_load_action; + stencil0.store_action = stencil_store_action; + stencil0.clear_stencil = 0u; + stencil0.texture = context.GetResourceAllocator()->CreateTexture( + stencil_storage_mode, stencil_tex0); + + if (!stencil0.texture) { + return {}; + } + + stencil0.texture->SetLabel(SPrintF("%s Stencil Texture", label.c_str())); RenderTarget target; target.SetColorAttachment(std::move(color0), 0u); diff --git a/impeller/renderer/render_target.h b/impeller/renderer/render_target.h index 786e56ee7e295..b81f32e0add06 100644 --- a/impeller/renderer/render_target.h +++ b/impeller/renderer/render_target.h @@ -30,6 +30,18 @@ class RenderTarget { LoadAction stencil_load_action = LoadAction::kClear, StoreAction stencil_store_action = StoreAction::kDontCare); + static RenderTarget CreateOffscreenMSAA( + const Context& context, + ISize size, + std::string label = "Offscreen MSAA", + StorageMode color_storage_mode = StorageMode::kDeviceTransient, + StorageMode color_resolve_storage_mode = StorageMode::kDevicePrivate, + LoadAction color_load_action = LoadAction::kClear, + StoreAction color_store_action = StoreAction::kMultisampleResolve, + StorageMode stencil_storage_mode = StorageMode::kDeviceTransient, + LoadAction stencil_load_action = LoadAction::kClear, + StoreAction stencil_store_action = StoreAction::kDontCare); + RenderTarget(); ~RenderTarget(); From c17a9fff2e849a49344df0dba30276e1ab97c6f4 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 00:42:25 -0400 Subject: [PATCH 517/558] Roll Dart SDK from 9be467274ae4 to 840523e16e25 (1 revision) (#35658) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ab668f8551cb8..3c7049959ad46 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '9be467274ae4677c83643b3fdb8993242deacd6d', + 'dart_revision': '840523e16e25a7371d6488d605a7ac52fad00892', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 2605516948b0f..1ecca3ae0e338 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 4f50b1892f0f65856019ac283dfc46c4 +Signature: bf7bd79e1c0eb8c16498e616fc251b09 UNUSED LICENSES: From 59fe006561db70e862a02e7ac83056356bbe07a7 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 23 Aug 2022 23:09:21 -0700 Subject: [PATCH 518/558] [Impeller] Fix bug where the intermediary root pass is getting created even when nothing reads from it (#35661) --- impeller/entity/entity_pass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 953cb4052e114..06a32b6643316 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -531,7 +531,7 @@ void EntityPass::SetBlendMode(Entity::BlendMode blend_mode) { void EntityPass::SetBackdropFilter(std::optional proc) { backdrop_filter_proc_ = proc; - if (superpass_) { + if (proc.has_value() && superpass_) { superpass_->reads_from_pass_texture_ = true; } } From 1f929978611e7ec7f3a29c7eafe2962c5f3db8a5 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 02:15:10 -0400 Subject: [PATCH 519/558] Roll Skia from 6cec033662c7 to 130469423b72 (1 revision) (#35660) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 3c7049959ad46..487f9c532d4b9 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': '6cec033662c7d8a36287d644cefbe519c75d1c07', + 'skia_revision': '130469423b72fd18054bd76a592272986020630f', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index acdc01cf5b893..60b435874e0f0 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 38fcb61f9829ff4621df57cb85cd8463 +Signature: c1754f94fe482c677c1db8317a8ddecc UNUSED LICENSES: From 24e4568bf47770e978ce6d9540955583255e658f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 03:17:13 -0400 Subject: [PATCH 520/558] Roll Fuchsia Mac SDK from Es8SXkqDOYZ5dgYTq... to XrmzJCUPGAd4klJlw... (#35663) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 487f9c532d4b9..7a13363525d02 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'Es8SXkqDOYZ5dgYTq4UVERgHhIPYuo1vKJJUF55pnO4C' + 'version': 'XrmzJCUPGAd4klJlwQ4SCiDFfA2Ie9IIuu4WzKCFgEgC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 0834a5f96a08a1b0afc84c91eb704ac7f48521a3 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 03:43:16 -0400 Subject: [PATCH 521/558] Roll Skia from 130469423b72 to 94fcb0a06405 (2 revisions) (#35665) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 7a13363525d02..930a93da507ea 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': '130469423b72fd18054bd76a592272986020630f', + 'skia_revision': '94fcb0a064058f0359803271c3656d35834582e1', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 60b435874e0f0..def29ff71bfff 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: c1754f94fe482c677c1db8317a8ddecc +Signature: cf64a8121d2bc1cc9e45f2037368d035 UNUSED LICENSES: From 38189251c0072019251a3e8c2c74385ca2dd3cd1 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 05:01:29 -0400 Subject: [PATCH 522/558] Roll Dart SDK from 840523e16e25 to 539f256f8b4b (1 revision) (#35666) --- DEPS | 4 ++-- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 930a93da507ea..d34a3a1cd3762 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '840523e16e25a7371d6488d605a7ac52fad00892', + 'dart_revision': '539f256f8b4b0dd6936daac19b34eb4fea220e9c', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -209,7 +209,7 @@ deps = { Var('dart_git') + '/ffi.git@fb5f2667826c0900e551d19101052f84e35f41bf', 'src/third_party/dart/third_party/pkg/file': - Var('dart_git') + '/external/github.com/google/file.dart@0132eeedea2933513bf230513a766a8baeab0c4f', + Var('dart_git') + '/external/github.com/google/file.dart@b2e31cb6ef40b223701dbfa0b907fe58468484d7', 'src/third_party/dart/third_party/pkg/fixnum': Var('dart_git') + '/fixnum.git@e0b17cc1f639c55a9c24947392c64b5a68992535', diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 1ecca3ae0e338..639f5f3e6d43e 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: bf7bd79e1c0eb8c16498e616fc251b09 +Signature: 96a953f119145ece42ec4269764ead98 UNUSED LICENSES: From 5d7c74d16242b9247bade593d96bea474f402126 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 06:58:26 -0400 Subject: [PATCH 523/558] Roll Skia from 94fcb0a06405 to c54c285a35e7 (1 revision) (#35667) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d34a3a1cd3762..e2845346939eb 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': '94fcb0a064058f0359803271c3656d35834582e1', + 'skia_revision': 'c54c285a35e7c9e07bd06bbc5633a8f720b50f9b', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index def29ff71bfff..fc8bceb07edc5 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: cf64a8121d2bc1cc9e45f2037368d035 +Signature: 4f78190fda4917ef8c9ca223f81ae8c9 UNUSED LICENSES: From d73878d9b8ee15dba82f4ff2f424f3ba50e841fd Mon Sep 17 00:00:00 2001 From: hangyu Date: Wed, 24 Aug 2022 20:19:55 +0800 Subject: [PATCH 524/558] Support BoldText for a11y in android (#35589) * Update AccessibilityBridge.java * Add test * lint * lint * Add TargetApi * Add comment * Update constant --- .../io/flutter/view/AccessibilityBridge.java | 30 +++++++++++++++++++ .../flutter/view/AccessibilityBridgeTest.java | 30 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/shell/platform/android/io/flutter/view/AccessibilityBridge.java b/shell/platform/android/io/flutter/view/AccessibilityBridge.java index 6168954f58bb0..8b05faa1600b6 100644 --- a/shell/platform/android/io/flutter/view/AccessibilityBridge.java +++ b/shell/platform/android/io/flutter/view/AccessibilityBridge.java @@ -9,6 +9,7 @@ import android.app.Activity; import android.content.ContentResolver; import android.content.Context; +import android.content.res.Configuration; import android.database.ContentObserver; import android.graphics.Rect; import android.net.Uri; @@ -120,6 +121,9 @@ public class AccessibilityBridge extends AccessibilityNodeProvider { // and the most significant 16 bits are used for engine generated IDs. private static final int MIN_ENGINE_GENERATED_NODE_ID = 1 << 16; + // Font weight adjustment for bold text. FontWeight.Bold - FontWeight.Normal = w700 - w400 = 300. + private static final int BOLD_TEXT_WEIGHT_ADJUSTMENT = 300; + /// Value is derived from ACTION_TYPE_MASK in AccessibilityNodeInfo.java private static int FIRST_RESOURCE_ID = 267386881; @@ -476,6 +480,12 @@ public void onTouchExplorationStateChanged(boolean isTouchExplorationEnabled) { this.contentResolver.registerContentObserver(transitionUri, false, animationScaleObserver); } + // Tells Flutter whether the text should be bolded or not. If the user changes bold text + // setting, the configuration will change and trigger a re-build of the accesibiltyBridge. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + setBoldTextFlag(); + } + platformViewsAccessibilityDelegate.attachAccessibilityBridge(this); } @@ -539,6 +549,26 @@ private boolean shouldSetCollectionInfo(final SemanticsNode semanticsNode) { accessibilityFocusedSemanticsNode, o -> o.hasFlag(Flag.HAS_IMPLICIT_SCROLLING))); } + @TargetApi(31) + @RequiresApi(31) + private void setBoldTextFlag() { + if (rootAccessibilityView == null || rootAccessibilityView.getResources() == null) { + return; + } + int fontWeightAdjustment = + rootAccessibilityView.getResources().getConfiguration().fontWeightAdjustment; + boolean shouldBold = + fontWeightAdjustment != Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED + && fontWeightAdjustment >= BOLD_TEXT_WEIGHT_ADJUSTMENT; + + if (shouldBold) { + accessibilityFeatureFlags |= AccessibilityFeature.BOLD_TEXT.value; + } else { + accessibilityFeatureFlags &= AccessibilityFeature.BOLD_TEXT.value; + } + sendLatestAccessibilityFlagsToFlutter(); + } + @VisibleForTesting public AccessibilityNodeInfo obtainAccessibilityNodeInfo(View rootView, int virtualViewId) { return AccessibilityNodeInfo.obtain(rootView, virtualViewId); diff --git a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java index 155401992df05..a88c0323a7b33 100644 --- a/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java +++ b/shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java @@ -25,6 +25,8 @@ import android.app.Activity; import android.content.ContentResolver; import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Rect; import android.os.Bundle; import android.text.SpannableString; @@ -1031,6 +1033,34 @@ public void itSetsFocusabilityBasedOnFlagsCorrectly() { assertTrue(node2Info.isFocusable()); } + @TargetApi(31) + @Test + public void itSetsBoldTextFlagCorrectly() { + AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); + AccessibilityViewEmbedder mockViewEmbedder = mock(AccessibilityViewEmbedder.class); + AccessibilityManager mockManager = mock(AccessibilityManager.class); + View mockRootView = mock(View.class); + Context context = mock(Context.class); + Resources resource = mock(Resources.class); + Configuration config = new Configuration(); + config.fontWeightAdjustment = 300; + + when(mockRootView.getContext()).thenReturn(context); + when(mockRootView.getResources()).thenReturn(resource); + when(resource.getConfiguration()).thenReturn(config); + + AccessibilityBridge accessibilityBridge = + setUpBridge( + /*rootAccessibilityView=*/ mockRootView, + /*accessibilityChannel=*/ mockChannel, + /*accessibilityManager=*/ mockManager, + /*contentResolver=*/ null, + /*accessibilityViewEmbedder=*/ mockViewEmbedder, + /*platformViewsAccessibilityDelegate=*/ null); + + verify(mockChannel).setAccessibilityFeatures(1 << 3); + } + @Test public void itSetsFocusedNodeBeforeSendingEvent() { AccessibilityChannel mockChannel = mock(AccessibilityChannel.class); From c8ba879d2ee388b5d0d60692168b23ac9b8fd771 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 09:02:23 -0400 Subject: [PATCH 525/558] Roll Dart SDK from 539f256f8b4b to 859e9bbe6f0a (1 revision) (#35668) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e2845346939eb..6a907be4c2d9e 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '539f256f8b4b0dd6936daac19b34eb4fea220e9c', + 'dart_revision': '859e9bbe6f0ad5c1a6bff4ee1d854eb3fd0a3da7', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From 9c16a5c9466895cdff04a94fbaa226bd8f02d303 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 24 Aug 2022 06:52:32 -0700 Subject: [PATCH 526/558] Make sure disposed image shaders are safe to use on paint, asser that they are not used (#35662) --- lib/ui/painting.dart | 7 +++++++ lib/ui/painting/image_shader.cc | 1 + lib/ui/painting/paint.cc | 32 ++++++++++++++++------------- testing/dart/image_shader_test.dart | 29 +++++++++++++++++++++++++- 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 95ff6d5009f20..aee511203699d 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1398,6 +1398,12 @@ class Paint { return _objects?[_kShaderIndex] as Shader?; } set shader(Shader? value) { + assert(() { + if (value is ImageShader) { + assert(!value.debugDisposed, 'Attempted to set a disposed shader to $this'); + } + return true; + }()); _ensureObjectsInitialized()[_kShaderIndex] = value; } @@ -4031,6 +4037,7 @@ class ImageShader extends Shader { FilterQuality? filterQuality, }) : assert(image != null), // image is checked on the engine side + assert(!image.debugDisposed), assert(tmx != null), assert(tmy != null), assert(matrix4 != null), diff --git a/lib/ui/painting/image_shader.cc b/lib/ui/painting/image_shader.cc index 85d4740de5a73..bd00fd1766e78 100644 --- a/lib/ui/painting/image_shader.cc +++ b/lib/ui/painting/image_shader.cc @@ -70,6 +70,7 @@ int ImageShader::height() { } void ImageShader::dispose() { + cached_shader_.reset(); image_.reset(); ClearDartWrapper(); } diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index ccf0d11117367..9749c220f2ed0 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -95,16 +95,17 @@ const SkPaint* Paint::paint(SkPaint& paint) const { Dart_Handle shader = values[kShaderIndex]; if (!Dart_IsNull(shader)) { - Shader* decoded = tonic::DartConverter::FromDart(shader); - auto sampling = - ImageFilter::SamplingFromIndex(uint_data[kFilterQualityIndex]); - auto color_source = decoded->shader(sampling); - // TODO(dnfield): Remove this restriction. - // This currently is only used by paragraph code. Once SkParagraph does - // not need to take an SkPaint, we won't be restricted in this way because - // we will not need to access the shader on the UI task runner. - if (color_source->owning_context() != DlImage::OwningContext::kRaster) { - paint.setShader(color_source->skia_object()); + if (Shader* decoded = tonic::DartConverter::FromDart(shader)) { + auto sampling = + ImageFilter::SamplingFromIndex(uint_data[kFilterQualityIndex]); + auto color_source = decoded->shader(sampling); + // TODO(dnfield): Remove this restriction. + // This currently is only used by paragraph code. Once SkParagraph does + // not need to take an SkPaint, we won't be restricted in this way + // because we will not need to access the shader on the UI task runner. + if (color_source->owning_context() != DlImage::OwningContext::kRaster) { + paint.setShader(color_source->skia_object()); + } } } @@ -227,10 +228,13 @@ bool Paint::sync_to(DisplayListBuilder* builder, if (Dart_IsNull(shader)) { builder->setColorSource(nullptr); } else { - Shader* decoded = tonic::DartConverter::FromDart(shader); - auto sampling = - ImageFilter::SamplingFromIndex(uint_data[kFilterQualityIndex]); - builder->setColorSource(decoded->shader(sampling).get()); + if (Shader* decoded = tonic::DartConverter::FromDart(shader)) { + auto sampling = + ImageFilter::SamplingFromIndex(uint_data[kFilterQualityIndex]); + builder->setColorSource(decoded->shader(sampling).get()); + } else { + builder->setColorSource(nullptr); + } } } diff --git a/testing/dart/image_shader_test.dart b/testing/dart/image_shader_test.dart index ea174ac29fa8c..6124e5746d5ab 100644 --- a/testing/dart/image_shader_test.dart +++ b/testing/dart/image_shader_test.dart @@ -18,7 +18,7 @@ void main() { test('Construct an ImageShader', () async { final Image image = await createImage(50, 50); final ImageShader shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Float64List(16)); - final Paint paint = Paint()..shader=shader; + final Paint paint = Paint()..shader = shader; const Rect rect = Rect.fromLTRB(0, 0, 100, 100); testCanvas((Canvas canvas) => canvas.drawRect(rect, paint)); @@ -33,6 +33,33 @@ void main() { image.dispose(); }); + test('ImageShader with disposed image', () async { + final Image image = await createImage(50, 50); + image.dispose(); + + if (assertsEnabled) { + expectAssertion(() => ImageShader(image, TileMode.clamp, TileMode.clamp, Float64List(16))); + } else { + throwsException(() => ImageShader(image, TileMode.clamp, TileMode.clamp, Float64List(16))); + } + }); + + test('Disposed image shader in a paint', () async { + final Image image = await createImage(50, 50); + final ImageShader shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Float64List(16)); + shader.dispose(); + + if (assertsEnabled) { + expectAssertion(() => Paint()..shader = shader); + return; + } + final Paint paint = Paint()..shader = shader; + const Rect rect = Rect.fromLTRB(0, 0, 100, 100); + testCanvas((Canvas canvas) => canvas.drawRect(rect, paint)); + image.dispose(); + + }); + test('Construct an ImageShader - GPU image', () async { final PictureRecorder recorder = PictureRecorder(); final Canvas canvas = Canvas(recorder); From 5ce72b373e1a01f1dce3f9186f2f252338b5b912 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 11:08:20 -0400 Subject: [PATCH 527/558] Roll Skia from c54c285a35e7 to 9540beb7057b (1 revision) (#35670) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6a907be4c2d9e..ff35083e30e24 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': 'c54c285a35e7c9e07bd06bbc5633a8f720b50f9b', + 'skia_revision': '9540beb7057b6672ebb761c1d11e3cecb34daa33', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index fc8bceb07edc5..dccdb216e5acd 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 4f78190fda4917ef8c9ca223f81ae8c9 +Signature: c40d3bf4d423e88cf5d5175923084dcb UNUSED LICENSES: From dc14649e1a51a7b149e36efb1d8cb8d22c468a1d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 12:35:12 -0400 Subject: [PATCH 528/558] Roll Skia from 9540beb7057b to d965473d8719 (4 revisions) (#35671) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ff35083e30e24..8d39f2f0dd147 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': '9540beb7057b6672ebb761c1d11e3cecb34daa33', + 'skia_revision': 'd965473d8719ad1993d1bf80dfc5b052f343daaa', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index dccdb216e5acd..83d92d7c73ef8 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: c40d3bf4d423e88cf5d5175923084dcb +Signature: 785aed939cedae2da29bcf033244936c UNUSED LICENSES: From fa86e2d8279ca7ab3c441f3857c726789cc8002b Mon Sep 17 00:00:00 2001 From: godofredoc Date: Wed, 24 Aug 2022 09:42:50 -0700 Subject: [PATCH 529/558] Zip FlutterMacOS.framework. (#35623) --- sky/tools/create_macos_framework.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sky/tools/create_macos_framework.py b/sky/tools/create_macos_framework.py index c34e20216ca1d..7f6200070391e 100755 --- a/sky/tools/create_macos_framework.py +++ b/sky/tools/create_macos_framework.py @@ -102,10 +102,9 @@ def process_framework(dst, args, fat_framework, fat_framework_binary): dsym_out = os.path.splitext(fat_framework)[0] + '.dSYM' subprocess.check_call([DSYMUTIL, '-o', dsym_out, fat_framework_binary]) subprocess.check_call([ - 'zip', '-r', - '%s/FlutterMacOS.dSYM.zip' % dst, - '%s/FlutterMacOS.dSYM/Contents' % dst - ]) + 'zip', '-r', 'FlutterMacOS.dSYM.zip', 'FlutterMacOS.dSYM' + ], + cwd=dst) if args.strip: # copy unstripped @@ -114,6 +113,12 @@ def process_framework(dst, args, fat_framework, fat_framework_binary): subprocess.check_call(["strip", "-x", "-S", fat_framework_binary]) + # Zip FlutterMacOS.framework. + subprocess.check_call([ + 'zip', '-r', 'FlutterMacOS.framework.zip', 'FlutterMacOS.framework' + ], + cwd=dst) + if __name__ == '__main__': sys.exit(main()) From ce987d4cb1388fa3c59dc9f41fe58e04926e7294 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 12:58:07 -0400 Subject: [PATCH 530/558] Roll Dart SDK from 859e9bbe6f0a to 691aa6246705 (1 revision) (#35672) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 8d39f2f0dd147..ca0040439d7ca 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '859e9bbe6f0ad5c1a6bff4ee1d854eb3fd0a3da7', + 'dart_revision': '691aa6246705eb9604f291434444b6c83373f2a5', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From ab3569684ed9466c7338734694ea2390204fcafc Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 14:23:15 -0400 Subject: [PATCH 531/558] Roll Skia from d965473d8719 to f0593b093a72 (2 revisions) (#35675) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ca0040439d7ca..1b76dd667caef 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': 'd965473d8719ad1993d1bf80dfc5b052f343daaa', + 'skia_revision': 'f0593b093a7207fe8c8b808f88581bbfe6ac8d43', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 83d92d7c73ef8..37d8de8417da8 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 785aed939cedae2da29bcf033244936c +Signature: 70a01a38f7238b5b3f42cfcecc352d17 UNUSED LICENSES: From 474082412be1cd9f363468b97788c9276191a4f1 Mon Sep 17 00:00:00 2001 From: Alexander Biggs Date: Wed, 24 Aug 2022 16:00:39 -0400 Subject: [PATCH 532/558] [fuchsia] Document `found != flatland_views.end()`. (#35607) This crash has come up a number of times and we tend to burn time looking in the wrong places for the fix. Documenting some stuff about how we've fixed it previously in the error message. --- .../fuchsia/flutter/flatland_external_view_embedder.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc index 54d91c1fe8a8e..41049c39fa839 100644 --- a/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc +++ b/shell/platform/fuchsia/flutter/flatland_external_view_embedder.cc @@ -184,7 +184,14 @@ void FlatlandExternalViewEmbedder::SubmitFrame( // Get the FlatlandView structure corresponding to the platform view. auto found = flatland_views_.find(layer_id.value()); - FML_CHECK(found != flatland_views_.end()); + FML_CHECK(found != flatland_views_.end()) + << "No FlatlandView for layer_id = " << layer_id.value() + << ". This typically indicates that the Dart code in " + "Fuchsia's fuchsia_scenic_flutter library failed to create " + "the platform view, leading to a crash later down the road in " + "the Flutter Engine code that tries to find that platform view. " + "Check the Flutter Framework for changes to PlatformView that " + "might have caused a regression."; auto& viewport = found->second; // Compute mutators, and size for the platform view. From c6c872137be6e26fc50261106f1dc8a47c9eb347 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 16:03:19 -0400 Subject: [PATCH 533/558] Roll Skia from f0593b093a72 to 8acbc3ce4e84 (7 revisions) (#35676) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 1b76dd667caef..1a563eb74bab1 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': 'f0593b093a7207fe8c8b808f88581bbfe6ac8d43', + 'skia_revision': '8acbc3ce4e84117bc0c70817aa8a74337157756b', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 37d8de8417da8..b42a8a5b0c375 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 70a01a38f7238b5b3f42cfcecc352d17 +Signature: 3155d1b7b337abffe925d5c33bd183ed UNUSED LICENSES: From 74170910709da8f492f47db245d7315671ce00c4 Mon Sep 17 00:00:00 2001 From: Michael Ludwig Date: Wed, 24 Aug 2022 16:06:28 -0400 Subject: [PATCH 534/558] Set temporary GN arg for Skia roll (#35651) --- tools/gn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/gn b/tools/gn index 2b8e94f3363fe..7b218ff116802 100755 --- a/tools/gn +++ b/tools/gn @@ -232,6 +232,8 @@ def to_gn_args(args): gn_args['skia_use_wuffs'] = True gn_args['skia_use_expat'] = args.target_os == 'android' gn_args['skia_use_fontconfig'] = args.enable_fontconfig + gn_args['skia_use_legacy_layer_bounds' + ] = True # Temporary: See skbug.com/12083, skbug.com/12303. if args.enable_skshaper: gn_args['skia_use_icu'] = True From 1c5c7052b907883073cb3bd222427adb8acac9e4 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Wed, 24 Aug 2022 13:24:16 -0700 Subject: [PATCH 535/558] Revert "Zip FlutterMacOS.framework. (#35623)" (#35680) This reverts commit fa86e2d8279ca7ab3c441f3857c726789cc8002b. --- sky/tools/create_macos_framework.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sky/tools/create_macos_framework.py b/sky/tools/create_macos_framework.py index 7f6200070391e..c34e20216ca1d 100755 --- a/sky/tools/create_macos_framework.py +++ b/sky/tools/create_macos_framework.py @@ -102,9 +102,10 @@ def process_framework(dst, args, fat_framework, fat_framework_binary): dsym_out = os.path.splitext(fat_framework)[0] + '.dSYM' subprocess.check_call([DSYMUTIL, '-o', dsym_out, fat_framework_binary]) subprocess.check_call([ - 'zip', '-r', 'FlutterMacOS.dSYM.zip', 'FlutterMacOS.dSYM' - ], - cwd=dst) + 'zip', '-r', + '%s/FlutterMacOS.dSYM.zip' % dst, + '%s/FlutterMacOS.dSYM/Contents' % dst + ]) if args.strip: # copy unstripped @@ -113,12 +114,6 @@ def process_framework(dst, args, fat_framework, fat_framework_binary): subprocess.check_call(["strip", "-x", "-S", fat_framework_binary]) - # Zip FlutterMacOS.framework. - subprocess.check_call([ - 'zip', '-r', 'FlutterMacOS.framework.zip', 'FlutterMacOS.framework' - ], - cwd=dst) - if __name__ == '__main__': sys.exit(main()) From 983e3abdadc5fa7e31fa74a6611cc920493070af Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 24 Aug 2022 13:26:09 -0700 Subject: [PATCH 536/558] [Impeller] Fix matrix printing (#35656) --- impeller/geometry/geometry_unittests.cc | 30 +++++++++++++++++++++++++ impeller/geometry/matrix.h | 5 +++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/impeller/geometry/geometry_unittests.cc b/impeller/geometry/geometry_unittests.cc index 76f34073fdf9a..0957acf76b23a 100644 --- a/impeller/geometry/geometry_unittests.cc +++ b/impeller/geometry/geometry_unittests.cc @@ -5,6 +5,7 @@ #include "impeller/geometry/geometry_unittests.h" #include +#include #include "flutter/testing/testing.h" #include "impeller/geometry/constants.h" @@ -1330,5 +1331,34 @@ TEST(GeometryTest, VerticesConstructorAndGetters) { ASSERT_EQ(vertices.GetMode(), VertexMode::kTriangle); } +TEST(GeometryTest, MatrixPrinting) { + std::stringstream stream; + + Matrix m; + + stream << m; + + ASSERT_EQ(stream.str(), R"(( + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 1.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 1.000000, +))"); + + stream.str(""); + stream.clear(); + + m = Matrix::MakeTranslation(Vector3(10, 20, 30)); + + stream << m; + + ASSERT_EQ(stream.str(), R"(( + 1.000000, 0.000000, 0.000000, 10.000000, + 0.000000, 1.000000, 0.000000, 20.000000, + 0.000000, 0.000000, 1.000000, 30.000000, + 0.000000, 0.000000, 0.000000, 1.000000, +))"); +} + } // namespace testing } // namespace impeller diff --git a/impeller/geometry/matrix.h b/impeller/geometry/matrix.h index 8bdb250b61b56..29bbb949b3918 100644 --- a/impeller/geometry/matrix.h +++ b/impeller/geometry/matrix.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include @@ -374,10 +375,10 @@ static_assert(sizeof(struct Matrix) == sizeof(Scalar) * 16, namespace std { inline std::ostream& operator<<(std::ostream& out, const impeller::Matrix& m) { - out << "("; + out << "(" << std::endl << std::fixed; for (size_t i = 0; i < 4u; i++) { for (size_t j = 0; j < 4u; j++) { - out << m.e[i][j] << ","; + out << std::setw(15) << m.e[j][i] << ","; } out << std::endl; } From c9876d7a3a119e0e6f1f6f783f95da3dd58c5010 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 16:42:04 -0400 Subject: [PATCH 537/558] Roll Fuchsia Mac SDK from XrmzJCUPGAd4klJlw... to uiiEV3lEQoosICL43... (#35677) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 1a563eb74bab1..ebb1e1aecbeef 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'XrmzJCUPGAd4klJlwQ4SCiDFfA2Ie9IIuu4WzKCFgEgC' + 'version': 'uiiEV3lEQoosICL439Dnn0Ws0-K3akCMnRmkl8kbBdEC' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 4cb9cfe3123d138e3215ede6b49f9b463c24a22a Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 16:55:10 -0400 Subject: [PATCH 538/558] Roll Dart SDK from 691aa6246705 to b535e8d0bfbe (1 revision) (#35679) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index ebb1e1aecbeef..fefb4270936d4 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '691aa6246705eb9604f291434444b6c83373f2a5', + 'dart_revision': 'b535e8d0bfbedd5a7580a020befd1c46452ac633', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py From f85f8f880206633e7a1196543e2c3a8119b1079d Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 18:11:32 -0400 Subject: [PATCH 539/558] Roll Skia from 8acbc3ce4e84 to 502e75091b90 (5 revisions) (#35683) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 96 ++++++++++++++++---------------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/DEPS b/DEPS index fefb4270936d4..d158b0b1f268c 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': '8acbc3ce4e84117bc0c70817aa8a74337157756b', + 'skia_revision': '502e75091b9086aa57cd62d6f31b38945b421153', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index b42a8a5b0c375..e9e12d243ea52 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 3155d1b7b337abffe925d5c33bd183ed +Signature: 82861add9083a3ea845d3eedf9236ef0 UNUSED LICENSES: @@ -2126,7 +2126,6 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkDescriptorSet.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkDescriptorSet.h FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkDescriptorSetManager.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkDescriptorSetManager.h -FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkExtensions.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkFramebuffer.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkFramebuffer.h FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkImageView.cpp @@ -2150,6 +2149,7 @@ FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkUniformHandler.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkUniformHandler.h FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkVaryingHandler.cpp FILE: ../../../third_party/skia/src/gpu/ganesh/vk/GrVkVaryingHandler.h +FILE: ../../../third_party/skia/src/gpu/vk/VulkanExtensions.cpp FILE: ../../../third_party/skia/src/images/SkImageEncoderPriv.h FILE: ../../../third_party/skia/src/opts/SkChecksum_opts.h FILE: ../../../third_party/skia/src/opts/SkOpts_avx.cpp @@ -7151,6 +7151,53 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== +==================================================================================================== +LIBRARY: skia +ORIGIN: ../../../third_party/skia/include/gpu/vk/VulkanExtensions.h + ../../../third_party/skia/LICENSE +TYPE: LicenseType.bsd +FILE: ../../../third_party/skia/include/gpu/vk/VulkanExtensions.h +FILE: ../../../third_party/skia/include/gpu/vk/VulkanTypes.h +FILE: ../../../third_party/skia/src/gpu/ganesh/dawn/GrDawnAsyncWait.cpp +FILE: ../../../third_party/skia/src/gpu/ganesh/dawn/GrDawnAsyncWait.h +FILE: ../../../third_party/skia/src/gpu/piet/PietTypes.h +FILE: ../../../third_party/skia/src/gpu/piet/Render.cpp +FILE: ../../../third_party/skia/src/gpu/piet/Render.h +FILE: ../../../third_party/skia/src/gpu/piet/Scene.cpp +FILE: ../../../third_party/skia/src/gpu/piet/Scene.h +FILE: ../../../third_party/skia/src/gpu/tessellate/MidpointContourParser.h +FILE: ../../../third_party/skia/src/sksl/SkSLPosition.cpp +---------------------------------------------------------------------------------------------------- +Copyright 2022 Google LLC. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +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. +==================================================================================================== + ==================================================================================================== LIBRARY: skia ORIGIN: ../../../third_party/skia/include/utils/SkEventTracer.h + ../../../third_party/skia/LICENSE @@ -7818,51 +7865,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== -==================================================================================================== -LIBRARY: skia -ORIGIN: ../../../third_party/skia/src/gpu/ganesh/dawn/GrDawnAsyncWait.cpp + ../../../third_party/skia/LICENSE -TYPE: LicenseType.bsd -FILE: ../../../third_party/skia/src/gpu/ganesh/dawn/GrDawnAsyncWait.cpp -FILE: ../../../third_party/skia/src/gpu/ganesh/dawn/GrDawnAsyncWait.h -FILE: ../../../third_party/skia/src/gpu/piet/PietTypes.h -FILE: ../../../third_party/skia/src/gpu/piet/Render.cpp -FILE: ../../../third_party/skia/src/gpu/piet/Render.h -FILE: ../../../third_party/skia/src/gpu/piet/Scene.cpp -FILE: ../../../third_party/skia/src/gpu/piet/Scene.h -FILE: ../../../third_party/skia/src/gpu/tessellate/MidpointContourParser.h -FILE: ../../../third_party/skia/src/sksl/SkSLPosition.cpp ----------------------------------------------------------------------------------------------------- -Copyright 2022 Google LLC. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -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. -==================================================================================================== - ==================================================================================================== LIBRARY: skia ORIGIN: ../../../third_party/skia/src/gpu/ganesh/ops/SmallPathRenderer.cpp + ../../../third_party/skia/LICENSE From 56acfad13d6ca009bb5c2b46eec983045792ac25 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 24 Aug 2022 15:15:26 -0700 Subject: [PATCH 540/558] [Impeller] Don't store the pass multisample texture when nothing is going to read it (#35681) --- impeller/entity/entity_pass.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 06a32b6643316..76bc5d8918037 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -309,13 +309,13 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( *renderer.GetContext(), // context ISize::Ceil(subpass_coverage->size), // size "EntityPass", // label - StorageMode::kDevicePrivate, // color_storage_mode + StorageMode::kDeviceTransient, // color_storage_mode StorageMode::kDevicePrivate, // color_resolve_storage_mode LoadAction::kClear, // color_load_action - StoreAction::kStoreAndMultisampleResolve, // color_store_action - StorageMode::kDeviceTransient, // stencil_storage_mode - LoadAction::kClear, // stencil_load_action - StoreAction::kDontCare // stencil_store_action + StoreAction::kMultisampleResolve, // color_store_action + StorageMode::kDeviceTransient, // stencil_storage_mode + LoadAction::kClear, // stencil_load_action + StoreAction::kDontCare // stencil_store_action ); } From ac62ebf8718bfd00280a0b821279505174563229 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 24 Aug 2022 15:19:42 -0700 Subject: [PATCH 541/558] [Impeller] Downsample gaussian blur passes bidirectionally (#35561) --- .../contents/filters/filter_contents.cc | 6 ++-- .../entity/contents/filters/filter_contents.h | 1 + .../filters/gaussian_blur_filter_contents.cc | 36 ++++++++++++------- .../filters/gaussian_blur_filter_contents.h | 3 ++ 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/impeller/entity/contents/filters/filter_contents.cc b/impeller/entity/contents/filters/filter_contents.cc index 10e3601ea0212..ef5047966e71d 100644 --- a/impeller/entity/contents/filters/filter_contents.cc +++ b/impeller/entity/contents/filters/filter_contents.cc @@ -79,6 +79,7 @@ std::shared_ptr FilterContents::MakeDirectionalGaussianBlur( BlurStyle blur_style, Entity::TileMode tile_mode, FilterInput::Ref source_override, + Sigma secondary_sigma, const Matrix& effect_transform) { auto blur = std::make_shared(); blur->SetInputs({input}); @@ -87,6 +88,7 @@ std::shared_ptr FilterContents::MakeDirectionalGaussianBlur( blur->SetBlurStyle(blur_style); blur->SetTileMode(tile_mode); blur->SetSourceOverride(source_override); + blur->SetSecondarySigma(secondary_sigma); blur->SetEffectTransform(effect_transform); return blur; } @@ -100,10 +102,10 @@ std::shared_ptr FilterContents::MakeGaussianBlur( const Matrix& effect_transform) { auto x_blur = MakeDirectionalGaussianBlur(input, sigma_x, Point(1, 0), BlurStyle::kNormal, tile_mode, - nullptr, effect_transform); + nullptr, {}, effect_transform); auto y_blur = MakeDirectionalGaussianBlur(FilterInput::Make(x_blur), sigma_y, Point(0, 1), blur_style, tile_mode, - input, effect_transform); + input, sigma_x, effect_transform); return y_blur; } diff --git a/impeller/entity/contents/filters/filter_contents.h b/impeller/entity/contents/filters/filter_contents.h index 87333aed8f4f2..acffb71e8e540 100644 --- a/impeller/entity/contents/filters/filter_contents.h +++ b/impeller/entity/contents/filters/filter_contents.h @@ -48,6 +48,7 @@ class FilterContents : public Contents { BlurStyle blur_style = BlurStyle::kNormal, Entity::TileMode tile_mode = Entity::TileMode::kDecal, FilterInput::Ref alpha_mask = nullptr, + Sigma secondary_sigma = {}, const Matrix& effect_transform = Matrix()); static std::shared_ptr MakeGaussianBlur( diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc index ea350055d2f01..47dadff5c895a 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.cc @@ -32,6 +32,10 @@ void DirectionalGaussianBlurFilterContents::SetSigma(Sigma sigma) { blur_sigma_ = sigma; } +void DirectionalGaussianBlurFilterContents::SetSecondarySigma(Sigma sigma) { + secondary_blur_sigma_ = sigma; +} + void DirectionalGaussianBlurFilterContents::SetDirection(Vector2 direction) { blur_direction_ = direction.Normalize(); if (blur_direction_.IsZero()) { @@ -221,12 +225,22 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( return pass.AddCommand(cmd); }; - Scalar x_scale = - 1.0 / - std::ceil(std::log2(std::max(2.0f, transformed_blur_radius_length))); - auto scaled_texture_width = pass_texture_rect.size.width * x_scale; - auto out_texture = renderer.MakeSubpass( - ISize(scaled_texture_width, pass_texture_rect.size.height), callback); + Vector2 scale; + { + scale.x = + 1.0 / + std::ceil(std::log2(std::max(2.0f, transformed_blur_radius_length))); + + Scalar y_radius = std::abs(pass_transform.GetDirectionScale(Vector2( + 0, source_override_ ? Radius{secondary_blur_sigma_}.radius : 1))); + scale.y = 1.0 / std::ceil(std::log2(std::max(2.0f, y_radius))); + } + + Vector2 scaled_size = pass_texture_rect.size * scale; + ISize floored_size = ISize(scaled_size.x, scaled_size.y); + + auto out_texture = renderer.MakeSubpass(floored_size, callback); + if (!out_texture) { return std::nullopt; } @@ -238,12 +252,10 @@ std::optional DirectionalGaussianBlurFilterContents::RenderFilter( return Snapshot{ .texture = out_texture, - .transform = texture_rotate.Invert() * - Matrix::MakeTranslation(pass_texture_rect.origin) * - Matrix::MakeScale(Vector2( - (1 / x_scale) * (scaled_texture_width / - std::floor(scaled_texture_width)), - 1)), + .transform = + texture_rotate.Invert() * + Matrix::MakeTranslation(pass_texture_rect.origin) * + Matrix::MakeScale((1 / scale) * (scaled_size / floored_size)), .sampler_descriptor = sampler_desc}; } diff --git a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h index 1e2ec6b3ab544..7c4e44d68ece5 100644 --- a/impeller/entity/contents/filters/gaussian_blur_filter_contents.h +++ b/impeller/entity/contents/filters/gaussian_blur_filter_contents.h @@ -19,6 +19,8 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents { void SetSigma(Sigma sigma); + void SetSecondarySigma(Sigma sigma); + void SetDirection(Vector2 direction); void SetBlurStyle(BlurStyle blur_style); @@ -42,6 +44,7 @@ class DirectionalGaussianBlurFilterContents final : public FilterContents { const Matrix& effect_transform, const Rect& coverage) const override; Sigma blur_sigma_; + Sigma secondary_blur_sigma_; Vector2 blur_direction_; BlurStyle blur_style_ = BlurStyle::kNormal; Entity::TileMode tile_mode_ = Entity::TileMode::kDecal; From f10ffb4b73b1c8d9f5485d03ee1d9509fb719eb6 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Wed, 24 Aug 2022 15:56:58 -0700 Subject: [PATCH 542/558] Eliminates Dart->Host response copy for large buffers (#35468) --- ci/licenses_golden/licenses_flutter | 1 + lib/ui/BUILD.gn | 1 + lib/ui/fixtures/ui_test.dart | 15 ++++ lib/ui/platform_dispatcher.dart | 4 + .../window/platform_message_response_dart.cc | 39 ++++++++-- ...latform_message_response_dart_unittests.cc | 73 +++++++++++++++++++ .../tonic/typed_data/dart_byte_data.cc | 8 +- third_party/tonic/typed_data/dart_byte_data.h | 1 + 8 files changed, 133 insertions(+), 9 deletions(-) create mode 100644 lib/ui/window/platform_message_response_dart_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 93b67b395ffd5..aa22485f2aba3 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1100,6 +1100,7 @@ FILE: ../../../flutter/lib/ui/window/platform_message_response.cc FILE: ../../../flutter/lib/ui/window/platform_message_response.h FILE: ../../../flutter/lib/ui/window/platform_message_response_dart.cc FILE: ../../../flutter/lib/ui/window/platform_message_response_dart.h +FILE: ../../../flutter/lib/ui/window/platform_message_response_dart_unittests.cc FILE: ../../../flutter/lib/ui/window/pointer_data.cc FILE: ../../../flutter/lib/ui/window/pointer_data.h FILE: ../../../flutter/lib/ui/window/pointer_data_packet.cc diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 6a2916d9cb622..d9f1a893cfbdb 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -231,6 +231,7 @@ if (enable_unittests) { "painting/vertices_unittests.cc", "semantics/semantics_update_builder_unittests.cc", "window/platform_configuration_unittests.cc", + "window/platform_message_response_dart_unittests.cc", "window/pointer_data_packet_converter_unittests.cc", ] diff --git a/lib/ui/fixtures/ui_test.dart b/lib/ui/fixtures/ui_test.dart index b0c7cdb697a1c..55281721199be 100644 --- a/lib/ui/fixtures/ui_test.dart +++ b/lib/ui/fixtures/ui_test.dart @@ -228,6 +228,21 @@ void frameCallback(_Image, int) { print('called back'); } +@pragma('vm:entry-point') +void platformMessageResponseTest() { + _callPlatformMessageResponseDart((ByteData? result) { + if (result is UnmodifiableByteDataView && + result.lengthInBytes == 100) { + _finishCallResponse(true); + } else { + _finishCallResponse(false); + } + }); +} + +void _callPlatformMessageResponseDart(void Function(ByteData? result) callback) native 'CallPlatformMessageResponseDart'; +void _finishCallResponse(bool didPass) native 'FinishCallResponse'; + @pragma('vm:entry-point') void messageCallback(dynamic data) {} diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index 1a86c5846bf46..9a3d7e9f6b73e 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -69,6 +69,10 @@ const double _kUnsetGestureSetting = -1.0; // See embedder.cc::kFlutterKeyDataChannel for more information. const String _kFlutterKeyDataChannel = 'flutter/keydata'; +@pragma('vm:entry-point') +ByteData? _wrapUnmodifiableByteData(ByteData? byteData) => + byteData == null ? null : UnmodifiableByteDataView(byteData); + /// Platform event dispatcher singleton. /// /// The most basic interface to the host operating system's interface. diff --git a/lib/ui/window/platform_message_response_dart.cc b/lib/ui/window/platform_message_response_dart.cc index 39d55f41d736b..66c07c31c36ed 100644 --- a/lib/ui/window/platform_message_response_dart.cc +++ b/lib/ui/window/platform_message_response_dart.cc @@ -17,6 +17,11 @@ static std::atomic platform_message_counter = 1; namespace flutter { namespace { + +void MappingFinalizer(void* isolate_callback_data, void* peer) { + delete static_cast(peer); +} + template void PostCompletion(Callback&& callback, const TaskRunner& ui_task_runner, @@ -63,11 +68,35 @@ PlatformMessageResponseDart::~PlatformMessageResponseDart() { } void PlatformMessageResponseDart::Complete(std::unique_ptr data) { - PostCompletion(std::move(callback_), ui_task_runner_, &is_complete_, channel_, - [data = std::move(data)] { - return tonic::DartByteData::Create(data->GetMapping(), - data->GetSize()); - }); + PostCompletion( + std::move(callback_), ui_task_runner_, &is_complete_, channel_, + [data = std::move(data)]() mutable { + Dart_Handle byte_buffer; + intptr_t size = data->GetSize(); + if (data->GetSize() > tonic::DartByteData::kExternalSizeThreshold) { + const void* mapping = data->GetMapping(); + byte_buffer = Dart_NewUnmodifiableExternalTypedDataWithFinalizer( + /*type=*/Dart_TypedData_kByteData, + /*data=*/mapping, + /*length=*/size, + /*peer=*/data.release(), + /*external_allocation_size=*/size, + /*callback=*/MappingFinalizer); + } else { + Dart_Handle mutable_byte_buffer = + tonic::DartByteData::Create(data->GetMapping(), data->GetSize()); + Dart_Handle ui_lib = Dart_LookupLibrary( + tonic::DartConverter().ToDart("dart:ui")); + FML_DCHECK(!(Dart_IsNull(ui_lib) || Dart_IsError(ui_lib))); + byte_buffer = Dart_Invoke(ui_lib, + tonic::DartConverter().ToDart( + "_wrapUnmodifiableByteData"), + 1, &mutable_byte_buffer); + FML_DCHECK(!(Dart_IsNull(byte_buffer) || Dart_IsError(byte_buffer))); + } + + return byte_buffer; + }); } void PlatformMessageResponseDart::CompleteEmpty() { diff --git a/lib/ui/window/platform_message_response_dart_unittests.cc b/lib/ui/window/platform_message_response_dart_unittests.cc new file mode 100644 index 0000000000000..b4a90db65a71d --- /dev/null +++ b/lib/ui/window/platform_message_response_dart_unittests.cc @@ -0,0 +1,73 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/common/task_runners.h" +#include "flutter/fml/mapping.h" +#include "flutter/fml/synchronization/waitable_event.h" +#include "flutter/lib/ui/window/platform_message_response_dart.h" +#include "flutter/runtime/dart_vm.h" +#include "flutter/shell/common/shell_test.h" +#include "flutter/shell/common/thread_host.h" +#include "flutter/testing/testing.h" + +namespace flutter { +namespace testing { + +TEST_F(ShellTest, PlatformMessageResponseDart) { + bool did_pass = false; + auto message_latch = std::make_shared(); + TaskRunners task_runners("test", // label + GetCurrentTaskRunner(), // platform + CreateNewThread(), // raster + CreateNewThread(), // ui + CreateNewThread() // io + ); + + auto nativeCallPlatformMessageResponseDart = + [ui_task_runner = + task_runners.GetUITaskRunner()](Dart_NativeArguments args) { + auto dart_state = std::make_shared(); + auto response = fml::MakeRefCounted( + tonic::DartPersistentValue(tonic::DartState::Current(), + Dart_GetNativeArgument(args, 0)), + ui_task_runner, "foobar"); + uint8_t* data = static_cast(malloc(100)); + auto mapping = std::make_unique(data, 100); + response->Complete(std::move(mapping)); + }; + + AddNativeCallback("CallPlatformMessageResponseDart", + CREATE_NATIVE_ENTRY(nativeCallPlatformMessageResponseDart)); + + auto nativeFinishCallResponse = [message_latch, + &did_pass](Dart_NativeArguments args) { + did_pass = + tonic::DartConverter::FromDart(Dart_GetNativeArgument(args, 0)); + message_latch->Signal(); + }; + + AddNativeCallback("FinishCallResponse", + CREATE_NATIVE_ENTRY(nativeFinishCallResponse)); + + Settings settings = CreateSettingsForFixture(); + + std::unique_ptr shell = + CreateShell(std::move(settings), std::move(task_runners)); + + ASSERT_TRUE(shell->IsSetup()); + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("platformMessageResponseTest"); + + shell->RunEngine(std::move(configuration), [](auto result) { + ASSERT_EQ(result, Engine::RunStatus::Success); + }); + + message_latch->Wait(); + + ASSERT_TRUE(did_pass); + DestroyShell(std::move(shell), std::move(task_runners)); +} + +} // namespace testing +} // namespace flutter diff --git a/third_party/tonic/typed_data/dart_byte_data.cc b/third_party/tonic/typed_data/dart_byte_data.cc index cab038d14f85d..7416f12f62221 100644 --- a/third_party/tonic/typed_data/dart_byte_data.cc +++ b/third_party/tonic/typed_data/dart_byte_data.cc @@ -12,16 +12,16 @@ namespace tonic { namespace { -// For large objects it is more efficient to use an external typed data object -// with a buffer allocated outside the Dart heap. -const int kExternalSizeThreshold = 1000; - void FreeFinalizer(void* isolate_callback_data, void* peer) { free(peer); } } // anonymous namespace +// For large objects it is more efficient to use an external typed data object +// with a buffer allocated outside the Dart heap. +const size_t DartByteData::kExternalSizeThreshold = 1000; + Dart_Handle DartByteData::Create(const void* data, size_t length) { if (length < kExternalSizeThreshold) { auto handle = DartByteData{data, length}.dart_handle(); diff --git a/third_party/tonic/typed_data/dart_byte_data.h b/third_party/tonic/typed_data/dart_byte_data.h index 9e14bc969fb8e..911d0d5da0d7e 100644 --- a/third_party/tonic/typed_data/dart_byte_data.h +++ b/third_party/tonic/typed_data/dart_byte_data.h @@ -14,6 +14,7 @@ namespace tonic { class DartByteData { public: + static const size_t kExternalSizeThreshold; static Dart_Handle Create(const void* data, size_t length); explicit DartByteData(Dart_Handle list); From 7406fd81865292772689a1bbbc2239c665ba07d8 Mon Sep 17 00:00:00 2001 From: Harry Terkelsen Date: Wed, 24 Aug 2022 16:19:31 -0700 Subject: [PATCH 543/558] [reland] Canvaskit get googlefont data (#35646) --- ci/licenses_golden/licenses_flutter | 2 + lib/web_ui/README.md | 13 + lib/web_ui/dev/felt.dart | 2 + .../dev/generate_fallback_font_data.dart | 289 +++++++++ lib/web_ui/lib/initialization.dart | 1 + lib/web_ui/lib/src/engine.dart | 2 + .../engine/canvaskit/font_fallback_data.dart | 151 +++++ .../src/engine/canvaskit/font_fallbacks.dart | 609 ++---------------- .../src/engine/canvaskit/interval_tree.dart | 2 +- .../lib/src/engine/canvaskit/noto_font.dart | 98 +++ lib/web_ui/lib/src/engine/initialization.dart | 13 + .../test/canvaskit/canvas_golden_test.dart | 5 +- lib/web_ui/test/canvaskit/common.dart | 1 + .../canvaskit/fallback_fonts_golden_test.dart | 278 +++++--- 14 files changed, 820 insertions(+), 646 deletions(-) create mode 100644 lib/web_ui/dev/generate_fallback_font_data.dart create mode 100644 lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart create mode 100644 lib/web_ui/lib/src/engine/canvaskit/noto_font.dart diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index aa22485f2aba3..fdb7e3c834ee2 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1140,6 +1140,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/canvaskit_canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/color_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/embedded_views_diff.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/fonts.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/image.dart @@ -1152,6 +1153,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_scene_builder.d FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/layer_tree.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/mask_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/n_way_canvas.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/painting.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/canvaskit/path_metrics.dart diff --git a/lib/web_ui/README.md b/lib/web_ui/README.md index d13e1ee6b145d..f4e87cb31c6eb 100644 --- a/lib/web_ui/README.md +++ b/lib/web_ui/README.md @@ -205,6 +205,19 @@ directly), follow these steps to roll to the new version: If you have questions, contact the Flutter Web team on Flutter Discord on the #hackers-web-🌍 channel. +### Rolling Noto Font Data + +In order to generate new data for the Noto fallback fonts, you will need +a GoogleFonts API key. Once you have one, run: + +``` +./dev/felt generate-fallback-font-data --key= +``` + +This will generate the file `lib/src/engine/canvaskit/font_fallback_data.dart` with +the latest data from GoogleFonts. This generated file should then be rolled in with +a PR to the engine. + ### Configuration files `browser_lock.yaml` contains the version of browsers we use to test Flutter for diff --git a/lib/web_ui/dev/felt.dart b/lib/web_ui/dev/felt.dart index 1048c8bdcf3a6..2e6e6d156cf46 100644 --- a/lib/web_ui/dev/felt.dart +++ b/lib/web_ui/dev/felt.dart @@ -9,6 +9,7 @@ import 'package:args/command_runner.dart'; import 'build.dart'; import 'clean.dart'; import 'exceptions.dart'; +import 'generate_fallback_font_data.dart'; import 'licenses.dart'; import 'run.dart'; import 'test_runner.dart'; @@ -20,6 +21,7 @@ CommandRunner runner = CommandRunner( ) ..addCommand(BuildCommand()) ..addCommand(CleanCommand()) + ..addCommand(GenerateFallbackFontDataCommand()) ..addCommand(LicensesCommand()) ..addCommand(RunCommand()) ..addCommand(TestCommand()); diff --git a/lib/web_ui/dev/generate_fallback_font_data.dart b/lib/web_ui/dev/generate_fallback_font_data.dart new file mode 100644 index 0000000000000..7ae4aae65eb8c --- /dev/null +++ b/lib/web_ui/dev/generate_fallback_font_data.dart @@ -0,0 +1,289 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert' show jsonDecode; +import 'dart:io' as io; + +import 'package:args/command_runner.dart'; +import 'package:http/http.dart' as http; +import 'package:path/path.dart' as path; + +import 'environment.dart'; +import 'exceptions.dart'; +import 'utils.dart'; + +class GenerateFallbackFontDataCommand extends Command + with ArgUtils { + GenerateFallbackFontDataCommand() { + argParser.addOption( + 'key', + defaultsTo: '', + help: 'The Google Fonts API key. Used to get data about fonts hosted on ' + 'Google Fonts.', + ); + argParser.addFlag( + 'download-test-fonts', + defaultsTo: true, + help: 'Whether to download the Noto fonts into a local folder to use in' + 'tests.', + ); + } + + @override + final String name = 'generate-fallback-font-data'; + + @override + final String description = 'Generate fallback font data from GoogleFonts'; + + String get apiKey => stringArg('key'); + + bool get downloadTestFonts => boolArg('download-test-fonts'); + + @override + Future run() async { + await _generateFallbackFontData(); + return true; + } + + Future _generateFallbackFontData() async { + if (apiKey.isEmpty) { + throw UsageException('No Google Fonts API key provided', argParser.usage); + } + final http.Client client = http.Client(); + final http.Response response = await client.get(Uri.parse( + 'https://www.googleapis.com/webfonts/v1/webfonts?key=$apiKey')); + if (response.statusCode != 200) { + throw ToolExit('Failed to download Google Fonts list.'); + } + final Map googleFontsResult = + jsonDecode(response.body) as Map; + final List> fontDatas = + (googleFontsResult['items'] as List) + .cast>(); + final Map urlForFamily = {}; + for (final Map fontData in fontDatas) { + if (fallbackFonts.contains(fontData['family'])) { + final Uri uri = Uri.parse(fontData['files']['regular'] as String); + urlForFamily[fontData['family'] as String] = uri; + } + } + final Map charsetForFamily = {}; + final io.Directory fontDir = downloadTestFonts + ? await io.Directory(path.join( + environment.webUiBuildDir.path, + 'assets', + 'noto', + )).create(recursive: true) + : await io.Directory.systemTemp.createTemp('fonts'); + // Delete old fonts in the font directory. + await for (final io.FileSystemEntity file in fontDir.list()) { + await file.delete(); + } + for (final String family in fallbackFonts) { + print('Downloading $family...'); + final Uri uri = urlForFamily[family]!; + final http.Response fontResponse = await client.get(uri); + if (fontResponse.statusCode != 200) { + throw ToolExit('Failed to download font for $family'); + } + final io.File fontFile = + io.File(path.join(fontDir.path, path.basename(uri.path))); + await fontFile.writeAsBytes(fontResponse.bodyBytes); + final io.ProcessResult fcQueryResult = + await io.Process.run('fc-query', [ + '--format=%{charset}', + '--', + fontFile.path, + ]); + final String encodedCharset = fcQueryResult.stdout as String; + charsetForFamily[family] = encodedCharset; + } + + final StringBuffer sb = StringBuffer(); + + sb.writeln('// Copyright 2013 The Flutter Authors. All rights reserved.'); + sb.writeln('// Use of this source code is governed by a BSD-style license ' + 'that can be'); + sb.writeln('// found in the LICENSE file.'); + sb.writeln(); + sb.writeln('// DO NOT EDIT! This file is generated. See:'); + sb.writeln('// dev/generate_fallback_font_data.dart'); + sb.writeln("import 'noto_font.dart';"); + sb.writeln(); + sb.writeln('final List fallbackFonts = ['); + for (final String family in fallbackFonts) { + sb.write(" NotoFont.fromFlatRanges('$family', '${urlForFamily[family]!}', " + '['); + for (final String range in charsetForFamily[family]!.split(' ')) { + String? start; + String? end; + final List parts = range.split('-'); + if (parts.length == 1) { + start = parts[0]; + end = parts[0]; + } else { + start = parts[0]; + end = parts[1]; + } + sb.write('0x$start,0x$end,'); + } + sb.writeln(']),'); + } + sb.writeln('];'); + + final io.File fontDataFile = io.File(path.join( + environment.webUiRootDir.path, + 'lib', + 'src', + 'engine', + 'canvaskit', + 'font_fallback_data.dart', + )); + await fontDataFile.writeAsString(sb.toString()); + } +} + +const List fallbackFonts = [ + 'Noto Sans', + 'Noto Emoji', + 'Noto Sans Symbols', + 'Noto Sans Symbols 2', + 'Noto Sans Adlam', + 'Noto Sans Anatolian Hieroglyphs', + 'Noto Sans Arabic', + 'Noto Sans Armenian', + 'Noto Sans Avestan', + 'Noto Sans Balinese', + 'Noto Sans Bamum', + 'Noto Sans Bassa Vah', + 'Noto Sans Batak', + 'Noto Sans Bengali', + 'Noto Sans Bhaiksuki', + 'Noto Sans Brahmi', + 'Noto Sans Buginese', + 'Noto Sans Buhid', + 'Noto Sans Canadian Aboriginal', + 'Noto Sans Carian', + 'Noto Sans Caucasian Albanian', + 'Noto Sans Chakma', + 'Noto Sans Cham', + 'Noto Sans Cherokee', + 'Noto Sans Coptic', + 'Noto Sans Cuneiform', + 'Noto Sans Cypriot', + 'Noto Sans Deseret', + 'Noto Sans Devanagari', + 'Noto Sans Duployan', + 'Noto Sans Egyptian Hieroglyphs', + 'Noto Sans Elbasan', + 'Noto Sans Elymaic', + 'Noto Sans Georgian', + 'Noto Sans Glagolitic', + 'Noto Sans Gothic', + 'Noto Sans Grantha', + 'Noto Sans Gujarati', + 'Noto Sans Gunjala Gondi', + 'Noto Sans Gurmukhi', + 'Noto Sans HK', + 'Noto Sans Hanunoo', + 'Noto Sans Hatran', + 'Noto Sans Hebrew', + 'Noto Sans Imperial Aramaic', + 'Noto Sans Indic Siyaq Numbers', + 'Noto Sans Inscriptional Pahlavi', + 'Noto Sans Inscriptional Parthian', + 'Noto Sans JP', + 'Noto Sans Javanese', + 'Noto Sans KR', + 'Noto Sans Kaithi', + 'Noto Sans Kannada', + 'Noto Sans Kayah Li', + 'Noto Sans Kharoshthi', + 'Noto Sans Khmer', + 'Noto Sans Khojki', + 'Noto Sans Khudawadi', + 'Noto Sans Lao', + 'Noto Sans Lepcha', + 'Noto Sans Limbu', + 'Noto Sans Linear A', + 'Noto Sans Linear B', + 'Noto Sans Lisu', + 'Noto Sans Lycian', + 'Noto Sans Lydian', + 'Noto Sans Mahajani', + 'Noto Sans Malayalam', + 'Noto Sans Mandaic', + 'Noto Sans Manichaean', + 'Noto Sans Marchen', + 'Noto Sans Masaram Gondi', + 'Noto Sans Math', + 'Noto Sans Mayan Numerals', + 'Noto Sans Medefaidrin', + 'Noto Sans Meetei Mayek', + 'Noto Sans Meroitic', + 'Noto Sans Miao', + 'Noto Sans Modi', + 'Noto Sans Mongolian', + 'Noto Sans Mro', + 'Noto Sans Multani', + 'Noto Sans Myanmar', + 'Noto Sans N Ko', + 'Noto Sans Nabataean', + 'Noto Sans New Tai Lue', + 'Noto Sans Newa', + 'Noto Sans Nushu', + 'Noto Sans Ogham', + 'Noto Sans Ol Chiki', + 'Noto Sans Old Hungarian', + 'Noto Sans Old Italic', + 'Noto Sans Old North Arabian', + 'Noto Sans Old Permic', + 'Noto Sans Old Persian', + 'Noto Sans Old Sogdian', + 'Noto Sans Old South Arabian', + 'Noto Sans Old Turkic', + 'Noto Sans Oriya', + 'Noto Sans Osage', + 'Noto Sans Osmanya', + 'Noto Sans Pahawh Hmong', + 'Noto Sans Palmyrene', + 'Noto Sans Pau Cin Hau', + 'Noto Sans Phags Pa', + 'Noto Sans Phoenician', + 'Noto Sans Psalter Pahlavi', + 'Noto Sans Rejang', + 'Noto Sans Runic', + 'Noto Sans SC', + 'Noto Sans Saurashtra', + 'Noto Sans Sharada', + 'Noto Sans Shavian', + 'Noto Sans Siddham', + 'Noto Sans Sinhala', + 'Noto Sans Sogdian', + 'Noto Sans Sora Sompeng', + 'Noto Sans Soyombo', + 'Noto Sans Sundanese', + 'Noto Sans Syloti Nagri', + 'Noto Sans Syriac', + 'Noto Sans TC', + 'Noto Sans Tagalog', + 'Noto Sans Tagbanwa', + 'Noto Sans Tai Le', + 'Noto Sans Tai Tham', + 'Noto Sans Tai Viet', + 'Noto Sans Takri', + 'Noto Sans Tamil', + 'Noto Sans Tamil Supplement', + 'Noto Sans Telugu', + 'Noto Sans Thaana', + 'Noto Sans Thai', + 'Noto Sans Tifinagh', + 'Noto Sans Tirhuta', + 'Noto Sans Ugaritic', + 'Noto Sans Vai', + 'Noto Sans Wancho', + 'Noto Sans Warang Citi', + 'Noto Sans Yi', + 'Noto Sans Zanabazar Square', +]; diff --git a/lib/web_ui/lib/initialization.dart b/lib/web_ui/lib/initialization.dart index 8ee067b5ef8cf..e19f24103cdf4 100644 --- a/lib/web_ui/lib/initialization.dart +++ b/lib/web_ui/lib/initialization.dart @@ -112,6 +112,7 @@ set debugEmulateFlutterTesterEnvironment(bool value) { engine.window.webOnlyDebugPhysicalSizeOverride = logicalSize * window.devicePixelRatio; } + engine.debugDisableFontFallbacks = value; } bool _debugEmulateFlutterTesterEnvironment = false; diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 32b4fd13e479f..bbf9a5aacc5a4 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -26,6 +26,7 @@ export 'engine/canvaskit/canvaskit_canvas.dart'; export 'engine/canvaskit/color_filter.dart'; export 'engine/canvaskit/embedded_views.dart'; export 'engine/canvaskit/embedded_views_diff.dart'; +export 'engine/canvaskit/font_fallback_data.dart'; export 'engine/canvaskit/font_fallbacks.dart'; export 'engine/canvaskit/fonts.dart'; export 'engine/canvaskit/image.dart'; @@ -38,6 +39,7 @@ export 'engine/canvaskit/layer_scene_builder.dart'; export 'engine/canvaskit/layer_tree.dart'; export 'engine/canvaskit/mask_filter.dart'; export 'engine/canvaskit/n_way_canvas.dart'; +export 'engine/canvaskit/noto_font.dart'; export 'engine/canvaskit/painting.dart'; export 'engine/canvaskit/path.dart'; export 'engine/canvaskit/path_metrics.dart'; diff --git a/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart b/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart new file mode 100644 index 0000000000000..41c64cf61c7c6 --- /dev/null +++ b/lib/web_ui/lib/src/engine/canvaskit/font_fallback_data.dart @@ -0,0 +1,151 @@ +// 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. + +// DO NOT EDIT! This file is generated. See: +// dev/generate_fallback_font_data.dart +import 'noto_font.dart'; + +final List fallbackFonts = [ + NotoFont.fromFlatRanges('Noto Sans', 'http://fonts.gstatic.com/s/notosans/v27/o-0IIpQlx3QUlC5A4PNb4j5Ba_2c7A.ttf', [0x20,0x7e,0xa0,0x377,0x37a,0x37f,0x384,0x38a,0x38c,0x38c,0x38e,0x3a1,0x3a3,0x3e1,0x3f0,0x52f,0x900,0x97f,0x1ab0,0x1ac0,0x1c80,0x1c88,0x1cd0,0x1cf6,0x1cf8,0x1cf9,0x1d00,0x1df9,0x1dfb,0x1f15,0x1f18,0x1f1d,0x1f20,0x1f45,0x1f48,0x1f4d,0x1f50,0x1f57,0x1f59,0x1f59,0x1f5b,0x1f5b,0x1f5d,0x1f5d,0x1f5f,0x1f7d,0x1f80,0x1fb4,0x1fb6,0x1fc4,0x1fc6,0x1fd3,0x1fd6,0x1fdb,0x1fdd,0x1fef,0x1ff2,0x1ff4,0x1ff6,0x1ffe,0x2000,0x2064,0x2066,0x2071,0x2074,0x208e,0x2090,0x209c,0x20a0,0x20bf,0x20f0,0x20f0,0x2100,0x215f,0x2184,0x2184,0x2189,0x2189,0x2212,0x2212,0x2215,0x2215,0x25cc,0x25cc,0x2c60,0x2c7f,0x2de0,0x2e52,0xa640,0xa69f,0xa700,0xa7bf,0xa7c2,0xa7ca,0xa7f5,0xa7ff,0xa830,0xa839,0xa8e0,0xa8ff,0xa92e,0xa92e,0xab30,0xab6b,0xfb00,0xfb06,0xfe00,0xfe00,0xfe20,0xfe2f,0xfeff,0xfeff,0xfffc,0xfffd,]), + NotoFont.fromFlatRanges('Noto Emoji', 'http://fonts.gstatic.com/s/notoemoji/v26/bMrnmSyK7YY-MEu6aWjPDs-ar6uWaGWuob-r0jwvS-FGJCMY.ttf', [0x20,0x20,0x23,0x23,0x2a,0x2a,0x30,0x39,0xa9,0xa9,0xae,0xae,0x200d,0x200d,0x203c,0x203c,0x2049,0x2049,0x20e3,0x20e3,0x2122,0x2122,0x2139,0x2139,0x2194,0x2199,0x21a9,0x21aa,0x231a,0x231b,0x2328,0x2328,0x23cf,0x23cf,0x23e9,0x23f3,0x23f8,0x23fa,0x24c2,0x24c2,0x25aa,0x25ab,0x25b6,0x25b6,0x25c0,0x25c0,0x25fb,0x25fe,0x2600,0x2604,0x260e,0x260e,0x2611,0x2611,0x2614,0x2615,0x2618,0x2618,0x261d,0x261d,0x2620,0x2620,0x2622,0x2623,0x2626,0x2626,0x262a,0x262a,0x262e,0x262f,0x2638,0x263a,0x2640,0x2640,0x2642,0x2642,0x2648,0x2653,0x265f,0x2660,0x2663,0x2663,0x2665,0x2666,0x2668,0x2668,0x267b,0x267b,0x267e,0x267f,0x2692,0x2697,0x2699,0x2699,0x269b,0x269c,0x26a0,0x26a1,0x26a7,0x26a7,0x26aa,0x26ab,0x26b0,0x26b1,0x26bd,0x26be,0x26c4,0x26c5,0x26c8,0x26c8,0x26ce,0x26cf,0x26d1,0x26d1,0x26d3,0x26d4,0x26e9,0x26ea,0x26f0,0x26f5,0x26f7,0x26fa,0x26fd,0x26fd,0x2702,0x2702,0x2705,0x2705,0x2708,0x270d,0x270f,0x270f,0x2712,0x2712,0x2714,0x2714,0x2716,0x2716,0x271d,0x271d,0x2721,0x2721,0x2728,0x2728,0x2733,0x2734,0x2744,0x2744,0x2747,0x2747,0x274c,0x274c,0x274e,0x274e,0x2753,0x2755,0x2757,0x2757,0x2763,0x2764,0x2795,0x2797,0x27a1,0x27a1,0x27b0,0x27b0,0x27bf,0x27bf,0x2934,0x2935,0x2b05,0x2b07,0x2b1b,0x2b1c,0x2b50,0x2b50,0x2b55,0x2b55,0x3030,0x3030,0x303d,0x303d,0x3297,0x3297,0x3299,0x3299,0xfe0e,0xfe0f,0x1f004,0x1f004,0x1f0cf,0x1f0cf,0x1f170,0x1f171,0x1f17e,0x1f17f,0x1f18e,0x1f18e,0x1f191,0x1f19a,0x1f1e6,0x1f1ff,0x1f201,0x1f202,0x1f21a,0x1f21a,0x1f22f,0x1f22f,0x1f232,0x1f23a,0x1f250,0x1f251,0x1f300,0x1f321,0x1f324,0x1f393,0x1f396,0x1f397,0x1f399,0x1f39b,0x1f39e,0x1f3f0,0x1f3f3,0x1f3f5,0x1f3f7,0x1f4fd,0x1f4ff,0x1f53d,0x1f549,0x1f54e,0x1f550,0x1f567,0x1f56f,0x1f570,0x1f573,0x1f57a,0x1f587,0x1f587,0x1f58a,0x1f58d,0x1f590,0x1f590,0x1f595,0x1f596,0x1f5a4,0x1f5a5,0x1f5a8,0x1f5a8,0x1f5b1,0x1f5b2,0x1f5bc,0x1f5bc,0x1f5c2,0x1f5c4,0x1f5d1,0x1f5d3,0x1f5dc,0x1f5de,0x1f5e1,0x1f5e1,0x1f5e3,0x1f5e3,0x1f5e8,0x1f5e8,0x1f5ef,0x1f5ef,0x1f5f3,0x1f5f3,0x1f5fa,0x1f64f,0x1f680,0x1f6c5,0x1f6cb,0x1f6d2,0x1f6d5,0x1f6d7,0x1f6dd,0x1f6e5,0x1f6e9,0x1f6e9,0x1f6eb,0x1f6ec,0x1f6f0,0x1f6f0,0x1f6f3,0x1f6fc,0x1f7e0,0x1f7eb,0x1f7f0,0x1f7f0,0x1f90c,0x1f93a,0x1f93c,0x1f945,0x1f947,0x1f9ff,0x1fa70,0x1fa74,0x1fa78,0x1fa7c,0x1fa80,0x1fa86,0x1fa90,0x1faac,0x1fab0,0x1faba,0x1fac0,0x1fac5,0x1fad0,0x1fad9,0x1fae0,0x1fae7,0x1faf0,0x1faf6,0xe0030,0xe0039,0xe0061,0xe007a,0xe007f,0xe007f,0xfe4e5,0xfe4ee,0xfe82c,0xfe82c,0xfe82e,0xfe837,]), + NotoFont.fromFlatRanges('Noto Sans Symbols', 'http://fonts.gstatic.com/s/notosanssymbols/v34/rP2up3q65FkAtHfwd-eIS2brbDN6gxP34F9jRRCe4W3gfQ8gavVFRkzrbQ.ttf', [0x20,0x20,0x30,0x39,0x41,0x5a,0x61,0x7a,0xa0,0xa0,0x20dd,0x20e0,0x20e2,0x20e4,0x2160,0x2183,0x2185,0x2188,0x218a,0x218b,0x2190,0x2199,0x2300,0x230f,0x2311,0x2315,0x2317,0x2317,0x231c,0x231f,0x2322,0x2323,0x2329,0x232a,0x232c,0x2335,0x237c,0x237c,0x2380,0x2394,0x2396,0x239a,0x23af,0x23af,0x23be,0x23cd,0x23d0,0x23db,0x23e2,0x23e8,0x2460,0x24ff,0x25cc,0x25cc,0x260a,0x260d,0x2613,0x2613,0x2624,0x262f,0x2638,0x263b,0x263d,0x2653,0x2669,0x267e,0x2690,0x269d,0x26a2,0x26a9,0x26ad,0x26bc,0x26ce,0x26ce,0x26e2,0x26ff,0x271d,0x2721,0x2776,0x2793,0x2921,0x2922,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f190,0x1f19b,0x1f1ac,0x1f546,0x1f549,0x1f54f,0x1f54f,0x1f610,0x1f610,0x1f700,0x1f773,]), + NotoFont.fromFlatRanges('Noto Sans Symbols 2', 'http://fonts.gstatic.com/s/notosanssymbols2/v15/I_uyMoGduATTei9eI8daxVHDyfisHr71ypPqfX71-AI.ttf', [0x20,0x20,0x23,0x23,0x2a,0x2a,0x30,0x39,0x7f,0xa0,0x2022,0x2022,0x20e2,0x20e3,0x21af,0x21af,0x21e6,0x21f0,0x21f3,0x21f3,0x2218,0x2219,0x2299,0x2299,0x22c4,0x22c6,0x2316,0x2316,0x2318,0x2318,0x231a,0x231b,0x2324,0x2328,0x232b,0x232b,0x237b,0x237b,0x237d,0x237f,0x2394,0x2394,0x23ce,0x23cf,0x23e9,0x23ea,0x23ed,0x23ef,0x23f1,0x2426,0x2440,0x244a,0x25a0,0x2609,0x260e,0x2612,0x2614,0x2623,0x2630,0x2637,0x263c,0x263c,0x2654,0x2668,0x267f,0x268f,0x269e,0x26a1,0x26aa,0x26ac,0x26bd,0x26cd,0x26cf,0x26e1,0x2700,0x2704,0x2706,0x2709,0x270b,0x271c,0x2722,0x2727,0x2729,0x274b,0x274d,0x274d,0x274f,0x2753,0x2756,0x2775,0x2794,0x2794,0x2798,0x27af,0x27b1,0x27be,0x2800,0x28ff,0x2981,0x2981,0x29bf,0x29bf,0x29eb,0x29eb,0x2b00,0x2b0d,0x2b12,0x2b2f,0x2b4d,0x2b73,0x2b76,0x2b95,0x2b97,0x2bfd,0x2bff,0x2bff,0x4dc0,0x4dff,0xfff9,0xfffb,0x10140,0x1018e,0x10190,0x1019c,0x101a0,0x101a0,0x101d0,0x101fd,0x102e0,0x102fb,0x10e60,0x10e7e,0x1d2e0,0x1d2f3,0x1d300,0x1d356,0x1d360,0x1d378,0x1f000,0x1f02b,0x1f030,0x1f093,0x1f0a0,0x1f0ae,0x1f0b1,0x1f0bf,0x1f0c1,0x1f0cf,0x1f0d1,0x1f0f5,0x1f30d,0x1f30f,0x1f315,0x1f315,0x1f31c,0x1f31c,0x1f321,0x1f32c,0x1f336,0x1f336,0x1f378,0x1f378,0x1f37d,0x1f37d,0x1f393,0x1f39f,0x1f3a7,0x1f3a7,0x1f3ac,0x1f3ae,0x1f3c2,0x1f3c2,0x1f3c4,0x1f3c4,0x1f3c6,0x1f3c6,0x1f3ca,0x1f3ce,0x1f3d4,0x1f3e0,0x1f3ed,0x1f3ed,0x1f3f1,0x1f3f3,0x1f3f5,0x1f3f7,0x1f408,0x1f408,0x1f415,0x1f415,0x1f41f,0x1f41f,0x1f426,0x1f426,0x1f43f,0x1f43f,0x1f441,0x1f442,0x1f446,0x1f449,0x1f44c,0x1f44e,0x1f453,0x1f453,0x1f46a,0x1f46a,0x1f47d,0x1f47d,0x1f4a3,0x1f4a3,0x1f4b0,0x1f4b0,0x1f4b3,0x1f4b3,0x1f4b9,0x1f4b9,0x1f4bb,0x1f4bb,0x1f4bf,0x1f4bf,0x1f4c8,0x1f4cb,0x1f4da,0x1f4da,0x1f4df,0x1f4df,0x1f4e4,0x1f4e6,0x1f4ea,0x1f4ed,0x1f4f7,0x1f4f7,0x1f4f9,0x1f4fb,0x1f4fd,0x1f4fe,0x1f503,0x1f503,0x1f507,0x1f50a,0x1f50d,0x1f50d,0x1f512,0x1f513,0x1f53e,0x1f545,0x1f54a,0x1f54a,0x1f550,0x1f579,0x1f57b,0x1f594,0x1f597,0x1f5a3,0x1f5a5,0x1f5fa,0x1f650,0x1f67f,0x1f687,0x1f687,0x1f68d,0x1f68d,0x1f691,0x1f691,0x1f694,0x1f694,0x1f698,0x1f698,0x1f6ad,0x1f6ad,0x1f6b2,0x1f6b2,0x1f6b9,0x1f6ba,0x1f6bc,0x1f6bc,0x1f6c6,0x1f6cb,0x1f6cd,0x1f6cf,0x1f6d3,0x1f6d7,0x1f6e0,0x1f6ea,0x1f6f0,0x1f6f3,0x1f6f7,0x1f6fc,0x1f780,0x1f7d8,0x1f7e0,0x1f7eb,0x1f800,0x1f80b,0x1f810,0x1f847,0x1f850,0x1f859,0x1f860,0x1f887,0x1f890,0x1f8ad,0x1f8b0,0x1f8b1,0x1f93b,0x1f93b,0x1f946,0x1f946,0x1fa00,0x1fa53,0x1fa60,0x1fa6d,0x1fa70,0x1fa74,0x1fa78,0x1fa7a,0x1fa80,0x1fa86,0x1fa90,0x1faa8,0x1fab0,0x1fab6,0x1fac0,0x1fac2,0x1fad0,0x1fad6,0x1fb00,0x1fb92,0x1fb94,0x1fbca,0x1fbf0,0x1fbf9,]), + NotoFont.fromFlatRanges('Noto Sans Adlam', 'http://fonts.gstatic.com/s/notosansadlam/v19/neIczCCpqp0s5pPusPamd81eMfjPonvqdbYxxpgufnv0TGnBZLwhuvk.ttf', [0x20,0x2f,0x3a,0x40,0x5b,0x5f,0x7b,0x7d,0xa0,0xa0,0xab,0xab,0xbb,0xbb,0x61f,0x61f,0x640,0x640,0x2013,0x2015,0x2018,0x201e,0x2020,0x2022,0x2026,0x2026,0x2030,0x2030,0x2039,0x203a,0x2044,0x2044,0x204f,0x204f,0x25cc,0x25cc,0x2e28,0x2e29,0x2e41,0x2e41,0x1e900,0x1e94b,0x1e950,0x1e959,0x1e95e,0x1e95f,]), + NotoFont.fromFlatRanges('Noto Sans Anatolian Hieroglyphs', 'http://fonts.gstatic.com/s/notosansanatolianhieroglyphs/v14/ijw9s4roRME5LLRxjsRb8A0gKPSWq4BbDmHHu6j2pEtUJzZWXybIymc5QYo.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200b,0x14400,0x14646,]), + NotoFont.fromFlatRanges('Noto Sans Arabic', 'http://fonts.gstatic.com/s/notosansarabic/v18/nwpxtLGrOAZMl5nJ_wfgRg3DrWFZWsnVBJ_sS6tlqHHFlhQ5l3sQWIHPqzCfyGyvu3CBFQLaig.ttf', [0x20,0x21,0x2c,0x2e,0x30,0x3a,0xa0,0xa0,0xab,0xab,0xbb,0xbb,0x34f,0x34f,0x600,0x61c,0x61e,0x6ff,0x750,0x77f,0x8a0,0x8b4,0x8b6,0x8be,0x8d3,0x8ff,0x200b,0x2011,0x204f,0x204f,0x25cc,0x25cc,0x2e41,0x2e41,0xfb50,0xfbc1,0xfbd3,0xfd3f,0xfd50,0xfd8f,0xfd92,0xfdc7,0xfdf0,0xfdfd,0xfe70,0xfe74,0xfe76,0xfefc,]), + NotoFont.fromFlatRanges('Noto Sans Armenian', 'http://fonts.gstatic.com/s/notosansarmenian/v32/ZgN0jOZKPa7CHqq0h37c7ReDUubm2SEdFXp7ig73qtTY5idb74R9UdM3y2nZLorxb60iYy6zF3Eg.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x308,0x308,0x531,0x556,0x559,0x58a,0x58d,0x58f,0x2010,0x2010,0x25cc,0x25cc,0xfb13,0xfb17,]), + NotoFont.fromFlatRanges('Noto Sans Avestan', 'http://fonts.gstatic.com/s/notosansavestan/v17/bWti7ejKfBziStx7lIzKOLQZKhIJkyu9SASLji8U.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200c,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x2e30,0x2e31,0x10b00,0x10b35,0x10b39,0x10b3f,]), + NotoFont.fromFlatRanges('Noto Sans Balinese', 'http://fonts.gstatic.com/s/notosansbalinese/v18/NaPwcYvSBuhTirw6IaFn6UrRDaqje-lpbbRtYf-Fwu2Ov7fdhE5Vd222PPY.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1b00,0x1b4b,0x1b50,0x1b7c,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Bamum', 'http://fonts.gstatic.com/s/notosansbamum/v18/uk-0EGK3o6EruUbnwovcbBTkkklK_Ya_PBHfNGTPEddO-_gLykxEkxA.ttf', [0x20,0x20,0xa0,0xa0,0xa6a0,0xa6f7,0x16800,0x16a38,]), + NotoFont.fromFlatRanges('Noto Sans Bassa Vah', 'http://fonts.gstatic.com/s/notosansbassavah/v15/PN_sRee-r3f7LnqsD5sax12gjZn7mBpL_4c2VNUQptE.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x16ad0,0x16aed,0x16af0,0x16af5,]), + NotoFont.fromFlatRanges('Noto Sans Batak', 'http://fonts.gstatic.com/s/notosansbatak/v15/gok2H6TwAEdtF9N8-mdTCQvT-Zdgo4_PHuk74A.ttf', [0x20,0x20,0xa0,0xa0,0x1bc0,0x1bf3,0x1bfc,0x1bff,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Bengali', 'http://fonts.gstatic.com/s/notosansbengali/v20/Cn-SJsCGWQxOjaGwMQ6fIiMywrNJIky6nvd8BjzVMvJx2mcSPVFpVEqE-6KmsolLudCk8izI0lc.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0x980,0x983,0x985,0x98c,0x98f,0x990,0x993,0x9a8,0x9aa,0x9b0,0x9b2,0x9b2,0x9b6,0x9b9,0x9bc,0x9c4,0x9c7,0x9c8,0x9cb,0x9ce,0x9d7,0x9d7,0x9dc,0x9dd,0x9df,0x9e3,0x9e6,0x9fe,0x1cd0,0x1cd0,0x1cd2,0x1cd2,0x1cd5,0x1cd6,0x1cd8,0x1cd8,0x1ce1,0x1ce1,0x1cea,0x1cea,0x1ced,0x1ced,0x1cf2,0x1cf2,0x1cf5,0x1cf7,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa8f1,0xa8f1,]), + NotoFont.fromFlatRanges('Noto Sans Bhaiksuki', 'http://fonts.gstatic.com/s/notosansbhaiksuki/v15/UcC63EosKniBH4iELXATsSBWdvUHXxhj8rLUdU4wh9U.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200b,0x25cc,0x25cc,0x11c00,0x11c08,0x11c0a,0x11c36,0x11c38,0x11c45,0x11c50,0x11c6c,]), + NotoFont.fromFlatRanges('Noto Sans Brahmi', 'http://fonts.gstatic.com/s/notosansbrahmi/v15/vEFK2-VODB8RrNDvZSUmQQIIByV18tK1W77HtMo.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0x11000,0x1104d,0x11052,0x1106f,0x1107f,0x1107f,]), + NotoFont.fromFlatRanges('Noto Sans Buginese', 'http://fonts.gstatic.com/s/notosansbuginese/v15/esDM30ldNv-KYGGJpKGk18phe_7Da6_gtfuEXLmNtw.ttf', [0x20,0x20,0xa0,0xa0,0x1a00,0x1a1b,0x1a1e,0x1a1f,0x200b,0x200d,0x25cc,0x25cc,0xa9cf,0xa9cf,]), + NotoFont.fromFlatRanges('Noto Sans Buhid', 'http://fonts.gstatic.com/s/notosansbuhid/v17/Dxxy8jiXMW75w3OmoDXVWJD7YwzAe6tgnaFoGA.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1735,0x1736,0x1740,0x1753,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Canadian Aboriginal', 'http://fonts.gstatic.com/s/notosanscanadianaboriginal/v19/4C_TLjTuEqPj-8J01CwaGkiZ9os0iGVkezM1mUT-j_Lmlzda6uH_nnX1bzigWLn_yAsg0q0uhQ.ttf', [0x20,0x20,0xa0,0xa0,0x131,0x131,0x2c7,0x2c7,0x2d8,0x2db,0x307,0x307,0x1400,0x167f,0x18b0,0x18f5,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Carian', 'http://fonts.gstatic.com/s/notosanscarian/v15/LDIpaoiONgYwA9Yc6f0gUILeMIOgs7ob9yGLmfI.ttf', [0x20,0x20,0xa0,0xa0,0x102a0,0x102d0,]), + NotoFont.fromFlatRanges('Noto Sans Caucasian Albanian', 'http://fonts.gstatic.com/s/notosanscaucasianalbanian/v16/nKKA-HM_FYFRJvXzVXaANsU0VzsAc46QGOkWytlTs-TXrYDmoVmRSZo.ttf', [0x20,0x20,0xa0,0xa0,0x304,0x304,0x331,0x331,0x25cc,0x25cc,0xfe20,0xfe2f,0x10530,0x10563,0x1056f,0x1056f,]), + NotoFont.fromFlatRanges('Noto Sans Chakma', 'http://fonts.gstatic.com/s/notosanschakma/v15/Y4GQYbJ8VTEp4t3MKJSMjg5OIzhi4JjTQhYBeYo.ttf', [0x20,0x20,0xa0,0xa0,0x9e6,0x9ef,0x1040,0x1049,0x200c,0x200d,0x25cc,0x25cc,0x11100,0x11134,0x11136,0x11146,]), + NotoFont.fromFlatRanges('Noto Sans Cham', 'http://fonts.gstatic.com/s/notosanscham/v19/pe06MIySN5pO62Z5YkFyQb_bbuRhe6D4yip43qfcERwcv7GykboaLg.ttf', [0x20,0x22,0x27,0x29,0x2c,0x2f,0x3a,0x3b,0x3f,0x3f,0xa0,0xa0,0xad,0xad,0x200c,0x200d,0x2010,0x2010,0x25cc,0x25cc,0xaa00,0xaa36,0xaa40,0xaa4d,0xaa50,0xaa59,0xaa5c,0xaa5f,]), + NotoFont.fromFlatRanges('Noto Sans Cherokee', 'http://fonts.gstatic.com/s/notosanscherokee/v17/KFOPCm6Yu8uF-29fiz9vQF9YWK6Z8O10cHNA0cSkZCHYWi5PDkm5rAffjl0.ttf', [0x20,0x20,0xa0,0xa0,0x300,0x302,0x304,0x304,0x30b,0x30c,0x323,0x324,0x330,0x331,0x13a0,0x13f5,0x13f8,0x13fd,0xab70,0xabbf,]), + NotoFont.fromFlatRanges('Noto Sans Coptic', 'http://fonts.gstatic.com/s/notosanscoptic/v15/iJWfBWmUZi_OHPqn4wq6kgqumOEd78u_VG0xR4Y.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x300,0x302,0x304,0x305,0x307,0x308,0x323,0x323,0x33f,0x33f,0x361,0x361,0x374,0x375,0x3e2,0x3ef,0x1dcd,0x1dcd,0x2010,0x2010,0x25cc,0x25cc,0x2c80,0x2cf3,0x2cf9,0x2cff,0xfe24,0xfe26,0x102e0,0x102fb,]), + NotoFont.fromFlatRanges('Noto Sans Cuneiform', 'http://fonts.gstatic.com/s/notosanscuneiform/v15/bMrrmTWK7YY-MF22aHGGd7H8PhJtvBDWgb9JlRQueeQ.ttf', [0x20,0x20,0xa0,0xa0,0x12000,0x12399,0x12400,0x1246e,0x12470,0x12474,0x12480,0x12543,]), + NotoFont.fromFlatRanges('Noto Sans Cypriot', 'http://fonts.gstatic.com/s/notosanscypriot/v15/8AtzGta9PYqQDjyp79a6f8Cj-3a3cxIsK5MPpahF.ttf', [0x20,0x20,0xa0,0xa0,0x10800,0x10805,0x10808,0x10808,0x1080a,0x10835,0x10837,0x10838,0x1083c,0x1083c,0x1083f,0x1083f,]), + NotoFont.fromFlatRanges('Noto Sans Deseret', 'http://fonts.gstatic.com/s/notosansdeseret/v15/MwQsbgPp1eKH6QsAVuFb9AZM6MMr2Vq9ZnJSZtQG.ttf', [0x20,0x20,0xa0,0xa0,0x10400,0x1044f,]), + NotoFont.fromFlatRanges('Noto Sans Devanagari', 'http://fonts.gstatic.com/s/notosansdevanagari/v19/TuGoUUFzXI5FBtUq5a8bjKYTZjtRU6Sgv3NaV_SNmI0b8QQCQmHn6B2OHjbL_08AlXQly-AzoFoW4Ow.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x900,0x97f,0x1cd0,0x1cf6,0x1cf8,0x1cf9,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x20f0,0x20f0,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa839,0xa8e0,0xa8ff,]), + NotoFont.fromFlatRanges('Noto Sans Duployan', 'http://fonts.gstatic.com/s/notosansduployan/v16/gokzH7nwAEdtF9N8-mdTDx_X9JM5wsvrFsIn6WYDvA.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x1bc00,0x1bc6a,0x1bc70,0x1bc7c,0x1bc80,0x1bc88,0x1bc90,0x1bc99,0x1bc9c,0x1bca3,]), + NotoFont.fromFlatRanges('Noto Sans Egyptian Hieroglyphs', 'http://fonts.gstatic.com/s/notosansegyptianhieroglyphs/v26/vEF42-tODB8RrNDvZSUmRhcQHzx1s7y_F9-j3qSzEcbEYindSVK8xRg7iw.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x13000,0x1342e,]), + NotoFont.fromFlatRanges('Noto Sans Elbasan', 'http://fonts.gstatic.com/s/notosanselbasan/v15/-F6rfiZqLzI2JPCgQBnw400qp1trvHdlre4dFcFh.ttf', [0x20,0x20,0xa0,0xa0,0xb7,0xb7,0x305,0x305,0x391,0x3a1,0x3a3,0x3a9,0x3da,0x3da,0x3dc,0x3dc,0x3de,0x3de,0x25cc,0x25cc,0x10500,0x10527,]), + NotoFont.fromFlatRanges('Noto Sans Elymaic', 'http://fonts.gstatic.com/s/notosanselymaic/v15/UqyKK9YTJW5liNMhTMqe9vUFP65ZD4AjWOT0zi2V.ttf', [0x20,0x20,0xa0,0xa0,0x10fe0,0x10ff6,]), + NotoFont.fromFlatRanges('Noto Sans Georgian', 'http://fonts.gstatic.com/s/notosansgeorgian/v36/PlIaFke5O6RzLfvNNVSitxkr76PRHBC4Ytyq-Gof7PUs4S7zWn-8YDB09HFNdpvnzFj-f5WK0OQV.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x589,0x589,0x10a0,0x10c5,0x10c7,0x10c7,0x10cd,0x10cd,0x10d0,0x10ff,0x1c90,0x1cba,0x1cbd,0x1cbf,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20be,0x20be,0x2122,0x2122,0x2212,0x2212,0x2d00,0x2d25,0x2d27,0x2d27,0x2d2d,0x2d2d,]), + NotoFont.fromFlatRanges('Noto Sans Glagolitic', 'http://fonts.gstatic.com/s/notosansglagolitic/v15/1q2ZY4-BBFBst88SU_tOj4J-4yuNF_HI4ERK4Amu7nM1.ttf', [0x20,0x20,0xa0,0xa0,0x303,0x303,0x305,0x305,0x484,0x484,0x487,0x487,0x2c00,0x2c2e,0x2c30,0x2c5e,0xa66f,0xa66f,0x1e000,0x1e006,0x1e008,0x1e018,0x1e01b,0x1e021,0x1e023,0x1e024,0x1e026,0x1e02a,]), + NotoFont.fromFlatRanges('Noto Sans Gothic', 'http://fonts.gstatic.com/s/notosansgothic/v15/TuGKUUVzXI5FBtUq5a8bj6wRbzxTFMX40kFQRx0.ttf', [0x20,0x20,0xa0,0xa0,0x304,0x305,0x308,0x308,0x331,0x331,0x10330,0x1034a,]), + NotoFont.fromFlatRanges('Noto Sans Grantha', 'http://fonts.gstatic.com/s/notosansgrantha/v15/3y976akwcCjmsU8NDyrKo3IQfQ4o-r8cFeulHc6N.ttf', [0x20,0x20,0xa0,0xa0,0x951,0x952,0x964,0x965,0xbaa,0xbaa,0xbb5,0xbb5,0xbe6,0xbf2,0x1cd0,0x1cd0,0x1cd2,0x1cd3,0x1cf2,0x1cf4,0x1cf8,0x1cf9,0x200c,0x200d,0x20f0,0x20f0,0x25cc,0x25cc,0x11300,0x11303,0x11305,0x1130c,0x1130f,0x11310,0x11313,0x11328,0x1132a,0x11330,0x11332,0x11333,0x11335,0x11339,0x1133b,0x11344,0x11347,0x11348,0x1134b,0x1134d,0x11350,0x11350,0x11357,0x11357,0x1135d,0x11363,0x11366,0x1136c,0x11370,0x11374,]), + NotoFont.fromFlatRanges('Noto Sans Gujarati', 'http://fonts.gstatic.com/s/notosansgujarati/v19/wlpWgx_HC1ti5ViekvcxnhMlCVo3f5pv17ivlzsUB14gg1TMR2Gw4VceEl7MA_ypFwPM_OdiEH0s.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xa81,0xa83,0xa85,0xa8d,0xa8f,0xa91,0xa93,0xaa8,0xaaa,0xab0,0xab2,0xab3,0xab5,0xab9,0xabc,0xac5,0xac7,0xac9,0xacb,0xacd,0xad0,0xad0,0xae0,0xae3,0xae6,0xaf1,0xaf9,0xaff,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa839,]), + NotoFont.fromFlatRanges('Noto Sans Gunjala Gondi', 'http://fonts.gstatic.com/s/notosansgunjalagondi/v15/bWto7e7KfBziStx7lIzKPrcSMwcEnCv6DW7n5hcVXYMTK4q1.ttf', [0x20,0x21,0x25,0x25,0x27,0x2f,0x3a,0x3a,0x3c,0x3f,0xa0,0xa0,0xd7,0xd7,0xf7,0xf7,0x200c,0x200d,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x2212,0x2212,0x25cc,0x25cc,0x11d60,0x11d65,0x11d67,0x11d68,0x11d6a,0x11d8e,0x11d90,0x11d91,0x11d93,0x11d98,0x11da0,0x11da9,]), + NotoFont.fromFlatRanges('Noto Sans Gurmukhi', 'http://fonts.gstatic.com/s/notosansgurmukhi/v18/w8g9H3EvQP81sInb43inmyN9zZ7hb7ATbSWo4q8dJ74a3cVrYFQ_bogT0-gPeG1OenbxZ_trdp7h.ttf', [0x20,0x23,0x25,0x25,0x27,0x3f,0x5b,0x5f,0x7b,0x7e,0xa0,0xa0,0xad,0xad,0xd7,0xd7,0xf7,0xf7,0x951,0x952,0x964,0x965,0xa01,0xa03,0xa05,0xa0a,0xa0f,0xa10,0xa13,0xa28,0xa2a,0xa30,0xa32,0xa33,0xa35,0xa36,0xa38,0xa39,0xa3c,0xa3c,0xa3e,0xa42,0xa47,0xa48,0xa4b,0xa4d,0xa51,0xa51,0xa59,0xa5c,0xa5e,0xa5e,0xa66,0xa76,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x20b9,0x20b9,0x2212,0x2212,0x25cc,0x25cc,0x262c,0x262c,0xa830,0xa839,]), + NotoFont.fromFlatRanges('Noto Sans HK', 'http://fonts.gstatic.com/s/notosanshk/v21/nKKQ-GM_FYFRJvXzVXaAPe9hMnB3Eu7mOQ.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x3435,0x3435,0x3440,0x3440,0x344a,0x344a,0x344c,0x344c,0x3464,0x3464,0x3473,0x3473,0x347a,0x347a,0x347d,0x347e,0x3493,0x3493,0x3496,0x3496,0x34a5,0x34a5,0x34af,0x34af,0x34bc,0x34bc,0x34c1,0x34c1,0x34c8,0x34c8,0x34df,0x34df,0x34e4,0x34e4,0x34e6,0x34e6,0x34fb,0x34fb,0x3506,0x3506,0x353e,0x353e,0x3551,0x3551,0x3553,0x3553,0x3559,0x3559,0x3561,0x3561,0x356d,0x356d,0x3570,0x3570,0x3572,0x3572,0x3577,0x3578,0x3584,0x3584,0x3597,0x3598,0x35a1,0x35a1,0x35a5,0x35a5,0x35ad,0x35ad,0x35bf,0x35bf,0x35c1,0x35c1,0x35c5,0x35c5,0x35c7,0x35c7,0x35ca,0x35ca,0x35ce,0x35ce,0x35d2,0x35d2,0x35d6,0x35d6,0x35db,0x35db,0x35dd,0x35dd,0x35f1,0x35f3,0x35fb,0x35fb,0x35fe,0x35fe,0x3609,0x3609,0x3618,0x3618,0x361a,0x361a,0x3623,0x3623,0x3625,0x3625,0x362d,0x362d,0x3635,0x3635,0x3639,0x3639,0x363e,0x363e,0x3647,0x3649,0x364e,0x364e,0x365f,0x365f,0x3661,0x3661,0x367a,0x367a,0x3681,0x3681,0x369a,0x369a,0x36a5,0x36a5,0x36aa,0x36aa,0x36ac,0x36ac,0x36b0,0x36b1,0x36b5,0x36b5,0x36b9,0x36b9,0x36bc,0x36bc,0x36c1,0x36c1,0x36c3,0x36c5,0x36c7,0x36c8,0x36d3,0x36d4,0x36d6,0x36d6,0x36dd,0x36dd,0x36e1,0x36e2,0x36e5,0x36e6,0x36f5,0x36f5,0x3701,0x3701,0x3703,0x3703,0x3708,0x3708,0x370a,0x370a,0x370d,0x370d,0x371c,0x371c,0x3722,0x3723,0x3725,0x3725,0x372c,0x372d,0x3730,0x3730,0x3732,0x3733,0x373a,0x373a,0x3740,0x3740,0x3743,0x3743,0x3762,0x3762,0x376f,0x376f,0x3797,0x3797,0x37a0,0x37a0,0x37b9,0x37b9,0x37be,0x37be,0x37d6,0x37d6,0x37f2,0x37f2,0x37f8,0x37f8,0x37fb,0x37fb,0x380f,0x380f,0x3819,0x3819,0x3820,0x3820,0x382d,0x382d,0x3836,0x3836,0x3838,0x3838,0x3863,0x3863,0x3875,0x3875,0x38a0,0x38a0,0x38c3,0x38c3,0x38cc,0x38cc,0x38d1,0x38d1,0x38d4,0x38d4,0x38fa,0x38fa,0x3908,0x3908,0x3914,0x3914,0x3927,0x3927,0x3932,0x3932,0x393f,0x393f,0x394d,0x394d,0x3963,0x3963,0x3978,0x3978,0x3980,0x3980,0x3989,0x398a,0x3992,0x3992,0x3999,0x3999,0x399b,0x399b,0x39a1,0x39a1,0x39a4,0x39a4,0x39b8,0x39b8,0x39dc,0x39dc,0x39e2,0x39e2,0x39e5,0x39e5,0x39ec,0x39ec,0x39f8,0x39f8,0x39fb,0x39fb,0x39fe,0x39fe,0x3a01,0x3a01,0x3a03,0x3a03,0x3a06,0x3a06,0x3a17,0x3a18,0x3a29,0x3a2a,0x3a34,0x3a34,0x3a4b,0x3a4b,0x3a52,0x3a52,0x3a57,0x3a57,0x3a5c,0x3a5c,0x3a5e,0x3a5e,0x3a66,0x3a67,0x3a97,0x3a97,0x3aab,0x3aab,0x3abd,0x3abd,0x3ade,0x3ade,0x3ae0,0x3ae0,0x3af0,0x3af0,0x3af2,0x3af2,0x3af5,0x3af5,0x3afb,0x3afb,0x3b0e,0x3b0e,0x3b19,0x3b19,0x3b22,0x3b22,0x3b2b,0x3b2b,0x3b39,0x3b39,0x3b42,0x3b42,0x3b58,0x3b58,0x3b60,0x3b60,0x3b71,0x3b72,0x3b7b,0x3b7c,0x3b80,0x3b80,0x3b95,0x3b96,0x3b99,0x3b99,0x3ba1,0x3ba1,0x3bbc,0x3bbc,0x3bbe,0x3bbe,0x3bc2,0x3bc2,0x3bc4,0x3bc4,0x3bd7,0x3bd7,0x3bdd,0x3bdd,0x3bec,0x3bec,0x3bf2,0x3bf4,0x3c0d,0x3c0d,0x3c11,0x3c11,0x3c15,0x3c15,0x3c18,0x3c18,0x3c54,0x3c54,0x3c8b,0x3c8b,0x3ccb,0x3ccb,0x3ccd,0x3ccd,0x3cd1,0x3cd1,0x3cd6,0x3cd6,0x3cdc,0x3cdc,0x3ceb,0x3ceb,0x3cef,0x3cef,0x3d12,0x3d13,0x3d1d,0x3d1d,0x3d32,0x3d32,0x3d3b,0x3d3b,0x3d46,0x3d46,0x3d4c,0x3d4c,0x3d4e,0x3d4e,0x3d51,0x3d51,0x3d5f,0x3d5f,0x3d62,0x3d62,0x3d69,0x3d6a,0x3d6f,0x3d6f,0x3d75,0x3d75,0x3d7d,0x3d7d,0x3d85,0x3d85,0x3d88,0x3d88,0x3d8a,0x3d8a,0x3d8f,0x3d8f,0x3d91,0x3d91,0x3da5,0x3da5,0x3dad,0x3dad,0x3db4,0x3db4,0x3dbf,0x3dbf,0x3dc6,0x3dc7,0x3dc9,0x3dc9,0x3dcc,0x3dcd,0x3dd3,0x3dd3,0x3ddb,0x3ddb,0x3de7,0x3de8,0x3deb,0x3deb,0x3df3,0x3df4,0x3df7,0x3df7,0x3dfc,0x3dfd,0x3e06,0x3e06,0x3e40,0x3e40,0x3e43,0x3e43,0x3e48,0x3e48,0x3e55,0x3e55,0x3e74,0x3e74,0x3ea8,0x3eaa,0x3ead,0x3ead,0x3eb1,0x3eb1,0x3eb8,0x3eb8,0x3ebf,0x3ebf,0x3ec2,0x3ec2,0x3ec7,0x3ec7,0x3eca,0x3eca,0x3ecc,0x3ecc,0x3ed0,0x3ed1,0x3ed6,0x3ed7,0x3eda,0x3edb,0x3ede,0x3ede,0x3ee1,0x3ee2,0x3ee7,0x3ee7,0x3ee9,0x3ee9,0x3eeb,0x3eec,0x3ef0,0x3ef0,0x3ef3,0x3ef4,0x3efa,0x3efa,0x3efc,0x3efc,0x3eff,0x3f00,0x3f04,0x3f04,0x3f06,0x3f07,0x3f0e,0x3f0e,0x3f53,0x3f53,0x3f58,0x3f59,0x3f63,0x3f63,0x3f7c,0x3f7c,0x3f93,0x3f93,0x3fc0,0x3fc0,0x3fc8,0x3fc8,0x3fd7,0x3fd7,0x3fdc,0x3fdc,0x3fe5,0x3fe5,0x3fed,0x3fed,0x3ff9,0x3ffa,0x4004,0x4004,0x4009,0x4009,0x401d,0x401d,0x4039,0x4039,0x4045,0x4045,0x4053,0x4053,0x4057,0x4057,0x4062,0x4062,0x4065,0x4065,0x406a,0x406a,0x406f,0x406f,0x4071,0x4071,0x40a8,0x40a8,0x40b4,0x40b4,0x40bb,0x40bb,0x40bf,0x40bf,0x40c8,0x40c8,0x40d8,0x40d8,0x40df,0x40df,0x40f8,0x40f8,0x40fa,0x40fa,0x4102,0x4104,0x4109,0x4109,0x410e,0x410e,0x4131,0x4132,0x4167,0x4167,0x416c,0x416c,0x416e,0x416e,0x417c,0x417c,0x417f,0x417f,0x4181,0x4181,0x4190,0x4190,0x41b2,0x41b2,0x41c4,0x41c4,0x41ca,0x41ca,0x41cf,0x41cf,0x41db,0x41db,0x41ed,0x41ed,0x41ef,0x41ef,0x41f9,0x41f9,0x4211,0x4211,0x4223,0x4223,0x4240,0x4240,0x4260,0x4260,0x426a,0x426a,0x4276,0x4276,0x427a,0x427a,0x428c,0x428c,0x4294,0x4294,0x42a2,0x42a2,0x42b5,0x42b5,0x42b9,0x42b9,0x42bc,0x42bc,0x42f4,0x42f4,0x42fb,0x42fc,0x430a,0x430a,0x432b,0x432b,0x436e,0x436e,0x4397,0x4397,0x439a,0x439a,0x43ba,0x43ba,0x43c1,0x43c1,0x43d9,0x43d9,0x43df,0x43df,0x43ed,0x43ed,0x43f0,0x43f0,0x43f2,0x43f2,0x4401,0x4402,0x4413,0x4413,0x4425,0x4425,0x442d,0x442d,0x447a,0x447a,0x448f,0x448f,0x4491,0x4491,0x449f,0x44a0,0x44a2,0x44a2,0x44b0,0x44b0,0x44b7,0x44b7,0x44bd,0x44bd,0x44c0,0x44c0,0x44c3,0x44c3,0x44c5,0x44c5,0x44ce,0x44ce,0x44dd,0x44df,0x44e1,0x44e1,0x44e4,0x44e4,0x44e9,0x44ec,0x44f4,0x44f4,0x4503,0x4504,0x4509,0x4509,0x450b,0x450b,0x4516,0x4516,0x451b,0x451b,0x451d,0x451d,0x4527,0x4527,0x452e,0x452e,0x4533,0x4533,0x4536,0x4536,0x453b,0x453b,0x453d,0x453d,0x453f,0x453f,0x4543,0x4543,0x4551,0x4552,0x4555,0x4555,0x4558,0x4558,0x455c,0x455c,0x4561,0x4562,0x456a,0x456a,0x456d,0x456d,0x4577,0x4578,0x4585,0x4585,0x45a6,0x45a6,0x45b3,0x45b3,0x45da,0x45da,0x45e9,0x45ea,0x4603,0x4603,0x4606,0x4606,0x460f,0x460f,0x4615,0x4615,0x4617,0x4617,0x465b,0x465b,0x467a,0x467a,0x4680,0x4680,0x46a1,0x46a1,0x46ae,0x46ae,0x46bb,0x46bb,0x46cf,0x46d0,0x46f5,0x46f5,0x46f7,0x46f7,0x4713,0x4713,0x4718,0x4718,0x4736,0x4736,0x4744,0x4744,0x474e,0x474f,0x477c,0x477c,0x4798,0x4798,0x47a6,0x47a6,0x47d5,0x47d5,0x47ed,0x47ed,0x47f4,0x47f4,0x4800,0x4800,0x480b,0x480b,0x4837,0x4837,0x485d,0x485d,0x4871,0x4871,0x489b,0x489b,0x48ad,0x48ae,0x48d0,0x48d0,0x48dd,0x48dd,0x48ed,0x48ed,0x48f3,0x48f3,0x48fa,0x48fa,0x4906,0x4906,0x4911,0x4911,0x491e,0x491e,0x4925,0x4925,0x492a,0x492a,0x492d,0x492d,0x492f,0x4930,0x4935,0x4935,0x493c,0x493c,0x493e,0x493e,0x4945,0x4945,0x4951,0x4951,0x4953,0x4953,0x4965,0x4965,0x496a,0x496a,0x4972,0x4972,0x4989,0x4989,0x49a1,0x49a1,0x49a7,0x49a7,0x49df,0x49df,0x49e5,0x49e5,0x49e7,0x49e7,0x4a0f,0x4a0f,0x4a1d,0x4a1d,0x4a24,0x4a24,0x4a35,0x4a35,0x4a96,0x4a96,0x4aa4,0x4aa4,0x4ab4,0x4ab4,0x4ab8,0x4ab8,0x4ad1,0x4ad1,0x4ae4,0x4ae4,0x4aff,0x4aff,0x4b10,0x4b10,0x4b19,0x4b19,0x4b20,0x4b20,0x4b2c,0x4b2c,0x4b37,0x4b37,0x4b6f,0x4b70,0x4b72,0x4b72,0x4b7b,0x4b7b,0x4b7e,0x4b7e,0x4b8e,0x4b8e,0x4b90,0x4b90,0x4b93,0x4b93,0x4b96,0x4b97,0x4b9d,0x4b9d,0x4bbd,0x4bbe,0x4bc0,0x4bc0,0x4c04,0x4c04,0x4c07,0x4c07,0x4c0e,0x4c0e,0x4c32,0x4c32,0x4c3b,0x4c3b,0x4c3e,0x4c3e,0x4c40,0x4c40,0x4c47,0x4c47,0x4c57,0x4c57,0x4c5b,0x4c5b,0x4c6d,0x4c6d,0x4c77,0x4c77,0x4c7b,0x4c7b,0x4c7d,0x4c7d,0x4c81,0x4c81,0x4c85,0x4c85,0x4ca4,0x4ca4,0x4cae,0x4cae,0x4cb0,0x4cb0,0x4cb7,0x4cb7,0x4ccd,0x4ccd,0x4ce1,0x4ce2,0x4ced,0x4ced,0x4d07,0x4d07,0x4d09,0x4d09,0x4d10,0x4d10,0x4d34,0x4d34,0x4d76,0x4d77,0x4d89,0x4d89,0x4d91,0x4d91,0x4d9c,0x4d9c,0x4e00,0x4e01,0x4e03,0x4e04,0x4e07,0x4e11,0x4e14,0x4e16,0x4e18,0x4e1a,0x4e1c,0x4e1c,0x4e1e,0x4e1f,0x4e21,0x4e22,0x4e24,0x4e24,0x4e26,0x4e26,0x4e28,0x4e28,0x4e2a,0x4e33,0x4e36,0x4e39,0x4e3b,0x4e3d,0x4e3f,0x4e3f,0x4e42,0x4e43,0x4e45,0x4e45,0x4e47,0x4e49,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e52,0x4e53,0x4e56,0x4e56,0x4e58,0x4e5f,0x4e69,0x4e6a,0x4e73,0x4e73,0x4e78,0x4e78,0x4e7e,0x4e89,0x4e8b,0x4e8e,0x4e91,0x4e95,0x4e98,0x4e9b,0x4e9e,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eae,0x4eb3,0x4eb3,0x4eb6,0x4eb7,0x4eb9,0x4ebc,0x4ebf,0x4ec4,0x4ec6,0x4ecb,0x4ecd,0x4ece,0x4ed4,0x4eda,0x4edc,0x4edf,0x4ee1,0x4ee1,0x4ee3,0x4ee5,0x4ee8,0x4eeb,0x4eee,0x4eee,0x4ef0,0x4ef8,0x4efb,0x4efb,0x4efd,0x4efd,0x4eff,0x4f05,0x4f08,0x4f0b,0x4f0d,0x4f15,0x4f17,0x4f1a,0x4f1d,0x4f1d,0x4f22,0x4f22,0x4f28,0x4f29,0x4f2c,0x4f2d,0x4f2f,0x4f30,0x4f32,0x4f34,0x4f36,0x4f3f,0x4f41,0x4f43,0x4f45,0x4f49,0x4f4b,0x4f64,0x4f67,0x4f67,0x4f69,0x4f6c,0x4f6e,0x4f70,0x4f72,0x4f8b,0x4f8d,0x4f8d,0x4f8f,0x4f92,0x4f94,0x4f98,0x4f9a,0x4f9e,0x4fa2,0x4fa2,0x4fa8,0x4fa8,0x4fab,0x4fab,0x4fae,0x4fb0,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbd,0x4fbd,0x4fbf,0x4fc5,0x4fc7,0x4fd1,0x4fd3,0x4fd4,0x4fd6,0x4fe1,0x4fe4,0x4fe5,0x4fec,0x4fec,0x4fee,0x4ffa,0x4ffd,0x4ffe,0x5000,0x5000,0x5003,0x5003,0x5005,0x5009,0x500b,0x500f,0x5011,0x501c,0x501e,0x5023,0x5025,0x5031,0x5033,0x5035,0x5037,0x5037,0x503b,0x503c,0x5040,0x5041,0x5043,0x5043,0x5045,0x504f,0x5051,0x5051,0x5053,0x5053,0x5055,0x5058,0x505a,0x5066,0x5068,0x5070,0x5072,0x5077,0x507a,0x507a,0x507d,0x507d,0x5080,0x5083,0x5085,0x5085,0x5087,0x5088,0x508b,0x508e,0x5090,0x5092,0x5094,0x5096,0x5098,0x509e,0x50a2,0x50a3,0x50a6,0x50a6,0x50ac,0x50b8,0x50ba,0x50bf,0x50c1,0x50c2,0x50c4,0x50cb,0x50cd,0x50d1,0x50d3,0x50d7,0x50d9,0x50db,0x50dd,0x50dd,0x50df,0x50e1,0x50e3,0x50ea,0x50ec,0x50f1,0x50f3,0x50f6,0x50f8,0x50f9,0x50fb,0x510e,0x5110,0x5115,0x5117,0x5118,0x511a,0x511a,0x511c,0x511c,0x511f,0x5122,0x5124,0x5126,0x5129,0x512b,0x512d,0x512e,0x5130,0x5135,0x5137,0x513d,0x513f,0x5141,0x5143,0x5149,0x514b,0x514d,0x5151,0x5152,0x5154,0x5157,0x5159,0x5163,0x5165,0x5165,0x5167,0x516e,0x5171,0x5171,0x5174,0x5179,0x517c,0x517c,0x5180,0x5180,0x5182,0x5182,0x5186,0x518a,0x518d,0x518d,0x518f,0x518f,0x5191,0x5198,0x519a,0x519a,0x519c,0x519c,0x519e,0x519e,0x51a0,0x51a0,0x51a2,0x51a2,0x51a4,0x51a5,0x51a7,0x51a8,0x51aa,0x51ac,0x51ae,0x51ae,0x51b0,0x51b9,0x51bc,0x51be,0x51c3,0x51d4,0x51d7,0x51d8,0x51db,0x51e2,0x51e4,0x51e4,0x51ed,0x51ed,0x51f0,0x51f1,0x51f3,0x51f6,0x51f8,0x51fa,0x51fc,0x51fe,0x5200,0x5203,0x5205,0x520c,0x520e,0x520e,0x5210,0x5213,0x5216,0x5217,0x521c,0x5221,0x5224,0x522a,0x522e,0x522e,0x5230,0x5238,0x523a,0x523c,0x5241,0x5241,0x5243,0x5244,0x5246,0x5247,0x5249,0x524f,0x5252,0x5252,0x5254,0x5257,0x5259,0x5262,0x5268,0x526f,0x5272,0x5275,0x5277,0x527d,0x527f,0x5284,0x5287,0x528d,0x528f,0x5291,0x5293,0x5294,0x5296,0x529b,0x529f,0x52a1,0x52a3,0x52a4,0x52a6,0x52a6,0x52a8,0x52ae,0x52b5,0x52b5,0x52b9,0x52b9,0x52bb,0x52bc,0x52be,0x52be,0x52c0,0x52c3,0x52c5,0x52c5,0x52c7,0x52c7,0x52c9,0x52c9,0x52cc,0x52cd,0x52d0,0x52d3,0x52d5,0x52d9,0x52db,0x52db,0x52dd,0x52e4,0x52e6,0x52e6,0x52e9,0x52e9,0x52eb,0x52eb,0x52ef,0x52f1,0x52f3,0x52f5,0x52f7,0x52fc,0x52fe,0x52ff,0x5301,0x5301,0x5305,0x5306,0x5308,0x530b,0x530d,0x5312,0x5315,0x5317,0x5319,0x531a,0x531c,0x531d,0x531f,0x5324,0x5327,0x5327,0x532a,0x532a,0x532c,0x532d,0x532f,0x5334,0x5337,0x5339,0x533b,0x5345,0x5347,0x534a,0x534c,0x534e,0x5351,0x5354,0x5357,0x5357,0x535a,0x535a,0x535c,0x5361,0x5363,0x5364,0x5366,0x5367,0x5369,0x5369,0x536c,0x5375,0x5377,0x5379,0x537b,0x537f,0x5382,0x5382,0x5384,0x5384,0x538a,0x538a,0x538e,0x538f,0x5392,0x5394,0x5396,0x539a,0x539c,0x53a0,0x53a2,0x53a2,0x53a4,0x53ae,0x53b0,0x53b0,0x53b2,0x53b2,0x53b4,0x53b4,0x53b6,0x53b6,0x53b9,0x53b9,0x53bb,0x53bb,0x53c1,0x53c3,0x53c5,0x53c5,0x53c8,0x53cd,0x53d0,0x53d2,0x53d4,0x53d4,0x53d6,0x53db,0x53df,0x53e6,0x53e8,0x53f3,0x53f5,0x53f8,0x53fb,0x53fc,0x53fe,0x53fe,0x5401,0x5401,0x5403,0x5404,0x5406,0x5414,0x5416,0x5416,0x5418,0x5421,0x5423,0x5439,0x543b,0x5443,0x5445,0x5448,0x544a,0x544f,0x5454,0x5454,0x5460,0x546d,0x546f,0x5478,0x547a,0x5482,0x5484,0x5488,0x548b,0x5498,0x549a,0x549a,0x549c,0x549c,0x549e,0x549e,0x54a0,0x54b4,0x54b6,0x54c9,0x54cb,0x54d0,0x54d6,0x54d6,0x54da,0x54da,0x54de,0x54de,0x54e0,0x54eb,0x54ed,0x54ef,0x54f1,0x54f3,0x54f7,0x54f8,0x54fa,0x54fd,0x54ff,0x54ff,0x5501,0x5514,0x5517,0x5518,0x551a,0x551a,0x551e,0x551e,0x5523,0x5523,0x5525,0x5528,0x552a,0x5539,0x553b,0x553c,0x553e,0x5541,0x5543,0x554b,0x554d,0x5553,0x5555,0x5557,0x555c,0x555f,0x5561,0x5566,0x5569,0x556b,0x5571,0x5573,0x5575,0x5577,0x5579,0x5579,0x557b,0x5584,0x5586,0x5595,0x5598,0x559a,0x559c,0x559d,0x559f,0x559f,0x55a1,0x55ae,0x55b0,0x55b5,0x55b9,0x55bc,0x55bf,0x55df,0x55e1,0x55ea,0x55ec,0x55ec,0x55ee,0x55f2,0x55f5,0x55f7,0x55f9,0x5602,0x5604,0x5606,0x5608,0x5609,0x560c,0x5617,0x561b,0x5623,0x5625,0x5625,0x5627,0x5627,0x5629,0x562a,0x562c,0x5630,0x5632,0x563b,0x563d,0x5643,0x5645,0x5646,0x5648,0x564a,0x564c,0x5650,0x5652,0x5654,0x5657,0x565a,0x565d,0x565e,0x5660,0x5666,0x5668,0x5674,0x5676,0x567c,0x567e,0x5687,0x5689,0x5690,0x5692,0x5693,0x5695,0x5695,0x5697,0x569a,0x569c,0x569f,0x56a1,0x56a1,0x56a4,0x56a8,0x56aa,0x56af,0x56b1,0x56b7,0x56b9,0x56b9,0x56bc,0x56c3,0x56c5,0x56c6,0x56c8,0x56cd,0x56d1,0x56d1,0x56d3,0x56d4,0x56d6,0x56d7,0x56da,0x56db,0x56dd,0x56e2,0x56e4,0x56e5,0x56e7,0x56e7,0x56ea,0x56eb,0x56ed,0x56f1,0x56f7,0x56f7,0x56f9,0x56fb,0x56fd,0x56fd,0x56ff,0x5704,0x5707,0x570d,0x5712,0x5716,0x5718,0x5718,0x571a,0x5720,0x5722,0x5723,0x5728,0x572a,0x572c,0x5730,0x5732,0x5734,0x573b,0x573b,0x573d,0x5743,0x5745,0x5747,0x5749,0x5752,0x5754,0x5754,0x5757,0x5757,0x575b,0x575b,0x575f,0x575f,0x5761,0x5762,0x5764,0x5764,0x5766,0x576b,0x576d,0x576d,0x576f,0x5777,0x577a,0x5780,0x5782,0x5783,0x5788,0x5788,0x578a,0x578d,0x578f,0x5790,0x5793,0x5795,0x5797,0x57a5,0x57a7,0x57a7,0x57aa,0x57aa,0x57ae,0x57ae,0x57b3,0x57b6,0x57b8,0x57bf,0x57c1,0x57c4,0x57c6,0x57c8,0x57cb,0x57cc,0x57ce,0x57d0,0x57d2,0x57d2,0x57d4,0x57d5,0x57d7,0x57d7,0x57dc,0x57e7,0x57e9,0x57e9,0x57ec,0x57fe,0x5800,0x580e,0x5810,0x5810,0x5812,0x5812,0x5814,0x5814,0x5818,0x5819,0x581b,0x581e,0x5820,0x582a,0x582c,0x583b,0x583d,0x583d,0x583f,0x5840,0x5844,0x5844,0x5847,0x584f,0x5851,0x5855,0x5857,0x585f,0x5862,0x5865,0x5868,0x5869,0x586b,0x586d,0x586f,0x586f,0x5871,0x5876,0x5879,0x5883,0x5885,0x588b,0x588e,0x5894,0x5896,0x5896,0x5898,0x589a,0x589c,0x58a1,0x58a3,0x58a3,0x58a5,0x58ac,0x58ae,0x58b1,0x58b3,0x58b3,0x58b5,0x58b6,0x58ba,0x58bf,0x58c1,0x58c2,0x58c5,0x58c9,0x58cb,0x58cb,0x58ce,0x58d6,0x58d8,0x58e0,0x58e2,0x58e4,0x58e7,0x58e9,0x58eb,0x58ec,0x58ef,0x58f0,0x58f2,0x58f4,0x58f9,0x58ff,0x5902,0x5907,0x590a,0x590a,0x590c,0x590f,0x5911,0x5912,0x5914,0x5917,0x5919,0x591a,0x591c,0x591d,0x591f,0x5920,0x5922,0x5922,0x5924,0x5925,0x5927,0x5927,0x5929,0x592f,0x5931,0x5932,0x5934,0x5934,0x5937,0x5938,0x593c,0x593c,0x593e,0x593e,0x5940,0x5940,0x5944,0x5945,0x5947,0x594a,0x594e,0x5951,0x5953,0x5955,0x5957,0x5958,0x595a,0x595a,0x595c,0x595c,0x5960,0x5962,0x5965,0x5965,0x5967,0x5967,0x5969,0x596e,0x5970,0x5979,0x597b,0x5985,0x5989,0x598a,0x598d,0x5990,0x5992,0x5994,0x5996,0x599a,0x599d,0x59a8,0x59ac,0x59ac,0x59ae,0x59c1,0x59c3,0x59d4,0x59d6,0x59d6,0x59d8,0x59de,0x59e0,0x59e1,0x59e3,0x59e6,0x59e8,0x5a03,0x5a09,0x5a0d,0x5a0f,0x5a0f,0x5a11,0x5a13,0x5a15,0x5a1c,0x5a1e,0x5a21,0x5a23,0x5a25,0x5a27,0x5a27,0x5a29,0x5a2e,0x5a33,0x5a33,0x5a35,0x5a39,0x5a3c,0x5a3e,0x5a40,0x5a4a,0x5a4c,0x5a4d,0x5a50,0x5a6e,0x5a70,0x5a71,0x5a77,0x5a7f,0x5a81,0x5a84,0x5a86,0x5a86,0x5a88,0x5a88,0x5a8a,0x5a8c,0x5a8e,0x5a97,0x5a99,0x5aa2,0x5aa4,0x5aa7,0x5aa9,0x5aac,0x5aae,0x5ac4,0x5ac6,0x5acf,0x5ad1,0x5ad1,0x5ad3,0x5ad3,0x5ad5,0x5ae6,0x5ae8,0x5aee,0x5af0,0x5af0,0x5af2,0x5afb,0x5afd,0x5aff,0x5b01,0x5b03,0x5b05,0x5b05,0x5b07,0x5b09,0x5b0b,0x5b0d,0x5b0f,0x5b11,0x5b13,0x5b17,0x5b19,0x5b1b,0x5b1d,0x5b21,0x5b23,0x5b28,0x5b2a,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b38,0x5b38,0x5b3c,0x5b41,0x5b43,0x5b48,0x5b4a,0x5b51,0x5b53,0x5b58,0x5b5a,0x5b5d,0x5b5f,0x5b5f,0x5b62,0x5b66,0x5b68,0x5b69,0x5b6b,0x5b6e,0x5b70,0x5b78,0x5b7a,0x5b7d,0x5b7f,0x5b85,0x5b87,0x5b89,0x5b8b,0x5b8c,0x5b8e,0x5b90,0x5b92,0x5b93,0x5b95,0x5b9f,0x5ba2,0x5ba8,0x5baa,0x5baa,0x5bac,0x5bae,0x5bb0,0x5bb0,0x5bb3,0x5bb9,0x5bbf,0x5bc7,0x5bca,0x5bce,0x5bd0,0x5bd9,0x5bdb,0x5bdb,0x5bde,0x5bec,0x5bee,0x5bf3,0x5bf5,0x5bf6,0x5bf8,0x5bf8,0x5bfa,0x5bfa,0x5bff,0x5bff,0x5c01,0x5c01,0x5c03,0x5c05,0x5c07,0x5c16,0x5c1a,0x5c1a,0x5c1c,0x5c1c,0x5c1e,0x5c20,0x5c22,0x5c25,0x5c28,0x5c28,0x5c2a,0x5c2a,0x5c2c,0x5c2c,0x5c30,0x5c31,0x5c33,0x5c33,0x5c37,0x5c3c,0x5c3e,0x5c41,0x5c44,0x5c51,0x5c53,0x5c56,0x5c58,0x5c59,0x5c5c,0x5c5e,0x5c60,0x5c60,0x5c62,0x5c65,0x5c67,0x5c6a,0x5c6c,0x5c6f,0x5c71,0x5c71,0x5c73,0x5c74,0x5c78,0x5c7c,0x5c7e,0x5c7e,0x5c83,0x5c83,0x5c85,0x5c86,0x5c88,0x5c8d,0x5c8f,0x5c95,0x5c99,0x5c9a,0x5c9c,0x5cb1,0x5cb3,0x5cb3,0x5cb5,0x5cb8,0x5cba,0x5cba,0x5cc1,0x5cc2,0x5cc6,0x5ccc,0x5cce,0x5cdb,0x5cde,0x5cdf,0x5ce5,0x5ce5,0x5ce8,0x5cea,0x5cec,0x5cf1,0x5cf4,0x5cf9,0x5cfb,0x5cfd,0x5cff,0x5d01,0x5d06,0x5d07,0x5d0b,0x5d12,0x5d14,0x5d1b,0x5d1d,0x5d20,0x5d22,0x5d29,0x5d2c,0x5d2c,0x5d2e,0x5d3a,0x5d3c,0x5d43,0x5d45,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d52,0x5d55,0x5d57,0x5d59,0x5d59,0x5d5b,0x5d5b,0x5d5e,0x5d5e,0x5d62,0x5d63,0x5d65,0x5d65,0x5d67,0x5d69,0x5d6b,0x5d6c,0x5d6f,0x5d72,0x5d74,0x5d74,0x5d77,0x5d82,0x5d84,0x5d8b,0x5d8d,0x5d8e,0x5d92,0x5d95,0x5d97,0x5d97,0x5d99,0x5d9a,0x5d9c,0x5da2,0x5da4,0x5da4,0x5da7,0x5db2,0x5db4,0x5dba,0x5dbc,0x5dbd,0x5dc0,0x5dc3,0x5dc6,0x5dc7,0x5dc9,0x5dc9,0x5dcb,0x5dcb,0x5dcd,0x5dcd,0x5dcf,0x5dcf,0x5dd1,0x5dd2,0x5dd4,0x5dd8,0x5ddb,0x5ddb,0x5ddd,0x5de2,0x5de5,0x5de8,0x5deb,0x5deb,0x5dee,0x5dee,0x5df0,0x5df5,0x5df7,0x5df7,0x5df9,0x5df9,0x5dfd,0x5dff,0x5e02,0x5e04,0x5e06,0x5e06,0x5e09,0x5e0c,0x5e0e,0x5e0e,0x5e11,0x5e12,0x5e14,0x5e1b,0x5e1d,0x5e1d,0x5e1f,0x5e25,0x5e28,0x5e29,0x5e2b,0x5e2b,0x5e2d,0x5e2e,0x5e33,0x5e34,0x5e36,0x5e38,0x5e3d,0x5e3e,0x5e40,0x5e45,0x5e48,0x5e48,0x5e4a,0x5e4f,0x5e53,0x5e55,0x5e57,0x5e59,0x5e5b,0x5e63,0x5e66,0x5e70,0x5e72,0x5e76,0x5e78,0x5e80,0x5e82,0x5e84,0x5e86,0x5e8d,0x5e8f,0x5e8f,0x5e92,0x5e92,0x5e95,0x5e97,0x5e99,0x5e9c,0x5ea0,0x5ea0,0x5ea2,0x5ea8,0x5eaa,0x5eae,0x5eb0,0x5eb9,0x5ebd,0x5ebe,0x5ec1,0x5ec2,0x5ec4,0x5ece,0x5ed0,0x5ee3,0x5ee5,0x5ee9,0x5eec,0x5eec,0x5eee,0x5eef,0x5ef1,0x5ef4,0x5ef6,0x5efc,0x5efe,0x5eff,0x5f01,0x5f02,0x5f04,0x5f05,0x5f07,0x5f08,0x5f0a,0x5f0f,0x5f12,0x5f15,0x5f17,0x5f18,0x5f1a,0x5f1b,0x5f1d,0x5f1d,0x5f1f,0x5f1f,0x5f22,0x5f29,0x5f2d,0x5f2e,0x5f30,0x5f31,0x5f33,0x5f33,0x5f35,0x5f38,0x5f3a,0x5f3c,0x5f40,0x5f40,0x5f43,0x5f46,0x5f48,0x5f51,0x5f54,0x5f54,0x5f56,0x5f59,0x5f5c,0x5f5e,0x5f61,0x5f65,0x5f67,0x5f67,0x5f69,0x5f6d,0x5f6f,0x5f74,0x5f76,0x5f79,0x5f7b,0x5f83,0x5f85,0x5f8c,0x5f90,0x5f92,0x5f96,0x5f99,0x5f9b,0x5f9c,0x5f9e,0x5fa1,0x5fa4,0x5faf,0x5fb1,0x5fb2,0x5fb5,0x5fb7,0x5fb9,0x5fc5,0x5fc9,0x5fc9,0x5fcc,0x5fcd,0x5fcf,0x5fd2,0x5fd4,0x5fd9,0x5fdb,0x5fdb,0x5fdd,0x5fe1,0x5fe3,0x5fe5,0x5fe8,0x5fe8,0x5fea,0x5feb,0x5fed,0x5fef,0x5ff1,0x5ff1,0x5ff3,0x5ff5,0x5ff7,0x5ff8,0x5ffa,0x5ffb,0x5ffd,0x5ffd,0x5fff,0x6000,0x6009,0x6017,0x6019,0x601e,0x6020,0x602f,0x6031,0x6035,0x6037,0x6037,0x6039,0x6039,0x603b,0x603b,0x6040,0x6047,0x6049,0x604d,0x6050,0x6050,0x6052,0x6055,0x6058,0x605b,0x605d,0x605f,0x6062,0x6070,0x6072,0x6072,0x6075,0x6075,0x6077,0x6077,0x607e,0x6081,0x6083,0x608a,0x608c,0x608e,0x6090,0x6090,0x6092,0x6092,0x6094,0x6097,0x609a,0x60a0,0x60a2,0x60a4,0x60a6,0x60a8,0x60b0,0x60c1,0x60c3,0x60cf,0x60d1,0x60d1,0x60d3,0x60d5,0x60d7,0x60e4,0x60e6,0x60e9,0x60f0,0x6101,0x6103,0x6110,0x6112,0x6116,0x6118,0x611d,0x611f,0x6120,0x6122,0x6123,0x6127,0x6129,0x612b,0x612c,0x612e,0x6130,0x6132,0x6132,0x6134,0x6134,0x6136,0x6137,0x613b,0x613b,0x613d,0x6142,0x6144,0x6150,0x6152,0x6156,0x6158,0x6168,0x616a,0x616c,0x616e,0x6177,0x6179,0x617a,0x617c,0x617e,0x6180,0x6183,0x6187,0x6187,0x6189,0x618e,0x6190,0x6196,0x6198,0x619d,0x619f,0x619f,0x61a1,0x61a2,0x61a4,0x61a4,0x61a7,0x61ba,0x61bc,0x61bc,0x61be,0x61c3,0x61c5,0x61cd,0x61cf,0x61d0,0x61d3,0x61d3,0x61d6,0x61d6,0x61d8,0x61d8,0x61da,0x61da,0x61de,0x61e0,0x61e2,0x61eb,0x61ed,0x61ee,0x61f0,0x61f2,0x61f5,0x6201,0x6203,0x6204,0x6207,0x620a,0x620c,0x620e,0x6210,0x6212,0x6214,0x6216,0x6219,0x621b,0x621f,0x6225,0x6227,0x6227,0x6229,0x622e,0x6230,0x6230,0x6232,0x6234,0x6236,0x6237,0x6239,0x623a,0x623d,0x6243,0x6246,0x624e,0x6250,0x6254,0x6258,0x625c,0x625e,0x625e,0x6260,0x6266,0x6268,0x6268,0x626d,0x6274,0x6276,0x6277,0x6279,0x628a,0x628c,0x628c,0x628e,0x6298,0x629d,0x629d,0x62a4,0x62a4,0x62a6,0x62a6,0x62a8,0x62b1,0x62b3,0x62b6,0x62b8,0x62b9,0x62bb,0x62bf,0x62c1,0x62dc,0x62df,0x62df,0x62e5,0x62e5,0x62eb,0x6303,0x6307,0x6309,0x630b,0x6311,0x6313,0x6316,0x6318,0x6318,0x6328,0x632f,0x6331,0x633e,0x6340,0x6351,0x6354,0x635a,0x635d,0x635d,0x6364,0x6365,0x6367,0x6369,0x636b,0x6372,0x6375,0x637d,0x637f,0x6385,0x6387,0x6392,0x6394,0x6394,0x6396,0x6399,0x639b,0x63a5,0x63a7,0x63b1,0x63b9,0x63b9,0x63bd,0x63be,0x63c0,0x63d3,0x63d5,0x63eb,0x63ed,0x63f6,0x63f8,0x63f9,0x63fb,0x63fc,0x63fe,0x63fe,0x6406,0x6407,0x6409,0x6410,0x6412,0x6418,0x641a,0x641c,0x641e,0x6428,0x642a,0x6430,0x6432,0x643b,0x643d,0x6441,0x6443,0x6443,0x644b,0x644b,0x644d,0x644e,0x6450,0x6454,0x6458,0x6461,0x6465,0x6469,0x646b,0x647d,0x647f,0x647f,0x6482,0x6482,0x6485,0x6485,0x6487,0x648d,0x648f,0x6493,0x6495,0x649a,0x649c,0x64a0,0x64a2,0x64a6,0x64a9,0x64a9,0x64ab,0x64b4,0x64b6,0x64b6,0x64bb,0x64c5,0x64c7,0x64c7,0x64c9,0x64cb,0x64cd,0x64d0,0x64d2,0x64d4,0x64d6,0x64db,0x64dd,0x64dd,0x64e0,0x64ed,0x64ef,0x64f4,0x64f7,0x64f8,0x64fa,0x6501,0x6503,0x6504,0x6506,0x6507,0x6509,0x650a,0x650c,0x6511,0x6513,0x6519,0x651b,0x6526,0x6529,0x6530,0x6532,0x6539,0x653b,0x653b,0x653d,0x653f,0x6541,0x6541,0x6543,0x6543,0x6545,0x6546,0x6548,0x654a,0x654d,0x654d,0x654f,0x654f,0x6551,0x6551,0x6553,0x655a,0x655c,0x655f,0x6562,0x6568,0x656a,0x656d,0x656f,0x656f,0x6572,0x657c,0x657f,0x6589,0x658b,0x658c,0x6590,0x6592,0x6594,0x6597,0x6599,0x6599,0x659b,0x65a2,0x65a4,0x65a5,0x65a7,0x65a8,0x65aa,0x65ac,0x65ae,0x65b0,0x65b2,0x65b3,0x65b5,0x65b9,0x65bb,0x65bf,0x65c1,0x65c6,0x65cb,0x65d4,0x65d6,0x65d7,0x65da,0x65db,0x65dd,0x65e3,0x65e5,0x65e6,0x65e8,0x65e9,0x65ec,0x65f5,0x65fa,0x65fd,0x65ff,0x6600,0x6602,0x6615,0x6618,0x6618,0x661c,0x6628,0x662b,0x662b,0x662d,0x6636,0x6639,0x663a,0x6641,0x6645,0x6647,0x664d,0x664f,0x664f,0x6651,0x6653,0x6657,0x6657,0x6659,0x6668,0x666a,0x666c,0x666e,0x6674,0x6676,0x667e,0x6680,0x6680,0x6684,0x668e,0x6690,0x6692,0x6694,0x669a,0x669d,0x669d,0x669f,0x66a2,0x66a4,0x66a4,0x66a8,0x66ab,0x66ad,0x66bb,0x66bd,0x66c0,0x66c4,0x66c4,0x66c6,0x66cf,0x66d2,0x66d2,0x66d6,0x66d6,0x66d8,0x66de,0x66e0,0x66e0,0x66e3,0x66e4,0x66e6,0x66e9,0x66eb,0x66ee,0x66f0,0x66f4,0x66f6,0x66f9,0x66fc,0x66fc,0x66fe,0x6705,0x6708,0x6710,0x6712,0x6719,0x671b,0x671b,0x671d,0x6723,0x6725,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6736,0x6738,0x673f,0x6744,0x6749,0x674b,0x6751,0x6753,0x6753,0x6755,0x6757,0x6759,0x675a,0x675c,0x6762,0x6767,0x6767,0x676a,0x677f,0x6781,0x6787,0x6789,0x6789,0x678b,0x6795,0x6797,0x679a,0x679c,0x679d,0x679f,0x67a0,0x67a4,0x67a4,0x67ac,0x67ac,0x67ae,0x67bb,0x67bf,0x67c6,0x67c8,0x67d4,0x67d6,0x67df,0x67e2,0x67e7,0x67e9,0x67fa,0x67fc,0x67fc,0x67fe,0x6804,0x680d,0x680d,0x6810,0x6810,0x6812,0x6814,0x6816,0x6818,0x681a,0x6822,0x6825,0x6826,0x6828,0x682b,0x682d,0x682f,0x6831,0x683e,0x6840,0x6851,0x6853,0x6856,0x685d,0x685d,0x6865,0x6865,0x686b,0x686b,0x686d,0x686f,0x6871,0x6872,0x6874,0x6879,0x687b,0x688c,0x688f,0x6894,0x6896,0x6898,0x689b,0x689d,0x689f,0x68a4,0x68a6,0x68b6,0x68b9,0x68b9,0x68bd,0x68bd,0x68c1,0x68c1,0x68c3,0x68ce,0x68d0,0x68d8,0x68da,0x68da,0x68dc,0x68e1,0x68e3,0x68e4,0x68e6,0x68ec,0x68ee,0x68fd,0x6900,0x6915,0x6917,0x691b,0x6925,0x6925,0x692a,0x692a,0x692c,0x692c,0x692f,0x6930,0x6932,0x6939,0x693b,0x6946,0x6948,0x694c,0x694e,0x694f,0x6951,0x697b,0x6980,0x6980,0x6982,0x6983,0x6985,0x6986,0x698a,0x698a,0x698d,0x698e,0x6990,0x6991,0x6993,0x699c,0x699e,0x69b7,0x69b9,0x69b9,0x69bb,0x69c4,0x69c6,0x69c6,0x69c9,0x69d1,0x69d3,0x69d6,0x69d9,0x69d9,0x69e1,0x69e2,0x69e4,0x69e9,0x69eb,0x69ee,0x69f1,0x69f4,0x69f6,0x6a0d,0x6a0f,0x6a0f,0x6a11,0x6a11,0x6a13,0x6a21,0x6a23,0x6a23,0x6a25,0x6a29,0x6a2b,0x6a2d,0x6a32,0x6a35,0x6a38,0x6a41,0x6a43,0x6a49,0x6a4b,0x6a5b,0x6a5d,0x6a6b,0x6a6d,0x6a6d,0x6a6f,0x6a6f,0x6a71,0x6a71,0x6a74,0x6a74,0x6a76,0x6a76,0x6a7a,0x6a7a,0x6a7e,0x6a85,0x6a87,0x6a87,0x6a89,0x6a8a,0x6a8c,0x6a97,0x6a99,0x6aa8,0x6aab,0x6aaf,0x6ab1,0x6abb,0x6abd,0x6abe,0x6ac2,0x6ac3,0x6ac5,0x6acd,0x6acf,0x6ad1,0x6ad3,0x6ad4,0x6ad8,0x6ae1,0x6ae5,0x6ae5,0x6ae7,0x6ae8,0x6aea,0x6aec,0x6aee,0x6af1,0x6af3,0x6af3,0x6af6,0x6af6,0x6af8,0x6afc,0x6b00,0x6b00,0x6b02,0x6b05,0x6b08,0x6b0b,0x6b0f,0x6b13,0x6b16,0x6b1a,0x6b1d,0x6b1e,0x6b20,0x6b21,0x6b23,0x6b23,0x6b25,0x6b25,0x6b28,0x6b28,0x6b2c,0x6b2d,0x6b2f,0x6b2f,0x6b31,0x6b3f,0x6b41,0x6b43,0x6b45,0x6b4e,0x6b50,0x6b52,0x6b54,0x6b57,0x6b59,0x6b59,0x6b5b,0x6b5c,0x6b5e,0x6b67,0x6b6a,0x6b6a,0x6b6d,0x6b6d,0x6b6f,0x6b6f,0x6b72,0x6b72,0x6b74,0x6b74,0x6b76,0x6b7b,0x6b7e,0x6b84,0x6b86,0x6b86,0x6b88,0x6b8a,0x6b8c,0x6b8f,0x6b91,0x6b91,0x6b94,0x6b99,0x6b9b,0x6b9b,0x6b9e,0x6ba0,0x6ba2,0x6ba7,0x6baa,0x6bab,0x6bad,0x6bb0,0x6bb2,0x6bb3,0x6bb5,0x6bb7,0x6bba,0x6bba,0x6bbc,0x6bbd,0x6bbf,0x6bc1,0x6bc3,0x6bcd,0x6bcf,0x6bd0,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdc,0x6bde,0x6bde,0x6be0,0x6be4,0x6be6,0x6be8,0x6bea,0x6bec,0x6bef,0x6bf0,0x6bf2,0x6bf3,0x6bf7,0x6c06,0x6c08,0x6c09,0x6c0b,0x6c0d,0x6c0f,0x6c11,0x6c13,0x6c16,0x6c18,0x6c1d,0x6c1f,0x6c21,0x6c23,0x6c28,0x6c2a,0x6c2c,0x6c2e,0x6c3b,0x6c3d,0x6c43,0x6c46,0x6c46,0x6c49,0x6c50,0x6c52,0x6c52,0x6c54,0x6c55,0x6c57,0x6c61,0x6c65,0x6c6b,0x6c6d,0x6c76,0x6c78,0x6c7b,0x6c7d,0x6c90,0x6c92,0x6c96,0x6c98,0x6c9d,0x6c9f,0x6c9f,0x6ca2,0x6ca2,0x6caa,0x6cb4,0x6cb6,0x6cc7,0x6cc9,0x6cd7,0x6cd9,0x6ce3,0x6ce5,0x6ce5,0x6ce7,0x6cf3,0x6cf5,0x6cf5,0x6cf9,0x6cf9,0x6cff,0x6d12,0x6d16,0x6d1b,0x6d1d,0x6d20,0x6d22,0x6d22,0x6d24,0x6d42,0x6d4e,0x6d4e,0x6d57,0x6d5c,0x6d5e,0x6d6a,0x6d6c,0x6d72,0x6d74,0x6d98,0x6d9a,0x6d9a,0x6da4,0x6da5,0x6daa,0x6dac,0x6dae,0x6daf,0x6db1,0x6db5,0x6db7,0x6dc0,0x6dc2,0x6dc2,0x6dc4,0x6dcd,0x6dcf,0x6de6,0x6de8,0x6df7,0x6df9,0x6dfe,0x6e00,0x6e00,0x6e02,0x6e05,0x6e0a,0x6e0a,0x6e0f,0x6e0f,0x6e15,0x6e15,0x6e18,0x6e1d,0x6e1f,0x6e36,0x6e38,0x6e41,0x6e43,0x6e47,0x6e49,0x6e4b,0x6e4d,0x6e69,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e71,0x6e74,0x6e76,0x6e79,0x6e7c,0x6e7c,0x6e86,0x6e86,0x6e88,0x6e89,0x6e8b,0x6e8b,0x6e8d,0x6e90,0x6e92,0x6e94,0x6e96,0x6ea7,0x6eaa,0x6eab,0x6eae,0x6ed6,0x6ed8,0x6edd,0x6ee2,0x6ee2,0x6ee8,0x6ee9,0x6eeb,0x6eef,0x6ef1,0x6ef2,0x6ef4,0x6f0f,0x6f12,0x6f1a,0x6f1c,0x6f1c,0x6f1e,0x6f27,0x6f29,0x6f41,0x6f43,0x6f44,0x6f4e,0x6f58,0x6f5a,0x6f64,0x6f66,0x6f67,0x6f69,0x6f70,0x6f72,0x6f74,0x6f76,0x6f82,0x6f84,0x6f8e,0x6f90,0x6f90,0x6f92,0x6f97,0x6f9d,0x6fb6,0x6fb8,0x6fc4,0x6fc6,0x6fcf,0x6fd3,0x6fd5,0x6fd8,0x6fe4,0x6fe6,0x6fe9,0x6feb,0x6ff2,0x6ff4,0x6ff4,0x6ff6,0x6ff8,0x6ffa,0x6ffc,0x6ffe,0x7001,0x7003,0x7007,0x7009,0x700f,0x7011,0x7011,0x7014,0x7024,0x7026,0x702c,0x702f,0x7035,0x7037,0x703c,0x703e,0x7046,0x7048,0x704d,0x7050,0x7052,0x7054,0x7058,0x705a,0x706c,0x706e,0x7071,0x7074,0x707a,0x707c,0x707f,0x7081,0x7086,0x7089,0x708b,0x708e,0x708f,0x7091,0x7096,0x7098,0x709a,0x709f,0x70a1,0x70a3,0x70a7,0x70a9,0x70a9,0x70ab,0x70b1,0x70b3,0x70b5,0x70b7,0x70be,0x70c0,0x70c0,0x70c4,0x70c8,0x70ca,0x70da,0x70dc,0x70e2,0x70e4,0x70e4,0x70ef,0x70f1,0x70f3,0x7100,0x7102,0x7102,0x7104,0x7106,0x7109,0x710e,0x7110,0x7110,0x7113,0x7113,0x7117,0x7117,0x7119,0x7123,0x7125,0x7126,0x7128,0x7129,0x712b,0x712c,0x712e,0x7136,0x713a,0x713b,0x713e,0x713e,0x7140,0x7147,0x7149,0x7154,0x7156,0x715a,0x715c,0x716c,0x716e,0x716e,0x7170,0x7178,0x717a,0x717e,0x7180,0x7182,0x7184,0x718a,0x718c,0x718c,0x718e,0x7192,0x7194,0x7194,0x7196,0x71a5,0x71a7,0x71aa,0x71ac,0x71ad,0x71af,0x71b5,0x71b7,0x71ba,0x71bc,0x71cb,0x71ce,0x71d2,0x71d4,0x71d6,0x71d8,0x71dd,0x71df,0x71e2,0x71e4,0x71e8,0x71eb,0x71ee,0x71f0,0x71f2,0x71f4,0x71f6,0x71f8,0x71f9,0x71fb,0x7203,0x7205,0x7207,0x7209,0x720a,0x720c,0x7210,0x7213,0x7217,0x7219,0x721b,0x721d,0x721f,0x7222,0x722e,0x7230,0x7230,0x7235,0x7236,0x7238,0x723b,0x723d,0x7242,0x7244,0x7244,0x7246,0x724c,0x724f,0x7250,0x7252,0x7253,0x7255,0x7263,0x7266,0x7267,0x7269,0x726a,0x726c,0x726c,0x726e,0x7270,0x7272,0x7274,0x7276,0x7279,0x727b,0x7282,0x7284,0x7289,0x728b,0x7298,0x729a,0x729b,0x729d,0x729f,0x72a1,0x72aa,0x72ac,0x72b0,0x72b2,0x72b2,0x72b4,0x72b5,0x72ba,0x72ba,0x72bd,0x72bd,0x72bf,0x72c6,0x72c9,0x72ce,0x72d0,0x72d2,0x72d4,0x72d4,0x72d6,0x72da,0x72dc,0x72dc,0x72df,0x72e4,0x72e6,0x72e6,0x72e8,0x72eb,0x72f3,0x72f4,0x72f6,0x7302,0x7304,0x7304,0x7307,0x7308,0x730a,0x730c,0x730f,0x7313,0x7316,0x7319,0x731b,0x731e,0x7322,0x7323,0x7325,0x732e,0x7330,0x733c,0x733e,0x7345,0x7348,0x734a,0x734c,0x7352,0x7357,0x735b,0x735d,0x7362,0x7365,0x736c,0x736e,0x7378,0x737a,0x738c,0x738e,0x738f,0x7392,0x7398,0x739c,0x73a2,0x73a4,0x73ad,0x73b2,0x73bc,0x73be,0x73c0,0x73c2,0x73d0,0x73d2,0x73de,0x73e0,0x73eb,0x73ed,0x73ef,0x73f3,0x740d,0x7411,0x7412,0x7414,0x7417,0x7419,0x7426,0x7428,0x743a,0x743c,0x743c,0x743f,0x7457,0x7459,0x7465,0x7467,0x7476,0x7479,0x747a,0x747c,0x7483,0x7485,0x748d,0x7490,0x7490,0x7492,0x7492,0x7494,0x7495,0x7497,0x74a1,0x74a3,0x74ab,0x74ad,0x74ad,0x74af,0x74b2,0x74b4,0x74bb,0x74bd,0x74c3,0x74c5,0x74c6,0x74c8,0x74c8,0x74ca,0x74cc,0x74cf,0x74d0,0x74d3,0x74e9,0x74ec,0x74ec,0x74ee,0x74ee,0x74f0,0x74f2,0x74f4,0x74f8,0x74fb,0x74fb,0x74fd,0x7500,0x7502,0x7505,0x7507,0x7508,0x750b,0x751a,0x751c,0x751f,0x7521,0x7522,0x7525,0x7526,0x7528,0x7535,0x7537,0x753b,0x753d,0x7540,0x7542,0x7542,0x7546,0x7548,0x754a,0x754f,0x7551,0x7551,0x7553,0x7555,0x7559,0x755d,0x755f,0x7560,0x7562,0x7567,0x756a,0x7570,0x7572,0x7572,0x7576,0x757a,0x757d,0x7580,0x7583,0x7584,0x7586,0x7587,0x758a,0x7592,0x7594,0x7595,0x7598,0x759a,0x759d,0x759e,0x75a2,0x75a5,0x75a7,0x75a7,0x75aa,0x75ab,0x75b0,0x75b6,0x75b8,0x75c5,0x75c7,0x75c8,0x75ca,0x75d2,0x75d4,0x75d5,0x75d7,0x75e4,0x75e6,0x75e7,0x75ed,0x75ed,0x75ef,0x7603,0x7607,0x760d,0x760f,0x7611,0x7613,0x7616,0x7619,0x7629,0x762c,0x762d,0x762f,0x7635,0x7638,0x7638,0x763a,0x763d,0x7640,0x7640,0x7642,0x7643,0x7646,0x7649,0x764c,0x7654,0x7656,0x765a,0x765c,0x765c,0x765f,0x7662,0x7664,0x7667,0x7669,0x766a,0x766c,0x7676,0x7678,0x767f,0x7681,0x7682,0x7684,0x7684,0x7686,0x768b,0x768e,0x7690,0x7692,0x7693,0x7695,0x7696,0x7699,0x769e,0x76a1,0x76a1,0x76a4,0x76a6,0x76aa,0x76ab,0x76ad,0x76b0,0x76b4,0x76b5,0x76b7,0x76b8,0x76ba,0x76bb,0x76bd,0x76bf,0x76c2,0x76c6,0x76c8,0x76ca,0x76cc,0x76ce,0x76d2,0x76d4,0x76d6,0x76d6,0x76d9,0x76df,0x76e1,0x76e1,0x76e3,0x76e7,0x76e9,0x76ea,0x76ec,0x76f5,0x76f7,0x76fc,0x76fe,0x76fe,0x7701,0x7701,0x7703,0x7705,0x7707,0x770c,0x770e,0x7713,0x7715,0x7715,0x7719,0x771b,0x771d,0x7720,0x7722,0x7729,0x772b,0x772b,0x772d,0x772d,0x772f,0x772f,0x7731,0x773e,0x7740,0x7740,0x7743,0x7747,0x774a,0x774f,0x7752,0x7752,0x7754,0x7756,0x7758,0x775c,0x775e,0x7763,0x7765,0x776f,0x7772,0x7772,0x7777,0x7785,0x7787,0x7789,0x778b,0x778f,0x7791,0x7791,0x7793,0x7793,0x7795,0x7795,0x7797,0x77a3,0x77a5,0x77a5,0x77a7,0x77a8,0x77aa,0x77ad,0x77af,0x77b7,0x77b9,0x77bf,0x77c2,0x77c5,0x77c7,0x77c7,0x77c9,0x77d0,0x77d3,0x77d5,0x77d7,0x77de,0x77e0,0x77e0,0x77e2,0x77e3,0x77e5,0x77e9,0x77ec,0x77f4,0x77f7,0x77fe,0x7802,0x7803,0x7805,0x7806,0x7808,0x7809,0x780c,0x7814,0x7818,0x7818,0x781c,0x7823,0x7825,0x7835,0x7837,0x7839,0x783c,0x783d,0x7842,0x7845,0x7847,0x784e,0x7850,0x7854,0x785c,0x785e,0x7860,0x7860,0x7862,0x7862,0x7864,0x7866,0x7868,0x7871,0x7879,0x787c,0x787e,0x7881,0x7883,0x7889,0x788c,0x788f,0x7891,0x7891,0x7893,0x789a,0x789e,0x78a5,0x78a7,0x78ad,0x78af,0x78b4,0x78b6,0x78b6,0x78b8,0x78bc,0x78be,0x78be,0x78c1,0x78c1,0x78c3,0x78c5,0x78c7,0x78d5,0x78d7,0x78d8,0x78da,0x78db,0x78dd,0x78e5,0x78e7,0x78ea,0x78ec,0x78f5,0x78f7,0x78f7,0x78f9,0x78ff,0x7901,0x7902,0x7904,0x7906,0x7909,0x7909,0x790c,0x790c,0x790e,0x790e,0x7910,0x7914,0x7917,0x7917,0x7919,0x7919,0x791b,0x791e,0x7921,0x7921,0x7923,0x792f,0x7931,0x7936,0x7938,0x7942,0x7944,0x794c,0x794f,0x7965,0x7967,0x796b,0x796d,0x796d,0x7970,0x7974,0x7979,0x797a,0x797c,0x7983,0x7986,0x7988,0x798a,0x798b,0x798d,0x799d,0x799f,0x79a2,0x79a4,0x79ae,0x79b0,0x79b4,0x79b6,0x79bb,0x79bd,0x79c1,0x79c4,0x79c6,0x79c8,0x79d2,0x79d4,0x79d6,0x79d8,0x79d8,0x79dc,0x79e0,0x79e2,0x79e4,0x79e6,0x79e7,0x79e9,0x79ee,0x79f1,0x79f1,0x79f4,0x79f4,0x79f6,0x79f8,0x79fa,0x79fb,0x7a00,0x7a00,0x7a02,0x7a06,0x7a08,0x7a08,0x7a0a,0x7a0e,0x7a10,0x7a15,0x7a17,0x7a1c,0x7a1e,0x7a20,0x7a22,0x7a22,0x7a26,0x7a26,0x7a28,0x7a28,0x7a2a,0x7a32,0x7a37,0x7a37,0x7a39,0x7a40,0x7a43,0x7a4e,0x7a54,0x7a54,0x7a56,0x7a58,0x7a5a,0x7a5c,0x7a5f,0x7a62,0x7a65,0x7a65,0x7a67,0x7a69,0x7a6b,0x7a6e,0x7a70,0x7a72,0x7a74,0x7a76,0x7a78,0x7a7b,0x7a7d,0x7a81,0x7a83,0x7a8c,0x7a8f,0x7a99,0x7a9e,0x7aa0,0x7aa2,0x7aa3,0x7aa8,0x7aac,0x7aae,0x7ab8,0x7aba,0x7abc,0x7abe,0x7ac5,0x7ac7,0x7acb,0x7acf,0x7acf,0x7ad1,0x7ad1,0x7ad3,0x7ad3,0x7ad8,0x7add,0x7adf,0x7ae0,0x7ae2,0x7ae7,0x7ae9,0x7aeb,0x7aed,0x7aef,0x7af6,0x7af7,0x7af9,0x7b01,0x7b04,0x7b06,0x7b08,0x7b0c,0x7b0e,0x7b14,0x7b18,0x7b1b,0x7b1d,0x7b20,0x7b22,0x7b35,0x7b38,0x7b39,0x7b3b,0x7b3b,0x7b40,0x7b40,0x7b42,0x7b52,0x7b54,0x7b56,0x7b58,0x7b58,0x7b60,0x7b67,0x7b69,0x7b69,0x7b6c,0x7b78,0x7b7b,0x7b7b,0x7b82,0x7b82,0x7b84,0x7b85,0x7b87,0x7b88,0x7b8a,0x7b92,0x7b94,0x7b9d,0x7ba0,0x7ba4,0x7bac,0x7baf,0x7bb1,0x7bb2,0x7bb4,0x7bb5,0x7bb7,0x7bb9,0x7bbe,0x7bbe,0x7bc0,0x7bc1,0x7bc4,0x7bc7,0x7bc9,0x7bcc,0x7bce,0x7bd0,0x7bd4,0x7bd5,0x7bd8,0x7bec,0x7bf0,0x7bf4,0x7bf7,0x7c03,0x7c05,0x7c07,0x7c09,0x7c12,0x7c15,0x7c15,0x7c19,0x7c19,0x7c1b,0x7c23,0x7c25,0x7c2d,0x7c30,0x7c30,0x7c33,0x7c33,0x7c35,0x7c35,0x7c37,0x7c39,0x7c3b,0x7c40,0x7c42,0x7c45,0x7c47,0x7c4a,0x7c4c,0x7c4d,0x7c50,0x7c51,0x7c53,0x7c54,0x7c56,0x7c57,0x7c59,0x7c5d,0x7c5f,0x7c60,0x7c63,0x7c67,0x7c69,0x7c70,0x7c72,0x7c75,0x7c78,0x7c81,0x7c83,0x7c86,0x7c88,0x7c8a,0x7c8c,0x7c8e,0x7c91,0x7c92,0x7c94,0x7c98,0x7c9c,0x7c9c,0x7c9e,0x7c9f,0x7ca1,0x7ca3,0x7ca5,0x7ca8,0x7cac,0x7cac,0x7cae,0x7caf,0x7cb1,0x7cb5,0x7cb8,0x7cbf,0x7cc2,0x7cc3,0x7cc5,0x7cc5,0x7cc7,0x7cce,0x7cd0,0x7cd7,0x7cd9,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce6,0x7ce8,0x7cea,0x7cea,0x7cec,0x7cf9,0x7cfb,0x7cfe,0x7d00,0x7d22,0x7d25,0x7d25,0x7d28,0x7d29,0x7d2b,0x7d2c,0x7d2e,0x7d33,0x7d35,0x7d36,0x7d38,0x7d47,0x7d4a,0x7d4a,0x7d4d,0x7d56,0x7d58,0x7d58,0x7d5a,0x7d5f,0x7d61,0x7d63,0x7d66,0x7d6b,0x7d6d,0x7d73,0x7d79,0x7d7d,0x7d7f,0x7d81,0x7d83,0x7d86,0x7d88,0x7d89,0x7d8b,0x7d8f,0x7d91,0x7d97,0x7d9c,0x7da4,0x7da6,0x7db5,0x7db7,0x7dc2,0x7dc4,0x7dc7,0x7dc9,0x7dd0,0x7dd2,0x7dd4,0x7dd7,0x7de1,0x7de3,0x7dea,0x7dec,0x7dec,0x7dee,0x7df7,0x7df9,0x7dfe,0x7e03,0x7e03,0x7e07,0x7e17,0x7e1a,0x7e25,0x7e27,0x7e27,0x7e29,0x7e2b,0x7e2d,0x7e49,0x7e4c,0x7e4c,0x7e50,0x7e5c,0x7e5e,0x7e63,0x7e65,0x7e65,0x7e67,0x7e70,0x7e72,0x7e82,0x7e86,0x7e88,0x7e8a,0x7e8f,0x7e91,0x7e9c,0x7e9f,0x7e9f,0x7ea4,0x7ea4,0x7eac,0x7eac,0x7eba,0x7eba,0x7ec7,0x7ec7,0x7ecf,0x7ecf,0x7edf,0x7edf,0x7f06,0x7f06,0x7f36,0x7f3a,0x7f3d,0x7f41,0x7f43,0x7f45,0x7f47,0x7f55,0x7f58,0x7f58,0x7f5b,0x7f61,0x7f63,0x7f63,0x7f65,0x7f6e,0x7f70,0x7f73,0x7f75,0x7f7f,0x7f83,0x7f83,0x7f85,0x7f8f,0x7f91,0x7f97,0x7f9a,0x7f9e,0x7fa0,0x7fa9,0x7fac,0x7fc3,0x7fc5,0x7fc5,0x7fc7,0x7fc7,0x7fc9,0x7fd2,0x7fd4,0x7fd5,0x7fd7,0x7fd7,0x7fdb,0x7fe3,0x7fe5,0x7ff5,0x7ff7,0x8008,0x800b,0x8012,0x8014,0x8019,0x801b,0x8021,0x8024,0x8026,0x8028,0x802a,0x802c,0x802c,0x802e,0x8031,0x8033,0x8037,0x8039,0x8039,0x803b,0x803f,0x8043,0x8043,0x8046,0x8048,0x804a,0x804a,0x804f,0x8052,0x8054,0x8054,0x8056,0x8056,0x8058,0x8058,0x805a,0x805e,0x8061,0x8064,0x8066,0x8067,0x806c,0x806c,0x806f,0x8073,0x8075,0x8079,0x807d,0x8080,0x8082,0x8082,0x8084,0x8087,0x8089,0x808c,0x808f,0x8090,0x8092,0x8093,0x8095,0x8096,0x8098,0x809d,0x809f,0x809f,0x80a1,0x80a3,0x80a5,0x80a5,0x80a7,0x80a7,0x80a9,0x80ab,0x80ad,0x80af,0x80b1,0x80b2,0x80b4,0x80b8,0x80ba,0x80ba,0x80bc,0x80bd,0x80c2,0x80ca,0x80cc,0x80d1,0x80d4,0x80de,0x80e0,0x80e1,0x80e3,0x80e6,0x80e9,0x80e9,0x80ec,0x80ed,0x80ef,0x80f6,0x80f8,0x80fe,0x8100,0x8103,0x8105,0x810a,0x810c,0x810c,0x810e,0x810e,0x8112,0x8112,0x8114,0x811b,0x811d,0x811f,0x8121,0x8125,0x8127,0x8127,0x8129,0x812d,0x812f,0x8132,0x8134,0x8134,0x8137,0x8137,0x8139,0x813a,0x813d,0x813e,0x8142,0x8144,0x8146,0x8148,0x814a,0x8156,0x8159,0x815c,0x815e,0x815e,0x8160,0x8162,0x8164,0x8167,0x8169,0x8169,0x816b,0x8174,0x8176,0x817a,0x817c,0x817d,0x817f,0x8180,0x8182,0x8184,0x8186,0x818d,0x818f,0x818f,0x8193,0x8193,0x8195,0x8195,0x8197,0x81a0,0x81a2,0x81a3,0x81a5,0x81ac,0x81ae,0x81ae,0x81b0,0x81b7,0x81b9,0x81ca,0x81cc,0x81cd,0x81cf,0x81d2,0x81d5,0x81d5,0x81d7,0x81db,0x81dd,0x81ea,0x81ec,0x81ef,0x81f2,0x81f4,0x81f6,0x81fc,0x81fe,0x8202,0x8204,0x8205,0x8207,0x820d,0x8210,0x8212,0x8214,0x8216,0x8218,0x8218,0x821a,0x8222,0x8225,0x8226,0x8228,0x822d,0x822f,0x822f,0x8232,0x823a,0x823c,0x8240,0x8242,0x8242,0x8244,0x8245,0x8247,0x8247,0x8249,0x8249,0x824b,0x824b,0x824e,0x825c,0x825e,0x825f,0x8261,0x8266,0x8268,0x8269,0x826b,0x826f,0x8271,0x8272,0x8274,0x8280,0x8283,0x8285,0x8287,0x8287,0x828a,0x828b,0x828d,0x8294,0x8298,0x829b,0x829d,0x82b1,0x82b3,0x82c0,0x82c2,0x82c4,0x82ca,0x82ca,0x82cf,0x82d9,0x82db,0x82dc,0x82de,0x82e8,0x82ea,0x8309,0x830b,0x830d,0x8316,0x831e,0x8320,0x8320,0x8322,0x8322,0x8324,0x832d,0x832f,0x832f,0x8331,0x833d,0x833f,0x8345,0x8347,0x8354,0x8356,0x8357,0x8362,0x8363,0x8366,0x8366,0x836f,0x836f,0x8373,0x8378,0x837a,0x837f,0x8381,0x8381,0x8383,0x8383,0x8385,0x839e,0x83a0,0x83a0,0x83a2,0x83ac,0x83ae,0x83b0,0x83b9,0x83b9,0x83bd,0x83cf,0x83d1,0x83d1,0x83d3,0x83d9,0x83db,0x83e5,0x83e7,0x83f6,0x83f8,0x83ff,0x8401,0x8401,0x8403,0x8407,0x8409,0x8414,0x8416,0x8416,0x8418,0x8418,0x841b,0x841c,0x8420,0x8421,0x8423,0x8424,0x8426,0x8426,0x8429,0x8429,0x842b,0x8440,0x8442,0x844e,0x8450,0x8469,0x846b,0x847a,0x847d,0x8480,0x8482,0x8482,0x8484,0x8484,0x8486,0x8486,0x8488,0x8488,0x848d,0x8494,0x8496,0x84a4,0x84a7,0x84b2,0x84b4,0x84b4,0x84b6,0x84b6,0x84b8,0x84c2,0x84c4,0x84c7,0x84c9,0x84d4,0x84d6,0x84d7,0x84da,0x84db,0x84de,0x84de,0x84e1,0x84e2,0x84e4,0x84e5,0x84e7,0x84ec,0x84ee,0x84f4,0x84f6,0x8500,0x8502,0x851a,0x851c,0x8521,0x8523,0x8531,0x8533,0x8534,0x8538,0x8538,0x853b,0x853b,0x853d,0x853e,0x8540,0x854e,0x8551,0x855b,0x855d,0x8571,0x8573,0x8573,0x8575,0x857c,0x857e,0x857e,0x8580,0x8591,0x8593,0x85a4,0x85a6,0x85aa,0x85af,0x85b1,0x85b3,0x85ba,0x85bd,0x85c9,0x85cb,0x85cb,0x85cd,0x85d2,0x85d5,0x85da,0x85dc,0x85e6,0x85e8,0x85f2,0x85f4,0x85f4,0x85f6,0x8602,0x8604,0x8607,0x8609,0x860d,0x860f,0x8611,0x8613,0x8614,0x8616,0x861c,0x861e,0x862a,0x862c,0x862f,0x8631,0x8636,0x8638,0x863c,0x863e,0x8640,0x8642,0x8643,0x8645,0x8648,0x864b,0x864e,0x8650,0x8650,0x8652,0x8656,0x8659,0x8659,0x865b,0x865c,0x865e,0x865f,0x8661,0x8665,0x8667,0x8674,0x8677,0x8677,0x8679,0x867c,0x867e,0x867e,0x8685,0x8687,0x868a,0x868e,0x8690,0x869a,0x869c,0x869e,0x86a0,0x86a5,0x86a7,0x86aa,0x86ad,0x86ad,0x86af,0x86c9,0x86cb,0x86cc,0x86d0,0x86d1,0x86d3,0x86d4,0x86d6,0x86df,0x86e2,0x86e4,0x86e6,0x86e6,0x86e8,0x86ed,0x86ef,0x86ef,0x86f5,0x86fb,0x86fe,0x86fe,0x8700,0x870e,0x8711,0x8713,0x8715,0x8715,0x8718,0x871c,0x871e,0x871e,0x8720,0x872a,0x872c,0x872e,0x8730,0x8735,0x8737,0x8738,0x873a,0x873c,0x873e,0x8743,0x8746,0x8746,0x874c,0x8771,0x8773,0x877b,0x877d,0x877d,0x8781,0x8789,0x878b,0x878d,0x878f,0x8794,0x8796,0x8798,0x879a,0x879f,0x87a2,0x87a5,0x87a9,0x87c6,0x87c8,0x87cc,0x87ce,0x87ce,0x87d1,0x87d4,0x87d6,0x87e8,0x87ea,0x87ef,0x87f2,0x87f7,0x87f9,0x87fc,0x87fe,0x8806,0x8808,0x880d,0x880f,0x8811,0x8813,0x8819,0x881b,0x881d,0x881f,0x8833,0x8835,0x8839,0x883b,0x8846,0x8848,0x8848,0x884a,0x884f,0x8852,0x8853,0x8855,0x8857,0x8859,0x885b,0x885d,0x885e,0x8860,0x8865,0x8867,0x886b,0x886d,0x8872,0x8874,0x8877,0x8879,0x8879,0x887c,0x8884,0x8887,0x8889,0x888b,0x8893,0x8895,0x88a2,0x88a4,0x88a4,0x88a7,0x88a8,0x88aa,0x88ac,0x88ae,0x88ae,0x88b1,0x88b2,0x88b4,0x88ba,0x88bc,0x88c2,0x88c5,0x88c5,0x88c7,0x88c7,0x88c9,0x88d0,0x88d2,0x88d2,0x88d4,0x88df,0x88e1,0x88e1,0x88e6,0x88e8,0x88eb,0x88ec,0x88ee,0x8902,0x8905,0x8907,0x8909,0x890c,0x890e,0x890e,0x8910,0x891a,0x891e,0x891f,0x8921,0x8927,0x8929,0x8933,0x8935,0x8938,0x893b,0x893e,0x8941,0x8944,0x8946,0x8947,0x8949,0x8949,0x894b,0x894d,0x894f,0x8954,0x8956,0x8966,0x8969,0x896f,0x8971,0x8974,0x8976,0x8977,0x8979,0x897c,0x897e,0x8983,0x8985,0x898b,0x898f,0x898f,0x8991,0x8991,0x8993,0x8998,0x899b,0x899f,0x89a1,0x89a7,0x89a9,0x89aa,0x89ac,0x89af,0x89b2,0x89b2,0x89b6,0x89b7,0x89b9,0x89ba,0x89bc,0x89c1,0x89c6,0x89c6,0x89d2,0x89d6,0x89d9,0x89dd,0x89df,0x89e9,0x89eb,0x89ed,0x89f0,0x89f4,0x89f6,0x89f8,0x89fa,0x89fc,0x89fe,0x8a00,0x8a02,0x8a04,0x8a07,0x8a08,0x8a0a,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a13,0x8a15,0x8a18,0x8a1b,0x8a1f,0x8a22,0x8a23,0x8a25,0x8a25,0x8a27,0x8a27,0x8a29,0x8a2d,0x8a30,0x8a31,0x8a34,0x8a34,0x8a36,0x8a36,0x8a38,0x8a41,0x8a44,0x8a46,0x8a48,0x8a4a,0x8a4c,0x8a52,0x8a54,0x8a59,0x8a5b,0x8a5b,0x8a5e,0x8a5e,0x8a60,0x8a63,0x8a66,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a77,0x8a79,0x8a7c,0x8a7e,0x8a7f,0x8a81,0x8a87,0x8a8b,0x8a8d,0x8a8f,0x8a96,0x8a98,0x8a9a,0x8a9c,0x8a9c,0x8a9e,0x8a9e,0x8aa0,0x8aa1,0x8aa3,0x8aac,0x8aaf,0x8ab0,0x8ab2,0x8ab2,0x8ab4,0x8ab4,0x8ab6,0x8ab6,0x8ab8,0x8ac0,0x8ac2,0x8ac9,0x8acb,0x8acd,0x8acf,0x8acf,0x8ad1,0x8ae2,0x8ae4,0x8ae4,0x8ae6,0x8ae8,0x8aea,0x8aeb,0x8aed,0x8afc,0x8afe,0x8b02,0x8b04,0x8b08,0x8b0a,0x8b20,0x8b22,0x8b28,0x8b2a,0x8b31,0x8b33,0x8b33,0x8b35,0x8b37,0x8b39,0x8b43,0x8b45,0x8b5a,0x8b5c,0x8b60,0x8b62,0x8b63,0x8b65,0x8b6d,0x8b6f,0x8b70,0x8b74,0x8b74,0x8b77,0x8b7b,0x8b7d,0x8b86,0x8b88,0x8b88,0x8b8a,0x8b8c,0x8b8e,0x8b90,0x8b92,0x8b96,0x8b98,0x8b9c,0x8b9e,0x8ba0,0x8bbe,0x8bbe,0x8be2,0x8be2,0x8c37,0x8c37,0x8c39,0x8c39,0x8c3b,0x8c3f,0x8c41,0x8c43,0x8c45,0x8c51,0x8c54,0x8c57,0x8c5a,0x8c5a,0x8c5c,0x8c5d,0x8c5f,0x8c5f,0x8c61,0x8c62,0x8c64,0x8c66,0x8c68,0x8c6d,0x8c6f,0x8c73,0x8c75,0x8c7b,0x8c7d,0x8c7d,0x8c80,0x8c82,0x8c84,0x8c86,0x8c89,0x8c8a,0x8c8c,0x8c8d,0x8c8f,0x8c95,0x8c97,0x8ca5,0x8ca7,0x8cad,0x8caf,0x8cb0,0x8cb2,0x8cc5,0x8cc7,0x8cc8,0x8cca,0x8cca,0x8ccc,0x8ccd,0x8ccf,0x8ccf,0x8cd1,0x8cd7,0x8cd9,0x8cee,0x8cf0,0x8cf5,0x8cf7,0x8cfe,0x8d00,0x8d00,0x8d02,0x8d0d,0x8d0f,0x8d19,0x8d1b,0x8d1d,0x8d64,0x8d64,0x8d66,0x8d69,0x8d6b,0x8d70,0x8d72,0x8d74,0x8d76,0x8d7b,0x8d7d,0x8d7d,0x8d80,0x8d82,0x8d84,0x8d85,0x8d89,0x8d8a,0x8d8c,0x8d96,0x8d99,0x8d99,0x8d9b,0x8d9c,0x8d9f,0x8da1,0x8da3,0x8da3,0x8da5,0x8daf,0x8db2,0x8db7,0x8db9,0x8dba,0x8dbc,0x8dbc,0x8dbe,0x8dc3,0x8dc5,0x8dc8,0x8dcb,0x8dd1,0x8dd3,0x8ddd,0x8ddf,0x8de4,0x8de6,0x8dec,0x8dee,0x8df4,0x8dfa,0x8dfa,0x8dfc,0x8e07,0x8e09,0x8e0a,0x8e0d,0x8e2b,0x8e2d,0x8e2e,0x8e30,0x8e31,0x8e33,0x8e36,0x8e38,0x8e3a,0x8e3c,0x8e42,0x8e44,0x8e50,0x8e53,0x8e57,0x8e59,0x8e6a,0x8e6c,0x8e6d,0x8e6f,0x8e6f,0x8e71,0x8e78,0x8e7a,0x8e7c,0x8e7e,0x8e7e,0x8e80,0x8e82,0x8e84,0x8e8e,0x8e90,0x8e98,0x8e9a,0x8e9a,0x8e9d,0x8ea1,0x8ea3,0x8ead,0x8eb0,0x8eb0,0x8eb2,0x8eb2,0x8eb6,0x8eb6,0x8eb9,0x8eba,0x8ebc,0x8ebd,0x8ec0,0x8ec0,0x8ec2,0x8ec3,0x8ec9,0x8ecf,0x8ed1,0x8ed4,0x8ed7,0x8ed8,0x8eda,0x8ee2,0x8ee4,0x8ee9,0x8eeb,0x8eef,0x8ef1,0x8ef2,0x8ef4,0x8efc,0x8efe,0x8f03,0x8f05,0x8f0b,0x8f0d,0x8f0e,0x8f10,0x8f20,0x8f23,0x8f26,0x8f29,0x8f2a,0x8f2c,0x8f30,0x8f32,0x8f39,0x8f3b,0x8f3c,0x8f3e,0x8f4b,0x8f4d,0x8f64,0x8f66,0x8f67,0x8f6e,0x8f6e,0x8f93,0x8f93,0x8f9b,0x8f9c,0x8f9f,0x8fa0,0x8fa3,0x8fa3,0x8fa5,0x8fa8,0x8fad,0x8fbc,0x8fbe,0x8fbf,0x8fc1,0x8fc2,0x8fc4,0x8fc6,0x8fc9,0x8fd7,0x8fda,0x8fda,0x8fe0,0x8fe6,0x8fe8,0x8fe8,0x8fea,0x8feb,0x8fed,0x8fee,0x8ff0,0x8ff0,0x8ff4,0x9006,0x9008,0x9008,0x900b,0x900d,0x900f,0x9012,0x9014,0x9017,0x9019,0x9024,0x902d,0x902f,0x9031,0x9038,0x903c,0x903f,0x9041,0x9042,0x9044,0x9044,0x9046,0x9047,0x9049,0x9056,0x9058,0x9059,0x905b,0x905e,0x9060,0x9064,0x9067,0x9069,0x906b,0x9070,0x9072,0x9088,0x908a,0x908b,0x908d,0x908d,0x908f,0x9091,0x9094,0x9095,0x9097,0x9099,0x909b,0x909b,0x909e,0x90a3,0x90a5,0x90a8,0x90aa,0x90aa,0x90ae,0x90b6,0x90b8,0x90b8,0x90bb,0x90bb,0x90bd,0x90bf,0x90c1,0x90c1,0x90c3,0x90c5,0x90c7,0x90c8,0x90ca,0x90cb,0x90ce,0x90ce,0x90d4,0x90dd,0x90df,0x90e5,0x90e8,0x90ed,0x90ef,0x90f5,0x90f9,0x9109,0x910b,0x910b,0x910d,0x9112,0x9114,0x9114,0x9116,0x9124,0x9126,0x9136,0x9138,0x913b,0x913e,0x9141,0x9143,0x9153,0x9155,0x915a,0x915c,0x915c,0x915e,0x9165,0x9167,0x916a,0x916c,0x916c,0x916e,0x9170,0x9172,0x917a,0x917c,0x917c,0x9180,0x9187,0x9189,0x9193,0x9196,0x9196,0x9199,0x91a3,0x91a5,0x91a5,0x91a7,0x91b7,0x91b9,0x91be,0x91c0,0x91c7,0x91c9,0x91c9,0x91cb,0x91d1,0x91d3,0x91da,0x91dc,0x91dd,0x91df,0x91df,0x91e2,0x91ee,0x91f1,0x91f1,0x91f3,0x91fa,0x91fd,0x920a,0x920c,0x921a,0x921c,0x921c,0x921e,0x921e,0x9221,0x9221,0x9223,0x9228,0x922a,0x922b,0x922d,0x922e,0x9230,0x923a,0x923c,0x9241,0x9244,0x9246,0x9248,0x9258,0x925a,0x925b,0x925d,0x9267,0x926b,0x9270,0x9272,0x9272,0x9276,0x928f,0x9291,0x9291,0x9293,0x929d,0x92a0,0x92ac,0x92ae,0x92ae,0x92b1,0x92b7,0x92b9,0x92bc,0x92be,0x92d5,0x92d7,0x92d9,0x92db,0x92db,0x92dd,0x92e1,0x92e3,0x92f4,0x92f6,0x9304,0x9306,0x9309,0x930b,0x9310,0x9312,0x9316,0x9318,0x931b,0x931d,0x9331,0x9333,0x9336,0x9338,0x9339,0x933c,0x933c,0x9340,0x9352,0x9354,0x935c,0x935e,0x936e,0x9370,0x9371,0x9373,0x937e,0x9380,0x938a,0x938c,0x9392,0x9394,0x93aa,0x93ac,0x93b5,0x93b7,0x93b8,0x93bb,0x93bb,0x93bd,0x93bd,0x93bf,0x93c0,0x93c2,0x93c4,0x93c6,0x93c8,0x93ca,0x93e4,0x93e6,0x93e8,0x93ec,0x93ec,0x93ee,0x93ee,0x93f0,0x93f1,0x93f3,0x9401,0x9403,0x9404,0x9406,0x9419,0x941b,0x941b,0x941d,0x941d,0x9420,0x9420,0x9424,0x9433,0x9435,0x9440,0x9442,0x944d,0x944f,0x9452,0x9454,0x9455,0x9457,0x9458,0x945b,0x945b,0x945d,0x945e,0x9460,0x9460,0x9462,0x9465,0x9467,0x9479,0x947b,0x9483,0x9485,0x9485,0x949f,0x949f,0x94a2,0x94a2,0x94c1,0x94c1,0x94c3,0x94c3,0x94dc,0x94dc,0x94f6,0x94f6,0x952d,0x952d,0x9547,0x9547,0x9577,0x9578,0x957a,0x957d,0x957f,0x9580,0x9582,0x9583,0x9585,0x9586,0x9588,0x9589,0x958b,0x9594,0x9596,0x9599,0x959b,0x959c,0x959e,0x95ae,0x95b0,0x95b2,0x95b5,0x95b7,0x95b9,0x95c0,0x95c3,0x95c3,0x95c5,0x95cd,0x95d0,0x95d6,0x95da,0x95dc,0x95de,0x95e5,0x95e8,0x95e8,0x95f4,0x95f4,0x961c,0x961e,0x9620,0x9624,0x9628,0x9628,0x962a,0x962a,0x962c,0x9633,0x9638,0x963d,0x963f,0x9645,0x964a,0x9651,0x9653,0x9654,0x9656,0x9656,0x9658,0x9658,0x965b,0x965f,0x9661,0x9664,0x9669,0x966d,0x966f,0x9678,0x967b,0x967e,0x9680,0x9681,0x9683,0x968b,0x968d,0x968f,0x9691,0x9699,0x969b,0x969c,0x969e,0x969e,0x96a1,0x96a5,0x96a7,0x96aa,0x96ac,0x96ac,0x96ae,0x96ae,0x96b0,0x96b1,0x96b3,0x96b4,0x96b6,0x96b6,0x96b8,0x96b9,0x96bb,0x96bd,0x96bf,0x96ce,0x96d2,0x96df,0x96e1,0x96e3,0x96e5,0x96e5,0x96e8,0x96ea,0x96ef,0x96f2,0x96f4,0x96fb,0x96fd,0x96fd,0x96ff,0x9700,0x9702,0x9709,0x970b,0x970b,0x970d,0x9713,0x9716,0x9716,0x9718,0x9719,0x971b,0x972c,0x972e,0x9732,0x9734,0x9736,0x9738,0x973a,0x973d,0x9744,0x9746,0x974b,0x9751,0x9752,0x9755,0x9758,0x975a,0x9762,0x9766,0x9766,0x9768,0x976a,0x976c,0x976e,0x9770,0x9774,0x9776,0x9778,0x977a,0x9785,0x9787,0x978b,0x978d,0x978f,0x9794,0x9794,0x9797,0x97a6,0x97a8,0x97a8,0x97aa,0x97ae,0x97b1,0x97b4,0x97b6,0x97bb,0x97bd,0x97c9,0x97cb,0x97d0,0x97d2,0x97d9,0x97dc,0x97e1,0x97e3,0x97e3,0x97e5,0x97e6,0x97ed,0x97ee,0x97f0,0x97f3,0x97f5,0x97f6,0x97f8,0x97fb,0x97fd,0x9808,0x980a,0x980a,0x980c,0x9818,0x981b,0x9821,0x9823,0x9824,0x9826,0x9829,0x982b,0x982b,0x982d,0x9830,0x9832,0x9835,0x9837,0x9839,0x983b,0x983b,0x9841,0x9841,0x9843,0x9853,0x9856,0x9859,0x985b,0x9860,0x9862,0x986c,0x986f,0x9875,0x98a8,0x98a9,0x98ac,0x98af,0x98b1,0x98b4,0x98b6,0x98c4,0x98c6,0x98cc,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e3,0x98e5,0x98e7,0x98e9,0x98ed,0x98ef,0x98ef,0x98f1,0x98f2,0x98f4,0x98f6,0x98f9,0x98fa,0x98fc,0x98fe,0x9900,0x9900,0x9902,0x9903,0x9905,0x9905,0x9907,0x990a,0x990c,0x990c,0x990e,0x990e,0x9910,0x991c,0x991e,0x991f,0x9921,0x9921,0x9924,0x9925,0x9927,0x9933,0x9935,0x9935,0x9937,0x9943,0x9945,0x9945,0x9947,0x994e,0x9950,0x9959,0x995b,0x995f,0x9961,0x9963,0x9996,0x9999,0x999b,0x999e,0x99a1,0x99a1,0x99a3,0x99a8,0x99aa,0x99b5,0x99b8,0x99bd,0x99c1,0x99c5,0x99c7,0x99c7,0x99c9,0x99c9,0x99cb,0x99dd,0x99df,0x99e7,0x99e9,0x99ea,0x99ec,0x99ee,0x99f0,0x99f1,0x99f4,0x99ff,0x9a01,0x9a07,0x9a09,0x9a11,0x9a14,0x9a16,0x9a19,0x9a27,0x9a29,0x9a32,0x9a34,0x9a46,0x9a48,0x9a4a,0x9a4c,0x9a50,0x9a52,0x9a5c,0x9a5e,0x9a60,0x9a62,0x9a6c,0x9a8f,0x9a8f,0x9aa8,0x9aa8,0x9aab,0x9aab,0x9aad,0x9aad,0x9aaf,0x9ab4,0x9ab6,0x9ac2,0x9ac6,0x9ac7,0x9aca,0x9aca,0x9acd,0x9acd,0x9acf,0x9ad8,0x9adc,0x9adc,0x9adf,0x9ae3,0x9ae6,0x9ae7,0x9aeb,0x9aef,0x9af1,0x9af4,0x9af6,0x9af7,0x9af9,0x9aff,0x9b01,0x9b06,0x9b08,0x9b12,0x9b14,0x9b1a,0x9b1e,0x9b20,0x9b22,0x9b25,0x9b27,0x9b2b,0x9b2d,0x9b2f,0x9b31,0x9b35,0x9b37,0x9b37,0x9b39,0x9b3c,0x9b3e,0x9b46,0x9b48,0x9b48,0x9b4a,0x9b52,0x9b54,0x9b56,0x9b58,0x9b5b,0x9b5f,0x9b61,0x9b64,0x9b64,0x9b66,0x9b69,0x9b6c,0x9b6c,0x9b6f,0x9b71,0x9b74,0x9b77,0x9b7a,0x9b83,0x9b85,0x9b88,0x9b8b,0x9b8b,0x9b8d,0x9b93,0x9b95,0x9b95,0x9b97,0x9b97,0x9b9a,0x9b9b,0x9b9d,0x9ba2,0x9ba4,0x9ba6,0x9ba8,0x9ba8,0x9baa,0x9bab,0x9bad,0x9bb0,0x9bb5,0x9bb6,0x9bb8,0x9bb9,0x9bbd,0x9bbd,0x9bbf,0x9bc1,0x9bc3,0x9bc4,0x9bc6,0x9bca,0x9bcf,0x9bcf,0x9bd3,0x9bd7,0x9bd9,0x9bde,0x9be0,0x9be2,0x9be4,0x9bed,0x9bf0,0x9bf1,0x9bf4,0x9bf4,0x9bf7,0x9bf8,0x9bfd,0x9bfd,0x9bff,0x9bff,0x9c02,0x9c02,0x9c05,0x9c0e,0x9c10,0x9c10,0x9c12,0x9c15,0x9c17,0x9c17,0x9c1b,0x9c1d,0x9c1f,0x9c21,0x9c23,0x9c26,0x9c28,0x9c29,0x9c2b,0x9c2d,0x9c2f,0x9c2f,0x9c31,0x9c37,0x9c39,0x9c41,0x9c44,0x9c50,0x9c52,0x9c59,0x9c5d,0x9c60,0x9c62,0x9c63,0x9c66,0x9c68,0x9c6d,0x9c6e,0x9c71,0x9c75,0x9c77,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9cea,0x9ced,0x9ced,0x9cf1,0x9cf7,0x9cf9,0x9cfd,0x9cff,0x9d00,0x9d02,0x9d09,0x9d0c,0x9d0c,0x9d10,0x9d10,0x9d12,0x9d12,0x9d14,0x9d19,0x9d1b,0x9d1b,0x9d1d,0x9d23,0x9d25,0x9d26,0x9d28,0x9d29,0x9d2d,0x9d31,0x9d33,0x9d34,0x9d36,0x9d39,0x9d3b,0x9d3b,0x9d3d,0x9d45,0x9d49,0x9d4c,0x9d4e,0x9d54,0x9d56,0x9d61,0x9d67,0x9d75,0x9d77,0x9d79,0x9d7b,0x9d8c,0x9d90,0x9d90,0x9d92,0x9d94,0x9d96,0x9dad,0x9daf,0x9daf,0x9db1,0x9dc5,0x9dc7,0x9ddf,0x9de1,0x9de6,0x9de8,0x9de9,0x9deb,0x9df0,0x9df2,0x9e07,0x9e09,0x9e15,0x9e17,0x9e1f,0x9e75,0x9e75,0x9e79,0x9e7d,0x9e7f,0x9e8e,0x9e90,0x9ea2,0x9ea4,0x9eb1,0x9eb4,0x9eb7,0x9ebb,0x9ec4,0x9ec6,0x9ec8,0x9ecc,0x9ed1,0x9ed3,0x9ed6,0x9ed8,0x9ed8,0x9eda,0x9ee0,0x9ee2,0x9ee2,0x9ee4,0x9ee8,0x9eeb,0x9eeb,0x9eed,0x9f02,0x9f06,0x9f0a,0x9f0e,0x9f10,0x9f12,0x9f13,0x9f15,0x9f1c,0x9f1e,0x9f1e,0x9f20,0x9f20,0x9f22,0x9f39,0x9f3b,0x9f3b,0x9f3d,0x9f3e,0x9f40,0x9f50,0x9f52,0x9f67,0x9f69,0x9f6c,0x9f6e,0x9f72,0x9f74,0x9f7b,0x9f7e,0x9f7f,0x9f8d,0x9f8e,0x9f90,0x9f92,0x9f94,0x9f99,0x9f9c,0x9f9c,0x9f9f,0x9fa0,0x9fa2,0x9fa2,0x9fa4,0x9fb3,0x9fc7,0x9fcb,0x9fd0,0x9fd0,0xf900,0xf908,0xf90b,0xf90d,0xf915,0xf915,0xf917,0xf917,0xf91a,0xf91a,0xf922,0xf922,0xf92d,0xf92d,0xf934,0xf934,0xf937,0xf937,0xf93a,0xf93a,0xf943,0xf943,0xf947,0xf948,0xf94a,0xf94a,0xf952,0xf952,0xf95e,0xf95e,0xf962,0xf962,0xf965,0xf965,0xf967,0xf967,0xf96d,0xf96d,0xf972,0xf972,0xf976,0xf976,0xf978,0xf979,0xf97b,0xf97b,0xf97e,0xf97e,0xf980,0xf980,0xf986,0xf986,0xf98a,0xf98a,0xf98e,0xf98e,0xf995,0xf995,0xf99c,0xf99d,0xf99f,0xf99f,0xf9b5,0xf9b5,0xf9bb,0xf9bb,0xf9bd,0xf9be,0xf9c5,0xf9c6,0xf9c8,0xf9c8,0xf9d0,0xf9d0,0xf9d8,0xf9d9,0xf9dc,0xf9de,0xf9e0,0xf9e0,0xf9e2,0xf9e4,0xf9e7,0xf9e7,0xf9e9,0xf9e9,0xf9f4,0xf9f5,0xf9fa,0xf9fa,0xf9fd,0xf9fd,0xf9ff,0xf9ff,0xfa02,0xfa02,0xfa05,0xfa08,0xfa0a,0xfa0a,0xfa0c,0xfa0d,0xfa33,0xfa35,0xfa3a,0xfa3a,0xfa49,0xfa49,0xfa4b,0xfa4b,0xfa5d,0xfa5e,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x20021,0x20021,0x2003e,0x2003e,0x20046,0x20046,0x2004e,0x2004e,0x20068,0x20068,0x20086,0x20087,0x2008a,0x2008a,0x20094,0x20094,0x200ca,0x200cd,0x200d1,0x200d1,0x200ee,0x200ee,0x2010c,0x2010c,0x2010e,0x2010e,0x20118,0x20118,0x201a4,0x201a4,0x201a9,0x201a9,0x201ab,0x201ab,0x201c1,0x201c1,0x201d4,0x201d4,0x201f2,0x201f2,0x20204,0x20204,0x2020c,0x2020c,0x20214,0x20214,0x20239,0x20239,0x2025b,0x2025b,0x20274,0x20275,0x20299,0x20299,0x2029e,0x2029e,0x202a0,0x202a0,0x202b7,0x202b7,0x202bf,0x202c0,0x202e5,0x202e5,0x2030a,0x2030a,0x20325,0x20325,0x20341,0x20341,0x20345,0x20347,0x2037e,0x20380,0x203a0,0x203a0,0x203a7,0x203a7,0x203b5,0x203b5,0x203c9,0x203c9,0x203cb,0x203cb,0x203f5,0x203f5,0x203fc,0x203fc,0x20413,0x20414,0x2041f,0x2041f,0x20465,0x20465,0x20487,0x20487,0x2048e,0x2048e,0x20491,0x20492,0x204a3,0x204a3,0x204d7,0x204d7,0x204fc,0x204fc,0x204fe,0x204fe,0x20547,0x20547,0x2058e,0x2058e,0x205a5,0x205a5,0x205b3,0x205b3,0x205c3,0x205c3,0x205ca,0x205ca,0x205d0,0x205d0,0x205d5,0x205d5,0x205df,0x205e0,0x205eb,0x205eb,0x20611,0x20611,0x20615,0x20615,0x20619,0x2061a,0x20628,0x20628,0x20630,0x20630,0x20656,0x20656,0x20676,0x20676,0x2070e,0x2070e,0x20731,0x20731,0x20779,0x20779,0x2082c,0x2082c,0x20873,0x20873,0x208d5,0x208d5,0x20916,0x20916,0x20923,0x20923,0x20954,0x20954,0x20979,0x20979,0x209e7,0x209e7,0x20a11,0x20a11,0x20a50,0x20a50,0x20a6f,0x20a6f,0x20a8a,0x20a8a,0x20ab4,0x20ab4,0x20ac2,0x20ac2,0x20acd,0x20acd,0x20b0d,0x20b0d,0x20b8f,0x20b8f,0x20b9f,0x20b9f,0x20ba8,0x20ba9,0x20bbf,0x20bbf,0x20bc6,0x20bc6,0x20bcb,0x20bcb,0x20be2,0x20be2,0x20beb,0x20beb,0x20bfb,0x20bfb,0x20bff,0x20bff,0x20c0b,0x20c0b,0x20c0d,0x20c0d,0x20c20,0x20c20,0x20c34,0x20c34,0x20c3a,0x20c3b,0x20c41,0x20c43,0x20c53,0x20c53,0x20c65,0x20c65,0x20c77,0x20c78,0x20c7c,0x20c7c,0x20c8d,0x20c8d,0x20c96,0x20c96,0x20c9c,0x20c9c,0x20cb5,0x20cb5,0x20cb8,0x20cb8,0x20ccf,0x20ccf,0x20cd3,0x20cd6,0x20cdd,0x20cdd,0x20ced,0x20ced,0x20cff,0x20cff,0x20d15,0x20d15,0x20d28,0x20d28,0x20d31,0x20d32,0x20d46,0x20d49,0x20d4c,0x20d4e,0x20d6f,0x20d6f,0x20d71,0x20d71,0x20d74,0x20d74,0x20d7c,0x20d7c,0x20d7e,0x20d7f,0x20d96,0x20d96,0x20d9c,0x20d9c,0x20da7,0x20da7,0x20db2,0x20db2,0x20dc8,0x20dc8,0x20e04,0x20e04,0x20e09,0x20e0a,0x20e0d,0x20e11,0x20e16,0x20e16,0x20e1d,0x20e1d,0x20e4c,0x20e4c,0x20e6d,0x20e6d,0x20e73,0x20e73,0x20e75,0x20e7b,0x20e8c,0x20e8c,0x20e96,0x20e96,0x20e98,0x20e98,0x20e9d,0x20e9d,0x20ea2,0x20ea2,0x20eaa,0x20eac,0x20eb6,0x20eb6,0x20ed7,0x20ed8,0x20edd,0x20edd,0x20ef8,0x20efb,0x20f1d,0x20f1d,0x20f26,0x20f26,0x20f2d,0x20f2e,0x20f30,0x20f31,0x20f3b,0x20f3b,0x20f4c,0x20f4c,0x20f64,0x20f64,0x20f8d,0x20f8d,0x20f90,0x20f90,0x20fad,0x20fad,0x20fb4,0x20fb6,0x20fbc,0x20fbc,0x20fdf,0x20fdf,0x20fea,0x20fed,0x21014,0x21014,0x2101d,0x2101e,0x2104f,0x2104f,0x2105c,0x2105c,0x2106f,0x2106f,0x21075,0x21078,0x2107b,0x2107b,0x21088,0x21088,0x21096,0x21096,0x2109d,0x2109d,0x210b4,0x210b4,0x210bf,0x210c1,0x210c7,0x210c9,0x210cf,0x210cf,0x210d3,0x210d3,0x210e4,0x210e4,0x210f4,0x210f6,0x2112f,0x2112f,0x2113b,0x2113b,0x2113d,0x2113d,0x21145,0x21145,0x21148,0x21148,0x2114f,0x2114f,0x21180,0x21180,0x21187,0x21187,0x211d9,0x211d9,0x2123c,0x2123c,0x2124f,0x2124f,0x2127c,0x2127c,0x212a8,0x212a9,0x212b0,0x212b0,0x212e3,0x212e3,0x212fe,0x212fe,0x21302,0x21305,0x21336,0x21336,0x2133a,0x2133a,0x21375,0x21376,0x2138e,0x2138e,0x21398,0x21398,0x2139c,0x2139c,0x213c5,0x213c6,0x213ed,0x213ed,0x213fe,0x213fe,0x21413,0x21413,0x21416,0x21416,0x21424,0x21424,0x2143f,0x2143f,0x21452,0x21452,0x21454,0x21455,0x2148a,0x2148a,0x21497,0x21497,0x214b6,0x214b6,0x214e8,0x214e8,0x214fd,0x214fd,0x21577,0x21577,0x21582,0x21582,0x21596,0x21596,0x2160a,0x2160a,0x21613,0x21613,0x21619,0x21619,0x2163e,0x2163e,0x21661,0x21661,0x21692,0x21692,0x216b8,0x216b8,0x216ba,0x216ba,0x216c0,0x216c2,0x216d3,0x216d3,0x216d5,0x216d5,0x216df,0x216df,0x216e6,0x216e8,0x216fa,0x216fc,0x216fe,0x216fe,0x2170d,0x2170d,0x21710,0x21710,0x21726,0x21726,0x2173a,0x2173c,0x21757,0x21757,0x2176c,0x21771,0x21773,0x21774,0x217ab,0x217ab,0x217b0,0x217b5,0x217c3,0x217c3,0x217c7,0x217c7,0x217d9,0x217dc,0x217df,0x217df,0x217ef,0x217ef,0x217f5,0x217f6,0x217f8,0x217fc,0x21820,0x21820,0x21828,0x2182a,0x2182d,0x2182d,0x21839,0x2183b,0x21840,0x21840,0x21845,0x21845,0x21852,0x21852,0x2185e,0x2185e,0x21861,0x21864,0x21877,0x21877,0x2187b,0x2187b,0x21883,0x21885,0x2189e,0x218a2,0x218be,0x218bf,0x218d1,0x218d1,0x218d6,0x218d9,0x218fa,0x218fa,0x21903,0x21905,0x21910,0x21912,0x21915,0x21915,0x2191c,0x2191c,0x21922,0x21922,0x21927,0x21927,0x2193b,0x2193b,0x21944,0x21944,0x21958,0x21958,0x2196a,0x2196a,0x2197c,0x2197c,0x21980,0x21980,0x21983,0x21983,0x21988,0x21988,0x21996,0x21996,0x219db,0x219db,0x219f3,0x219f3,0x21a2d,0x21a2d,0x21a34,0x21a34,0x21a45,0x21a45,0x21a4b,0x21a4b,0x21a63,0x21a63,0x21b44,0x21b44,0x21bc1,0x21bc2,0x21c2a,0x21c2a,0x21c70,0x21c70,0x21ca2,0x21ca2,0x21ca5,0x21ca5,0x21cac,0x21cac,0x21d46,0x21d46,0x21d53,0x21d53,0x21d5e,0x21d5e,0x21d90,0x21d90,0x21db6,0x21db6,0x21dba,0x21dba,0x21dca,0x21dca,0x21dd1,0x21dd1,0x21deb,0x21deb,0x21df9,0x21df9,0x21e1c,0x21e1c,0x21e23,0x21e23,0x21e37,0x21e37,0x21e3d,0x21e3d,0x21e89,0x21e89,0x21ea4,0x21ea4,0x21ea8,0x21ea8,0x21ec8,0x21ec8,0x21ed5,0x21ed5,0x21f0f,0x21f0f,0x21f15,0x21f15,0x21f6a,0x21f6a,0x21f9e,0x21f9e,0x21fa1,0x21fa1,0x21fe8,0x21fe8,0x22045,0x22045,0x22049,0x22049,0x2207e,0x2207e,0x2209a,0x2209a,0x220c7,0x220c7,0x220fc,0x220fc,0x2212a,0x2212a,0x2215b,0x2215b,0x22173,0x22173,0x2217a,0x2217a,0x221a1,0x221a1,0x221c1,0x221c1,0x221c3,0x221c3,0x22208,0x22208,0x2227c,0x2227c,0x22321,0x22321,0x22325,0x22325,0x223bd,0x223bd,0x223d0,0x223d0,0x223d7,0x223d7,0x223fa,0x223fa,0x22465,0x22465,0x22471,0x22471,0x2248b,0x2248b,0x22491,0x22491,0x224b0,0x224b0,0x224bc,0x224bc,0x224c1,0x224c1,0x224c9,0x224c9,0x224cc,0x224cc,0x224ed,0x224ed,0x22513,0x22513,0x2251b,0x2251b,0x22530,0x22530,0x22554,0x22554,0x2258d,0x2258d,0x225af,0x225af,0x225be,0x225be,0x2261b,0x2261c,0x2262b,0x2262b,0x22668,0x22668,0x2267a,0x2267a,0x22696,0x22696,0x22698,0x22698,0x226f4,0x226f6,0x22712,0x22712,0x22714,0x22714,0x2271b,0x2271b,0x2271f,0x2271f,0x2272a,0x2272a,0x22775,0x22775,0x22781,0x22781,0x22796,0x22796,0x227b4,0x227b5,0x227cd,0x227cd,0x22803,0x22803,0x2285f,0x22860,0x22871,0x22871,0x228ad,0x228ad,0x228c1,0x228c1,0x228f7,0x228f7,0x22926,0x22926,0x22939,0x22939,0x2294f,0x2294f,0x22967,0x22967,0x2296b,0x2296b,0x22980,0x22980,0x22993,0x22993,0x22a66,0x22a66,0x22acf,0x22acf,0x22ad5,0x22ad5,0x22ae6,0x22ae6,0x22ae8,0x22ae8,0x22b0e,0x22b0e,0x22b22,0x22b22,0x22b3f,0x22b3f,0x22b43,0x22b43,0x22b6a,0x22b6a,0x22bca,0x22bca,0x22bce,0x22bce,0x22c26,0x22c27,0x22c38,0x22c38,0x22c4c,0x22c4c,0x22c51,0x22c51,0x22c55,0x22c55,0x22c62,0x22c62,0x22c88,0x22c88,0x22c9b,0x22c9b,0x22ca1,0x22ca1,0x22ca9,0x22ca9,0x22cb2,0x22cb2,0x22cb7,0x22cb7,0x22cc2,0x22cc2,0x22cc6,0x22cc6,0x22cc9,0x22cc9,0x22d07,0x22d08,0x22d12,0x22d12,0x22d44,0x22d44,0x22d4c,0x22d4c,0x22d67,0x22d67,0x22d8d,0x22d8d,0x22d95,0x22d95,0x22da0,0x22da0,0x22da3,0x22da4,0x22db7,0x22db7,0x22dee,0x22dee,0x22e0d,0x22e0d,0x22e36,0x22e36,0x22e42,0x22e42,0x22e78,0x22e78,0x22e8b,0x22e8b,0x22eb3,0x22eb3,0x22eef,0x22eef,0x22f74,0x22f74,0x22fcc,0x22fcc,0x22fe3,0x22fe3,0x23033,0x23033,0x23044,0x23044,0x2304b,0x2304b,0x23066,0x23066,0x2307d,0x2307e,0x2308e,0x2308e,0x230b7,0x230b7,0x230bc,0x230bc,0x230da,0x230da,0x23103,0x23103,0x2313d,0x2313d,0x2317d,0x2317d,0x23182,0x23182,0x231a4,0x231a5,0x231b3,0x231b3,0x231c8,0x231c9,0x231ea,0x231ea,0x231f7,0x231f9,0x2320f,0x2320f,0x23225,0x23225,0x2322f,0x2322f,0x23231,0x23234,0x23256,0x23256,0x2325e,0x2325e,0x23262,0x23262,0x23281,0x23281,0x23289,0x2328a,0x232ab,0x232ad,0x232d2,0x232d2,0x232e0,0x232e1,0x23300,0x23300,0x2330a,0x2330a,0x2331f,0x2331f,0x233b4,0x233b4,0x233cc,0x233cc,0x233de,0x233de,0x233e6,0x233e6,0x233f4,0x233f5,0x233f9,0x233fa,0x233fe,0x233fe,0x23400,0x23400,0x2343f,0x2343f,0x23450,0x23450,0x2346f,0x2346f,0x23472,0x23472,0x234e5,0x234e5,0x23519,0x23519,0x23530,0x23530,0x23551,0x23551,0x2355a,0x2355a,0x23567,0x23567,0x23595,0x23595,0x23599,0x23599,0x2359c,0x2359c,0x235bb,0x235bb,0x235cd,0x235cf,0x235f3,0x235f3,0x23600,0x23600,0x23617,0x23617,0x2361a,0x2361a,0x2363c,0x2363c,0x23640,0x23640,0x23659,0x23659,0x2365f,0x2365f,0x23677,0x23677,0x2368e,0x2368e,0x2369e,0x2369e,0x236a6,0x236a6,0x236ad,0x236ad,0x236ba,0x236ba,0x236df,0x236df,0x236ee,0x236ee,0x23703,0x23703,0x23716,0x23716,0x23720,0x23720,0x2372d,0x2372d,0x2372f,0x2372f,0x2373f,0x2373f,0x23766,0x23766,0x23781,0x23781,0x237a2,0x237a2,0x237bc,0x237bc,0x237c2,0x237c2,0x237d5,0x237d7,0x2383a,0x2383a,0x239c2,0x239c2,0x23aa7,0x23aa7,0x23adb,0x23adb,0x23aee,0x23aee,0x23afa,0x23afa,0x23b1a,0x23b1a,0x23b5a,0x23b5a,0x23c63,0x23c63,0x23c99,0x23c9b,0x23cb5,0x23cb5,0x23cb7,0x23cb7,0x23cc7,0x23cc9,0x23cfc,0x23cff,0x23d40,0x23d40,0x23d5b,0x23d5b,0x23d7e,0x23d7e,0x23d8f,0x23d8f,0x23db6,0x23dbd,0x23de3,0x23de3,0x23df8,0x23df8,0x23e06,0x23e06,0x23e11,0x23e11,0x23e2c,0x23e31,0x23e39,0x23e39,0x23e88,0x23e8b,0x23eb9,0x23eb9,0x23ebf,0x23ebf,0x23ed7,0x23ed7,0x23ef7,0x23efc,0x23f35,0x23f35,0x23f41,0x23f41,0x23f4a,0x23f4a,0x23f61,0x23f61,0x23f7f,0x23f82,0x23f8f,0x23f8f,0x23fb4,0x23fb4,0x23fb7,0x23fb7,0x23fc0,0x23fc0,0x23fc5,0x23fc5,0x23feb,0x23ff0,0x24011,0x24011,0x24039,0x2403d,0x24057,0x24057,0x24085,0x24085,0x2408b,0x2408d,0x24091,0x24091,0x240c9,0x240c9,0x240e1,0x240e1,0x240ec,0x240ec,0x24104,0x24104,0x2410f,0x2410f,0x24119,0x24119,0x2413f,0x24140,0x24144,0x24144,0x2414e,0x2414e,0x24155,0x24157,0x2415c,0x2415c,0x2415f,0x2415f,0x24161,0x24161,0x24177,0x24177,0x2417a,0x2417a,0x241a3,0x241a5,0x241ac,0x241ac,0x241b5,0x241b5,0x241cd,0x241cd,0x241e2,0x241e2,0x241fc,0x241fc,0x2421b,0x2421b,0x2424b,0x2424b,0x24256,0x24256,0x24259,0x24259,0x24276,0x24278,0x24284,0x24284,0x24293,0x24293,0x24295,0x24295,0x242a5,0x242a5,0x242bf,0x242bf,0x242c1,0x242c1,0x242c9,0x242ca,0x242ee,0x242ee,0x242fa,0x242fa,0x2430d,0x2430d,0x2431a,0x2431a,0x24334,0x24334,0x24348,0x24348,0x24362,0x24365,0x2438c,0x2438c,0x24396,0x24396,0x2439c,0x2439c,0x243bd,0x243bd,0x243c1,0x243c1,0x243e9,0x243ea,0x243f2,0x243f2,0x243f8,0x243f8,0x24404,0x24404,0x24435,0x24436,0x2445a,0x2445b,0x24473,0x24473,0x24487,0x24488,0x244b9,0x244b9,0x244bc,0x244bc,0x244ce,0x244ce,0x244d3,0x244d3,0x244d6,0x244d6,0x24505,0x24505,0x24521,0x24521,0x24578,0x24578,0x245c8,0x245c8,0x24618,0x24618,0x2462a,0x2462a,0x24665,0x24665,0x24674,0x24674,0x24697,0x24697,0x246d4,0x246d4,0x24706,0x24706,0x24725,0x24725,0x2472f,0x2472f,0x2478f,0x2478f,0x247e0,0x247e0,0x24812,0x24812,0x24823,0x24823,0x24882,0x24882,0x248e9,0x248e9,0x248f0,0x248f3,0x248fb,0x248fb,0x248ff,0x24901,0x2490c,0x2490c,0x24916,0x24917,0x24919,0x24919,0x2492f,0x2492f,0x24933,0x24934,0x2493e,0x24943,0x24962,0x24963,0x24974,0x24976,0x2497b,0x2497b,0x2497f,0x2497f,0x24982,0x24982,0x24988,0x2498f,0x24994,0x24994,0x249a4,0x249a4,0x249a7,0x249a7,0x249a9,0x249a9,0x249ab,0x249ad,0x249b7,0x249bb,0x249c5,0x249c5,0x249d0,0x249d0,0x249da,0x249da,0x249de,0x249df,0x249e3,0x249e3,0x249e5,0x249e5,0x249ec,0x249ed,0x249f6,0x249f9,0x249fb,0x249fb,0x24a0e,0x24a0e,0x24a12,0x24a13,0x24a15,0x24a15,0x24a21,0x24a2a,0x24a3e,0x24a3e,0x24a42,0x24a42,0x24a45,0x24a45,0x24a4a,0x24a4a,0x24a4e,0x24a51,0x24a5d,0x24a5d,0x24a65,0x24a67,0x24a71,0x24a71,0x24a77,0x24a7a,0x24a8c,0x24a8c,0x24a93,0x24a96,0x24aa4,0x24aa7,0x24ab1,0x24ab3,0x24aba,0x24abc,0x24ac0,0x24ac0,0x24ac7,0x24ac7,0x24aca,0x24aca,0x24ad1,0x24ad1,0x24adf,0x24adf,0x24ae2,0x24ae2,0x24ae9,0x24ae9,0x24b0f,0x24b0f,0x24b6e,0x24b6e,0x24bf5,0x24bf5,0x24c09,0x24c09,0x24c9e,0x24c9f,0x24cc9,0x24cc9,0x24cd9,0x24cd9,0x24d06,0x24d06,0x24d13,0x24d13,0x24db8,0x24db8,0x24dea,0x24deb,0x24e3b,0x24e3b,0x24e50,0x24e50,0x24ea5,0x24ea5,0x24ea7,0x24ea7,0x24f0e,0x24f0e,0x24f5c,0x24f5c,0x24f82,0x24f82,0x24f86,0x24f86,0x24f97,0x24f97,0x24f9a,0x24f9a,0x24fa9,0x24fa9,0x24fb8,0x24fb8,0x24fc2,0x24fc2,0x2502c,0x2502c,0x25052,0x25052,0x2509d,0x2509d,0x2512b,0x2512b,0x25148,0x25148,0x2517d,0x2517e,0x251cd,0x251cd,0x251e3,0x251e3,0x251e6,0x251e7,0x25220,0x25221,0x25250,0x25250,0x25299,0x25299,0x252c7,0x252c7,0x252d8,0x252d8,0x2530e,0x2530e,0x25311,0x25311,0x25313,0x25313,0x25419,0x25419,0x25425,0x25425,0x2542f,0x25430,0x25446,0x25446,0x2546c,0x2546c,0x2546e,0x2546e,0x2549a,0x2549a,0x25531,0x25531,0x25535,0x25535,0x2553f,0x2553f,0x2555b,0x2555e,0x25562,0x25562,0x25565,0x25566,0x25581,0x25581,0x25584,0x25584,0x2558f,0x2558f,0x255b9,0x255b9,0x255d5,0x255d5,0x255db,0x255db,0x255e0,0x255e0,0x25605,0x25605,0x25635,0x25635,0x25651,0x25651,0x25683,0x25683,0x25695,0x25695,0x256e3,0x256e3,0x256f6,0x256f6,0x25706,0x25706,0x2571d,0x2571d,0x25725,0x25725,0x2573d,0x2573d,0x25772,0x25772,0x257c7,0x257c7,0x257df,0x257e1,0x25857,0x25857,0x2585d,0x2585d,0x25872,0x25872,0x258c8,0x258c8,0x258de,0x258de,0x258e1,0x258e1,0x25903,0x25903,0x25946,0x25946,0x25956,0x25956,0x259ac,0x259ac,0x259cc,0x259cc,0x25a54,0x25a54,0x25a95,0x25a95,0x25a9c,0x25a9c,0x25aae,0x25aaf,0x25ad7,0x25ad7,0x25ae9,0x25ae9,0x25b74,0x25b74,0x25b89,0x25b89,0x25bb3,0x25bb4,0x25bc6,0x25bc6,0x25be4,0x25be4,0x25be8,0x25be8,0x25c01,0x25c01,0x25c06,0x25c06,0x25c21,0x25c21,0x25c4a,0x25c4a,0x25c65,0x25c65,0x25c91,0x25c91,0x25ca4,0x25ca4,0x25cc0,0x25cc1,0x25cfe,0x25cfe,0x25d20,0x25d20,0x25d30,0x25d30,0x25d43,0x25d43,0x25d99,0x25d99,0x25db9,0x25db9,0x25e0e,0x25e0e,0x25e49,0x25e49,0x25e81,0x25e83,0x25ea6,0x25ea6,0x25ebc,0x25ebc,0x25ed7,0x25ed8,0x25f1a,0x25f1a,0x25f4b,0x25f4b,0x25fe1,0x25fe2,0x26021,0x26021,0x26029,0x26029,0x26048,0x26048,0x26064,0x26064,0x26083,0x26083,0x26097,0x26097,0x260a4,0x260a5,0x26102,0x26102,0x26121,0x26121,0x26159,0x2615c,0x261ad,0x261ae,0x261b2,0x261b2,0x261dd,0x261dd,0x26258,0x26258,0x26261,0x26261,0x2626a,0x2626b,0x262d0,0x262d0,0x26335,0x26335,0x2634b,0x2634c,0x26351,0x26351,0x263be,0x263be,0x263f5,0x263f5,0x263f8,0x263f8,0x26402,0x26402,0x26410,0x26412,0x2644a,0x2644a,0x26469,0x26469,0x26484,0x26484,0x26488,0x26489,0x2648d,0x2648d,0x26498,0x26498,0x26512,0x26512,0x26572,0x26572,0x265a0,0x265a0,0x265ad,0x265ad,0x265bf,0x265bf,0x26612,0x26612,0x26626,0x26626,0x266af,0x266af,0x266b1,0x266b1,0x266b5,0x266b5,0x266da,0x266da,0x266e8,0x266e8,0x266fc,0x266fc,0x26716,0x26716,0x26741,0x26741,0x26799,0x26799,0x267b3,0x267b4,0x267cc,0x267cc,0x2681c,0x2681c,0x26846,0x26846,0x2685e,0x2685e,0x2686e,0x2686e,0x26888,0x26888,0x2688a,0x2688a,0x26893,0x26893,0x268c7,0x268c7,0x2690e,0x2690e,0x26911,0x26911,0x26926,0x26926,0x26939,0x26939,0x26951,0x26951,0x269a8,0x269a8,0x269b5,0x269b5,0x269f2,0x269f2,0x269fa,0x269fa,0x26a2d,0x26a2e,0x26a34,0x26a34,0x26a42,0x26a42,0x26a51,0x26a52,0x26b05,0x26b05,0x26b0a,0x26b0a,0x26b13,0x26b13,0x26b15,0x26b15,0x26b23,0x26b23,0x26b28,0x26b28,0x26b50,0x26b53,0x26b5b,0x26b5b,0x26b75,0x26b75,0x26b82,0x26b82,0x26b96,0x26b97,0x26b9d,0x26b9d,0x26bb3,0x26bb3,0x26bc0,0x26bc0,0x26bf7,0x26bf7,0x26c21,0x26c21,0x26c40,0x26c41,0x26c46,0x26c46,0x26c7e,0x26c82,0x26ca4,0x26ca4,0x26cb7,0x26cb8,0x26cbd,0x26cbd,0x26cc0,0x26cc0,0x26cc3,0x26cc3,0x26cd1,0x26cd1,0x26d22,0x26d2a,0x26d51,0x26d51,0x26d74,0x26d74,0x26da0,0x26da7,0x26dae,0x26dae,0x26ddc,0x26ddc,0x26dea,0x26deb,0x26df0,0x26df0,0x26e00,0x26e00,0x26e05,0x26e05,0x26e07,0x26e07,0x26e12,0x26e12,0x26e42,0x26e45,0x26e6e,0x26e6e,0x26e72,0x26e72,0x26e77,0x26e77,0x26e84,0x26e84,0x26e88,0x26e88,0x26e8b,0x26e8b,0x26e99,0x26e99,0x26ed0,0x26ed7,0x26f26,0x26f26,0x26f73,0x26f74,0x26f9f,0x26f9f,0x26fa1,0x26fa1,0x26fbe,0x26fbe,0x26fde,0x26fdf,0x2700e,0x2700e,0x2704b,0x2704b,0x27052,0x27053,0x27088,0x27088,0x270ad,0x270af,0x270cd,0x270cd,0x270d2,0x270d2,0x270f0,0x270f0,0x270f8,0x270f8,0x27109,0x27109,0x2710c,0x2710d,0x27126,0x27127,0x27164,0x27165,0x27175,0x27175,0x271cd,0x271cd,0x2721b,0x2721b,0x27267,0x27267,0x27280,0x27280,0x27285,0x27285,0x2728b,0x2728b,0x272b2,0x272b2,0x272b6,0x272b6,0x272e6,0x272e6,0x27352,0x27352,0x2739a,0x2739a,0x273ff,0x273ff,0x27422,0x27422,0x27450,0x27450,0x27484,0x27484,0x27486,0x27486,0x27574,0x27574,0x275a3,0x275a3,0x275e0,0x275e0,0x275e4,0x275e4,0x275fd,0x275fe,0x27607,0x27607,0x2760c,0x2760c,0x27632,0x27632,0x27639,0x27639,0x27655,0x27657,0x27694,0x27694,0x2770f,0x2770f,0x27735,0x27736,0x27741,0x27741,0x2775e,0x2775e,0x27784,0x27785,0x277cc,0x277cc,0x27858,0x27858,0x27870,0x27870,0x2789d,0x2789d,0x278b2,0x278b2,0x278c8,0x278c8,0x27924,0x27924,0x27967,0x27967,0x2797a,0x2797a,0x279a0,0x279a0,0x279dd,0x279dd,0x279fd,0x279fd,0x27a0a,0x27a0a,0x27a0e,0x27a0e,0x27a3e,0x27a3e,0x27a53,0x27a53,0x27a59,0x27a59,0x27a79,0x27a79,0x27a84,0x27a84,0x27abd,0x27abe,0x27af4,0x27af4,0x27b06,0x27b06,0x27b0b,0x27b0b,0x27b18,0x27b18,0x27b38,0x27b3a,0x27b48,0x27b48,0x27b65,0x27b65,0x27bef,0x27bef,0x27bf4,0x27bf4,0x27c12,0x27c12,0x27c6c,0x27c6c,0x27cb1,0x27cb1,0x27cc5,0x27cc5,0x27d2f,0x27d2f,0x27d53,0x27d54,0x27d66,0x27d66,0x27d73,0x27d73,0x27d84,0x27d84,0x27d8f,0x27d8f,0x27d98,0x27d98,0x27dbd,0x27dbd,0x27ddc,0x27ddc,0x27e4d,0x27e4d,0x27e4f,0x27e4f,0x27f2e,0x27f2e,0x27fb7,0x27fb7,0x27ff9,0x27ff9,0x28002,0x28002,0x28009,0x28009,0x2801e,0x2801e,0x28023,0x28024,0x28048,0x28048,0x28083,0x28083,0x28090,0x28090,0x280bd,0x280be,0x280e8,0x280e9,0x280f4,0x280f4,0x2812e,0x2812e,0x2814f,0x2814f,0x2815d,0x2815d,0x2816f,0x2816f,0x28189,0x28189,0x281af,0x281af,0x281bc,0x281bc,0x28207,0x28207,0x28218,0x28218,0x2821a,0x2821a,0x28256,0x28256,0x2827c,0x2827c,0x2829b,0x2829b,0x282cd,0x282cd,0x282e2,0x282e2,0x28306,0x28306,0x28318,0x28318,0x2832f,0x2832f,0x2833a,0x2833a,0x28365,0x28365,0x2836d,0x2836d,0x2837d,0x2837d,0x2838a,0x2838a,0x28412,0x28412,0x28468,0x28468,0x2846c,0x2846c,0x28473,0x28473,0x28482,0x28482,0x28501,0x28501,0x2853c,0x2853d,0x2856c,0x2856c,0x285e8,0x285e8,0x285f4,0x285f4,0x28600,0x28600,0x2860b,0x2860b,0x28625,0x28625,0x2863b,0x2863b,0x286aa,0x286ab,0x286b2,0x286b2,0x286bc,0x286bc,0x286d8,0x286d8,0x286e6,0x286e6,0x2870f,0x2870f,0x28713,0x28713,0x28804,0x28804,0x2882b,0x2882b,0x2890d,0x2890d,0x28933,0x28933,0x28948,0x28949,0x28956,0x28956,0x28964,0x28964,0x28968,0x28968,0x2896c,0x2896d,0x2897e,0x2897e,0x28989,0x28989,0x289a8,0x289a8,0x289aa,0x289ab,0x289b8,0x289b8,0x289bc,0x289bc,0x289c0,0x289c0,0x289dc,0x289dc,0x289de,0x289de,0x289e1,0x289e1,0x289e3,0x289e4,0x289e7,0x289e8,0x289f9,0x289fc,0x28a0f,0x28a0f,0x28a16,0x28a16,0x28a25,0x28a25,0x28a29,0x28a29,0x28a32,0x28a32,0x28a36,0x28a36,0x28a44,0x28a4b,0x28a59,0x28a5a,0x28a81,0x28a83,0x28a9a,0x28a9c,0x28ac0,0x28ac0,0x28ac6,0x28ac6,0x28acb,0x28acc,0x28ace,0x28ace,0x28ade,0x28ae3,0x28ae5,0x28ae5,0x28aea,0x28aea,0x28afc,0x28afc,0x28b0c,0x28b0c,0x28b13,0x28b13,0x28b21,0x28b22,0x28b2b,0x28b2d,0x28b2f,0x28b2f,0x28b46,0x28b46,0x28b4c,0x28b4c,0x28b4e,0x28b4e,0x28b50,0x28b50,0x28b63,0x28b66,0x28b6c,0x28b6c,0x28b8f,0x28b8f,0x28b99,0x28b99,0x28b9c,0x28b9d,0x28bb9,0x28bb9,0x28bc2,0x28bc2,0x28bc5,0x28bc5,0x28bd4,0x28bd4,0x28bd7,0x28bd7,0x28bd9,0x28bda,0x28be7,0x28bec,0x28bf5,0x28bf5,0x28bff,0x28bff,0x28c03,0x28c03,0x28c09,0x28c09,0x28c1c,0x28c1d,0x28c23,0x28c23,0x28c26,0x28c26,0x28c2b,0x28c2b,0x28c30,0x28c30,0x28c39,0x28c39,0x28c3b,0x28c3b,0x28cca,0x28cca,0x28ccd,0x28ccd,0x28cd2,0x28cd2,0x28d34,0x28d34,0x28d99,0x28d99,0x28db9,0x28db9,0x28e0f,0x28e0f,0x28e36,0x28e36,0x28e39,0x28e39,0x28e65,0x28e66,0x28e97,0x28e97,0x28eac,0x28eac,0x28eb2,0x28eb3,0x28ed9,0x28ed9,0x28ee7,0x28ee7,0x28fc5,0x28fc5,0x29079,0x29079,0x29088,0x29088,0x2908b,0x2908b,0x29093,0x29093,0x290af,0x290b1,0x290c0,0x290c0,0x290e4,0x290e5,0x290ec,0x290ed,0x2910d,0x2910d,0x29110,0x29110,0x2913c,0x2913c,0x2914d,0x2914d,0x2915b,0x2915b,0x2915e,0x2915e,0x29170,0x29170,0x2919c,0x2919c,0x291a8,0x291a8,0x291d5,0x291d5,0x291eb,0x291eb,0x2941d,0x2941d,0x29420,0x29420,0x29433,0x29433,0x2943f,0x2943f,0x29448,0x29448,0x294d0,0x294d0,0x294d9,0x294da,0x294e5,0x294e5,0x294e7,0x294e7,0x2959e,0x2959e,0x295b0,0x295b0,0x295b8,0x295b8,0x295d7,0x295d7,0x295e9,0x295e9,0x295f4,0x295f4,0x2967f,0x2967f,0x29720,0x29720,0x29732,0x29732,0x297d4,0x297d4,0x29810,0x29810,0x29857,0x29857,0x298a4,0x298a4,0x298d1,0x298d1,0x298ea,0x298ea,0x298f1,0x298f1,0x298fa,0x298fa,0x29903,0x29903,0x29905,0x29905,0x2992f,0x2992f,0x29945,0x29945,0x29947,0x29949,0x2995d,0x2995d,0x2996a,0x2996a,0x2999d,0x2999d,0x299c3,0x299c3,0x299c9,0x299c9,0x29a28,0x29a28,0x29a4d,0x29a4d,0x29b05,0x29b05,0x29b0e,0x29b0e,0x29bd5,0x29bd5,0x29c73,0x29c73,0x29cad,0x29cad,0x29d3e,0x29d3e,0x29d5a,0x29d5a,0x29d7c,0x29d7c,0x29d98,0x29d98,0x29d9b,0x29d9b,0x29df6,0x29df6,0x29e06,0x29e06,0x29e2d,0x29e2d,0x29e68,0x29e68,0x29eac,0x29eac,0x29eb0,0x29eb0,0x29ec3,0x29ec3,0x29ef8,0x29ef8,0x29f23,0x29f23,0x29f30,0x29f30,0x29fb7,0x29fb7,0x29fde,0x29fde,0x2a014,0x2a014,0x2a087,0x2a087,0x2a0b9,0x2a0b9,0x2a0e1,0x2a0e1,0x2a0ed,0x2a0ed,0x2a0f3,0x2a0f3,0x2a0f8,0x2a0f8,0x2a0fe,0x2a0fe,0x2a107,0x2a107,0x2a123,0x2a123,0x2a133,0x2a134,0x2a150,0x2a150,0x2a192,0x2a193,0x2a1ab,0x2a1ab,0x2a1b4,0x2a1b5,0x2a1df,0x2a1df,0x2a1f5,0x2a1f5,0x2a220,0x2a220,0x2a233,0x2a233,0x2a293,0x2a293,0x2a29f,0x2a29f,0x2a2b2,0x2a2b2,0x2a2b4,0x2a2b4,0x2a2b6,0x2a2b6,0x2a2ba,0x2a2ba,0x2a2bd,0x2a2bd,0x2a2df,0x2a2df,0x2a2ff,0x2a2ff,0x2a351,0x2a351,0x2a3a9,0x2a3a9,0x2a3ed,0x2a3ed,0x2a434,0x2a434,0x2a45b,0x2a45b,0x2a5c6,0x2a5c6,0x2a5cb,0x2a5cb,0x2a601,0x2a601,0x2a632,0x2a632,0x2a64a,0x2a64a,0x2a65b,0x2a65b,0x2a6a9,0x2a6a9,0x2adff,0x2adff,0x2d544,0x2d544,0x2f825,0x2f825,0x2f83b,0x2f83b,0x2f840,0x2f840,0x2f878,0x2f878,0x2f894,0x2f894,0x2f8a6,0x2f8a6,0x2f8cd,0x2f8cd,0x2f8db,0x2f8db,0x2f994,0x2f994,0x2f9b2,0x2f9b2,0x2f9bc,0x2f9bc,0x2f9d4,0x2f9d4,0x30ede,0x30ede,0x3106c,0x3106c,]), + NotoFont.fromFlatRanges('Noto Sans Hanunoo', 'http://fonts.gstatic.com/s/notosanshanunoo/v15/f0Xs0fCv8dxkDWlZSoXOj6CphMloFsEsEpgL_ix2.ttf', [0x20,0x20,0xa0,0xa0,0x1720,0x1736,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Hatran', 'http://fonts.gstatic.com/s/notosanshatran/v15/A2BBn4Ne0RgnVF3Lnko-0sOBIfL_mM83r1nwzDs.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200c,0x108e0,0x108f2,0x108f4,0x108f5,0x108fb,0x108ff,]), + NotoFont.fromFlatRanges('Noto Sans Hebrew', 'http://fonts.gstatic.com/s/notosanshebrew/v38/or3HQ7v33eiDljA1IufXTtVf7V6RvEEdhQlk0LlGxCyaeNKYZC0sqk3xXGiXd4qtoiJltutR2g.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x34f,0x34f,0x591,0x5c7,0x5d0,0x5ea,0x5f0,0x5f4,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200c,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20aa,0x20aa,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xfb1d,0xfb36,0xfb38,0xfb3c,0xfb3e,0xfb3e,0xfb40,0xfb41,0xfb43,0xfb44,0xfb46,0xfb4f,]), + NotoFont.fromFlatRanges('Noto Sans Imperial Aramaic', 'http://fonts.gstatic.com/s/notosansimperialaramaic/v15/a8IMNpjwKmHXpgXbMIsbTc_kvks91LlLetBr5itQrtdml3YfPNno.ttf', [0x20,0x20,0xa0,0xa0,0x10840,0x10855,0x10857,0x1085f,]), + NotoFont.fromFlatRanges('Noto Sans Indic Siyaq Numbers', 'http://fonts.gstatic.com/s/notosansindicsiyaqnumbers/v15/6xK5dTJFKcWIu4bpRBjRZRpsIYHabOeZ8UZLubTzpXNHKx2WPOpVd5Iu.ttf', [0x20,0x20,0xa0,0xa0,0x627,0x627,0x660,0x669,0x6f0,0x6f9,0x1ec71,0x1ecb4,]), + NotoFont.fromFlatRanges('Noto Sans Inscriptional Pahlavi', 'http://fonts.gstatic.com/s/notosansinscriptionalpahlavi/v15/ll8UK3GaVDuxR-TEqFPIbsR79Xxz9WEKbwsjpz7VklYlC7FCVtqVOAYK0QA.ttf', [0x20,0x20,0xa0,0xa0,0x10b60,0x10b72,0x10b78,0x10b7f,]), + NotoFont.fromFlatRanges('Noto Sans Inscriptional Parthian', 'http://fonts.gstatic.com/s/notosansinscriptionalparthian/v15/k3k7o-IMPvpLmixcA63oYi-yStDkgXuXncL7dzfW3P4TAJ2yklBJ2jNkLlLr.ttf', [0x20,0x20,0xa0,0xa0,0x10b40,0x10b55,0x10b58,0x10b5f,]), + NotoFont.fromFlatRanges('Noto Sans JP', 'http://fonts.gstatic.com/s/notosansjp/v42/-F62fjtqLzI2JPCgQBnw7HFowAIO2lZ9hg.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x3402,0x3402,0x3405,0x3406,0x3427,0x3427,0x342c,0x342c,0x342e,0x342e,0x3468,0x3468,0x346a,0x346a,0x3488,0x3488,0x3492,0x3492,0x34b5,0x34b5,0x34bc,0x34bc,0x34c1,0x34c1,0x34c7,0x34c7,0x34db,0x34db,0x351f,0x351f,0x353e,0x353e,0x355d,0x355e,0x3563,0x3563,0x356e,0x356e,0x35a6,0x35a6,0x35a8,0x35a8,0x35c5,0x35c5,0x35da,0x35da,0x35de,0x35de,0x35f4,0x35f4,0x3605,0x3605,0x3614,0x3614,0x364a,0x364a,0x3691,0x3691,0x3696,0x3696,0x3699,0x3699,0x36cf,0x36cf,0x3761,0x3762,0x376b,0x376c,0x3775,0x3775,0x378d,0x378d,0x37c1,0x37c1,0x37e2,0x37e2,0x37e8,0x37e8,0x37f4,0x37f4,0x37fd,0x37fd,0x3800,0x3800,0x382f,0x382f,0x3836,0x3836,0x3840,0x3840,0x385c,0x385c,0x3861,0x3861,0x38a1,0x38a1,0x38ad,0x38ad,0x38fa,0x38fa,0x3917,0x3917,0x391a,0x391a,0x396f,0x396f,0x39a4,0x39a4,0x39b8,0x39b8,0x3a5c,0x3a5c,0x3a6e,0x3a6e,0x3a73,0x3a73,0x3a85,0x3a85,0x3ac4,0x3ac4,0x3acb,0x3acb,0x3ad6,0x3ad7,0x3aea,0x3aea,0x3af3,0x3af3,0x3b0e,0x3b0e,0x3b1a,0x3b1a,0x3b1c,0x3b1c,0x3b22,0x3b22,0x3b35,0x3b35,0x3b6d,0x3b6d,0x3b77,0x3b77,0x3b87,0x3b88,0x3b8d,0x3b8d,0x3ba4,0x3ba4,0x3bb6,0x3bb6,0x3bc3,0x3bc3,0x3bcd,0x3bcd,0x3bf0,0x3bf0,0x3bf3,0x3bf3,0x3c0f,0x3c0f,0x3c26,0x3c26,0x3cc3,0x3cc3,0x3cd2,0x3cd2,0x3d11,0x3d11,0x3d1e,0x3d1e,0x3d31,0x3d31,0x3d4e,0x3d4e,0x3d64,0x3d64,0x3d9a,0x3d9a,0x3dc0,0x3dc0,0x3dcc,0x3dcc,0x3dd4,0x3dd4,0x3e05,0x3e05,0x3e3f,0x3e40,0x3e60,0x3e60,0x3e66,0x3e66,0x3e68,0x3e68,0x3e83,0x3e83,0x3e8a,0x3e8a,0x3e94,0x3e94,0x3eda,0x3eda,0x3f57,0x3f57,0x3f72,0x3f72,0x3f75,0x3f75,0x3f77,0x3f77,0x3fae,0x3fae,0x3fb1,0x3fb1,0x3fc9,0x3fc9,0x3fd7,0x3fd7,0x3fdc,0x3fdc,0x4039,0x4039,0x4058,0x4058,0x4093,0x4093,0x4103,0x4103,0x4105,0x4105,0x4148,0x4148,0x414f,0x414f,0x4163,0x4163,0x41b4,0x41b4,0x41bf,0x41bf,0x41e6,0x41e6,0x41ee,0x41ee,0x41f3,0x41f3,0x4207,0x4207,0x420e,0x420e,0x4264,0x4264,0x4293,0x4293,0x42c6,0x42c6,0x42d6,0x42d6,0x42dd,0x42dd,0x4302,0x4302,0x432b,0x432b,0x4343,0x4343,0x43ee,0x43ee,0x43f0,0x43f0,0x4408,0x4408,0x440c,0x440c,0x4417,0x4417,0x441c,0x441c,0x4422,0x4422,0x4453,0x4453,0x445b,0x445b,0x4476,0x4476,0x447a,0x447a,0x4491,0x4491,0x44b3,0x44b3,0x44be,0x44be,0x44d4,0x44d4,0x4508,0x4508,0x450d,0x450d,0x4525,0x4525,0x4543,0x4543,0x457a,0x457a,0x459d,0x459d,0x45b8,0x45b8,0x45be,0x45be,0x45e5,0x45e5,0x45ea,0x45ea,0x460f,0x4610,0x4641,0x4641,0x4665,0x4665,0x46a1,0x46a1,0x46ae,0x46af,0x470c,0x470c,0x471f,0x471f,0x4764,0x4764,0x47e6,0x47e6,0x47fd,0x47fd,0x4816,0x4816,0x481e,0x481e,0x4844,0x4844,0x484e,0x484e,0x48b5,0x48b5,0x49b0,0x49b0,0x49e7,0x49e7,0x49fa,0x49fa,0x4a04,0x4a04,0x4a29,0x4a29,0x4abc,0x4abc,0x4b38,0x4b38,0x4b3b,0x4b3b,0x4b7e,0x4b7e,0x4bc2,0x4bc2,0x4bca,0x4bca,0x4bd2,0x4bd2,0x4be8,0x4be8,0x4c17,0x4c17,0x4c20,0x4c20,0x4c38,0x4c38,0x4cc4,0x4cc4,0x4cd1,0x4cd1,0x4ce1,0x4ce1,0x4d07,0x4d07,0x4d77,0x4d77,0x4e00,0x4e05,0x4e07,0x4e12,0x4e14,0x4e19,0x4e1e,0x4e1f,0x4e21,0x4e21,0x4e23,0x4e24,0x4e26,0x4e26,0x4e28,0x4e32,0x4e35,0x4e39,0x4e3b,0x4e3c,0x4e3f,0x4e45,0x4e47,0x4e48,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e51,0x4e51,0x4e55,0x4e5f,0x4e62,0x4e63,0x4e68,0x4e69,0x4e71,0x4e71,0x4e73,0x4e75,0x4e79,0x4e79,0x4e7e,0x4e80,0x4e82,0x4e82,0x4e85,0x4e86,0x4e88,0x4e8e,0x4e91,0x4e92,0x4e94,0x4e99,0x4e9b,0x4ea2,0x4ea4,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eb0,0x4eb3,0x4eb3,0x4eb6,0x4eb6,0x4eb9,0x4ebc,0x4ec0,0x4ec4,0x4ec6,0x4ec8,0x4eca,0x4ecb,0x4ecd,0x4ed0,0x4ed4,0x4edb,0x4edd,0x4ee5,0x4ee8,0x4ee8,0x4eeb,0x4eeb,0x4eed,0x4ef3,0x4ef5,0x4ef7,0x4efb,0x4f03,0x4f08,0x4f12,0x4f15,0x4f17,0x4f19,0x4f1a,0x4f1c,0x4f1d,0x4f2b,0x4f2b,0x4f2e,0x4f31,0x4f33,0x4f3e,0x4f40,0x4f40,0x4f42,0x4f43,0x4f46,0x4f49,0x4f4b,0x4f60,0x4f63,0x4f64,0x4f69,0x4f6a,0x4f6c,0x4f6c,0x4f6e,0x4f71,0x4f73,0x4f73,0x4f75,0x4f7f,0x4f81,0x4f86,0x4f88,0x4f94,0x4f96,0x4f9b,0x4f9d,0x4fa1,0x4fab,0x4fab,0x4fad,0x4faf,0x4fb2,0x4fb2,0x4fb5,0x4fb7,0x4fb9,0x4fb9,0x4fbb,0x4fc6,0x4fc8,0x4fd4,0x4fd7,0x4fd8,0x4fda,0x4fdd,0x4fdf,0x4fe6,0x4fee,0x4ff3,0x4ff5,0x4ff6,0x4ff8,0x4ff8,0x4ffa,0x4ffa,0x4ffc,0x5002,0x5004,0x5007,0x5009,0x5014,0x5016,0x501f,0x5021,0x502e,0x5030,0x5030,0x5032,0x5033,0x5035,0x5036,0x5039,0x5039,0x503b,0x503b,0x5040,0x5043,0x5045,0x504a,0x504c,0x504c,0x504e,0x5053,0x5055,0x5057,0x5059,0x505a,0x505c,0x505c,0x505f,0x5060,0x5062,0x5063,0x5065,0x5067,0x506a,0x506a,0x506c,0x506d,0x5070,0x5072,0x5074,0x5078,0x507d,0x507d,0x5080,0x5081,0x5083,0x5086,0x5088,0x5088,0x508a,0x508a,0x508d,0x5096,0x5098,0x509c,0x509e,0x50a3,0x50aa,0x50aa,0x50ac,0x50ad,0x50af,0x50b5,0x50b7,0x50b7,0x50b9,0x50bb,0x50bd,0x50be,0x50c0,0x50c0,0x50c2,0x50c5,0x50c7,0x50c7,0x50c9,0x50ca,0x50cc,0x50d1,0x50d3,0x50d6,0x50d8,0x50da,0x50dc,0x50df,0x50e1,0x50e9,0x50ed,0x50f6,0x50f9,0x50fb,0x50fe,0x50fe,0x5100,0x5104,0x5106,0x5109,0x510b,0x510e,0x5110,0x5110,0x5112,0x5112,0x5114,0x511f,0x5121,0x5121,0x5123,0x5123,0x5127,0x5128,0x512a,0x512a,0x512c,0x512d,0x512f,0x512f,0x5131,0x5135,0x5137,0x513c,0x513f,0x5150,0x5152,0x5155,0x5157,0x5158,0x515a,0x515a,0x515c,0x515c,0x515f,0x5160,0x5162,0x5162,0x5164,0x516e,0x5171,0x5171,0x5173,0x5179,0x517b,0x517c,0x517e,0x517e,0x5180,0x5180,0x5182,0x5186,0x5189,0x5193,0x5195,0x5199,0x519d,0x519d,0x51a0,0x51a6,0x51a8,0x51ad,0x51b0,0x51b8,0x51ba,0x51ba,0x51bc,0x51bf,0x51c2,0x51c6,0x51c8,0x51cd,0x51cf,0x51cf,0x51d1,0x51d6,0x51d8,0x51d8,0x51db,0x51e2,0x51e5,0x51e7,0x51e9,0x51ea,0x51ec,0x51ee,0x51f0,0x51fa,0x51fd,0x51fe,0x5200,0x5208,0x520a,0x520b,0x520e,0x520e,0x5211,0x5218,0x521d,0x521d,0x5222,0x5222,0x5224,0x522b,0x522e,0x522e,0x5230,0x5233,0x5235,0x523c,0x5243,0x5245,0x5247,0x5247,0x5249,0x524d,0x524f,0x524f,0x5254,0x5258,0x525a,0x5261,0x5263,0x5266,0x5269,0x526a,0x526c,0x526c,0x526e,0x5275,0x5277,0x5279,0x527d,0x527d,0x527f,0x5280,0x5282,0x5285,0x5287,0x528a,0x528c,0x528d,0x5291,0x5298,0x529a,0x529c,0x529f,0x52a0,0x52a3,0x52a7,0x52a9,0x52ad,0x52af,0x52b1,0x52b4,0x52be,0x52c0,0x52c1,0x52c3,0x52ca,0x52cc,0x52cd,0x52cf,0x52d2,0x52d4,0x52d9,0x52db,0x52ea,0x52ec,0x52ec,0x52f0,0x52fb,0x52fe,0x5303,0x5305,0x5308,0x530a,0x530d,0x530f,0x5311,0x5313,0x5313,0x5315,0x5321,0x5323,0x5325,0x5327,0x532d,0x532f,0x5333,0x5335,0x5335,0x5338,0x5343,0x5345,0x534d,0x5351,0x5354,0x5357,0x535c,0x535e,0x535e,0x5360,0x5361,0x5363,0x5367,0x5369,0x5369,0x536c,0x5375,0x5377,0x537b,0x537d,0x537f,0x5382,0x5384,0x5387,0x5389,0x538e,0x538e,0x5393,0x5394,0x5396,0x5396,0x5398,0x539a,0x539d,0x539d,0x539f,0x53a1,0x53a4,0x53a6,0x53a8,0x53ab,0x53ad,0x53b0,0x53b2,0x53b8,0x53ba,0x53bb,0x53bd,0x53bd,0x53c0,0x53c5,0x53c8,0x53cf,0x53d2,0x53d7,0x53d9,0x53db,0x53dd,0x53f8,0x53fa,0x53fa,0x5401,0x5404,0x5408,0x5413,0x541a,0x541b,0x541d,0x5421,0x5424,0x5424,0x5426,0x542f,0x5431,0x5431,0x5433,0x5436,0x5438,0x5439,0x543b,0x5440,0x5442,0x5444,0x5446,0x544a,0x544c,0x544f,0x5451,0x5451,0x5455,0x5455,0x545e,0x545f,0x5462,0x5462,0x5464,0x5464,0x5466,0x546e,0x5470,0x5471,0x5473,0x5477,0x547b,0x547d,0x547f,0x5481,0x5483,0x5486,0x5488,0x5492,0x5495,0x5496,0x549c,0x549c,0x549f,0x54a2,0x54a4,0x54af,0x54b1,0x54b3,0x54b7,0x54c4,0x54c6,0x54ca,0x54cd,0x54ce,0x54d8,0x54d8,0x54e0,0x54e2,0x54e5,0x54e6,0x54e8,0x54ea,0x54ec,0x54ef,0x54f1,0x54f3,0x54f6,0x54f6,0x54fa,0x54fa,0x54fc,0x5501,0x5504,0x5509,0x550c,0x5510,0x5514,0x5516,0x5527,0x5527,0x552a,0x552b,0x552e,0x552f,0x5531,0x5533,0x5535,0x5536,0x5538,0x5539,0x553b,0x553e,0x5540,0x5541,0x5544,0x5547,0x5549,0x554a,0x554c,0x554d,0x554f,0x5551,0x5553,0x5553,0x5556,0x5558,0x555a,0x555e,0x5560,0x5561,0x5563,0x5564,0x5566,0x5566,0x557b,0x5584,0x5586,0x558b,0x558e,0x558f,0x5591,0x5594,0x5597,0x559a,0x559c,0x559f,0x55a3,0x55a4,0x55a7,0x55ae,0x55b0,0x55b0,0x55b2,0x55b2,0x55b6,0x55b6,0x55bf,0x55bf,0x55c1,0x55c1,0x55c3,0x55c7,0x55c9,0x55c9,0x55cb,0x55cc,0x55ce,0x55ce,0x55d1,0x55d4,0x55d7,0x55d8,0x55da,0x55df,0x55e2,0x55e4,0x55e9,0x55e9,0x55ec,0x55ec,0x55ee,0x55ee,0x55f1,0x55f1,0x55f6,0x55f9,0x55fd,0x55ff,0x5605,0x560a,0x560d,0x5612,0x5614,0x5614,0x5616,0x5619,0x561b,0x561b,0x5620,0x5620,0x5628,0x5629,0x562c,0x562c,0x562f,0x5639,0x563b,0x563d,0x563f,0x5644,0x5646,0x5647,0x5649,0x5649,0x564b,0x5650,0x5653,0x5654,0x565b,0x565b,0x565e,0x565e,0x5660,0x5664,0x5666,0x5666,0x5668,0x566d,0x566f,0x566f,0x5671,0x5672,0x5674,0x5676,0x5678,0x5678,0x567a,0x567a,0x5680,0x5680,0x5684,0x5688,0x568a,0x568c,0x568f,0x568f,0x5694,0x5695,0x5699,0x569a,0x569d,0x56a0,0x56a2,0x56a2,0x56a5,0x56a9,0x56ab,0x56ae,0x56b1,0x56b4,0x56b6,0x56b7,0x56bc,0x56bc,0x56be,0x56be,0x56c0,0x56c3,0x56c5,0x56c5,0x56c8,0x56d1,0x56d3,0x56d3,0x56d7,0x56e1,0x56e3,0x56e8,0x56eb,0x56eb,0x56ed,0x56ee,0x56f0,0x56f3,0x56f6,0x56f7,0x56f9,0x56fa,0x56fd,0x56fd,0x56ff,0x5704,0x5707,0x570d,0x570f,0x570f,0x5711,0x5713,0x5715,0x5716,0x5718,0x5718,0x571a,0x571d,0x571f,0x572a,0x572c,0x5730,0x5733,0x5734,0x5737,0x5738,0x573b,0x573b,0x573d,0x5740,0x5742,0x5742,0x5745,0x5747,0x574a,0x574a,0x574c,0x5752,0x5759,0x5759,0x575f,0x575f,0x5761,0x5762,0x5764,0x576b,0x576d,0x5771,0x5773,0x5775,0x5777,0x5777,0x5779,0x577c,0x577e,0x577f,0x5781,0x5783,0x5788,0x5789,0x578b,0x578c,0x5793,0x5795,0x5797,0x5797,0x5799,0x579a,0x579c,0x57a4,0x57a7,0x57aa,0x57ac,0x57ac,0x57ae,0x57ae,0x57b0,0x57b0,0x57b3,0x57b3,0x57b8,0x57b8,0x57bd,0x57bd,0x57c0,0x57c0,0x57c3,0x57c3,0x57c6,0x57c8,0x57cb,0x57cc,0x57ce,0x57cf,0x57d2,0x57d7,0x57dc,0x57e1,0x57e3,0x57e4,0x57e6,0x57e7,0x57e9,0x57e9,0x57ed,0x57ed,0x57f0,0x57f0,0x57f4,0x5800,0x5802,0x5806,0x5808,0x580d,0x5815,0x5815,0x5819,0x5819,0x581b,0x581b,0x581d,0x5821,0x5824,0x5824,0x5826,0x5827,0x582a,0x582a,0x582d,0x582d,0x582f,0x5832,0x5834,0x5835,0x5839,0x583a,0x583d,0x583d,0x583f,0x5841,0x5849,0x584d,0x584f,0x5852,0x5854,0x5855,0x5857,0x585a,0x585e,0x585f,0x5861,0x5862,0x5864,0x5864,0x5867,0x5869,0x586b,0x586b,0x586d,0x586d,0x5870,0x5870,0x5872,0x5872,0x5875,0x5875,0x5878,0x5879,0x587c,0x587c,0x587e,0x5881,0x5883,0x5883,0x5885,0x5885,0x5887,0x588d,0x588f,0x5890,0x5893,0x5894,0x5896,0x5898,0x589c,0x58a2,0x58a6,0x58a6,0x58a8,0x58ab,0x58ae,0x58ae,0x58b1,0x58b3,0x58b8,0x58bc,0x58be,0x58be,0x58c1,0x58c5,0x58c7,0x58c8,0x58ca,0x58ca,0x58cc,0x58ce,0x58d0,0x58da,0x58dc,0x58e2,0x58e4,0x58e5,0x58e9,0x58e9,0x58eb,0x58ec,0x58ee,0x58f4,0x58f7,0x58f7,0x58f9,0x58fd,0x5902,0x5902,0x5905,0x5906,0x5909,0x590d,0x590f,0x5910,0x5912,0x5916,0x5918,0x591d,0x591f,0x591f,0x5921,0x5925,0x5927,0x5933,0x5935,0x5939,0x593d,0x593f,0x5943,0x5944,0x5946,0x5949,0x594e,0x5955,0x5957,0x595b,0x595d,0x5963,0x5965,0x5965,0x5967,0x596f,0x5972,0x5976,0x5978,0x5979,0x597b,0x597d,0x5981,0x5984,0x598a,0x598e,0x5992,0x5993,0x5995,0x5997,0x5999,0x5999,0x599b,0x599b,0x599d,0x599d,0x599f,0x599f,0x59a3,0x59a5,0x59a7,0x59a8,0x59ac,0x59b0,0x59b2,0x59b3,0x59b7,0x59b7,0x59b9,0x59bc,0x59be,0x59be,0x59c1,0x59c1,0x59c3,0x59c4,0x59c6,0x59c6,0x59c8,0x59cb,0x59cd,0x59cd,0x59d0,0x59d4,0x59d9,0x59da,0x59dc,0x59df,0x59e3,0x59e8,0x59ea,0x59ec,0x59ee,0x59ef,0x59f1,0x59f2,0x59f4,0x59f4,0x59f6,0x59f8,0x59fb,0x59fb,0x59ff,0x5a01,0x5a03,0x5a04,0x5a09,0x5a09,0x5a0c,0x5a0e,0x5a11,0x5a13,0x5a17,0x5a18,0x5a1a,0x5a1c,0x5a1e,0x5a20,0x5a23,0x5a25,0x5a27,0x5a2a,0x5a2d,0x5a2d,0x5a2f,0x5a30,0x5a35,0x5a36,0x5a3c,0x5a3c,0x5a40,0x5a41,0x5a44,0x5a49,0x5a4c,0x5a4c,0x5a50,0x5a50,0x5a55,0x5a55,0x5a5a,0x5a5a,0x5a5e,0x5a5e,0x5a62,0x5a63,0x5a65,0x5a67,0x5a6a,0x5a6a,0x5a6c,0x5a6d,0x5a77,0x5a77,0x5a7a,0x5a7b,0x5a7e,0x5a7f,0x5a84,0x5a84,0x5a8b,0x5a8b,0x5a90,0x5a90,0x5a92,0x5a93,0x5a96,0x5a96,0x5a99,0x5a9c,0x5a9e,0x5aa0,0x5aa2,0x5aa2,0x5aa7,0x5aa7,0x5aac,0x5aac,0x5ab1,0x5ab3,0x5ab5,0x5ab5,0x5ab8,0x5ab8,0x5aba,0x5abf,0x5ac1,0x5ac2,0x5ac4,0x5ac4,0x5ac6,0x5ac6,0x5ac8,0x5ac9,0x5acb,0x5acc,0x5acf,0x5ad0,0x5ad6,0x5ad7,0x5ada,0x5ada,0x5adc,0x5adc,0x5ae0,0x5ae1,0x5ae3,0x5ae3,0x5ae5,0x5ae6,0x5ae9,0x5aea,0x5aee,0x5aee,0x5af0,0x5af0,0x5af5,0x5af6,0x5afa,0x5afb,0x5afd,0x5afd,0x5b00,0x5b01,0x5b08,0x5b09,0x5b0b,0x5b0c,0x5b16,0x5b17,0x5b19,0x5b19,0x5b1b,0x5b1b,0x5b1d,0x5b1d,0x5b21,0x5b22,0x5b25,0x5b25,0x5b2a,0x5b2a,0x5b2c,0x5b2d,0x5b30,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b36,0x5b36,0x5b38,0x5b38,0x5b3e,0x5b3e,0x5b40,0x5b41,0x5b43,0x5b43,0x5b45,0x5b45,0x5b4b,0x5b4c,0x5b50,0x5b52,0x5b54,0x5b58,0x5b5a,0x5b5f,0x5b63,0x5b66,0x5b68,0x5b69,0x5b6b,0x5b6b,0x5b6e,0x5b71,0x5b73,0x5b73,0x5b75,0x5b76,0x5b78,0x5b78,0x5b7a,0x5b7a,0x5b7c,0x5b91,0x5b93,0x5b9d,0x5b9f,0x5b9f,0x5ba2,0x5ba6,0x5ba8,0x5ba9,0x5bac,0x5bba,0x5bbc,0x5bbc,0x5bbf,0x5bc7,0x5bc9,0x5bc9,0x5bcc,0x5bd0,0x5bd2,0x5bd4,0x5bd6,0x5bdb,0x5bdd,0x5be2,0x5be4,0x5be9,0x5beb,0x5bec,0x5bee,0x5bf1,0x5bf3,0x5bf6,0x5bf8,0x5bf8,0x5bfa,0x5bfa,0x5bfd,0x5bff,0x5c01,0x5c0f,0x5c11,0x5c14,0x5c16,0x5c17,0x5c19,0x5c1a,0x5c1e,0x5c20,0x5c22,0x5c24,0x5c26,0x5c26,0x5c28,0x5c2e,0x5c30,0x5c32,0x5c35,0x5c36,0x5c38,0x5c41,0x5c45,0x5c46,0x5c48,0x5c48,0x5c4a,0x5c4b,0x5c4d,0x5c51,0x5c53,0x5c53,0x5c55,0x5c55,0x5c59,0x5c5c,0x5c5e,0x5c65,0x5c67,0x5c69,0x5c6c,0x5c71,0x5c74,0x5c76,0x5c79,0x5c7d,0x5c87,0x5c88,0x5c8a,0x5c8a,0x5c8c,0x5c8c,0x5c8f,0x5c92,0x5c94,0x5c94,0x5c9d,0x5c9d,0x5c9f,0x5ca3,0x5ca6,0x5cad,0x5cb1,0x5cb8,0x5cba,0x5cbc,0x5cbe,0x5cbe,0x5cc5,0x5cc5,0x5cc7,0x5cc7,0x5cc9,0x5cc9,0x5ccb,0x5ccb,0x5cd0,0x5cd0,0x5cd2,0x5cd2,0x5cd7,0x5cd7,0x5cd9,0x5cd9,0x5cdd,0x5cdd,0x5ce0,0x5ce1,0x5ce6,0x5ce6,0x5ce8,0x5cea,0x5ced,0x5cf2,0x5cf4,0x5cf6,0x5cfa,0x5cfb,0x5cfd,0x5cfd,0x5d01,0x5d01,0x5d06,0x5d07,0x5d0b,0x5d0b,0x5d0d,0x5d0e,0x5d10,0x5d12,0x5d14,0x5d1b,0x5d1d,0x5d1d,0x5d1f,0x5d20,0x5d22,0x5d24,0x5d26,0x5d27,0x5d29,0x5d29,0x5d2b,0x5d2b,0x5d31,0x5d31,0x5d34,0x5d34,0x5d39,0x5d39,0x5d3d,0x5d3d,0x5d3f,0x5d3f,0x5d42,0x5d43,0x5d46,0x5d48,0x5d4a,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d53,0x5d55,0x5d55,0x5d59,0x5d59,0x5d5c,0x5d5c,0x5d5f,0x5d62,0x5d64,0x5d64,0x5d69,0x5d6a,0x5d6c,0x5d6d,0x5d6f,0x5d70,0x5d73,0x5d73,0x5d76,0x5d76,0x5d79,0x5d7a,0x5d7e,0x5d7f,0x5d81,0x5d84,0x5d87,0x5d88,0x5d8a,0x5d8c,0x5d90,0x5d90,0x5d92,0x5d95,0x5d97,0x5d97,0x5d99,0x5d99,0x5d9b,0x5d9b,0x5d9d,0x5d9d,0x5d9f,0x5da0,0x5da2,0x5da2,0x5da4,0x5da4,0x5da7,0x5da7,0x5dab,0x5dac,0x5dae,0x5dae,0x5db0,0x5db0,0x5db2,0x5db2,0x5db4,0x5db4,0x5db7,0x5dba,0x5dbc,0x5dbd,0x5dc3,0x5dc3,0x5dc7,0x5dc7,0x5dc9,0x5dc9,0x5dcb,0x5dce,0x5dd0,0x5dd3,0x5dd6,0x5dd9,0x5ddb,0x5ddb,0x5ddd,0x5dde,0x5de0,0x5de9,0x5deb,0x5deb,0x5dee,0x5dee,0x5df1,0x5df5,0x5df7,0x5df9,0x5dfb,0x5dfb,0x5dfd,0x5e00,0x5e02,0x5e03,0x5e06,0x5e07,0x5e0b,0x5e0d,0x5e11,0x5e12,0x5e14,0x5e16,0x5e18,0x5e1b,0x5e1d,0x5e1d,0x5e1f,0x5e20,0x5e25,0x5e25,0x5e28,0x5e28,0x5e2b,0x5e2b,0x5e2d,0x5e30,0x5e32,0x5e33,0x5e35,0x5e38,0x5e3d,0x5e3e,0x5e40,0x5e40,0x5e43,0x5e45,0x5e47,0x5e47,0x5e49,0x5e49,0x5e4b,0x5e4c,0x5e4e,0x5e4e,0x5e50,0x5e51,0x5e54,0x5e58,0x5e5b,0x5e5c,0x5e5e,0x5e5f,0x5e61,0x5e64,0x5e68,0x5e68,0x5e6a,0x5e6e,0x5e70,0x5e70,0x5e72,0x5e81,0x5e83,0x5e84,0x5e87,0x5e87,0x5e8a,0x5e8b,0x5e8e,0x5e8f,0x5e95,0x5e97,0x5e99,0x5e9a,0x5e9c,0x5e9c,0x5ea0,0x5ea0,0x5ea2,0x5ea2,0x5ea4,0x5ea8,0x5eaa,0x5ead,0x5eb1,0x5eb1,0x5eb3,0x5eb3,0x5eb5,0x5eb9,0x5ebd,0x5ebf,0x5ec1,0x5ec3,0x5ec6,0x5ec6,0x5ec8,0x5ecc,0x5ece,0x5ed6,0x5ed9,0x5ee3,0x5ee5,0x5ee5,0x5ee8,0x5ee9,0x5eeb,0x5eec,0x5ef0,0x5ef1,0x5ef3,0x5ef4,0x5ef6,0x5f04,0x5f06,0x5f11,0x5f13,0x5f19,0x5f1b,0x5f1f,0x5f21,0x5f29,0x5f2b,0x5f31,0x5f34,0x5f38,0x5f3a,0x5f41,0x5f44,0x5f45,0x5f47,0x5f48,0x5f4a,0x5f4a,0x5f4c,0x5f4e,0x5f50,0x5f51,0x5f53,0x5f54,0x5f56,0x5f59,0x5f5b,0x5f5d,0x5f60,0x5f67,0x5f69,0x5f6d,0x5f6f,0x5f75,0x5f77,0x5f7a,0x5f7c,0x5f85,0x5f87,0x5f8d,0x5f8f,0x5f93,0x5f96,0x5f99,0x5f9c,0x5f9e,0x5fa0,0x5fa2,0x5fa4,0x5fa4,0x5fa7,0x5fb1,0x5fb3,0x5fb5,0x5fb7,0x5fb9,0x5fbc,0x5fbd,0x5fc3,0x5fc5,0x5fc7,0x5fc9,0x5fcb,0x5fcd,0x5fd0,0x5fd4,0x5fd6,0x5fd9,0x5fdc,0x5fde,0x5fe0,0x5fe2,0x5fe4,0x5fe4,0x5fe8,0x5ff3,0x5ff5,0x5ff6,0x5ff8,0x5ff8,0x5ffa,0x5ffd,0x5fff,0x5fff,0x6007,0x6007,0x600a,0x600a,0x600d,0x6010,0x6012,0x601d,0x601f,0x6022,0x6024,0x602b,0x602d,0x602d,0x602f,0x602f,0x6031,0x6031,0x6033,0x6033,0x6035,0x6035,0x603a,0x603a,0x6040,0x6043,0x6046,0x604d,0x6050,0x6052,0x6054,0x6057,0x6059,0x605a,0x605d,0x605d,0x605f,0x6065,0x6067,0x606d,0x606f,0x6071,0x6075,0x6075,0x6077,0x6077,0x607e,0x607f,0x6081,0x6086,0x6088,0x608e,0x6091,0x6098,0x609a,0x609b,0x609d,0x60a0,0x60a2,0x60aa,0x60b0,0x60b8,0x60bb,0x60be,0x60c2,0x60c2,0x60c4,0x60cb,0x60ce,0x60cf,0x60d1,0x60d1,0x60d3,0x60d5,0x60d8,0x60e3,0x60e5,0x60e5,0x60e7,0x60e8,0x60ee,0x60ee,0x60f0,0x60fd,0x6100,0x6103,0x6106,0x610a,0x610c,0x6117,0x6119,0x611c,0x611e,0x6122,0x6127,0x6128,0x612a,0x612c,0x6130,0x6131,0x6134,0x6137,0x6139,0x613a,0x613c,0x613f,0x6141,0x6142,0x6144,0x614e,0x6153,0x6153,0x6155,0x6155,0x6158,0x615a,0x615d,0x6160,0x6162,0x6165,0x6167,0x6168,0x616b,0x616c,0x616e,0x6178,0x617b,0x6184,0x6187,0x6187,0x618a,0x618b,0x618d,0x618e,0x6190,0x6194,0x6196,0x619a,0x619c,0x619d,0x619f,0x61a0,0x61a4,0x61a5,0x61a7,0x61ae,0x61b2,0x61b2,0x61b6,0x61b6,0x61b8,0x61ba,0x61bc,0x61bc,0x61be,0x61be,0x61c0,0x61c3,0x61c6,0x61d0,0x61d5,0x61d5,0x61dc,0x61df,0x61e1,0x61e3,0x61e5,0x61e9,0x61ec,0x61ed,0x61ef,0x61ef,0x61f2,0x61f2,0x61f4,0x61f8,0x61fa,0x61fa,0x61fc,0x6201,0x6203,0x6204,0x6207,0x620a,0x620c,0x620e,0x6210,0x6216,0x621a,0x6223,0x6226,0x6227,0x6229,0x622b,0x622e,0x6234,0x6236,0x6236,0x6238,0x6239,0x623b,0x623b,0x623d,0x6244,0x6246,0x6249,0x624b,0x624e,0x6250,0x6256,0x6258,0x6258,0x625a,0x625c,0x625e,0x625e,0x6260,0x6261,0x6263,0x6264,0x6268,0x6268,0x626d,0x626f,0x6271,0x6271,0x6273,0x6273,0x6276,0x6276,0x6279,0x6280,0x6282,0x6285,0x6289,0x628a,0x628d,0x6299,0x629b,0x629c,0x629e,0x629e,0x62a6,0x62a6,0x62a8,0x62a8,0x62ab,0x62ac,0x62b1,0x62b1,0x62b3,0x62b3,0x62b5,0x62b7,0x62b9,0x62bf,0x62c2,0x62c2,0x62c4,0x62ca,0x62cc,0x62dd,0x62e0,0x62e1,0x62ea,0x62ea,0x62ec,0x62ef,0x62f1,0x62f7,0x62fc,0x62ff,0x6301,0x6304,0x6307,0x630d,0x6310,0x6311,0x6313,0x6313,0x6316,0x6316,0x6318,0x6319,0x631b,0x631b,0x631f,0x631f,0x6327,0x632b,0x632d,0x632d,0x632f,0x632f,0x6332,0x6332,0x6335,0x6336,0x6339,0x633f,0x6341,0x6344,0x6346,0x6346,0x6349,0x6350,0x6352,0x6355,0x6357,0x6359,0x635b,0x635c,0x6365,0x6369,0x636b,0x636e,0x6371,0x6372,0x6374,0x6378,0x637a,0x637d,0x637f,0x6380,0x6382,0x6384,0x6387,0x638a,0x638c,0x638c,0x638e,0x6390,0x6392,0x6392,0x6394,0x6396,0x6398,0x639b,0x639e,0x63af,0x63b2,0x63b2,0x63b4,0x63b5,0x63bb,0x63bb,0x63bd,0x63be,0x63c0,0x63c1,0x63c3,0x63c6,0x63c8,0x63c9,0x63ce,0x63d6,0x63da,0x63dc,0x63e0,0x63e1,0x63e3,0x63e3,0x63e5,0x63e5,0x63e9,0x63ee,0x63f2,0x63fa,0x6406,0x6406,0x6409,0x640a,0x640d,0x640d,0x640f,0x6410,0x6412,0x6414,0x6416,0x6418,0x641c,0x641c,0x641e,0x641e,0x6420,0x6420,0x6422,0x6422,0x6424,0x6426,0x6428,0x642a,0x642c,0x642d,0x642f,0x6430,0x6434,0x6436,0x643a,0x643a,0x643d,0x643f,0x6442,0x6442,0x644b,0x644b,0x644e,0x644f,0x6451,0x6454,0x6458,0x6458,0x645a,0x645d,0x645f,0x6461,0x6463,0x6463,0x6467,0x6467,0x6469,0x6469,0x646d,0x646d,0x646f,0x646f,0x6473,0x6474,0x6476,0x6476,0x6478,0x647b,0x647d,0x647d,0x6483,0x6483,0x6485,0x6485,0x6487,0x6488,0x648f,0x6493,0x6495,0x6495,0x6498,0x649b,0x649d,0x649f,0x64a1,0x64a1,0x64a3,0x64a6,0x64a8,0x64a9,0x64ab,0x64ae,0x64b0,0x64b0,0x64b2,0x64b3,0x64b9,0x64b9,0x64bb,0x64bf,0x64c1,0x64c2,0x64c4,0x64c5,0x64c7,0x64c7,0x64c9,0x64ce,0x64d0,0x64d2,0x64d4,0x64d5,0x64d7,0x64d8,0x64da,0x64da,0x64e0,0x64e7,0x64e9,0x64ea,0x64ec,0x64ed,0x64ef,0x64f2,0x64f4,0x64f7,0x64fa,0x64fb,0x64fd,0x6501,0x6504,0x6505,0x6508,0x650a,0x650f,0x650f,0x6513,0x6514,0x6516,0x6516,0x6518,0x6519,0x651b,0x651f,0x6522,0x6524,0x6526,0x6526,0x6529,0x652c,0x652e,0x652f,0x6531,0x6532,0x6534,0x653f,0x6543,0x6545,0x6547,0x6549,0x654d,0x6552,0x6554,0x6559,0x655d,0x6560,0x6562,0x6563,0x6566,0x6567,0x656b,0x656c,0x6570,0x6570,0x6572,0x6572,0x6574,0x6575,0x6577,0x6578,0x657a,0x657a,0x657d,0x657d,0x6581,0x6585,0x6587,0x658a,0x658c,0x658c,0x658e,0x658e,0x6590,0x6592,0x6595,0x6595,0x6597,0x6599,0x659b,0x659d,0x659f,0x65a1,0x65a3,0x65a7,0x65ab,0x65b0,0x65b2,0x65b5,0x65b7,0x65b9,0x65bc,0x65bf,0x65c1,0x65c6,0x65c8,0x65c9,0x65cb,0x65cc,0x65ce,0x65d0,0x65d2,0x65d2,0x65d4,0x65d4,0x65d6,0x65d9,0x65db,0x65db,0x65df,0x65e3,0x65e5,0x65e9,0x65ec,0x65ed,0x65f0,0x65f2,0x65f4,0x65f5,0x65f9,0x65fc,0x65fe,0x6600,0x6602,0x6604,0x6606,0x660a,0x660c,0x660f,0x6611,0x6616,0x661c,0x6631,0x6633,0x6637,0x6639,0x663c,0x663f,0x6646,0x6648,0x664c,0x664e,0x664f,0x6651,0x6652,0x6657,0x6670,0x6673,0x667c,0x667e,0x6681,0x6683,0x6684,0x6687,0x6689,0x668b,0x668e,0x6690,0x6692,0x6696,0x669d,0x669f,0x66a0,0x66a2,0x66a2,0x66a4,0x66a4,0x66a6,0x66a6,0x66ab,0x66ab,0x66ad,0x66ae,0x66b1,0x66b5,0x66b8,0x66b9,0x66bb,0x66bc,0x66be,0x66c4,0x66c6,0x66c9,0x66cc,0x66cc,0x66ce,0x66cf,0x66d4,0x66d4,0x66d6,0x66d6,0x66d9,0x66dd,0x66df,0x66e0,0x66e6,0x66e6,0x66e8,0x66e9,0x66eb,0x66ec,0x66ee,0x66ee,0x66f0,0x66f0,0x66f2,0x66f5,0x66f7,0x6701,0x6703,0x6703,0x6705,0x6705,0x6707,0x6709,0x670b,0x6710,0x6712,0x6717,0x6719,0x6719,0x671b,0x6720,0x6722,0x6722,0x6725,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6738,0x673a,0x673a,0x673d,0x673f,0x6741,0x6741,0x6743,0x6743,0x6745,0x6749,0x674c,0x6751,0x6753,0x6756,0x6759,0x6759,0x675c,0x6766,0x676a,0x676a,0x676c,0x6777,0x677b,0x677c,0x677e,0x6781,0x6784,0x6785,0x6787,0x6787,0x6789,0x6789,0x678b,0x678c,0x678e,0x6793,0x6795,0x679d,0x67a0,0x67a2,0x67a4,0x67a4,0x67a6,0x67a6,0x67a9,0x67a9,0x67af,0x67b9,0x67bb,0x67be,0x67c0,0x67c6,0x67c8,0x67ca,0x67ce,0x67d4,0x67d7,0x67de,0x67e1,0x67e2,0x67e4,0x67e4,0x67e6,0x67e7,0x67e9,0x67e9,0x67ec,0x67ec,0x67ee,0x67f7,0x67f9,0x67fc,0x67fe,0x67ff,0x6801,0x6805,0x6810,0x6810,0x6813,0x6814,0x6816,0x6819,0x681d,0x681f,0x6821,0x6822,0x6827,0x682d,0x682f,0x6834,0x6838,0x6839,0x683b,0x6846,0x6848,0x684a,0x684c,0x684e,0x6850,0x6855,0x6857,0x6859,0x685b,0x685d,0x685f,0x685f,0x6863,0x6863,0x6867,0x6867,0x686b,0x686b,0x686e,0x6872,0x6874,0x6877,0x6879,0x687c,0x687e,0x687f,0x6881,0x6886,0x6888,0x6888,0x688d,0x6890,0x6893,0x6894,0x6896,0x689d,0x689f,0x68a3,0x68a5,0x68ab,0x68ad,0x68b6,0x68b9,0x68bc,0x68c3,0x68c6,0x68c8,0x68cd,0x68cf,0x68da,0x68dc,0x68dd,0x68df,0x68e1,0x68e3,0x68e5,0x68e7,0x68e8,0x68ea,0x68f2,0x68f5,0x68f7,0x68f9,0x68fd,0x6900,0x6901,0x6903,0x6913,0x6916,0x6917,0x6919,0x691c,0x6921,0x6923,0x6925,0x6926,0x6928,0x6928,0x692a,0x692a,0x6930,0x6931,0x6933,0x6936,0x6938,0x6939,0x693b,0x693b,0x693d,0x693d,0x693f,0x693f,0x6942,0x6942,0x6945,0x6946,0x6949,0x694a,0x694e,0x694e,0x6953,0x6955,0x6957,0x6957,0x6959,0x695e,0x6960,0x6966,0x6968,0x6975,0x6977,0x6982,0x6986,0x6986,0x698a,0x698a,0x698d,0x698e,0x6991,0x6992,0x6994,0x6996,0x6998,0x6998,0x699b,0x699c,0x69a0,0x69a1,0x69a5,0x69a8,0x69ab,0x69ab,0x69ad,0x69b2,0x69b4,0x69b4,0x69b7,0x69b8,0x69ba,0x69bc,0x69be,0x69c1,0x69c3,0x69c3,0x69c5,0x69c5,0x69c7,0x69c8,0x69ca,0x69d1,0x69d3,0x69d3,0x69d6,0x69d9,0x69dd,0x69de,0x69e2,0x69e3,0x69e5,0x69e5,0x69e7,0x69eb,0x69ed,0x69ef,0x69f1,0x69f6,0x69f9,0x69f9,0x69fb,0x69fb,0x69fd,0x6a03,0x6a05,0x6a05,0x6a0a,0x6a0c,0x6a0f,0x6a0f,0x6a11,0x6a15,0x6a17,0x6a17,0x6a19,0x6a1b,0x6a1d,0x6a24,0x6a28,0x6a2b,0x6a2e,0x6a2e,0x6a30,0x6a30,0x6a32,0x6a3b,0x6a3d,0x6a3f,0x6a44,0x6a4b,0x6a4e,0x6a4e,0x6a50,0x6a52,0x6a54,0x6a56,0x6a58,0x6a59,0x6a5b,0x6a5b,0x6a5f,0x6a5f,0x6a61,0x6a62,0x6a64,0x6a64,0x6a66,0x6a67,0x6a6a,0x6a6b,0x6a71,0x6a73,0x6a78,0x6a78,0x6a7a,0x6a7a,0x6a7e,0x6a81,0x6a83,0x6a84,0x6a86,0x6a87,0x6a89,0x6a89,0x6a8b,0x6a8b,0x6a8d,0x6a8e,0x6a90,0x6a91,0x6a94,0x6a94,0x6a97,0x6a97,0x6a9b,0x6aa3,0x6aa5,0x6aa5,0x6aaa,0x6aac,0x6aae,0x6ab1,0x6ab3,0x6ab4,0x6ab8,0x6ab8,0x6abb,0x6abb,0x6abd,0x6abf,0x6ac1,0x6ac3,0x6ac6,0x6ac6,0x6ac8,0x6ac9,0x6acc,0x6acc,0x6ad0,0x6ad1,0x6ad3,0x6ad6,0x6ada,0x6adf,0x6ae2,0x6ae2,0x6ae4,0x6ae4,0x6ae7,0x6ae8,0x6aea,0x6aea,0x6aec,0x6aec,0x6af0,0x6af3,0x6af8,0x6af8,0x6afa,0x6afd,0x6b02,0x6b07,0x6b09,0x6b0b,0x6b0f,0x6b12,0x6b16,0x6b17,0x6b1b,0x6b1b,0x6b1d,0x6b21,0x6b23,0x6b24,0x6b27,0x6b28,0x6b2b,0x6b2c,0x6b2f,0x6b2f,0x6b32,0x6b32,0x6b35,0x6b3b,0x6b3d,0x6b3f,0x6b43,0x6b43,0x6b46,0x6b47,0x6b49,0x6b4a,0x6b4c,0x6b4e,0x6b50,0x6b50,0x6b52,0x6b54,0x6b56,0x6b56,0x6b58,0x6b59,0x6b5b,0x6b5b,0x6b5d,0x6b5d,0x6b5f,0x6b67,0x6b69,0x6b6c,0x6b6e,0x6b70,0x6b72,0x6b75,0x6b77,0x6b7b,0x6b7d,0x6b86,0x6b89,0x6b8b,0x6b8d,0x6b8d,0x6b95,0x6b98,0x6b9b,0x6b9b,0x6b9e,0x6ba0,0x6ba2,0x6ba4,0x6ba8,0x6bb5,0x6bb7,0x6bc0,0x6bc3,0x6bc9,0x6bcb,0x6bcf,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdb,0x6bdf,0x6bdf,0x6be1,0x6be1,0x6be3,0x6be3,0x6be6,0x6be7,0x6beb,0x6bec,0x6bee,0x6bef,0x6bf1,0x6bf1,0x6bf3,0x6bf3,0x6bf7,0x6bf7,0x6bf9,0x6bf9,0x6bff,0x6bff,0x6c02,0x6c02,0x6c04,0x6c05,0x6c08,0x6c0a,0x6c0d,0x6c14,0x6c17,0x6c17,0x6c19,0x6c19,0x6c1b,0x6c1b,0x6c1f,0x6c1f,0x6c23,0x6c24,0x6c26,0x6c28,0x6c2c,0x6c2c,0x6c2e,0x6c2e,0x6c33,0x6c38,0x6c3a,0x6c3b,0x6c3e,0x6c42,0x6c4a,0x6c4b,0x6c4d,0x6c50,0x6c52,0x6c52,0x6c54,0x6c55,0x6c57,0x6c57,0x6c59,0x6c60,0x6c62,0x6c62,0x6c67,0x6c68,0x6c6a,0x6c6b,0x6c6d,0x6c6d,0x6c6f,0x6c70,0x6c72,0x6c74,0x6c76,0x6c76,0x6c78,0x6c7b,0x6c7d,0x6c7e,0x6c81,0x6c89,0x6c8c,0x6c8d,0x6c90,0x6c90,0x6c92,0x6c9c,0x6c9f,0x6c9f,0x6ca1,0x6ca2,0x6caa,0x6cae,0x6cb0,0x6cb4,0x6cb8,0x6cbf,0x6cc1,0x6cc2,0x6cc4,0x6cc6,0x6cc9,0x6cca,0x6ccc,0x6ccd,0x6ccf,0x6cd7,0x6cd9,0x6cdd,0x6ce0,0x6ce3,0x6ce5,0x6ce5,0x6ce7,0x6cf4,0x6cfb,0x6cfb,0x6d00,0x6d01,0x6d04,0x6d04,0x6d07,0x6d07,0x6d0a,0x6d0c,0x6d0e,0x6d0f,0x6d11,0x6d13,0x6d17,0x6d17,0x6d19,0x6d1b,0x6d1e,0x6d1f,0x6d24,0x6d2b,0x6d2e,0x6d2f,0x6d31,0x6d36,0x6d38,0x6d39,0x6d3b,0x6d3f,0x6d41,0x6d41,0x6d44,0x6d45,0x6d57,0x6d5c,0x6d5e,0x6d61,0x6d63,0x6d67,0x6d69,0x6d6a,0x6d6c,0x6d6c,0x6d6e,0x6d70,0x6d74,0x6d74,0x6d77,0x6d79,0x6d7c,0x6d7c,0x6d80,0x6d82,0x6d85,0x6d85,0x6d87,0x6d8a,0x6d8c,0x6d8e,0x6d91,0x6d99,0x6d9b,0x6d9c,0x6daa,0x6dac,0x6dae,0x6daf,0x6db2,0x6db2,0x6db4,0x6db5,0x6db7,0x6db9,0x6dbc,0x6dbd,0x6dbf,0x6dc0,0x6dc2,0x6dc2,0x6dc4,0x6dc8,0x6dca,0x6dcc,0x6dce,0x6dd2,0x6dd5,0x6dd6,0x6dd8,0x6ddb,0x6ddd,0x6de2,0x6de4,0x6de6,0x6de8,0x6dec,0x6dee,0x6dfc,0x6e00,0x6e00,0x6e04,0x6e05,0x6e07,0x6e0b,0x6e13,0x6e13,0x6e15,0x6e15,0x6e17,0x6e17,0x6e19,0x6e1b,0x6e1d,0x6e27,0x6e29,0x6e29,0x6e2b,0x6e2f,0x6e32,0x6e32,0x6e34,0x6e34,0x6e36,0x6e36,0x6e38,0x6e3c,0x6e3e,0x6e3e,0x6e42,0x6e45,0x6e48,0x6e4f,0x6e51,0x6e54,0x6e56,0x6e58,0x6e5b,0x6e5f,0x6e62,0x6e63,0x6e67,0x6e68,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e72,0x6e73,0x6e76,0x6e76,0x6e7b,0x6e7b,0x6e7d,0x6e80,0x6e82,0x6e82,0x6e89,0x6e89,0x6e8c,0x6e8d,0x6e8f,0x6e90,0x6e93,0x6e93,0x6e96,0x6e96,0x6e98,0x6e99,0x6e9c,0x6e9d,0x6e9f,0x6ea0,0x6ea2,0x6ea2,0x6ea5,0x6ea5,0x6ea7,0x6ea7,0x6eaa,0x6eab,0x6ead,0x6eaf,0x6eb1,0x6eb4,0x6eb6,0x6eb7,0x6eba,0x6ebd,0x6ebf,0x6ec5,0x6ec7,0x6ecf,0x6ed1,0x6ed1,0x6ed3,0x6ed5,0x6ed9,0x6edb,0x6edd,0x6ede,0x6ee6,0x6ee6,0x6eeb,0x6eef,0x6ef2,0x6ef2,0x6ef4,0x6ef4,0x6ef7,0x6ef9,0x6efb,0x6efb,0x6efd,0x6eff,0x6f01,0x6f02,0x6f04,0x6f04,0x6f06,0x6f06,0x6f08,0x6f0a,0x6f0c,0x6f0d,0x6f0f,0x6f11,0x6f13,0x6f16,0x6f18,0x6f18,0x6f1a,0x6f1b,0x6f20,0x6f20,0x6f22,0x6f23,0x6f25,0x6f26,0x6f29,0x6f2d,0x6f2f,0x6f33,0x6f35,0x6f36,0x6f38,0x6f38,0x6f3b,0x6f3c,0x6f3e,0x6f3f,0x6f41,0x6f41,0x6f45,0x6f45,0x6f4f,0x6f4f,0x6f51,0x6f54,0x6f57,0x6f62,0x6f64,0x6f64,0x6f66,0x6f66,0x6f68,0x6f68,0x6f6c,0x6f70,0x6f74,0x6f74,0x6f78,0x6f78,0x6f7a,0x6f7a,0x6f7c,0x6f7e,0x6f80,0x6f84,0x6f86,0x6f88,0x6f8b,0x6f8e,0x6f90,0x6f94,0x6f96,0x6f98,0x6f9a,0x6f9a,0x6f9d,0x6f9d,0x6f9f,0x6fa1,0x6fa3,0x6fa8,0x6faa,0x6faa,0x6fae,0x6fb1,0x6fb3,0x6fb3,0x6fb5,0x6fb7,0x6fb9,0x6fb9,0x6fbc,0x6fbc,0x6fbe,0x6fbe,0x6fc0,0x6fc3,0x6fc5,0x6fca,0x6fd4,0x6fd5,0x6fd8,0x6fd8,0x6fda,0x6fdb,0x6fde,0x6fe1,0x6fe4,0x6fe4,0x6fe8,0x6fe9,0x6feb,0x6fec,0x6fee,0x6ff1,0x6ff3,0x6ff3,0x6ff5,0x6ff6,0x6ff9,0x6ffa,0x6ffc,0x6ffe,0x7000,0x7001,0x7005,0x7007,0x7009,0x700b,0x700d,0x700d,0x700f,0x700f,0x7011,0x7011,0x7015,0x7015,0x7017,0x7018,0x701a,0x701b,0x701d,0x7020,0x7023,0x7023,0x7026,0x7028,0x702c,0x702c,0x702f,0x7030,0x7032,0x7032,0x7034,0x7034,0x7037,0x7037,0x7039,0x703a,0x703c,0x703c,0x703e,0x703e,0x7043,0x7044,0x7047,0x704c,0x704e,0x704e,0x7051,0x7051,0x7054,0x7055,0x7058,0x7058,0x705d,0x705e,0x7063,0x7065,0x7069,0x7069,0x706b,0x706c,0x706e,0x7070,0x7075,0x7076,0x7078,0x7078,0x707c,0x707e,0x7081,0x7081,0x7085,0x7086,0x7089,0x708a,0x708e,0x708e,0x7092,0x7092,0x7094,0x7099,0x709b,0x709b,0x709f,0x709f,0x70a4,0x70a4,0x70ab,0x70b1,0x70b3,0x70b4,0x70b7,0x70bb,0x70c8,0x70c8,0x70ca,0x70cb,0x70cf,0x70cf,0x70d1,0x70d1,0x70d3,0x70d6,0x70d8,0x70d9,0x70dc,0x70dd,0x70df,0x70df,0x70e4,0x70e4,0x70ec,0x70ec,0x70f1,0x70f1,0x70f9,0x70fa,0x70fd,0x70fd,0x7103,0x7109,0x710b,0x710c,0x710f,0x710f,0x7114,0x7114,0x7119,0x711a,0x711c,0x711c,0x711e,0x711e,0x7120,0x7121,0x7126,0x7126,0x712b,0x712b,0x712d,0x7131,0x7136,0x7136,0x7138,0x7138,0x713c,0x713c,0x7141,0x7141,0x7145,0x7147,0x7149,0x714c,0x714e,0x714e,0x7150,0x7153,0x7155,0x7157,0x7159,0x715a,0x715c,0x715c,0x715e,0x715e,0x7160,0x7160,0x7162,0x7162,0x7164,0x7169,0x716c,0x716c,0x716e,0x716e,0x7179,0x7179,0x717d,0x717d,0x7180,0x7180,0x7184,0x7185,0x7187,0x7188,0x718a,0x718a,0x718c,0x718c,0x718f,0x718f,0x7192,0x7192,0x7194,0x7196,0x7199,0x719b,0x719f,0x71a0,0x71a2,0x71a2,0x71a8,0x71a8,0x71ac,0x71ac,0x71ae,0x71b3,0x71b9,0x71ba,0x71be,0x71c1,0x71c3,0x71c4,0x71c8,0x71c9,0x71cb,0x71cc,0x71ce,0x71ce,0x71d0,0x71d0,0x71d2,0x71d7,0x71d9,0x71da,0x71dc,0x71dc,0x71df,0x71e0,0x71e5,0x71e7,0x71ec,0x71ee,0x71f4,0x71f5,0x71f8,0x71f9,0x71fb,0x71fc,0x71fe,0x7200,0x7206,0x7209,0x720d,0x720d,0x7210,0x7210,0x7213,0x7213,0x7215,0x7215,0x7217,0x7217,0x721a,0x721b,0x721d,0x721d,0x721f,0x721f,0x7224,0x7224,0x7228,0x7228,0x722a,0x722d,0x722f,0x7230,0x7232,0x7232,0x7234,0x7236,0x7238,0x7243,0x7245,0x7248,0x724b,0x724c,0x724e,0x7250,0x7252,0x7253,0x7255,0x7263,0x7267,0x7269,0x726b,0x726b,0x726e,0x726f,0x7271,0x7272,0x7274,0x7274,0x7277,0x7279,0x727b,0x7282,0x7284,0x7284,0x7287,0x7287,0x7289,0x7289,0x728d,0x728e,0x7292,0x7293,0x7296,0x7296,0x729b,0x729b,0x72a0,0x72a0,0x72a2,0x72a2,0x72a7,0x72a8,0x72ac,0x72b2,0x72b4,0x72b4,0x72b6,0x72b6,0x72b9,0x72b9,0x72be,0x72be,0x72c0,0x72c4,0x72c6,0x72c7,0x72c9,0x72c9,0x72cc,0x72cc,0x72ce,0x72ce,0x72d0,0x72d0,0x72d2,0x72d2,0x72d5,0x72d9,0x72db,0x72db,0x72df,0x72e2,0x72e5,0x72e5,0x72e9,0x72e9,0x72ec,0x72ed,0x72f3,0x72f4,0x72f7,0x72fe,0x7302,0x7302,0x7304,0x7305,0x7307,0x7307,0x730a,0x730b,0x730d,0x730d,0x7312,0x7313,0x7316,0x7319,0x731b,0x731f,0x7322,0x7322,0x7324,0x7325,0x7327,0x732c,0x732e,0x732f,0x7331,0x7337,0x7339,0x733b,0x733d,0x733f,0x7343,0x7345,0x734d,0x7350,0x7352,0x7352,0x7356,0x7358,0x735d,0x7360,0x7363,0x7363,0x7366,0x736c,0x736e,0x7372,0x7375,0x7375,0x7377,0x737c,0x7380,0x7381,0x7383,0x7387,0x7389,0x738b,0x738e,0x738e,0x7390,0x7390,0x7393,0x7398,0x739c,0x739c,0x739e,0x73a0,0x73a2,0x73a2,0x73a5,0x73a6,0x73a8,0x73ab,0x73ad,0x73ad,0x73b2,0x73b3,0x73b5,0x73b5,0x73b7,0x73b7,0x73b9,0x73bd,0x73bf,0x73c0,0x73c2,0x73c2,0x73c5,0x73c6,0x73c8,0x73cf,0x73d2,0x73d3,0x73d6,0x73d6,0x73d9,0x73d9,0x73dd,0x73de,0x73e0,0x73e1,0x73e3,0x73e7,0x73e9,0x73ea,0x73ed,0x73ee,0x73f1,0x73f1,0x73f4,0x73f5,0x73f7,0x73fb,0x73fd,0x7401,0x7403,0x7407,0x7409,0x740a,0x7411,0x7411,0x7413,0x7413,0x741a,0x741b,0x7421,0x7422,0x7424,0x7426,0x7428,0x7436,0x7439,0x743a,0x743f,0x7441,0x7443,0x7444,0x7446,0x7447,0x744b,0x744b,0x744d,0x744d,0x7451,0x7453,0x7455,0x7455,0x7457,0x7457,0x7459,0x7460,0x7462,0x7464,0x7466,0x746b,0x746d,0x7473,0x7476,0x7476,0x747e,0x747e,0x7480,0x7481,0x7483,0x7483,0x7485,0x7489,0x748b,0x748b,0x748f,0x7492,0x7497,0x749a,0x749c,0x749c,0x749e,0x74a3,0x74a5,0x74ab,0x74ae,0x74b2,0x74b5,0x74b5,0x74b9,0x74bb,0x74bd,0x74bd,0x74bf,0x74bf,0x74c8,0x74ca,0x74cc,0x74cc,0x74cf,0x74d0,0x74d3,0x74d4,0x74d6,0x74d6,0x74d8,0x74d8,0x74da,0x74dc,0x74de,0x74e0,0x74e2,0x74e4,0x74e6,0x74eb,0x74ee,0x74f2,0x74f4,0x74f4,0x74f6,0x74f8,0x74fa,0x74fc,0x74ff,0x74ff,0x7501,0x7501,0x7503,0x7506,0x750c,0x750e,0x7511,0x7513,0x7515,0x7518,0x751a,0x751a,0x751c,0x751c,0x751e,0x752c,0x752f,0x7533,0x7536,0x7540,0x7543,0x7544,0x7546,0x7552,0x7554,0x7554,0x7557,0x7557,0x7559,0x7562,0x7564,0x7567,0x7569,0x756d,0x756f,0x757f,0x7581,0x7582,0x7585,0x7587,0x7589,0x758c,0x758e,0x7595,0x7599,0x759a,0x759c,0x759d,0x75a2,0x75a5,0x75ab,0x75ab,0x75b0,0x75b5,0x75b7,0x75ba,0x75bc,0x75c7,0x75ca,0x75ca,0x75cc,0x75cf,0x75d2,0x75d5,0x75d7,0x75d9,0x75db,0x75e4,0x75e7,0x75e7,0x75e9,0x75e9,0x75ec,0x75ec,0x75ee,0x75f4,0x75f9,0x75fa,0x75fc,0x75fc,0x75fe,0x7604,0x7607,0x760d,0x760f,0x760f,0x7612,0x7613,0x7615,0x7616,0x7618,0x7619,0x761b,0x7629,0x762d,0x762d,0x7630,0x7630,0x7632,0x7635,0x7638,0x763c,0x7640,0x764c,0x764e,0x764e,0x7652,0x7652,0x7655,0x7656,0x7658,0x7659,0x765c,0x765c,0x765f,0x765f,0x7661,0x7662,0x7664,0x7665,0x7667,0x766a,0x766c,0x7672,0x7674,0x7674,0x7676,0x7676,0x7678,0x7678,0x767a,0x767e,0x7680,0x7688,0x768b,0x768e,0x7690,0x7690,0x7693,0x7693,0x7695,0x7696,0x7699,0x76a8,0x76aa,0x76aa,0x76ad,0x76b0,0x76b4,0x76b4,0x76b6,0x76ba,0x76bd,0x76bd,0x76bf,0x76bf,0x76c1,0x76c3,0x76c5,0x76c6,0x76c8,0x76ce,0x76d2,0x76d2,0x76d4,0x76d4,0x76d6,0x76d7,0x76d9,0x76d9,0x76db,0x76dc,0x76de,0x76e1,0x76e3,0x76e8,0x76ea,0x76ec,0x76ee,0x76ee,0x76f0,0x76f2,0x76f4,0x76f4,0x76f6,0x76f6,0x76f8,0x76f9,0x76fb,0x76fc,0x76fe,0x76fe,0x7700,0x7701,0x7704,0x7704,0x7706,0x770c,0x770e,0x770e,0x7712,0x7712,0x7714,0x7715,0x7717,0x7717,0x7719,0x771c,0x771e,0x7720,0x7722,0x7722,0x7724,0x7726,0x7728,0x7729,0x772d,0x772f,0x7734,0x773a,0x773c,0x773e,0x7740,0x7740,0x7742,0x7742,0x7745,0x7747,0x774a,0x774a,0x774d,0x774f,0x7752,0x7752,0x7756,0x7758,0x775a,0x775c,0x775e,0x7768,0x776a,0x776c,0x7770,0x7770,0x7772,0x7774,0x7779,0x777a,0x777c,0x7780,0x7784,0x7784,0x778b,0x778e,0x7791,0x7791,0x7794,0x7796,0x779a,0x779a,0x779e,0x77a0,0x77a2,0x77a2,0x77a4,0x77a5,0x77a7,0x77a7,0x77a9,0x77aa,0x77ac,0x77b1,0x77b3,0x77b3,0x77b5,0x77b7,0x77b9,0x77b9,0x77bb,0x77bf,0x77c3,0x77c3,0x77c7,0x77c7,0x77c9,0x77c9,0x77cd,0x77cd,0x77d1,0x77d2,0x77d5,0x77d5,0x77d7,0x77d7,0x77d9,0x77dc,0x77de,0x77e0,0x77e2,0x77e7,0x77e9,0x77ea,0x77ec,0x77f1,0x77f3,0x77f4,0x77f8,0x77f8,0x77fb,0x77fc,0x7802,0x7802,0x7805,0x7806,0x7809,0x7809,0x780c,0x780e,0x7811,0x7812,0x7814,0x7815,0x7819,0x7819,0x781d,0x781d,0x7820,0x7823,0x7825,0x7827,0x782c,0x782e,0x7830,0x7830,0x7832,0x7832,0x7834,0x7835,0x7837,0x7837,0x783a,0x783a,0x783f,0x783f,0x7843,0x7845,0x7847,0x7848,0x784c,0x784c,0x784e,0x784f,0x7851,0x7852,0x785c,0x785e,0x7860,0x7861,0x7863,0x7864,0x7868,0x7868,0x786a,0x786c,0x786e,0x786f,0x7872,0x7872,0x7874,0x7874,0x787a,0x787a,0x787c,0x787c,0x787e,0x787e,0x7881,0x7881,0x7886,0x7887,0x788a,0x788a,0x788c,0x788f,0x7891,0x7891,0x7893,0x7895,0x7897,0x7898,0x789a,0x789a,0x789d,0x789f,0x78a1,0x78a1,0x78a3,0x78a4,0x78a7,0x78aa,0x78ac,0x78ad,0x78af,0x78b3,0x78b5,0x78b5,0x78ba,0x78bf,0x78c1,0x78c1,0x78c5,0x78cc,0x78ce,0x78ce,0x78d0,0x78d6,0x78da,0x78db,0x78df,0x78e1,0x78e4,0x78e4,0x78e6,0x78e8,0x78ea,0x78ea,0x78ec,0x78ec,0x78ef,0x78ef,0x78f2,0x78f4,0x78f6,0x78f7,0x78f9,0x78fb,0x78fd,0x7901,0x7906,0x7907,0x790c,0x790c,0x790e,0x790e,0x7910,0x7912,0x7919,0x791c,0x791e,0x7920,0x7925,0x792e,0x7930,0x7931,0x7934,0x7935,0x793a,0x7942,0x7944,0x794b,0x794f,0x7951,0x7953,0x7958,0x795a,0x7960,0x7962,0x7962,0x7965,0x7965,0x7967,0x7969,0x796b,0x796b,0x796d,0x796d,0x7972,0x7972,0x7977,0x7977,0x7979,0x797c,0x797e,0x7981,0x7984,0x7985,0x798a,0x798f,0x7991,0x7991,0x7993,0x7996,0x7998,0x7998,0x799b,0x799d,0x79a1,0x79a1,0x79a6,0x79ab,0x79ae,0x79b1,0x79b3,0x79b4,0x79b8,0x79bb,0x79bd,0x79c2,0x79c4,0x79c4,0x79c7,0x79cd,0x79cf,0x79cf,0x79d1,0x79d2,0x79d4,0x79d6,0x79d8,0x79d8,0x79da,0x79da,0x79dd,0x79e7,0x79e9,0x79ed,0x79f0,0x79f1,0x79f8,0x79f8,0x79fb,0x79fc,0x7a00,0x7a00,0x7a02,0x7a03,0x7a05,0x7a05,0x7a07,0x7a0e,0x7a11,0x7a11,0x7a14,0x7a15,0x7a17,0x7a1c,0x7a1e,0x7a21,0x7a27,0x7a27,0x7a2b,0x7a2b,0x7a2d,0x7a32,0x7a34,0x7a35,0x7a37,0x7a40,0x7a42,0x7a49,0x7a4c,0x7a50,0x7a55,0x7a57,0x7a59,0x7a59,0x7a5c,0x7a5d,0x7a5f,0x7a63,0x7a65,0x7a65,0x7a67,0x7a67,0x7a69,0x7a6b,0x7a6d,0x7a6d,0x7a70,0x7a70,0x7a74,0x7a76,0x7a78,0x7a7a,0x7a7d,0x7a86,0x7a88,0x7a88,0x7a8a,0x7a8b,0x7a90,0x7a98,0x7a9e,0x7aa0,0x7aa3,0x7aa3,0x7aa9,0x7aaa,0x7aac,0x7aac,0x7aae,0x7ab0,0x7ab3,0x7ab3,0x7ab5,0x7ab6,0x7ab9,0x7abf,0x7ac3,0x7acf,0x7ad1,0x7ad3,0x7ad5,0x7ad5,0x7ad9,0x7add,0x7adf,0x7ae3,0x7ae5,0x7aed,0x7aef,0x7af1,0x7af4,0x7af4,0x7af6,0x7af6,0x7af8,0x7afb,0x7afd,0x7aff,0x7b02,0x7b02,0x7b04,0x7b04,0x7b06,0x7b08,0x7b0a,0x7b0b,0x7b0f,0x7b0f,0x7b11,0x7b12,0x7b14,0x7b14,0x7b18,0x7b19,0x7b1b,0x7b1b,0x7b1e,0x7b20,0x7b23,0x7b23,0x7b25,0x7b31,0x7b33,0x7b36,0x7b39,0x7b39,0x7b3b,0x7b3b,0x7b3d,0x7b3d,0x7b3f,0x7b41,0x7b45,0x7b49,0x7b4b,0x7b56,0x7b5d,0x7b5d,0x7b60,0x7b60,0x7b64,0x7b67,0x7b69,0x7b6a,0x7b6c,0x7b75,0x7b77,0x7b77,0x7b79,0x7b7a,0x7b7f,0x7b7f,0x7b84,0x7b84,0x7b86,0x7b87,0x7b89,0x7b89,0x7b8b,0x7b8b,0x7b8d,0x7b92,0x7b94,0x7ba1,0x7ba5,0x7ba5,0x7baa,0x7baa,0x7bac,0x7bad,0x7baf,0x7bb2,0x7bb4,0x7bb6,0x7bb8,0x7bb8,0x7bba,0x7bbd,0x7bc0,0x7bc2,0x7bc4,0x7bcc,0x7bcf,0x7bcf,0x7bd4,0x7bd4,0x7bd6,0x7bd7,0x7bd9,0x7bdb,0x7bdd,0x7bdd,0x7be0,0x7be0,0x7be4,0x7be6,0x7be8,0x7bea,0x7bed,0x7bed,0x7bf0,0x7bf0,0x7bf2,0x7bfa,0x7bfc,0x7bfc,0x7bfe,0x7bfe,0x7c00,0x7c04,0x7c06,0x7c07,0x7c09,0x7c09,0x7c0b,0x7c0f,0x7c11,0x7c14,0x7c17,0x7c17,0x7c19,0x7c19,0x7c1b,0x7c1b,0x7c1e,0x7c21,0x7c23,0x7c23,0x7c25,0x7c28,0x7c2a,0x7c2c,0x7c2f,0x7c2f,0x7c31,0x7c31,0x7c33,0x7c34,0x7c36,0x7c3a,0x7c3d,0x7c40,0x7c42,0x7c43,0x7c45,0x7c46,0x7c4a,0x7c4a,0x7c4c,0x7c4d,0x7c4f,0x7c61,0x7c63,0x7c65,0x7c67,0x7c67,0x7c69,0x7c69,0x7c6c,0x7c70,0x7c72,0x7c73,0x7c75,0x7c75,0x7c79,0x7c79,0x7c7b,0x7c7e,0x7c81,0x7c83,0x7c86,0x7c87,0x7c89,0x7c89,0x7c8b,0x7c8b,0x7c8d,0x7c8d,0x7c8f,0x7c90,0x7c92,0x7c92,0x7c94,0x7c95,0x7c97,0x7c98,0x7c9b,0x7c9b,0x7c9e,0x7ca2,0x7ca4,0x7ca8,0x7cab,0x7cab,0x7cad,0x7cae,0x7cb0,0x7cb3,0x7cb6,0x7cb7,0x7cb9,0x7cc0,0x7cc2,0x7cc2,0x7cc4,0x7cc5,0x7cc7,0x7cca,0x7ccd,0x7ccf,0x7cd2,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce6,0x7ce7,0x7ce9,0x7ce9,0x7ceb,0x7ceb,0x7cef,0x7cef,0x7cf2,0x7cf2,0x7cf4,0x7cf6,0x7cf8,0x7cfb,0x7cfe,0x7cfe,0x7d00,0x7d00,0x7d02,0x7d0b,0x7d0d,0x7d0d,0x7d0f,0x7d1e,0x7d20,0x7d23,0x7d26,0x7d26,0x7d2a,0x7d33,0x7d35,0x7d35,0x7d39,0x7d3a,0x7d3c,0x7d48,0x7d4b,0x7d51,0x7d53,0x7d53,0x7d55,0x7d57,0x7d59,0x7d5e,0x7d61,0x7d63,0x7d65,0x7d68,0x7d6a,0x7d6a,0x7d6e,0x7d6e,0x7d70,0x7d73,0x7d75,0x7d76,0x7d78,0x7d7b,0x7d7d,0x7d7d,0x7d7f,0x7d7f,0x7d81,0x7d83,0x7d85,0x7d86,0x7d88,0x7d89,0x7d8b,0x7d8d,0x7d8f,0x7d8f,0x7d91,0x7d91,0x7d93,0x7d93,0x7d96,0x7d97,0x7d99,0x7da0,0x7da2,0x7da3,0x7da6,0x7da7,0x7daa,0x7dbb,0x7dbd,0x7dc0,0x7dc2,0x7dc7,0x7dca,0x7dd2,0x7dd5,0x7dda,0x7ddc,0x7dde,0x7de0,0x7de6,0x7de8,0x7ded,0x7def,0x7def,0x7df1,0x7df2,0x7df4,0x7df6,0x7df9,0x7dfb,0x7e00,0x7e01,0x7e04,0x7e05,0x7e08,0x7e0b,0x7e10,0x7e12,0x7e15,0x7e15,0x7e17,0x7e17,0x7e1b,0x7e23,0x7e26,0x7e28,0x7e2b,0x7e2f,0x7e31,0x7e33,0x7e35,0x7e37,0x7e39,0x7e3b,0x7e3d,0x7e3f,0x7e41,0x7e41,0x7e43,0x7e48,0x7e4a,0x7e4b,0x7e4d,0x7e4e,0x7e50,0x7e50,0x7e52,0x7e52,0x7e54,0x7e56,0x7e58,0x7e5a,0x7e5d,0x7e5f,0x7e61,0x7e62,0x7e65,0x7e67,0x7e69,0x7e6b,0x7e6d,0x7e70,0x7e73,0x7e73,0x7e75,0x7e75,0x7e78,0x7e79,0x7e7b,0x7e7f,0x7e81,0x7e83,0x7e86,0x7e8a,0x7e8c,0x7e96,0x7e98,0x7e98,0x7e9a,0x7e9f,0x7f36,0x7f36,0x7f38,0x7f38,0x7f3a,0x7f3f,0x7f43,0x7f45,0x7f47,0x7f47,0x7f4c,0x7f55,0x7f58,0x7f58,0x7f5b,0x7f5d,0x7f5f,0x7f61,0x7f63,0x7f6b,0x7f6d,0x7f6e,0x7f70,0x7f72,0x7f75,0x7f75,0x7f77,0x7f79,0x7f7d,0x7f80,0x7f82,0x7f83,0x7f85,0x7f88,0x7f8a,0x7f91,0x7f94,0x7f94,0x7f96,0x7f97,0x7f9a,0x7f9a,0x7f9c,0x7f9e,0x7fa1,0x7fa4,0x7fa6,0x7fa6,0x7fa8,0x7faa,0x7fad,0x7faf,0x7fb2,0x7fb2,0x7fb4,0x7fb4,0x7fb6,0x7fb6,0x7fb8,0x7fb9,0x7fbc,0x7fbd,0x7fbf,0x7fc1,0x7fc3,0x7fc3,0x7fc5,0x7fc6,0x7fc8,0x7fc8,0x7fca,0x7fca,0x7fcc,0x7fcc,0x7fce,0x7fcf,0x7fd2,0x7fd2,0x7fd4,0x7fd5,0x7fdb,0x7fdb,0x7fdf,0x7fe1,0x7fe3,0x7fe3,0x7fe5,0x7fe6,0x7fe8,0x7fe9,0x7feb,0x7fec,0x7fee,0x7ff0,0x7ff2,0x7ff3,0x7ff9,0x8008,0x800a,0x8019,0x801c,0x8021,0x8024,0x8024,0x8026,0x8026,0x8028,0x8028,0x802c,0x802c,0x802e,0x802e,0x8030,0x8030,0x8033,0x8037,0x8039,0x8040,0x8043,0x8044,0x8046,0x8046,0x804a,0x804a,0x8052,0x8052,0x8056,0x8056,0x8058,0x8058,0x805a,0x805a,0x805e,0x8062,0x8064,0x8064,0x8066,0x8066,0x8068,0x8068,0x806d,0x806d,0x806f,0x8077,0x8079,0x8079,0x807b,0x807b,0x807d,0x8081,0x8084,0x8089,0x808b,0x808c,0x808e,0x808e,0x8093,0x8093,0x8096,0x8096,0x8098,0x809e,0x80a1,0x80a2,0x80a4,0x80a7,0x80a9,0x80ad,0x80af,0x80af,0x80b1,0x80b2,0x80b4,0x80b4,0x80b8,0x80ba,0x80c3,0x80c6,0x80c8,0x80c8,0x80ca,0x80ca,0x80cc,0x80cf,0x80d2,0x80d2,0x80d4,0x80db,0x80dd,0x80de,0x80e0,0x80e1,0x80e4,0x80e6,0x80ed,0x80fe,0x8101,0x8103,0x8105,0x810b,0x810d,0x810d,0x8116,0x8118,0x811a,0x811c,0x811e,0x811e,0x8120,0x8120,0x8123,0x8124,0x8127,0x8127,0x8129,0x8129,0x812b,0x812c,0x812f,0x8131,0x8133,0x8133,0x8135,0x8135,0x8139,0x813a,0x813c,0x813e,0x8141,0x8141,0x8145,0x8147,0x814a,0x814c,0x814e,0x814e,0x8150,0x8155,0x8157,0x8157,0x815f,0x8161,0x8165,0x8169,0x816b,0x816b,0x816d,0x8171,0x8173,0x8174,0x8177,0x817a,0x817f,0x8186,0x8188,0x8188,0x818a,0x818b,0x818e,0x8190,0x8193,0x8193,0x8195,0x8196,0x8198,0x8198,0x819a,0x819e,0x81a0,0x81a0,0x81a2,0x81a4,0x81a8,0x81a9,0x81ae,0x81ae,0x81b0,0x81b0,0x81b2,0x81b5,0x81b8,0x81b8,0x81ba,0x81bb,0x81bd,0x81c3,0x81c5,0x81c6,0x81c8,0x81cb,0x81cd,0x81cf,0x81d1,0x81d1,0x81d3,0x81d3,0x81d5,0x81db,0x81dd,0x81e1,0x81e3,0x81e5,0x81e7,0x81e8,0x81ea,0x81ed,0x81ef,0x81f6,0x81f8,0x8205,0x8207,0x8210,0x8212,0x8214,0x8216,0x821f,0x8221,0x8222,0x8228,0x822c,0x822e,0x822e,0x8232,0x823a,0x823c,0x823c,0x8240,0x8240,0x8243,0x8247,0x8249,0x8249,0x824b,0x824b,0x824e,0x824f,0x8251,0x8251,0x8256,0x825a,0x825c,0x825d,0x825f,0x8260,0x8262,0x8264,0x8266,0x8268,0x826a,0x826b,0x826d,0x826f,0x8271,0x8272,0x8274,0x8274,0x8276,0x8279,0x827b,0x827b,0x827d,0x8281,0x8283,0x8284,0x8287,0x8287,0x8289,0x828b,0x828d,0x828e,0x8291,0x8294,0x8296,0x8296,0x8298,0x829b,0x829d,0x829d,0x829f,0x82a1,0x82a3,0x82b4,0x82b7,0x82bf,0x82c5,0x82c6,0x82d0,0x82d5,0x82d7,0x82d7,0x82d9,0x82dc,0x82de,0x82e8,0x82ea,0x82eb,0x82ed,0x82ed,0x82ef,0x82ef,0x82f1,0x82f1,0x82f3,0x82f4,0x82f6,0x82f7,0x82f9,0x82fb,0x82fd,0x82fe,0x8300,0x830c,0x830e,0x830e,0x8316,0x8318,0x831b,0x831f,0x8321,0x8323,0x8328,0x8328,0x832b,0x833a,0x833c,0x833d,0x8340,0x8340,0x8342,0x8347,0x8349,0x834a,0x834d,0x8358,0x835a,0x835a,0x8362,0x8363,0x8370,0x8370,0x8373,0x8373,0x8375,0x8375,0x8377,0x8378,0x837b,0x837d,0x837f,0x8380,0x8382,0x8382,0x8384,0x8387,0x8389,0x838a,0x838d,0x838e,0x8392,0x8396,0x8398,0x83a0,0x83a2,0x83a2,0x83a6,0x83ad,0x83b1,0x83b1,0x83b5,0x83b5,0x83bd,0x83c1,0x83c5,0x83c5,0x83c7,0x83c7,0x83c9,0x83ca,0x83cc,0x83cc,0x83ce,0x83d1,0x83d3,0x83d4,0x83d6,0x83d6,0x83d8,0x83d8,0x83dc,0x83dd,0x83df,0x83e1,0x83e5,0x83e5,0x83e8,0x83eb,0x83ef,0x83f2,0x83f4,0x83f4,0x83f6,0x83f9,0x83fb,0x83fd,0x8401,0x8401,0x8403,0x8404,0x8406,0x8407,0x840a,0x840f,0x8411,0x8411,0x8413,0x8413,0x8415,0x8415,0x8417,0x8417,0x8419,0x8419,0x8420,0x8420,0x8422,0x8422,0x8429,0x842a,0x842c,0x842c,0x842f,0x842f,0x8431,0x8431,0x8435,0x8435,0x8438,0x8439,0x843c,0x843d,0x8445,0x844a,0x844d,0x844f,0x8451,0x8452,0x8456,0x845c,0x845f,0x8467,0x8469,0x8471,0x8473,0x847a,0x847c,0x847d,0x8481,0x8482,0x8484,0x8485,0x848b,0x848b,0x8490,0x8490,0x8492,0x8495,0x8497,0x8497,0x8499,0x8499,0x849c,0x849c,0x849e,0x849f,0x84a1,0x84a1,0x84a6,0x84a6,0x84a8,0x84aa,0x84ad,0x84ad,0x84af,0x84af,0x84b1,0x84b2,0x84b4,0x84b4,0x84b8,0x84c2,0x84c4,0x84c4,0x84c6,0x84d1,0x84d3,0x84d3,0x84d6,0x84d6,0x84d9,0x84da,0x84dc,0x84dc,0x84e7,0x84e7,0x84ea,0x84ea,0x84ec,0x84ec,0x84ee,0x84f2,0x84f4,0x84f4,0x84f7,0x84f7,0x84fa,0x84fd,0x84ff,0x8500,0x8502,0x8503,0x8506,0x8507,0x850c,0x850c,0x850e,0x850e,0x8510,0x8511,0x8513,0x8515,0x8517,0x8518,0x851a,0x851c,0x851e,0x851f,0x8521,0x8527,0x852a,0x852d,0x852f,0x852f,0x8532,0x8536,0x853d,0x8541,0x8543,0x8543,0x8546,0x8546,0x8548,0x854b,0x854e,0x8553,0x8555,0x855a,0x855c,0x8564,0x8568,0x856b,0x856d,0x856d,0x856f,0x856f,0x8577,0x8577,0x8579,0x857b,0x857d,0x8581,0x8584,0x858c,0x858f,0x8591,0x8593,0x8594,0x8597,0x8599,0x859b,0x859d,0x859f,0x85a0,0x85a2,0x85a2,0x85a4,0x85b0,0x85b4,0x85b4,0x85b6,0x85ba,0x85bc,0x85bf,0x85c1,0x85c2,0x85c7,0x85c7,0x85c9,0x85cb,0x85cd,0x85d0,0x85d5,0x85d5,0x85d8,0x85da,0x85dc,0x85dd,0x85df,0x85e1,0x85e4,0x85e6,0x85e8,0x85ea,0x85ed,0x85ed,0x85f3,0x85f4,0x85f6,0x85f7,0x85f9,0x85fc,0x85fe,0x8600,0x8602,0x8602,0x8604,0x8607,0x860a,0x860b,0x860d,0x860e,0x8610,0x8613,0x8616,0x861b,0x861e,0x861e,0x8621,0x8622,0x8624,0x8624,0x8627,0x8627,0x8629,0x8629,0x862d,0x862d,0x862f,0x8630,0x8636,0x8636,0x8638,0x863a,0x863c,0x863d,0x863f,0x8642,0x8646,0x8646,0x864d,0x864e,0x8650,0x8650,0x8652,0x8664,0x8667,0x8667,0x8669,0x8669,0x866b,0x866c,0x866f,0x866f,0x8671,0x8671,0x8675,0x8677,0x8679,0x867b,0x867d,0x867d,0x8687,0x868d,0x8691,0x8691,0x8693,0x8693,0x8695,0x8696,0x8698,0x8698,0x869a,0x869a,0x869c,0x869d,0x86a1,0x86a1,0x86a3,0x86a4,0x86a6,0x86ab,0x86ad,0x86ad,0x86af,0x86b1,0x86b3,0x86b9,0x86bf,0x86c1,0x86c3,0x86c7,0x86c9,0x86c9,0x86cb,0x86cb,0x86cd,0x86ce,0x86d1,0x86d2,0x86d4,0x86d5,0x86d7,0x86d7,0x86d9,0x86dc,0x86de,0x86e0,0x86e3,0x86e7,0x86e9,0x86e9,0x86ec,0x86ef,0x86f8,0x86fe,0x8700,0x8700,0x8702,0x870b,0x870d,0x8714,0x8718,0x871a,0x871c,0x871c,0x871e,0x871f,0x8721,0x8723,0x8725,0x8725,0x8728,0x8729,0x872e,0x872f,0x8731,0x8732,0x8734,0x8734,0x8737,0x8737,0x8739,0x8740,0x8743,0x8743,0x8745,0x8745,0x8749,0x8749,0x874b,0x874e,0x8751,0x8751,0x8753,0x8753,0x8755,0x8755,0x8757,0x8759,0x875d,0x875d,0x875f,0x8761,0x8763,0x8766,0x8768,0x8768,0x876a,0x876a,0x876e,0x876f,0x8771,0x8772,0x8774,0x8774,0x8776,0x8776,0x8778,0x8778,0x877b,0x877c,0x877f,0x877f,0x8782,0x8789,0x878b,0x878e,0x8790,0x8790,0x8793,0x8793,0x8795,0x8795,0x8797,0x8799,0x879e,0x87a0,0x87a2,0x87a3,0x87a7,0x87a7,0x87ab,0x87af,0x87b1,0x87b1,0x87b3,0x87b3,0x87b5,0x87b5,0x87ba,0x87bb,0x87bd,0x87c1,0x87c4,0x87c4,0x87c6,0x87cb,0x87ce,0x87ce,0x87d0,0x87d0,0x87d2,0x87d2,0x87d5,0x87d6,0x87d9,0x87da,0x87dc,0x87dc,0x87df,0x87e0,0x87e2,0x87e6,0x87ea,0x87ed,0x87ef,0x87ef,0x87f1,0x87f3,0x87f5,0x87fb,0x87fe,0x87ff,0x8801,0x8801,0x8803,0x8803,0x8805,0x8807,0x8809,0x880b,0x880d,0x8816,0x8818,0x881c,0x881e,0x881f,0x8821,0x8823,0x8827,0x8828,0x882d,0x882e,0x8830,0x8832,0x8835,0x8836,0x8839,0x883c,0x8840,0x8846,0x8848,0x884e,0x8851,0x8853,0x8855,0x8864,0x8868,0x8869,0x886b,0x886b,0x886e,0x8872,0x8875,0x8875,0x8877,0x8877,0x8879,0x8879,0x887b,0x887b,0x887d,0x8882,0x8888,0x8888,0x888b,0x888b,0x888d,0x888d,0x8892,0x8892,0x8896,0x889c,0x889e,0x88a0,0x88a2,0x88a2,0x88a4,0x88a4,0x88a8,0x88a8,0x88aa,0x88ab,0x88ae,0x88ae,0x88b0,0x88b1,0x88b4,0x88b5,0x88b7,0x88b7,0x88ba,0x88ba,0x88bc,0x88c6,0x88ca,0x88cf,0x88d1,0x88d5,0x88d8,0x88d9,0x88db,0x88e1,0x88e7,0x88e8,0x88ef,0x88f5,0x88f7,0x88f9,0x88fc,0x88fe,0x8901,0x8902,0x8904,0x8904,0x8906,0x8907,0x890a,0x890a,0x890c,0x8910,0x8912,0x8913,0x8915,0x8916,0x8918,0x891a,0x891c,0x891e,0x8920,0x8920,0x8925,0x8928,0x892a,0x892b,0x8930,0x8932,0x8935,0x893b,0x893e,0x893e,0x8940,0x8946,0x8949,0x8949,0x894c,0x894d,0x894f,0x894f,0x8952,0x8952,0x8956,0x8957,0x895a,0x895c,0x895e,0x8964,0x8966,0x8966,0x896a,0x896b,0x896d,0x8970,0x8972,0x8975,0x8977,0x8977,0x897a,0x8981,0x8983,0x8983,0x8986,0x898b,0x898d,0x898d,0x898f,0x8990,0x8993,0x8998,0x899a,0x899c,0x899f,0x89a1,0x89a5,0x89a7,0x89a9,0x89aa,0x89ac,0x89ac,0x89af,0x89b0,0x89b2,0x89b7,0x89ba,0x89ba,0x89bc,0x89bd,0x89bf,0x89c1,0x89d2,0x89d2,0x89d4,0x89d8,0x89da,0x89da,0x89dc,0x89dd,0x89e3,0x89e3,0x89e5,0x89e7,0x89e9,0x89e9,0x89eb,0x89eb,0x89ed,0x89ed,0x89f1,0x89f1,0x89f3,0x89f4,0x89f6,0x89f6,0x89f8,0x89f9,0x89fd,0x89fd,0x89ff,0x8a05,0x8a07,0x8a08,0x8a0a,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a18,0x8a1b,0x8a1b,0x8a1d,0x8a26,0x8a2a,0x8a2d,0x8a2f,0x8a2f,0x8a31,0x8a31,0x8a33,0x8a37,0x8a3a,0x8a3e,0x8a40,0x8a41,0x8a43,0x8a43,0x8a45,0x8a49,0x8a4d,0x8a4e,0x8a50,0x8a58,0x8a5b,0x8a5e,0x8a60,0x8a63,0x8a65,0x8a67,0x8a69,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a73,0x8a75,0x8a77,0x8a79,0x8a7c,0x8a7e,0x8a80,0x8a82,0x8a87,0x8a89,0x8a89,0x8a8b,0x8a8d,0x8a8f,0x8a93,0x8a95,0x8a9a,0x8a9e,0x8aa1,0x8aa3,0x8aaa,0x8aac,0x8ab0,0x8ab2,0x8ab3,0x8ab6,0x8ab7,0x8ab9,0x8ab9,0x8abb,0x8abc,0x8abe,0x8abf,0x8ac2,0x8ac4,0x8ac6,0x8acd,0x8acf,0x8ad7,0x8ada,0x8ae2,0x8ae4,0x8ae4,0x8ae6,0x8ae7,0x8aeb,0x8aee,0x8af0,0x8af1,0x8af3,0x8af8,0x8afa,0x8afa,0x8afc,0x8afc,0x8afe,0x8b02,0x8b04,0x8b07,0x8b0a,0x8b11,0x8b14,0x8b14,0x8b16,0x8b17,0x8b19,0x8b21,0x8b26,0x8b26,0x8b28,0x8b28,0x8b2b,0x8b2d,0x8b30,0x8b30,0x8b33,0x8b33,0x8b37,0x8b37,0x8b39,0x8b39,0x8b3c,0x8b3c,0x8b3e,0x8b3e,0x8b41,0x8b46,0x8b48,0x8b49,0x8b4c,0x8b4f,0x8b51,0x8b54,0x8b56,0x8b56,0x8b58,0x8b5c,0x8b5e,0x8b5f,0x8b63,0x8b63,0x8b66,0x8b66,0x8b69,0x8b69,0x8b6b,0x8b6d,0x8b6f,0x8b72,0x8b74,0x8b74,0x8b76,0x8b79,0x8b7c,0x8b81,0x8b83,0x8b85,0x8b8a,0x8b90,0x8b92,0x8b96,0x8b99,0x8b9a,0x8b9c,0x8ba0,0x8c37,0x8c3a,0x8c3d,0x8c3f,0x8c41,0x8c41,0x8c45,0x8c4c,0x8c4e,0x8c51,0x8c53,0x8c55,0x8c57,0x8c5b,0x8c5d,0x8c5d,0x8c61,0x8c64,0x8c66,0x8c66,0x8c68,0x8c6d,0x8c73,0x8c73,0x8c75,0x8c76,0x8c78,0x8c7c,0x8c7e,0x8c7e,0x8c82,0x8c82,0x8c85,0x8c87,0x8c89,0x8c8e,0x8c90,0x8c90,0x8c92,0x8c94,0x8c98,0x8c99,0x8c9b,0x8ca2,0x8ca4,0x8ca4,0x8ca7,0x8cb0,0x8cb2,0x8cb4,0x8cb6,0x8cbd,0x8cbf,0x8ccb,0x8ccd,0x8ccf,0x8cd1,0x8cd3,0x8cd5,0x8cd6,0x8cd9,0x8cde,0x8ce0,0x8ce4,0x8ce6,0x8ce6,0x8ce8,0x8ce8,0x8cea,0x8cea,0x8cec,0x8ced,0x8cef,0x8cf2,0x8cf4,0x8cf5,0x8cf7,0x8cf8,0x8cfa,0x8cff,0x8d01,0x8d01,0x8d03,0x8d05,0x8d07,0x8d0b,0x8d0d,0x8d10,0x8d12,0x8d14,0x8d16,0x8d17,0x8d1b,0x8d1d,0x8d64,0x8d67,0x8d69,0x8d69,0x8d6b,0x8d6e,0x8d70,0x8d71,0x8d73,0x8d74,0x8d76,0x8d77,0x8d7f,0x8d7f,0x8d81,0x8d82,0x8d84,0x8d85,0x8d88,0x8d88,0x8d8a,0x8d8a,0x8d8d,0x8d8d,0x8d90,0x8d91,0x8d95,0x8d95,0x8d99,0x8d99,0x8d9e,0x8da0,0x8da3,0x8da3,0x8da6,0x8da6,0x8da8,0x8da8,0x8dab,0x8dac,0x8daf,0x8daf,0x8db2,0x8db3,0x8db5,0x8db5,0x8db7,0x8db7,0x8db9,0x8dbc,0x8dbe,0x8dbe,0x8dc0,0x8dc0,0x8dc2,0x8dc2,0x8dc5,0x8dc8,0x8dca,0x8dcc,0x8dce,0x8dcf,0x8dd1,0x8dd1,0x8dd4,0x8dd7,0x8dd9,0x8ddb,0x8ddd,0x8ddd,0x8ddf,0x8ddf,0x8de1,0x8de1,0x8de3,0x8de5,0x8de7,0x8de8,0x8dea,0x8dec,0x8def,0x8df5,0x8dfc,0x8dfd,0x8dff,0x8dff,0x8e01,0x8e01,0x8e04,0x8e06,0x8e08,0x8e0c,0x8e0f,0x8e11,0x8e14,0x8e14,0x8e16,0x8e16,0x8e1d,0x8e23,0x8e26,0x8e27,0x8e2a,0x8e2a,0x8e30,0x8e31,0x8e33,0x8e39,0x8e3d,0x8e3d,0x8e40,0x8e42,0x8e44,0x8e44,0x8e47,0x8e50,0x8e54,0x8e55,0x8e59,0x8e59,0x8e5b,0x8e64,0x8e69,0x8e69,0x8e6c,0x8e6d,0x8e6f,0x8e72,0x8e74,0x8e77,0x8e79,0x8e7c,0x8e81,0x8e85,0x8e87,0x8e87,0x8e89,0x8e8b,0x8e8d,0x8e8d,0x8e90,0x8e95,0x8e98,0x8e9b,0x8e9d,0x8e9e,0x8ea1,0x8ea2,0x8ea7,0x8ea7,0x8ea9,0x8eb1,0x8eb3,0x8eb3,0x8eb5,0x8eb6,0x8eba,0x8ebb,0x8ebe,0x8ebe,0x8ec0,0x8ec1,0x8ec3,0x8ec8,0x8eca,0x8ecd,0x8ecf,0x8ecf,0x8ed1,0x8ed2,0x8ed4,0x8ed4,0x8edb,0x8edc,0x8edf,0x8edf,0x8ee2,0x8ee3,0x8ee8,0x8ee8,0x8eeb,0x8eeb,0x8eed,0x8eee,0x8ef0,0x8ef1,0x8ef7,0x8efe,0x8f00,0x8f00,0x8f02,0x8f03,0x8f05,0x8f05,0x8f07,0x8f0a,0x8f0c,0x8f0c,0x8f0f,0x8f10,0x8f12,0x8f19,0x8f1b,0x8f21,0x8f23,0x8f23,0x8f25,0x8f2f,0x8f33,0x8f3b,0x8f3e,0x8f47,0x8f49,0x8f4a,0x8f4c,0x8f4f,0x8f51,0x8f55,0x8f57,0x8f58,0x8f5c,0x8f5f,0x8f61,0x8f66,0x8f9b,0x8fa8,0x8fad,0x8fb2,0x8fb4,0x8fb8,0x8fba,0x8fbc,0x8fbe,0x8fc2,0x8fc4,0x8fc6,0x8fc8,0x8fc8,0x8fca,0x8fcb,0x8fcd,0x8fce,0x8fd0,0x8fd5,0x8fda,0x8fda,0x8fe0,0x8fe0,0x8fe2,0x8fe6,0x8fe8,0x8feb,0x8fed,0x8ff1,0x8ff4,0x8ffb,0x8ffd,0x8ffe,0x9000,0x9006,0x9008,0x9008,0x900b,0x9011,0x9013,0x901b,0x901d,0x9023,0x9027,0x902a,0x902c,0x902f,0x9031,0x9039,0x903c,0x903c,0x903e,0x903f,0x9041,0x9045,0x9047,0x9047,0x9049,0x9056,0x9058,0x9059,0x905b,0x905e,0x9060,0x9063,0x9065,0x9069,0x906c,0x9070,0x9072,0x9072,0x9074,0x907a,0x907c,0x907d,0x907f,0x9085,0x9087,0x908c,0x908e,0x9091,0x9095,0x9095,0x9097,0x9099,0x909b,0x909b,0x90a0,0x90a3,0x90a5,0x90a6,0x90a8,0x90a8,0x90aa,0x90aa,0x90af,0x90b6,0x90b8,0x90b8,0x90bd,0x90be,0x90c1,0x90c1,0x90c3,0x90c5,0x90c7,0x90ca,0x90cc,0x90cc,0x90ce,0x90ce,0x90d2,0x90d2,0x90d5,0x90d5,0x90d7,0x90d9,0x90db,0x90df,0x90e1,0x90e2,0x90e4,0x90e5,0x90e8,0x90e8,0x90eb,0x90eb,0x90ed,0x90ed,0x90ef,0x90f0,0x90f2,0x90f2,0x90f4,0x90f7,0x90fd,0x9100,0x9102,0x9102,0x9104,0x9106,0x9108,0x9108,0x910d,0x910d,0x9110,0x9110,0x9112,0x9112,0x9114,0x911a,0x911c,0x911c,0x911e,0x911e,0x9120,0x9120,0x9122,0x9123,0x9125,0x9125,0x9127,0x9127,0x9129,0x9129,0x912d,0x9132,0x9134,0x9134,0x9136,0x9137,0x9139,0x913a,0x913c,0x913d,0x9143,0x9143,0x9146,0x914f,0x9152,0x9154,0x9156,0x915b,0x9161,0x9165,0x9167,0x9167,0x9169,0x916a,0x916c,0x916d,0x9172,0x9175,0x9177,0x917b,0x9181,0x9183,0x9185,0x9187,0x9189,0x918b,0x918d,0x918e,0x9190,0x9195,0x9197,0x9198,0x919c,0x919c,0x919e,0x919e,0x91a1,0x91a2,0x91a4,0x91a4,0x91a6,0x91a6,0x91a8,0x91a8,0x91aa,0x91b6,0x91b8,0x91b8,0x91ba,0x91bd,0x91bf,0x91c9,0x91cb,0x91d1,0x91d3,0x91d4,0x91d6,0x91df,0x91e1,0x91e1,0x91e3,0x91e7,0x91e9,0x91ea,0x91ec,0x91f1,0x91f5,0x91f7,0x91f9,0x91f9,0x91fb,0x91fd,0x91ff,0x9201,0x9204,0x9207,0x9209,0x920a,0x920c,0x920e,0x9210,0x9218,0x921c,0x921e,0x9223,0x9226,0x9228,0x9229,0x922c,0x922c,0x922e,0x9230,0x9233,0x923a,0x923c,0x923c,0x923e,0x9240,0x9242,0x924b,0x924d,0x9251,0x9256,0x925e,0x9260,0x9262,0x9264,0x9269,0x926e,0x9271,0x9275,0x9279,0x927b,0x9280,0x9283,0x9283,0x9285,0x9285,0x9288,0x928a,0x928d,0x928e,0x9291,0x9293,0x9295,0x929c,0x929f,0x92a0,0x92a4,0x92a5,0x92a7,0x92a8,0x92ab,0x92ab,0x92ad,0x92ad,0x92af,0x92af,0x92b2,0x92b3,0x92b6,0x92bd,0x92bf,0x92c3,0x92c5,0x92c8,0x92cb,0x92d0,0x92d2,0x92d3,0x92d5,0x92d5,0x92d7,0x92d9,0x92dc,0x92dd,0x92df,0x92e1,0x92e3,0x92e5,0x92e7,0x92ea,0x92ec,0x92ee,0x92f0,0x92f0,0x92f2,0x92f3,0x92f7,0x92fc,0x92ff,0x9300,0x9302,0x9302,0x9304,0x9304,0x9306,0x9306,0x9308,0x9308,0x930d,0x930d,0x930f,0x9311,0x9314,0x9315,0x9318,0x931a,0x931c,0x932c,0x932e,0x932f,0x9332,0x9337,0x933a,0x933b,0x9344,0x9344,0x9347,0x934b,0x934d,0x934d,0x9350,0x9352,0x9354,0x9358,0x935a,0x935c,0x935e,0x935e,0x9360,0x9360,0x9364,0x9365,0x9367,0x9367,0x9369,0x9371,0x9373,0x9376,0x937a,0x937a,0x937c,0x9382,0x9388,0x9388,0x938a,0x938d,0x938f,0x938f,0x9392,0x9392,0x9394,0x9398,0x939a,0x939b,0x939e,0x939e,0x93a1,0x93a1,0x93a3,0x93a4,0x93a6,0x93a9,0x93ab,0x93ae,0x93b0,0x93b0,0x93b4,0x93b6,0x93b9,0x93bb,0x93c1,0x93c1,0x93c3,0x93cd,0x93d0,0x93d1,0x93d3,0x93d3,0x93d6,0x93d9,0x93dc,0x93df,0x93e1,0x93e2,0x93e4,0x93e8,0x93f1,0x93f1,0x93f5,0x93f5,0x93f7,0x93fb,0x93fd,0x93fd,0x9401,0x9404,0x9407,0x9409,0x940d,0x9410,0x9413,0x941a,0x941f,0x941f,0x9421,0x9421,0x942b,0x942b,0x942e,0x942f,0x9431,0x9436,0x9438,0x9438,0x943a,0x943b,0x943d,0x943d,0x943f,0x943f,0x9441,0x9441,0x9443,0x9445,0x9448,0x9448,0x944a,0x944a,0x944c,0x944c,0x9451,0x9453,0x9455,0x9455,0x9459,0x945c,0x945e,0x9463,0x9468,0x9468,0x946a,0x946b,0x946d,0x9472,0x9475,0x9475,0x9477,0x9477,0x947c,0x947f,0x9481,0x9481,0x9483,0x9485,0x9577,0x9579,0x957e,0x9580,0x9582,0x9584,0x9586,0x958f,0x9591,0x9594,0x9596,0x9596,0x9598,0x9599,0x959d,0x95a9,0x95ab,0x95ad,0x95b1,0x95b2,0x95b4,0x95b4,0x95b6,0x95b6,0x95b9,0x95bf,0x95c3,0x95c3,0x95c6,0x95cd,0x95d0,0x95d6,0x95d8,0x95da,0x95dc,0x95e2,0x95e4,0x95e6,0x95e8,0x95e8,0x961c,0x961e,0x9621,0x9622,0x9624,0x9626,0x9628,0x9628,0x962a,0x962a,0x962c,0x962c,0x962e,0x962f,0x9631,0x9634,0x9637,0x963d,0x963f,0x9642,0x9644,0x9644,0x964b,0x964d,0x964f,0x9650,0x9652,0x9652,0x9654,0x9654,0x9656,0x9658,0x965b,0x965f,0x9661,0x9666,0x966a,0x966a,0x966c,0x966c,0x966e,0x966e,0x9670,0x9670,0x9672,0x9678,0x967a,0x967f,0x9681,0x9686,0x9688,0x968b,0x968d,0x968f,0x9691,0x9691,0x9694,0x969d,0x969f,0x96a0,0x96a3,0x96aa,0x96ae,0x96b4,0x96b6,0x96bd,0x96c0,0x96c1,0x96c4,0x96c7,0x96c9,0x96ce,0x96d1,0x96d2,0x96d5,0x96d6,0x96d8,0x96df,0x96e2,0x96e3,0x96e8,0x96eb,0x96ef,0x96f2,0x96f6,0x96f7,0x96f9,0x96fb,0x9700,0x9700,0x9702,0x970a,0x970d,0x970f,0x9711,0x9711,0x9713,0x9714,0x9716,0x9716,0x9719,0x971e,0x9721,0x9724,0x9727,0x9728,0x972a,0x972a,0x9730,0x9733,0x9736,0x9736,0x9738,0x9739,0x973b,0x973b,0x973d,0x973e,0x9741,0x9744,0x9746,0x974a,0x974d,0x974f,0x9751,0x9752,0x9755,0x975c,0x975e,0x975e,0x9760,0x9764,0x9766,0x976b,0x976d,0x976e,0x9771,0x9771,0x9773,0x9774,0x9776,0x977d,0x977f,0x9781,0x9784,0x9786,0x9789,0x9789,0x978b,0x978b,0x978d,0x978d,0x978f,0x9790,0x9795,0x979a,0x979c,0x979c,0x979e,0x97a0,0x97a2,0x97a3,0x97a6,0x97a6,0x97a8,0x97a8,0x97ab,0x97ae,0x97b1,0x97b6,0x97b8,0x97ba,0x97bc,0x97bc,0x97be,0x97bf,0x97c1,0x97c1,0x97c3,0x97ce,0x97d0,0x97d1,0x97d3,0x97d4,0x97d7,0x97d9,0x97db,0x97de,0x97e0,0x97e1,0x97e4,0x97e4,0x97e6,0x97e6,0x97ed,0x97ef,0x97f1,0x97f8,0x97fa,0x97fb,0x97ff,0x97ff,0x9801,0x9808,0x980a,0x980a,0x980c,0x9814,0x9816,0x981a,0x981c,0x981c,0x981e,0x981e,0x9820,0x9821,0x9823,0x9826,0x982b,0x9830,0x9832,0x9835,0x9837,0x9839,0x983b,0x983e,0x9844,0x9844,0x9846,0x9847,0x984a,0x984f,0x9851,0x985b,0x985e,0x985e,0x9862,0x9863,0x9865,0x9867,0x986a,0x986c,0x986f,0x9871,0x9873,0x9875,0x98a8,0x98a8,0x98aa,0x98ab,0x98ad,0x98b1,0x98b4,0x98b4,0x98b6,0x98b8,0x98ba,0x98bc,0x98bf,0x98bf,0x98c2,0x98c8,0x98cb,0x98cc,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e3,0x98e5,0x98e7,0x98e9,0x98eb,0x98ed,0x98f4,0x98f6,0x98f6,0x98fc,0x98fe,0x9902,0x9903,0x9905,0x9905,0x9907,0x990a,0x990c,0x990c,0x9910,0x9918,0x991a,0x9922,0x9924,0x9924,0x9926,0x9928,0x992b,0x992c,0x992e,0x992e,0x9931,0x9935,0x9939,0x993e,0x9940,0x9942,0x9945,0x9949,0x994b,0x994e,0x9950,0x9952,0x9954,0x9955,0x9957,0x9959,0x995b,0x995c,0x995e,0x9960,0x9963,0x9963,0x9996,0x9999,0x999b,0x999b,0x999d,0x999f,0x99a3,0x99a3,0x99a5,0x99a6,0x99a8,0x99a8,0x99ac,0x99ae,0x99b0,0x99b5,0x99b9,0x99ba,0x99bc,0x99bd,0x99bf,0x99bf,0x99c1,0x99c1,0x99c3,0x99c6,0x99c8,0x99c9,0x99d0,0x99d5,0x99d8,0x99df,0x99e1,0x99e2,0x99e7,0x99e7,0x99ea,0x99ee,0x99f0,0x99f2,0x99f4,0x99f5,0x99f8,0x99f9,0x99fb,0x99ff,0x9a01,0x9a05,0x9a08,0x9a08,0x9a0a,0x9a0c,0x9a0e,0x9a13,0x9a16,0x9a16,0x9a19,0x9a1a,0x9a1e,0x9a1e,0x9a20,0x9a20,0x9a22,0x9a24,0x9a27,0x9a28,0x9a2b,0x9a2b,0x9a2d,0x9a2e,0x9a30,0x9a31,0x9a33,0x9a33,0x9a35,0x9a38,0x9a3e,0x9a3e,0x9a40,0x9a45,0x9a47,0x9a47,0x9a4a,0x9a4e,0x9a51,0x9a52,0x9a54,0x9a58,0x9a5a,0x9a5b,0x9a5d,0x9a5d,0x9a5f,0x9a5f,0x9a62,0x9a62,0x9a64,0x9a65,0x9a69,0x9a6c,0x9aa8,0x9aa8,0x9aaa,0x9aaa,0x9aac,0x9ab0,0x9ab2,0x9ab2,0x9ab4,0x9ab9,0x9abb,0x9ac1,0x9ac3,0x9ac4,0x9ac6,0x9ac6,0x9ac8,0x9ac8,0x9ace,0x9ad9,0x9adb,0x9adc,0x9ade,0x9ae0,0x9ae2,0x9ae7,0x9ae9,0x9aef,0x9af1,0x9af5,0x9af7,0x9af7,0x9af9,0x9afb,0x9afd,0x9afd,0x9aff,0x9b06,0x9b08,0x9b09,0x9b0b,0x9b0e,0x9b10,0x9b10,0x9b12,0x9b12,0x9b16,0x9b16,0x9b18,0x9b1d,0x9b1f,0x9b20,0x9b22,0x9b23,0x9b25,0x9b2f,0x9b31,0x9b35,0x9b37,0x9b37,0x9b39,0x9b3d,0x9b41,0x9b45,0x9b48,0x9b48,0x9b4b,0x9b4f,0x9b51,0x9b51,0x9b54,0x9b58,0x9b5a,0x9b5b,0x9b5e,0x9b5e,0x9b61,0x9b61,0x9b63,0x9b63,0x9b65,0x9b66,0x9b68,0x9b68,0x9b6a,0x9b6f,0x9b72,0x9b79,0x9b7f,0x9b80,0x9b83,0x9b87,0x9b89,0x9b8b,0x9b8d,0x9b94,0x9b96,0x9b97,0x9b9a,0x9b9a,0x9b9d,0x9ba0,0x9ba6,0x9bae,0x9bb0,0x9bb2,0x9bb4,0x9bb4,0x9bb7,0x9bb9,0x9bbb,0x9bbc,0x9bbe,0x9bc1,0x9bc6,0x9bca,0x9bce,0x9bd2,0x9bd4,0x9bd4,0x9bd6,0x9bd8,0x9bdb,0x9bdb,0x9bdd,0x9bdd,0x9bdf,0x9bdf,0x9be1,0x9be5,0x9be7,0x9be8,0x9bea,0x9beb,0x9bee,0x9bf3,0x9bf5,0x9bf5,0x9bf7,0x9bfa,0x9bfd,0x9bfd,0x9bff,0x9c00,0x9c02,0x9c02,0x9c04,0x9c04,0x9c06,0x9c06,0x9c08,0x9c0d,0x9c0f,0x9c16,0x9c18,0x9c1e,0x9c21,0x9c2a,0x9c2d,0x9c32,0x9c35,0x9c37,0x9c39,0x9c3b,0x9c3d,0x9c3e,0x9c41,0x9c41,0x9c43,0x9c4a,0x9c4e,0x9c50,0x9c52,0x9c54,0x9c56,0x9c58,0x9c5a,0x9c61,0x9c63,0x9c63,0x9c65,0x9c65,0x9c67,0x9c6b,0x9c6d,0x9c6e,0x9c70,0x9c70,0x9c72,0x9c72,0x9c75,0x9c78,0x9c7a,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9ce9,0x9ceb,0x9cec,0x9cf0,0x9cf0,0x9cf2,0x9cf4,0x9cf6,0x9cf7,0x9cf9,0x9cf9,0x9d02,0x9d03,0x9d06,0x9d09,0x9d0b,0x9d0b,0x9d0e,0x9d0e,0x9d11,0x9d12,0x9d15,0x9d15,0x9d17,0x9d18,0x9d1b,0x9d1f,0x9d23,0x9d23,0x9d26,0x9d26,0x9d28,0x9d28,0x9d2a,0x9d2c,0x9d2f,0x9d30,0x9d32,0x9d34,0x9d3a,0x9d3f,0x9d41,0x9d48,0x9d4a,0x9d4a,0x9d50,0x9d54,0x9d59,0x9d59,0x9d5c,0x9d65,0x9d69,0x9d6c,0x9d6f,0x9d70,0x9d72,0x9d73,0x9d76,0x9d77,0x9d7a,0x9d7c,0x9d7e,0x9d7e,0x9d83,0x9d84,0x9d86,0x9d87,0x9d89,0x9d8a,0x9d8d,0x9d8f,0x9d92,0x9d93,0x9d95,0x9d9a,0x9da1,0x9da1,0x9da4,0x9da4,0x9da9,0x9dac,0x9dae,0x9daf,0x9db1,0x9db2,0x9db4,0x9db5,0x9db8,0x9dbd,0x9dbf,0x9dc4,0x9dc6,0x9dc7,0x9dc9,0x9dca,0x9dcf,0x9dcf,0x9dd3,0x9dd7,0x9dd9,0x9dda,0x9dde,0x9de0,0x9de3,0x9de3,0x9de5,0x9de7,0x9de9,0x9de9,0x9deb,0x9deb,0x9ded,0x9df0,0x9df2,0x9df4,0x9df8,0x9dfa,0x9dfd,0x9dfe,0x9e02,0x9e02,0x9e07,0x9e07,0x9e0a,0x9e0a,0x9e0d,0x9e0e,0x9e10,0x9e12,0x9e15,0x9e16,0x9e19,0x9e1f,0x9e75,0x9e75,0x9e78,0x9e7d,0x9e7f,0x9e85,0x9e87,0x9e88,0x9e8b,0x9e8c,0x9e8e,0x9e8f,0x9e91,0x9e93,0x9e95,0x9e98,0x9e9b,0x9e9b,0x9e9d,0x9e9f,0x9ea4,0x9ea6,0x9ea8,0x9eaa,0x9eac,0x9eb0,0x9eb3,0x9eb5,0x9eb8,0x9ebf,0x9ec3,0x9ec4,0x9ec6,0x9ec6,0x9ec8,0x9ec8,0x9ecb,0x9ed2,0x9ed4,0x9ed5,0x9ed8,0x9ed9,0x9edb,0x9ee0,0x9ee4,0x9ee5,0x9ee7,0x9ee8,0x9eec,0x9ef2,0x9ef4,0x9ef9,0x9efb,0x9eff,0x9f02,0x9f03,0x9f07,0x9f09,0x9f0e,0x9f17,0x9f19,0x9f1b,0x9f1f,0x9f22,0x9f26,0x9f26,0x9f2a,0x9f2c,0x9f2f,0x9f2f,0x9f31,0x9f32,0x9f34,0x9f34,0x9f37,0x9f37,0x9f39,0x9f3f,0x9f41,0x9f41,0x9f43,0x9f47,0x9f4a,0x9f4b,0x9f4e,0x9f50,0x9f52,0x9f58,0x9f5a,0x9f5a,0x9f5d,0x9f63,0x9f66,0x9f6a,0x9f6c,0x9f73,0x9f75,0x9f77,0x9f7a,0x9f7a,0x9f7d,0x9f7d,0x9f7f,0x9f7f,0x9f8d,0x9f8d,0x9f8f,0x9f92,0x9f94,0x9f97,0x9f99,0x9f99,0x9f9c,0x9fa3,0x9fa5,0x9fa5,0x9fb4,0x9fb4,0x9fbc,0x9fc2,0x9fc4,0x9fc4,0x9fc6,0x9fc6,0x9fcc,0x9fcc,0xf900,0xf959,0xf95b,0xf9f2,0xf9f4,0xfa0b,0xfa0e,0xfa6d,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x2000b,0x2000b,0x20089,0x2008a,0x200a2,0x200a2,0x200a4,0x200a4,0x200b0,0x200b0,0x200f5,0x200f5,0x20158,0x20158,0x201a2,0x201a2,0x20213,0x20213,0x2032b,0x2032b,0x20371,0x20371,0x20381,0x20381,0x203f9,0x203f9,0x2044a,0x2044a,0x20509,0x20509,0x2053f,0x2053f,0x205b1,0x205b1,0x205d6,0x205d6,0x20611,0x20611,0x20628,0x20628,0x206ec,0x206ec,0x2074f,0x2074f,0x207c8,0x207c8,0x20807,0x20807,0x2083a,0x2083a,0x208b9,0x208b9,0x2090e,0x2090e,0x2097c,0x2097c,0x20984,0x20984,0x2099d,0x2099d,0x20a64,0x20a64,0x20ad3,0x20ad3,0x20b1d,0x20b1d,0x20b9f,0x20b9f,0x20bb7,0x20bb7,0x20d45,0x20d45,0x20d58,0x20d58,0x20de1,0x20de1,0x20e64,0x20e64,0x20e6d,0x20e6d,0x20e95,0x20e95,0x20f5f,0x20f5f,0x21201,0x21201,0x2123d,0x2123d,0x21255,0x21255,0x21274,0x21274,0x2127b,0x2127b,0x212d7,0x212d7,0x212e4,0x212e4,0x212fd,0x212fd,0x2131b,0x2131b,0x21336,0x21336,0x21344,0x21344,0x213c4,0x213c4,0x2146d,0x2146e,0x215d7,0x215d7,0x21647,0x21647,0x216b4,0x216b4,0x21706,0x21706,0x21742,0x21742,0x218bd,0x218bd,0x219c3,0x219c3,0x21a1a,0x21a1a,0x21c56,0x21c56,0x21d2d,0x21d2d,0x21d45,0x21d45,0x21d62,0x21d62,0x21d78,0x21d78,0x21d92,0x21d92,0x21d9c,0x21d9c,0x21da1,0x21da1,0x21db7,0x21db7,0x21de0,0x21de0,0x21e33,0x21e34,0x21f1e,0x21f1e,0x21f76,0x21f76,0x21ffa,0x21ffa,0x2217b,0x2217b,0x22218,0x22218,0x2231e,0x2231e,0x223ad,0x223ad,0x22609,0x22609,0x226f3,0x226f3,0x2285b,0x2285b,0x228ab,0x228ab,0x2298f,0x2298f,0x22ab8,0x22ab8,0x22b46,0x22b46,0x22b4f,0x22b50,0x22ba6,0x22ba6,0x22c1d,0x22c1d,0x22c24,0x22c24,0x22de1,0x22de1,0x22e42,0x22e42,0x22feb,0x22feb,0x231b6,0x231b6,0x231c3,0x231c4,0x231f5,0x231f5,0x23372,0x23372,0x233cc,0x233cc,0x233d0,0x233d0,0x233d2,0x233d3,0x233d5,0x233d5,0x233da,0x233da,0x233df,0x233df,0x233e4,0x233e4,0x233fe,0x233fe,0x2344a,0x2344b,0x23451,0x23451,0x23465,0x23465,0x234e4,0x234e4,0x2355a,0x2355a,0x23594,0x23594,0x235c4,0x235c4,0x23638,0x2363a,0x23647,0x23647,0x2370c,0x2370c,0x2371c,0x2371c,0x2373f,0x2373f,0x23763,0x23764,0x237e7,0x237e7,0x237f1,0x237f1,0x237ff,0x237ff,0x23824,0x23824,0x2383d,0x2383d,0x23a98,0x23a98,0x23c7f,0x23c7f,0x23cbe,0x23cbe,0x23cfe,0x23cfe,0x23d00,0x23d00,0x23d0e,0x23d0e,0x23d40,0x23d40,0x23dd3,0x23dd3,0x23df9,0x23dfa,0x23f7e,0x23f7e,0x2404b,0x2404b,0x24096,0x24096,0x24103,0x24103,0x241c6,0x241c6,0x241fe,0x241fe,0x242ee,0x242ee,0x243bc,0x243bc,0x243d0,0x243d0,0x24629,0x24629,0x246a5,0x246a5,0x247f1,0x247f1,0x24896,0x24896,0x248e9,0x248e9,0x24a4d,0x24a4d,0x24b56,0x24b56,0x24b6f,0x24b6f,0x24c16,0x24c16,0x24d14,0x24d14,0x24e04,0x24e04,0x24e0e,0x24e0e,0x24e37,0x24e37,0x24e6a,0x24e6a,0x24e8b,0x24e8b,0x24ff2,0x24ff2,0x2504a,0x2504a,0x25055,0x25055,0x25122,0x25122,0x251a9,0x251a9,0x251cd,0x251cd,0x251e5,0x251e5,0x2521e,0x2521e,0x2524c,0x2524c,0x2542e,0x2542e,0x2548e,0x2548e,0x254d9,0x254d9,0x2550e,0x2550e,0x255a7,0x255a7,0x2567f,0x2567f,0x25771,0x25771,0x257a9,0x257a9,0x257b4,0x257b4,0x25874,0x25874,0x259c4,0x259c4,0x259cc,0x259cc,0x259d4,0x259d4,0x25ad7,0x25ad7,0x25ae3,0x25ae4,0x25af1,0x25af1,0x25bb2,0x25bb2,0x25c4b,0x25c4b,0x25c64,0x25c64,0x25da1,0x25da1,0x25e2e,0x25e2e,0x25e56,0x25e56,0x25e62,0x25e62,0x25e65,0x25e65,0x25ec2,0x25ec2,0x25ed8,0x25ed8,0x25ee8,0x25ee8,0x25f23,0x25f23,0x25f5c,0x25f5c,0x25fd4,0x25fd4,0x25fe0,0x25fe0,0x25ffb,0x25ffb,0x2600c,0x2600c,0x26017,0x26017,0x26060,0x26060,0x260ed,0x260ed,0x26222,0x26222,0x2626a,0x2626a,0x26270,0x26270,0x26286,0x26286,0x2634c,0x2634c,0x26402,0x26402,0x2667e,0x2667e,0x266b0,0x266b0,0x2671d,0x2671d,0x268dd,0x268dd,0x268ea,0x268ea,0x26951,0x26951,0x2696f,0x2696f,0x26999,0x26999,0x269dd,0x269dd,0x26a1e,0x26a1e,0x26a58,0x26a58,0x26a8c,0x26a8c,0x26ab7,0x26ab7,0x26aff,0x26aff,0x26c29,0x26c29,0x26c73,0x26c73,0x26c9e,0x26c9e,0x26cdd,0x26cdd,0x26e40,0x26e40,0x26e65,0x26e65,0x26f94,0x26f94,0x26ff6,0x26ff8,0x270f4,0x270f4,0x2710d,0x2710d,0x27139,0x27139,0x273da,0x273db,0x273fe,0x273fe,0x27410,0x27410,0x27449,0x27449,0x27614,0x27615,0x27631,0x27631,0x27684,0x27684,0x27693,0x27693,0x2770e,0x2770e,0x27723,0x27723,0x27752,0x27752,0x278b2,0x278b2,0x27985,0x27985,0x279b4,0x279b4,0x27a84,0x27a84,0x27bb3,0x27bb3,0x27bbe,0x27bbe,0x27bc7,0x27bc7,0x27c3c,0x27c3c,0x27cb8,0x27cb8,0x27d73,0x27d73,0x27da0,0x27da0,0x27e10,0x27e10,0x27eaf,0x27eaf,0x27fb7,0x27fb7,0x2808a,0x2808a,0x280bb,0x280bb,0x28277,0x28277,0x28282,0x28282,0x282f3,0x282f3,0x283cd,0x283cd,0x2840c,0x2840c,0x28455,0x28455,0x284dc,0x284dc,0x2856b,0x2856b,0x285c8,0x285c9,0x286d7,0x286d7,0x286fa,0x286fa,0x28946,0x28946,0x28949,0x28949,0x2896b,0x2896b,0x28987,0x28988,0x289ba,0x289bb,0x28a1e,0x28a1e,0x28a29,0x28a29,0x28a43,0x28a43,0x28a71,0x28a71,0x28a99,0x28a99,0x28acd,0x28acd,0x28add,0x28add,0x28ae4,0x28ae4,0x28bc1,0x28bc1,0x28bef,0x28bef,0x28cdd,0x28cdd,0x28d10,0x28d10,0x28d71,0x28d71,0x28dfb,0x28dfb,0x28e0f,0x28e0f,0x28e17,0x28e17,0x28e1f,0x28e1f,0x28e36,0x28e36,0x28e89,0x28e89,0x28eeb,0x28eeb,0x28ef6,0x28ef6,0x28f32,0x28f32,0x28ff8,0x28ff8,0x292a0,0x292a0,0x292b1,0x292b1,0x29490,0x29490,0x295cf,0x295cf,0x2967f,0x2967f,0x296f0,0x296f0,0x29719,0x29719,0x29750,0x29750,0x29810,0x29810,0x298c6,0x298c6,0x29a72,0x29a72,0x29d4b,0x29d4b,0x29ddb,0x29ddb,0x29e15,0x29e15,0x29e3d,0x29e3d,0x29e49,0x29e49,0x29e8a,0x29e8a,0x29ec4,0x29ec4,0x29edb,0x29edb,0x29ee9,0x29ee9,0x29fce,0x29fce,0x29fd7,0x29fd7,0x2a01a,0x2a01a,0x2a02f,0x2a02f,0x2a082,0x2a082,0x2a0f9,0x2a0f9,0x2a190,0x2a190,0x2a2b2,0x2a2b2,0x2a38c,0x2a38c,0x2a437,0x2a437,0x2a5f1,0x2a5f1,0x2a602,0x2a602,0x2a61a,0x2a61a,0x2a6b2,0x2a6b2,0x2a9e6,0x2a9e6,0x2b746,0x2b746,0x2b751,0x2b751,0x2b753,0x2b753,0x2b75a,0x2b75a,0x2b75c,0x2b75c,0x2b765,0x2b765,0x2b776,0x2b777,0x2b77c,0x2b77c,0x2b782,0x2b782,0x2b789,0x2b789,0x2b78b,0x2b78b,0x2b78e,0x2b78e,0x2b794,0x2b794,0x2b7ac,0x2b7ac,0x2b7af,0x2b7af,0x2b7bd,0x2b7bd,0x2b7c9,0x2b7c9,0x2b7cf,0x2b7cf,0x2b7d2,0x2b7d2,0x2b7d8,0x2b7d8,0x2b7f0,0x2b7f0,0x2b80d,0x2b80d,0x2b817,0x2b817,0x2b81a,0x2b81a,0x2d544,0x2d544,0x2e278,0x2e278,0x2e569,0x2e569,0x2e6ea,0x2e6ea,0x2f804,0x2f804,0x2f80f,0x2f80f,0x2f815,0x2f815,0x2f818,0x2f818,0x2f81a,0x2f81a,0x2f822,0x2f822,0x2f828,0x2f828,0x2f82c,0x2f82c,0x2f833,0x2f833,0x2f83f,0x2f83f,0x2f846,0x2f846,0x2f852,0x2f852,0x2f862,0x2f862,0x2f86d,0x2f86d,0x2f873,0x2f873,0x2f877,0x2f877,0x2f884,0x2f884,0x2f899,0x2f89a,0x2f8a6,0x2f8a6,0x2f8ac,0x2f8ac,0x2f8b2,0x2f8b2,0x2f8b6,0x2f8b6,0x2f8d3,0x2f8d3,0x2f8db,0x2f8dc,0x2f8e1,0x2f8e1,0x2f8e5,0x2f8e5,0x2f8ea,0x2f8ea,0x2f8ed,0x2f8ed,0x2f8fc,0x2f8fc,0x2f903,0x2f903,0x2f90b,0x2f90b,0x2f90f,0x2f90f,0x2f91a,0x2f91a,0x2f920,0x2f921,0x2f945,0x2f945,0x2f947,0x2f947,0x2f96c,0x2f96c,0x2f995,0x2f995,0x2f9d0,0x2f9d0,0x2f9de,0x2f9df,0x2f9f4,0x2f9f4,0x30ede,0x30ede,0x3106c,0x3106c,]), + NotoFont.fromFlatRanges('Noto Sans Javanese', 'http://fonts.gstatic.com/s/notosansjavanese/v15/2V0AKJkDAIA6Hp4zoSScDjV0Y-eoHAHJ8r88Rp29eA.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa980,0xa9cd,0xa9cf,0xa9d9,0xa9de,0xa9df,]), + NotoFont.fromFlatRanges('Noto Sans KR', 'http://fonts.gstatic.com/s/notosanskr/v27/PbykFmXiEBPT4ITbgNA5Cgm20HTs4JMMuA.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1100,0x11ff,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x349a,0x349a,0x34d7,0x34d7,0x3515,0x3515,0x3521,0x3521,0x353e,0x353e,0x35ff,0x35ff,0x366f,0x366f,0x36c3,0x36c5,0x36e6,0x36e6,0x3723,0x3723,0x372f,0x372f,0x373a,0x373a,0x37bc,0x37bc,0x380c,0x380c,0x3818,0x3818,0x3883,0x3883,0x38ba,0x38ba,0x38e7,0x38e7,0x38fd,0x38fd,0x3960,0x3960,0x3965,0x3965,0x3983,0x3983,0x3990,0x3990,0x39a5,0x39a5,0x39b6,0x39b6,0x3a39,0x3a39,0x3aa4,0x3aa4,0x3adc,0x3adc,0x3af6,0x3af6,0x3b03,0x3b03,0x3b23,0x3b23,0x3b79,0x3b79,0x3bf3,0x3bf3,0x3c14,0x3c14,0x3c24,0x3c24,0x3c2d,0x3c2d,0x3cbd,0x3cbe,0x3cfc,0x3cfc,0x3d17,0x3d17,0x3d5f,0x3d5f,0x3dbc,0x3dbc,0x3dc2,0x3dc2,0x3ec4,0x3ec4,0x3eed,0x3eed,0x3efd,0x3efd,0x3f04,0x3f04,0x402f,0x402f,0x4034,0x4034,0x4062,0x4062,0x40a9,0x40a9,0x40c9,0x40c9,0x4137,0x4137,0x41ac,0x41ac,0x4259,0x4259,0x43bb,0x43bb,0x43c7,0x43c7,0x43e7,0x43e7,0x43ea,0x43ea,0x4450,0x4450,0x4512,0x4512,0x45f2,0x45f2,0x4618,0x4618,0x46b7,0x46b7,0x46be,0x46be,0x46d4,0x46d4,0x46d8,0x46d8,0x46dd,0x46dd,0x472d,0x472d,0x476c,0x476c,0x477d,0x477d,0x479f,0x479f,0x4863,0x4863,0x4883,0x4883,0x4896,0x4896,0x48a6,0x48a6,0x4925,0x4925,0x499e,0x499e,0x49a5,0x49a5,0x49cb,0x49cb,0x4a12,0x4a12,0x4a2d,0x4a2d,0x4ab8,0x4ab8,0x4adf,0x4adf,0x4ae8,0x4ae8,0x4afb,0x4afb,0x4b53,0x4b53,0x4b71,0x4b71,0x4cdf,0x4ce0,0x4d1b,0x4d1b,0x4e00,0x4e01,0x4e03,0x4e03,0x4e07,0x4e0b,0x4e0d,0x4e0e,0x4e11,0x4e11,0x4e14,0x4e16,0x4e18,0x4e19,0x4e1e,0x4e1f,0x4e24,0x4e24,0x4e26,0x4e26,0x4e28,0x4e28,0x4e2b,0x4e2d,0x4e30,0x4e32,0x4e36,0x4e36,0x4e38,0x4e39,0x4e3b,0x4e3b,0x4e3f,0x4e3f,0x4e42,0x4e43,0x4e45,0x4e45,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e56,0x4e5b,0x4e5d,0x4e5f,0x4e67,0x4e67,0x4e6b,0x4e6d,0x4e71,0x4e71,0x4e73,0x4e73,0x4e76,0x4e77,0x4e7a,0x4e7c,0x4e7e,0x4e7e,0x4e80,0x4e80,0x4e82,0x4e82,0x4e85,0x4e86,0x4e88,0x4e89,0x4e8b,0x4e8c,0x4e8e,0x4e92,0x4e94,0x4e95,0x4e98,0x4e99,0x4e9b,0x4e9c,0x4e9e,0x4ea2,0x4ea4,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eae,0x4eb0,0x4eb0,0x4eb3,0x4eb4,0x4eb6,0x4eb6,0x4eb9,0x4ebb,0x4ec0,0x4ec1,0x4ec4,0x4ec4,0x4ec6,0x4ec7,0x4eca,0x4ecb,0x4ecd,0x4ecd,0x4ed4,0x4ed9,0x4edd,0x4edf,0x4ee1,0x4ee1,0x4ee3,0x4ee5,0x4eee,0x4eee,0x4ef0,0x4ef0,0x4ef2,0x4ef3,0x4ef5,0x4ef7,0x4efb,0x4efb,0x4efd,0x4efd,0x4eff,0x4f01,0x4f09,0x4f0b,0x4f0d,0x4f11,0x4f1a,0x4f1a,0x4f1d,0x4f1d,0x4f2f,0x4f30,0x4f34,0x4f34,0x4f36,0x4f36,0x4f38,0x4f38,0x4f3a,0x4f3a,0x4f3c,0x4f3e,0x4f42,0x4f43,0x4f46,0x4f49,0x4f4b,0x4f4b,0x4f4d,0x4f51,0x4f53,0x4f57,0x4f59,0x4f5f,0x4f69,0x4f6a,0x4f6f,0x4f70,0x4f73,0x4f74,0x4f76,0x4f76,0x4f78,0x4f81,0x4f83,0x4f84,0x4f86,0x4f86,0x4f88,0x4f8b,0x4f8d,0x4f92,0x4f94,0x4f94,0x4f96,0x4f98,0x4f9a,0x4f9d,0x4fae,0x4faf,0x4fb2,0x4fb2,0x4fb5,0x4fb6,0x4fb9,0x4fb9,0x4fbb,0x4fbb,0x4fbf,0x4fbf,0x4fc1,0x4fc5,0x4fc9,0x4fca,0x4fcc,0x4fd4,0x4fd7,0x4fdb,0x4fdd,0x4fe1,0x4fe3,0x4fe3,0x4fee,0x4ff1,0x4ff3,0x4ff6,0x4ff8,0x4ff8,0x4ffa,0x4ffa,0x4ffe,0x4ffe,0x5000,0x5000,0x5002,0x5002,0x5005,0x5007,0x5009,0x5009,0x500b,0x500b,0x500d,0x500d,0x500f,0x500f,0x5011,0x5014,0x5016,0x5016,0x5018,0x501a,0x501c,0x501c,0x501e,0x501f,0x5021,0x502e,0x5030,0x5030,0x503b,0x503b,0x5043,0x5044,0x5047,0x504a,0x504e,0x504f,0x5053,0x5053,0x5055,0x5056,0x5058,0x505a,0x505c,0x505c,0x5060,0x5060,0x5062,0x5062,0x5065,0x5066,0x506a,0x506a,0x5070,0x5070,0x5072,0x5072,0x5074,0x5076,0x5078,0x5078,0x5080,0x5080,0x5083,0x5083,0x5085,0x5085,0x508b,0x508b,0x508d,0x508d,0x5091,0x5092,0x5094,0x5094,0x5096,0x5096,0x5098,0x509b,0x509d,0x509e,0x50a2,0x50a2,0x50ac,0x50ae,0x50b2,0x50b5,0x50b7,0x50b7,0x50bd,0x50bf,0x50c2,0x50c2,0x50c4,0x50c5,0x50c9,0x50ca,0x50cf,0x50cf,0x50d1,0x50d1,0x50d4,0x50d6,0x50da,0x50db,0x50de,0x50de,0x50e2,0x50e2,0x50e5,0x50e7,0x50e9,0x50e9,0x50ec,0x50ee,0x50f5,0x50f5,0x50f9,0x50f9,0x50fb,0x50fb,0x50fe,0x5104,0x5106,0x5107,0x5109,0x5109,0x510b,0x510c,0x5110,0x5110,0x5112,0x5115,0x5117,0x5118,0x511a,0x511c,0x511f,0x511f,0x5121,0x5122,0x5124,0x5125,0x5127,0x5127,0x512a,0x512b,0x5131,0x5133,0x5135,0x5135,0x5137,0x513c,0x513f,0x5141,0x5143,0x5149,0x514b,0x514e,0x5150,0x5150,0x5152,0x5152,0x5154,0x5157,0x515a,0x515a,0x515c,0x515c,0x5162,0x5162,0x5165,0x5165,0x5167,0x516e,0x5171,0x5171,0x5175,0x5178,0x517c,0x517c,0x5180,0x5180,0x5182,0x5182,0x5186,0x5186,0x5189,0x518a,0x518c,0x518d,0x518f,0x518f,0x5191,0x5193,0x5195,0x5199,0x519e,0x519e,0x51a0,0x51a0,0x51a2,0x51a5,0x51aa,0x51ac,0x51b0,0x51b2,0x51b6,0x51b7,0x51bd,0x51be,0x51c4,0x51c6,0x51c9,0x51cd,0x51d2,0x51d2,0x51d4,0x51d4,0x51d6,0x51d6,0x51db,0x51de,0x51e0,0x51e1,0x51e9,0x51e9,0x51ed,0x51ed,0x51f0,0x51f1,0x51f3,0x51f6,0x51f8,0x51fa,0x51fd,0x51fd,0x5200,0x5203,0x5206,0x5208,0x520a,0x520a,0x520e,0x520e,0x5211,0x5211,0x5213,0x5213,0x5216,0x5217,0x521d,0x521d,0x5224,0x5227,0x5229,0x522a,0x522e,0x522e,0x5230,0x5233,0x5236,0x523b,0x5243,0x5244,0x5246,0x5247,0x5249,0x524d,0x5254,0x5257,0x525a,0x525b,0x525d,0x525f,0x5261,0x5261,0x5269,0x526a,0x526f,0x526f,0x5272,0x5272,0x5274,0x5275,0x5277,0x5277,0x527a,0x527a,0x527d,0x527d,0x527f,0x527f,0x5282,0x5283,0x5287,0x5289,0x528d,0x528d,0x5291,0x5293,0x5297,0x5298,0x529b,0x529b,0x529f,0x52a0,0x52a3,0x52a4,0x52a7,0x52a7,0x52a9,0x52ae,0x52b9,0x52b9,0x52be,0x52be,0x52c1,0x52c1,0x52c3,0x52c3,0x52c5,0x52c5,0x52c7,0x52c7,0x52c9,0x52c9,0x52cc,0x52cd,0x52d2,0x52d2,0x52d5,0x52d6,0x52d8,0x52d9,0x52db,0x52db,0x52dd,0x52e4,0x52e6,0x52e6,0x52ed,0x52ed,0x52f2,0x52f3,0x52f5,0x52f5,0x52f8,0x52fb,0x52fe,0x5303,0x5305,0x5305,0x5308,0x5308,0x530a,0x530a,0x530c,0x530d,0x530f,0x5310,0x5315,0x5317,0x5319,0x531a,0x5320,0x5321,0x5323,0x5323,0x5327,0x5327,0x532a,0x532a,0x532f,0x532f,0x5331,0x5331,0x5336,0x5336,0x5338,0x533b,0x533d,0x5341,0x5343,0x5345,0x5347,0x534a,0x534d,0x534d,0x5351,0x5354,0x5357,0x5357,0x535a,0x535a,0x535c,0x535c,0x535e,0x535e,0x5360,0x5361,0x5364,0x5364,0x5366,0x5366,0x5368,0x5369,0x536c,0x536c,0x536e,0x5375,0x5377,0x537b,0x537d,0x537f,0x5382,0x5382,0x5384,0x5384,0x538e,0x538e,0x5393,0x5393,0x5396,0x5396,0x5398,0x5398,0x539a,0x539a,0x539d,0x539d,0x539f,0x53a0,0x53a5,0x53a6,0x53aa,0x53aa,0x53ad,0x53ae,0x53b2,0x53b3,0x53b6,0x53b6,0x53b9,0x53b9,0x53bb,0x53bb,0x53c2,0x53c3,0x53c5,0x53c5,0x53c8,0x53cd,0x53d4,0x53d4,0x53d6,0x53d7,0x53d9,0x53d9,0x53db,0x53db,0x53df,0x53df,0x53e1,0x53e6,0x53e8,0x53f8,0x5401,0x5401,0x5403,0x5404,0x5408,0x5411,0x541b,0x541b,0x541d,0x541d,0x541f,0x5420,0x5426,0x5426,0x5429,0x5429,0x542b,0x542c,0x542e,0x542e,0x5431,0x5431,0x5433,0x5433,0x5436,0x5436,0x5438,0x5439,0x543b,0x543e,0x5440,0x5440,0x5442,0x5442,0x5446,0x5446,0x5448,0x5448,0x544a,0x544a,0x544e,0x544e,0x5451,0x5451,0x545d,0x545d,0x545f,0x545f,0x5462,0x5462,0x5464,0x5464,0x5466,0x5466,0x5468,0x5468,0x546a,0x546b,0x5470,0x5471,0x5473,0x5473,0x5475,0x5476,0x547b,0x547d,0x547f,0x5480,0x5484,0x5484,0x5486,0x5487,0x548b,0x5490,0x5496,0x5496,0x54a0,0x54a0,0x54a2,0x54a2,0x54a4,0x54a5,0x54a8,0x54a8,0x54ab,0x54ac,0x54af,0x54af,0x54b2,0x54b3,0x54b8,0x54b8,0x54bb,0x54bd,0x54bf,0x54c4,0x54c6,0x54c9,0x54e1,0x54e1,0x54e5,0x54e6,0x54e8,0x54e9,0x54ed,0x54ee,0x54f1,0x54f2,0x54fa,0x54fa,0x54fd,0x54fd,0x54ff,0x54ff,0x5504,0x5504,0x5506,0x5507,0x5509,0x5509,0x550e,0x5510,0x5514,0x5514,0x551c,0x551c,0x552b,0x552b,0x552e,0x552f,0x5531,0x5531,0x5533,0x5533,0x5535,0x5535,0x5539,0x5539,0x553c,0x553c,0x553e,0x553e,0x5540,0x5540,0x5542,0x5542,0x5544,0x5544,0x5546,0x5546,0x554a,0x554a,0x554f,0x554f,0x5553,0x5553,0x5556,0x5557,0x555c,0x555c,0x555e,0x555e,0x5563,0x5563,0x557b,0x5581,0x5583,0x5584,0x5586,0x5587,0x5589,0x558b,0x5591,0x5591,0x5593,0x5594,0x5598,0x559a,0x559c,0x559f,0x55a3,0x55a4,0x55a7,0x55ac,0x55ae,0x55ae,0x55b0,0x55b0,0x55c3,0x55c3,0x55c5,0x55c5,0x55c7,0x55c7,0x55c9,0x55c9,0x55d1,0x55d1,0x55d4,0x55d4,0x55da,0x55dc,0x55df,0x55e0,0x55e2,0x55e4,0x55f7,0x55f7,0x55fd,0x55ff,0x5604,0x5604,0x5606,0x5606,0x5608,0x5609,0x560c,0x5610,0x5612,0x5612,0x5614,0x5614,0x5616,0x5617,0x5629,0x5629,0x562c,0x562c,0x562f,0x562f,0x5632,0x5632,0x5634,0x5634,0x5636,0x5639,0x563b,0x563b,0x563f,0x563f,0x5641,0x5642,0x5649,0x5649,0x564b,0x564b,0x564d,0x564f,0x5653,0x5653,0x5664,0x5665,0x5668,0x566d,0x566f,0x566f,0x5672,0x5672,0x5674,0x5674,0x5676,0x5676,0x5678,0x5678,0x567a,0x567a,0x5680,0x5680,0x5684,0x5684,0x5686,0x5687,0x568f,0x568f,0x5699,0x569a,0x56a5,0x56a5,0x56a7,0x56a7,0x56ac,0x56ac,0x56ae,0x56ae,0x56b3,0x56b4,0x56b6,0x56b6,0x56bc,0x56bc,0x56c0,0x56c3,0x56c8,0x56ca,0x56cd,0x56cd,0x56d1,0x56d1,0x56d7,0x56d7,0x56da,0x56db,0x56de,0x56e0,0x56e3,0x56e3,0x56e6,0x56e7,0x56eb,0x56eb,0x56ed,0x56ee,0x56f0,0x56f0,0x56f3,0x56f3,0x56f7,0x56f7,0x56f9,0x56fa,0x56fd,0x56fd,0x56ff,0x56ff,0x5701,0x5704,0x5707,0x570b,0x570d,0x570d,0x5712,0x5713,0x5716,0x5716,0x5718,0x5718,0x571c,0x571c,0x571f,0x571f,0x5725,0x5725,0x5728,0x572a,0x572c,0x572e,0x5730,0x5730,0x573b,0x573b,0x573e,0x573e,0x5740,0x5742,0x5747,0x5747,0x574a,0x574a,0x574c,0x5751,0x5761,0x5761,0x5764,0x5764,0x5766,0x576a,0x576e,0x5771,0x5773,0x5773,0x5775,0x5775,0x5777,0x5778,0x577b,0x577c,0x5782,0x5782,0x5788,0x5788,0x578b,0x578c,0x5793,0x5793,0x5795,0x5795,0x579e,0x579e,0x57a0,0x57a0,0x57a2,0x57a4,0x57b8,0x57b8,0x57bd,0x57bd,0x57c3,0x57c3,0x57c6,0x57c9,0x57cb,0x57cb,0x57ce,0x57cf,0x57d1,0x57d2,0x57dc,0x57dc,0x57df,0x57e0,0x57e4,0x57e4,0x57e9,0x57e9,0x57ed,0x57ee,0x57f0,0x57f0,0x57f3,0x57f4,0x57f6,0x57f7,0x57f9,0x57fd,0x5800,0x5800,0x5802,0x5806,0x5808,0x580b,0x5817,0x5817,0x5819,0x5819,0x581d,0x581e,0x5820,0x5821,0x5823,0x5824,0x5826,0x5827,0x582a,0x582a,0x582d,0x582d,0x582f,0x5831,0x5834,0x5835,0x583a,0x583a,0x5840,0x5840,0x5849,0x584d,0x584f,0x5852,0x5854,0x5854,0x5857,0x585a,0x585e,0x585e,0x5861,0x5862,0x5864,0x5864,0x5869,0x5869,0x5875,0x5875,0x5879,0x5879,0x587c,0x587e,0x5880,0x5881,0x5883,0x5883,0x5885,0x5885,0x5889,0x588a,0x588c,0x588d,0x5890,0x5890,0x5893,0x5893,0x589c,0x589f,0x58a1,0x58a1,0x58a3,0x58a3,0x58a8,0x58a9,0x58ab,0x58ab,0x58ae,0x58ae,0x58b0,0x58b1,0x58b3,0x58b3,0x58ba,0x58bb,0x58be,0x58be,0x58c1,0x58c1,0x58c3,0x58c3,0x58c5,0x58c5,0x58c7,0x58c7,0x58ce,0x58ce,0x58d1,0x58d1,0x58d3,0x58d5,0x58d8,0x58da,0x58dc,0x58df,0x58e1,0x58e1,0x58e4,0x58e4,0x58eb,0x58ec,0x58ee,0x58f0,0x58f2,0x58f2,0x58f9,0x58fb,0x58fd,0x58fd,0x5902,0x5902,0x5906,0x5906,0x5908,0x5908,0x590a,0x590a,0x590f,0x5910,0x5914,0x5916,0x5919,0x591c,0x5922,0x5922,0x5924,0x5925,0x5927,0x5927,0x5929,0x592f,0x5931,0x5932,0x5937,0x5938,0x593d,0x593e,0x5944,0x5944,0x5947,0x5949,0x594c,0x594c,0x594e,0x5951,0x5953,0x5955,0x5957,0x5958,0x595a,0x595a,0x595c,0x595c,0x5960,0x5960,0x5962,0x5962,0x5967,0x5967,0x5969,0x596e,0x5972,0x5974,0x5976,0x5976,0x5978,0x5978,0x597d,0x597d,0x5982,0x5984,0x598a,0x598a,0x598c,0x598d,0x5991,0x5993,0x5996,0x5997,0x5999,0x5999,0x599d,0x599d,0x59a3,0x59a5,0x59a7,0x59a8,0x59ac,0x59ac,0x59af,0x59af,0x59b2,0x59b2,0x59b5,0x59b6,0x59b8,0x59b9,0x59bb,0x59bb,0x59be,0x59bf,0x59c1,0x59c1,0x59c3,0x59c3,0x59c6,0x59c6,0x59c8,0x59cb,0x59cd,0x59cd,0x59d0,0x59d4,0x59d9,0x59da,0x59dc,0x59de,0x59e2,0x59e6,0x59e8,0x59e8,0x59ea,0x59ec,0x59ee,0x59ee,0x59f0,0x59f0,0x59f2,0x59f2,0x59f7,0x59fc,0x59ff,0x59ff,0x5a01,0x5a01,0x5a03,0x5a03,0x5a09,0x5a0a,0x5a0d,0x5a0d,0x5a11,0x5a11,0x5a13,0x5a13,0x5a18,0x5a19,0x5a1b,0x5a1c,0x5a1f,0x5a20,0x5a23,0x5a23,0x5a25,0x5a25,0x5a27,0x5a27,0x5a29,0x5a29,0x5a2b,0x5a2b,0x5a2d,0x5a2d,0x5a35,0x5a36,0x5a3c,0x5a3c,0x5a3f,0x5a41,0x5a46,0x5a47,0x5a49,0x5a49,0x5a4b,0x5a4c,0x5a50,0x5a51,0x5a5a,0x5a5a,0x5a60,0x5a60,0x5a62,0x5a63,0x5a66,0x5a67,0x5a69,0x5a6a,0x5a6d,0x5a6d,0x5a72,0x5a72,0x5a77,0x5a77,0x5a7f,0x5a7f,0x5a84,0x5a84,0x5a8d,0x5a8d,0x5a90,0x5a90,0x5a92,0x5a93,0x5a95,0x5a95,0x5a9a,0x5a9b,0x5a9e,0x5a9f,0x5aa2,0x5aa2,0x5aa4,0x5aa4,0x5aa7,0x5aa7,0x5aaa,0x5aaa,0x5ab3,0x5ab3,0x5ab5,0x5ab5,0x5aba,0x5abf,0x5ac1,0x5ac2,0x5ac4,0x5ac4,0x5ac8,0x5ac9,0x5acb,0x5acc,0x5ad5,0x5ad7,0x5ad9,0x5adb,0x5add,0x5add,0x5ae0,0x5ae6,0x5ae9,0x5ae9,0x5aeb,0x5aeb,0x5aed,0x5aef,0x5af6,0x5af6,0x5afa,0x5afb,0x5afd,0x5afd,0x5b00,0x5b00,0x5b05,0x5b05,0x5b08,0x5b09,0x5b0b,0x5b0c,0x5b16,0x5b16,0x5b19,0x5b19,0x5b1b,0x5b1b,0x5b25,0x5b25,0x5b28,0x5b28,0x5b2a,0x5b2a,0x5b2d,0x5b2d,0x5b30,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b3e,0x5b40,0x5b43,0x5b43,0x5b45,0x5b45,0x5b4c,0x5b4c,0x5b50,0x5b51,0x5b54,0x5b58,0x5b5a,0x5b5d,0x5b5f,0x5b5f,0x5b61,0x5b61,0x5b63,0x5b66,0x5b69,0x5b69,0x5b6b,0x5b6b,0x5b70,0x5b71,0x5b75,0x5b76,0x5b78,0x5b78,0x5b7a,0x5b7a,0x5b7c,0x5b7c,0x5b7f,0x5b82,0x5b85,0x5b85,0x5b87,0x5b8c,0x5b8f,0x5b8f,0x5b93,0x5b93,0x5b95,0x5b9d,0x5b9f,0x5b9f,0x5ba2,0x5ba6,0x5bac,0x5bac,0x5bae,0x5bae,0x5bb0,0x5bb0,0x5bb3,0x5bb6,0x5bb8,0x5bb9,0x5bbf,0x5bc0,0x5bc2,0x5bc7,0x5bcc,0x5bcc,0x5bd0,0x5bd0,0x5bd2,0x5bd4,0x5bd6,0x5bd8,0x5bdb,0x5bdb,0x5bde,0x5bdf,0x5be1,0x5be2,0x5be4,0x5be9,0x5beb,0x5bf0,0x5bf5,0x5bf6,0x5bf8,0x5bfa,0x5bff,0x5bff,0x5c01,0x5c01,0x5c04,0x5c0f,0x5c11,0x5c11,0x5c14,0x5c14,0x5c16,0x5c16,0x5c19,0x5c19,0x5c1f,0x5c20,0x5c22,0x5c24,0x5c28,0x5c28,0x5c2b,0x5c2b,0x5c31,0x5c31,0x5c38,0x5c41,0x5c45,0x5c48,0x5c4b,0x5c4b,0x5c4d,0x5c4e,0x5c50,0x5c51,0x5c55,0x5c55,0x5c5b,0x5c5b,0x5c60,0x5c60,0x5c62,0x5c62,0x5c64,0x5c65,0x5c68,0x5c68,0x5c6c,0x5c6c,0x5c6f,0x5c6f,0x5c71,0x5c71,0x5c73,0x5c73,0x5c79,0x5c7a,0x5c88,0x5c88,0x5c8a,0x5c8a,0x5c8c,0x5c8c,0x5c8f,0x5c92,0x5c94,0x5c94,0x5c9d,0x5c9d,0x5ca1,0x5ca1,0x5ca3,0x5ca3,0x5ca5,0x5cad,0x5cb1,0x5cb1,0x5cb3,0x5cb3,0x5cb5,0x5cb5,0x5cb7,0x5cb8,0x5cba,0x5cba,0x5cbe,0x5cbe,0x5cc0,0x5cc0,0x5ccb,0x5ccb,0x5cd2,0x5cd2,0x5cd9,0x5cd9,0x5ce0,0x5ce0,0x5ce8,0x5ce9,0x5ced,0x5ced,0x5cef,0x5cf1,0x5cf4,0x5cf4,0x5cf6,0x5cf6,0x5cfb,0x5cfb,0x5cfd,0x5cfd,0x5d06,0x5d07,0x5d0d,0x5d0e,0x5d10,0x5d11,0x5d14,0x5d19,0x5d1b,0x5d1b,0x5d1f,0x5d1f,0x5d22,0x5d22,0x5d24,0x5d24,0x5d26,0x5d27,0x5d29,0x5d29,0x5d34,0x5d34,0x5d3d,0x5d3d,0x5d41,0x5d42,0x5d44,0x5d44,0x5d4b,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d50,0x5d53,0x5d54,0x5d69,0x5d69,0x5d6c,0x5d6c,0x5d6f,0x5d6f,0x5d71,0x5d71,0x5d81,0x5d82,0x5d84,0x5d84,0x5d86,0x5d87,0x5d8b,0x5d8b,0x5d92,0x5d92,0x5d94,0x5d95,0x5d99,0x5d99,0x5d9d,0x5d9d,0x5da0,0x5da0,0x5da2,0x5da2,0x5da7,0x5da7,0x5daa,0x5dab,0x5dae,0x5dae,0x5db0,0x5db0,0x5db7,0x5db8,0x5dba,0x5dba,0x5dbc,0x5dbe,0x5dc9,0x5dc9,0x5dcb,0x5dcb,0x5dcd,0x5dcd,0x5dd1,0x5dd3,0x5dd6,0x5dd6,0x5dda,0x5ddb,0x5ddd,0x5dde,0x5de0,0x5de2,0x5de5,0x5de8,0x5deb,0x5deb,0x5dee,0x5dee,0x5df1,0x5df5,0x5df7,0x5df9,0x5dfb,0x5dfb,0x5dfd,0x5dfe,0x5e02,0x5e03,0x5e06,0x5e06,0x5e09,0x5e09,0x5e0c,0x5e0c,0x5e11,0x5e11,0x5e15,0x5e16,0x5e19,0x5e1b,0x5e1d,0x5e1d,0x5e20,0x5e20,0x5e25,0x5e25,0x5e28,0x5e28,0x5e2b,0x5e2b,0x5e2d,0x5e2d,0x5e33,0x5e33,0x5e36,0x5e38,0x5e3d,0x5e3d,0x5e3f,0x5e40,0x5e43,0x5e45,0x5e47,0x5e47,0x5e4c,0x5e4c,0x5e4e,0x5e4e,0x5e54,0x5e55,0x5e58,0x5e58,0x5e5e,0x5e5f,0x5e61,0x5e63,0x5e68,0x5e68,0x5e6a,0x5e6c,0x5e70,0x5e74,0x5e76,0x5e80,0x5e83,0x5e84,0x5e87,0x5e87,0x5e8a,0x5e8b,0x5e8f,0x5e8f,0x5e95,0x5e97,0x5e9a,0x5e9a,0x5e9c,0x5e9c,0x5ea0,0x5ea0,0x5ea5,0x5ea8,0x5eab,0x5eab,0x5ead,0x5ead,0x5eb3,0x5eb3,0x5eb5,0x5eb8,0x5ebd,0x5ebe,0x5ec1,0x5ec2,0x5ec8,0x5ecb,0x5ecf,0x5ed1,0x5ed3,0x5ed3,0x5ed5,0x5ed6,0x5ed9,0x5edb,0x5edd,0x5ee3,0x5ee5,0x5ee5,0x5ee7,0x5ee9,0x5eec,0x5eec,0x5ef1,0x5ef1,0x5ef3,0x5ef4,0x5ef6,0x5ef7,0x5efa,0x5efb,0x5efe,0x5eff,0x5f01,0x5f01,0x5f03,0x5f04,0x5f07,0x5f08,0x5f0a,0x5f0b,0x5f0f,0x5f0f,0x5f11,0x5f15,0x5f17,0x5f18,0x5f1b,0x5f1b,0x5f1f,0x5f1f,0x5f22,0x5f22,0x5f25,0x5f27,0x5f29,0x5f29,0x5f2d,0x5f2d,0x5f31,0x5f31,0x5f34,0x5f35,0x5f37,0x5f37,0x5f3a,0x5f3a,0x5f3c,0x5f3c,0x5f3e,0x5f3e,0x5f40,0x5f40,0x5f46,0x5f46,0x5f48,0x5f48,0x5f4a,0x5f4a,0x5f4c,0x5f4c,0x5f4e,0x5f4e,0x5f50,0x5f51,0x5f53,0x5f54,0x5f56,0x5f59,0x5f5b,0x5f5b,0x5f5d,0x5f5d,0x5f61,0x5f62,0x5f64,0x5f67,0x5f69,0x5f6d,0x5f70,0x5f71,0x5f73,0x5f73,0x5f77,0x5f77,0x5f79,0x5f79,0x5f7c,0x5f7c,0x5f7f,0x5f82,0x5f85,0x5f85,0x5f87,0x5f8c,0x5f90,0x5f92,0x5f97,0x5f99,0x5f9c,0x5f9c,0x5f9e,0x5f9e,0x5fa0,0x5fa1,0x5fa3,0x5fa3,0x5fa7,0x5faa,0x5fac,0x5faf,0x5fb3,0x5fb3,0x5fb5,0x5fb5,0x5fb7,0x5fb7,0x5fb9,0x5fb9,0x5fbc,0x5fbd,0x5fc3,0x5fc5,0x5fc8,0x5fc9,0x5fcc,0x5fce,0x5fd0,0x5fd0,0x5fd2,0x5fd3,0x5fd5,0x5fd9,0x5fdc,0x5fe1,0x5fe4,0x5fe4,0x5fe8,0x5fe8,0x5feb,0x5feb,0x5fed,0x5fef,0x5ff1,0x5ff1,0x5ff5,0x5ff5,0x5ff8,0x5ff8,0x5ffb,0x5ffd,0x5fff,0x5fff,0x600a,0x600a,0x600d,0x600d,0x600f,0x600f,0x6012,0x6012,0x6014,0x6017,0x6019,0x6019,0x601b,0x601d,0x6020,0x6021,0x6025,0x602a,0x602f,0x6030,0x6033,0x6033,0x6041,0x6043,0x6046,0x6048,0x604a,0x604b,0x604d,0x604d,0x6050,0x6050,0x6052,0x6052,0x6055,0x6055,0x6059,0x605a,0x605d,0x605d,0x605f,0x6060,0x6062,0x6065,0x6068,0x606d,0x606f,0x6070,0x6075,0x6075,0x6081,0x6081,0x6083,0x6086,0x6089,0x608d,0x608f,0x608f,0x6092,0x6092,0x6094,0x6097,0x609a,0x609b,0x609f,0x60a0,0x60a2,0x60a4,0x60a7,0x60a7,0x60aa,0x60aa,0x60b0,0x60b6,0x60b8,0x60b8,0x60bb,0x60be,0x60c4,0x60c7,0x60c9,0x60c9,0x60cb,0x60cb,0x60cf,0x60cf,0x60d1,0x60d1,0x60d3,0x60d3,0x60d5,0x60d5,0x60d7,0x60e2,0x60f0,0x60f4,0x60f6,0x60fc,0x6100,0x6101,0x6103,0x6103,0x6106,0x6106,0x6108,0x6109,0x610d,0x610f,0x6114,0x6115,0x611a,0x611c,0x611e,0x611f,0x6122,0x6122,0x6127,0x6128,0x612b,0x612d,0x6130,0x6130,0x6134,0x6134,0x6137,0x6137,0x613c,0x613c,0x613e,0x613f,0x6142,0x6142,0x6144,0x6144,0x6146,0x6148,0x614a,0x614d,0x614f,0x614f,0x6152,0x6155,0x6158,0x615a,0x615c,0x615d,0x615f,0x6164,0x6167,0x6168,0x616a,0x616b,0x616e,0x616e,0x6170,0x6171,0x6173,0x6177,0x617a,0x617a,0x617c,0x617e,0x6181,0x6183,0x618a,0x618a,0x618d,0x618e,0x6190,0x6194,0x6196,0x6196,0x6198,0x619a,0x61a4,0x61a4,0x61a7,0x61a9,0x61ab,0x61ac,0x61ae,0x61af,0x61b2,0x61b2,0x61b6,0x61b6,0x61b8,0x61b8,0x61ba,0x61be,0x61c3,0x61c3,0x61c6,0x61cc,0x61cf,0x61cf,0x61d5,0x61d5,0x61d7,0x61d7,0x61de,0x61df,0x61e3,0x61e3,0x61e6,0x61e6,0x61f2,0x61f2,0x61f6,0x61f8,0x61fa,0x61fa,0x61fc,0x6200,0x6207,0x6208,0x620a,0x620a,0x620c,0x620e,0x6210,0x6212,0x6214,0x6216,0x6218,0x6218,0x621a,0x621a,0x621e,0x621f,0x6221,0x6222,0x6226,0x6227,0x6229,0x622a,0x622d,0x622e,0x6230,0x6236,0x6239,0x6239,0x623e,0x6241,0x6243,0x6243,0x6247,0x624e,0x6251,0x6253,0x6257,0x6258,0x625b,0x625c,0x625e,0x625e,0x6263,0x6263,0x6268,0x6268,0x626e,0x626e,0x6271,0x6271,0x6273,0x6273,0x6276,0x6276,0x6279,0x627a,0x627c,0x627c,0x627e,0x6280,0x6283,0x6284,0x6286,0x6286,0x6289,0x628a,0x628f,0x628f,0x6291,0x6292,0x6294,0x6298,0x629b,0x629b,0x62a6,0x62a6,0x62a8,0x62a8,0x62ab,0x62ac,0x62ae,0x62ae,0x62b1,0x62b2,0x62b5,0x62b5,0x62b9,0x62b9,0x62bc,0x62bd,0x62c2,0x62c2,0x62c4,0x62cd,0x62cf,0x62d9,0x62db,0x62dc,0x62e1,0x62e1,0x62ec,0x62ef,0x62f1,0x62f1,0x62f3,0x62f3,0x62f5,0x62f7,0x62fd,0x62ff,0x6301,0x6302,0x6307,0x6307,0x6309,0x6309,0x630c,0x630c,0x6310,0x6312,0x6328,0x6328,0x632a,0x632b,0x632f,0x632f,0x6339,0x633b,0x633d,0x633e,0x6342,0x6344,0x6346,0x6346,0x6349,0x6349,0x634c,0x6350,0x6353,0x6353,0x6355,0x6355,0x6357,0x6357,0x635a,0x635a,0x6367,0x6369,0x636b,0x636b,0x636e,0x636e,0x6371,0x6372,0x6376,0x6377,0x637a,0x637b,0x637f,0x6380,0x6383,0x6384,0x6387,0x638a,0x638c,0x638c,0x638e,0x638f,0x6392,0x6392,0x6396,0x6396,0x6398,0x6398,0x639b,0x639c,0x639f,0x63a2,0x63a5,0x63a5,0x63a7,0x63aa,0x63ac,0x63ac,0x63be,0x63be,0x63c0,0x63c0,0x63c3,0x63c4,0x63c6,0x63c6,0x63c9,0x63c9,0x63cf,0x63d0,0x63d2,0x63d2,0x63d6,0x63d6,0x63da,0x63db,0x63df,0x63e1,0x63e3,0x63e3,0x63e9,0x63e9,0x63eb,0x63eb,0x63ed,0x63ee,0x63f2,0x63f2,0x63f4,0x63f7,0x6406,0x6406,0x6409,0x6409,0x640d,0x640d,0x640f,0x640f,0x6412,0x6412,0x6414,0x6414,0x6416,0x6418,0x641c,0x641c,0x6420,0x6420,0x6422,0x6422,0x6424,0x6425,0x6428,0x6428,0x642a,0x642d,0x642f,0x6430,0x6434,0x6434,0x6436,0x6436,0x643a,0x643a,0x643e,0x643e,0x6458,0x6458,0x645b,0x645b,0x645e,0x645e,0x6460,0x6460,0x6467,0x6467,0x6469,0x6469,0x646d,0x646d,0x646f,0x646f,0x6473,0x6473,0x6478,0x647b,0x647d,0x647d,0x6485,0x6485,0x6488,0x6488,0x6490,0x6493,0x6495,0x6495,0x6499,0x649b,0x649d,0x649f,0x64a4,0x64a5,0x64a9,0x64a9,0x64ab,0x64ab,0x64ad,0x64ae,0x64b0,0x64b0,0x64b2,0x64b2,0x64bb,0x64bc,0x64be,0x64bf,0x64c1,0x64c1,0x64c4,0x64c5,0x64c7,0x64c7,0x64c9,0x64ca,0x64cd,0x64ce,0x64d0,0x64d0,0x64d2,0x64d2,0x64d4,0x64d5,0x64d7,0x64d8,0x64da,0x64da,0x64e0,0x64e3,0x64e5,0x64e7,0x64ec,0x64ed,0x64ef,0x64ef,0x64f1,0x64f2,0x64f4,0x64f4,0x64fa,0x64fa,0x64fe,0x64fe,0x6500,0x6500,0x6502,0x6502,0x6504,0x6504,0x6507,0x6507,0x650a,0x650a,0x650f,0x650f,0x6514,0x6514,0x6518,0x6519,0x651d,0x651d,0x6522,0x6524,0x652a,0x652c,0x652f,0x652f,0x6532,0x6532,0x6534,0x6539,0x653b,0x653b,0x653d,0x653f,0x6543,0x6543,0x6545,0x6545,0x6548,0x6549,0x654d,0x654f,0x6551,0x6552,0x6554,0x6559,0x655d,0x655e,0x6562,0x6563,0x6566,0x6566,0x656c,0x656d,0x6572,0x6572,0x6574,0x6575,0x6577,0x6578,0x657e,0x657e,0x6581,0x6583,0x6585,0x6585,0x6587,0x6587,0x6589,0x6589,0x658c,0x658c,0x6590,0x6591,0x6597,0x6597,0x6599,0x6599,0x659b,0x659d,0x659f,0x659f,0x65a1,0x65a1,0x65a4,0x65a5,0x65a7,0x65a7,0x65ab,0x65ad,0x65af,0x65b2,0x65b7,0x65b7,0x65b9,0x65b9,0x65bc,0x65bd,0x65bf,0x65bf,0x65c1,0x65c6,0x65ca,0x65cc,0x65cf,0x65cf,0x65d2,0x65d2,0x65d7,0x65d7,0x65e0,0x65e1,0x65e3,0x65e3,0x65e5,0x65e6,0x65e8,0x65e9,0x65ec,0x65ed,0x65f1,0x65f2,0x65f4,0x65f4,0x65fa,0x65fd,0x65ff,0x6600,0x6602,0x6603,0x6606,0x6607,0x6609,0x660a,0x660c,0x6611,0x6613,0x6615,0x661b,0x661c,0x661e,0x6621,0x6623,0x6625,0x6627,0x6628,0x662b,0x662b,0x662d,0x662d,0x662f,0x6631,0x6634,0x6637,0x663a,0x663b,0x6641,0x6644,0x6648,0x6649,0x664b,0x664c,0x664e,0x6651,0x6659,0x665b,0x665d,0x6662,0x6664,0x6669,0x666b,0x6670,0x6673,0x6674,0x6676,0x667b,0x667d,0x667d,0x667f,0x667f,0x6684,0x6684,0x6687,0x6689,0x668b,0x668c,0x668e,0x668e,0x6690,0x6691,0x6696,0x6698,0x669a,0x669a,0x669d,0x669e,0x66a0,0x66a0,0x66a2,0x66a3,0x66ab,0x66ac,0x66ae,0x66ae,0x66b1,0x66b5,0x66b8,0x66bb,0x66be,0x66c1,0x66c4,0x66c9,0x66d3,0x66d4,0x66d6,0x66d6,0x66d8,0x66de,0x66e0,0x66e0,0x66e3,0x66e3,0x66e6,0x66e6,0x66e8,0x66ea,0x66ec,0x66ec,0x66ee,0x66f0,0x66f2,0x66f4,0x66f7,0x66fa,0x66fc,0x66fc,0x66fe,0x6700,0x6703,0x6705,0x6708,0x670d,0x6710,0x6710,0x6714,0x6715,0x6717,0x6717,0x671b,0x671b,0x671d,0x6720,0x6722,0x6723,0x6726,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6734,0x6736,0x6736,0x673a,0x673a,0x673d,0x673e,0x6745,0x6746,0x6749,0x6749,0x674b,0x674c,0x674e,0x6751,0x6753,0x6753,0x6756,0x6756,0x675c,0x6760,0x6765,0x6765,0x676a,0x676a,0x676c,0x676d,0x676f,0x6773,0x6775,0x6775,0x6777,0x6777,0x677b,0x677c,0x677e,0x677f,0x6783,0x6783,0x6787,0x6787,0x6789,0x6789,0x678b,0x678c,0x678f,0x6790,0x6792,0x6793,0x6795,0x6795,0x6797,0x679a,0x679c,0x679d,0x67af,0x67b0,0x67b2,0x67b3,0x67b6,0x67b8,0x67be,0x67be,0x67c1,0x67c1,0x67c4,0x67c5,0x67ca,0x67ca,0x67cf,0x67d4,0x67d6,0x67da,0x67dd,0x67df,0x67e2,0x67e2,0x67e9,0x67e9,0x67ec,0x67ec,0x67ef,0x67f1,0x67f3,0x67f6,0x67f9,0x67f9,0x67fb,0x67fb,0x67fe,0x67ff,0x6803,0x6804,0x6810,0x6810,0x6812,0x6813,0x6816,0x6817,0x681d,0x681e,0x6821,0x6822,0x682a,0x682a,0x682e,0x682f,0x6831,0x6832,0x6834,0x6834,0x6838,0x6839,0x683b,0x683d,0x6840,0x6844,0x6846,0x6846,0x6848,0x6849,0x684e,0x684e,0x6850,0x6851,0x6853,0x6854,0x686d,0x686d,0x686f,0x686f,0x6874,0x6874,0x6876,0x6877,0x687e,0x687f,0x6881,0x6881,0x6883,0x6883,0x6885,0x6886,0x688f,0x688f,0x6893,0x6894,0x6897,0x6897,0x689b,0x689b,0x689d,0x689d,0x689f,0x68a3,0x68a7,0x68a8,0x68ad,0x68ad,0x68af,0x68b1,0x68b3,0x68b3,0x68b5,0x68b6,0x68c4,0x68c5,0x68c9,0x68cd,0x68d0,0x68d0,0x68d2,0x68d2,0x68d5,0x68d8,0x68da,0x68da,0x68df,0x68e0,0x68e3,0x68e3,0x68e7,0x68e8,0x68ec,0x68ec,0x68ee,0x68ee,0x68f2,0x68f2,0x68f9,0x68fd,0x6900,0x6901,0x6904,0x6906,0x690b,0x690b,0x690d,0x690f,0x6911,0x6912,0x6919,0x6919,0x691c,0x691c,0x6927,0x6927,0x6930,0x6930,0x6934,0x6934,0x6936,0x6936,0x6939,0x6939,0x693d,0x693d,0x693f,0x693f,0x6942,0x6942,0x694a,0x694a,0x694f,0x694f,0x6953,0x6955,0x6957,0x6957,0x6959,0x695a,0x695d,0x695e,0x6960,0x6963,0x6965,0x6965,0x6968,0x6968,0x696a,0x696f,0x6973,0x6973,0x6975,0x6975,0x6977,0x6979,0x697b,0x697b,0x697d,0x697d,0x698e,0x698e,0x6991,0x6991,0x6994,0x6995,0x6998,0x6998,0x699b,0x699c,0x699f,0x699f,0x69a4,0x69a7,0x69ad,0x69ae,0x69b0,0x69b2,0x69b4,0x69b4,0x69b7,0x69b7,0x69ba,0x69bc,0x69be,0x69c1,0x69c3,0x69c3,0x69c7,0x69c7,0x69ca,0x69d0,0x69d3,0x69d3,0x69d6,0x69d6,0x69e2,0x69e2,0x69e5,0x69ea,0x69ed,0x69ed,0x69f2,0x69f2,0x69f9,0x69f9,0x69fb,0x69fb,0x69fd,0x69fd,0x69ff,0x6a00,0x6a02,0x6a02,0x6a05,0x6a05,0x6a0a,0x6a0b,0x6a11,0x6a14,0x6a17,0x6a17,0x6a19,0x6a19,0x6a1b,0x6a1b,0x6a1e,0x6a1f,0x6a21,0x6a21,0x6a23,0x6a23,0x6a29,0x6a29,0x6a2b,0x6a2b,0x6a35,0x6a35,0x6a38,0x6a3b,0x6a3d,0x6a3d,0x6a43,0x6a45,0x6a47,0x6a4d,0x6a50,0x6a50,0x6a52,0x6a53,0x6a58,0x6a5a,0x6a5f,0x6a5f,0x6a61,0x6a62,0x6a64,0x6a64,0x6a66,0x6a66,0x6a6b,0x6a6b,0x6a72,0x6a72,0x6a75,0x6a75,0x6a7f,0x6a80,0x6a83,0x6a84,0x6a89,0x6a89,0x6a8d,0x6a8e,0x6a90,0x6a90,0x6a94,0x6a94,0x6a97,0x6a97,0x6a9c,0x6a9d,0x6a9f,0x6aa0,0x6aa2,0x6aa3,0x6aae,0x6aae,0x6ab3,0x6ab3,0x6ab6,0x6ab6,0x6abb,0x6abc,0x6abf,0x6abf,0x6ac2,0x6ac3,0x6ad3,0x6ad3,0x6ada,0x6adf,0x6ae8,0x6ae8,0x6aea,0x6aea,0x6aec,0x6aec,0x6af6,0x6af6,0x6afb,0x6afc,0x6b02,0x6b04,0x6b0a,0x6b0a,0x6b0c,0x6b0c,0x6b11,0x6b12,0x6b16,0x6b16,0x6b1e,0x6b1e,0x6b20,0x6b21,0x6b23,0x6b23,0x6b2c,0x6b2c,0x6b32,0x6b32,0x6b37,0x6b3b,0x6b3d,0x6b3f,0x6b43,0x6b43,0x6b46,0x6b47,0x6b49,0x6b4a,0x6b4c,0x6b4c,0x6b4e,0x6b4e,0x6b50,0x6b50,0x6b54,0x6b54,0x6b59,0x6b5b,0x6b5f,0x6b67,0x6b69,0x6b6a,0x6b6f,0x6b6f,0x6b72,0x6b72,0x6b77,0x6b7b,0x6b7f,0x6b80,0x6b82,0x6b84,0x6b86,0x6b86,0x6b89,0x6b8a,0x6b8d,0x6b8d,0x6b91,0x6b91,0x6b96,0x6b96,0x6b98,0x6b98,0x6b9e,0x6b9e,0x6ba2,0x6ba2,0x6ba4,0x6ba4,0x6bab,0x6bab,0x6bad,0x6baf,0x6bb2,0x6bb3,0x6bb5,0x6bb5,0x6bb7,0x6bb7,0x6bba,0x6bba,0x6bbc,0x6bbd,0x6bbf,0x6bc1,0x6bc4,0x6bc6,0x6bcb,0x6bcb,0x6bcd,0x6bcd,0x6bcf,0x6bcf,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdb,0x6beb,0x6bec,0x6bef,0x6bef,0x6bf3,0x6bf3,0x6bf8,0x6bf8,0x6bff,0x6bff,0x6c05,0x6c05,0x6c08,0x6c08,0x6c0f,0x6c11,0x6c13,0x6c14,0x6c17,0x6c17,0x6c1b,0x6c1b,0x6c23,0x6c24,0x6c33,0x6c38,0x6c3e,0x6c43,0x6c4b,0x6c4b,0x6c4e,0x6c50,0x6c52,0x6c55,0x6c57,0x6c57,0x6c59,0x6c60,0x6c66,0x6c66,0x6c68,0x6c6a,0x6c6d,0x6c6d,0x6c70,0x6c70,0x6c72,0x6c72,0x6c74,0x6c74,0x6c76,0x6c76,0x6c7a,0x6c7a,0x6c7d,0x6c7e,0x6c81,0x6c89,0x6c8c,0x6c8d,0x6c90,0x6c90,0x6c92,0x6c96,0x6c98,0x6c9b,0x6ca2,0x6ca2,0x6cab,0x6cac,0x6cae,0x6cae,0x6cb0,0x6cb1,0x6cb3,0x6cb3,0x6cb6,0x6cb6,0x6cb8,0x6cb9,0x6cbb,0x6cbf,0x6cc1,0x6cc2,0x6cc4,0x6cc6,0x6cc9,0x6cca,0x6ccc,0x6ccc,0x6cd0,0x6cd1,0x6cd3,0x6cd5,0x6cd7,0x6cd7,0x6cd9,0x6cdd,0x6ce0,0x6ce3,0x6ce5,0x6ce5,0x6ce8,0x6ce8,0x6ceb,0x6ceb,0x6cee,0x6cf1,0x6cf3,0x6cf3,0x6cff,0x6cff,0x6d04,0x6d04,0x6d07,0x6d07,0x6d0a,0x6d0c,0x6d11,0x6d12,0x6d14,0x6d14,0x6d17,0x6d17,0x6d19,0x6d19,0x6d1b,0x6d1b,0x6d1e,0x6d1f,0x6d23,0x6d23,0x6d25,0x6d25,0x6d27,0x6d2c,0x6d2e,0x6d2e,0x6d32,0x6d32,0x6d35,0x6d36,0x6d38,0x6d3e,0x6d41,0x6d41,0x6d59,0x6d5a,0x6d5c,0x6d5c,0x6d61,0x6d61,0x6d63,0x6d67,0x6d69,0x6d6a,0x6d6c,0x6d6c,0x6d6e,0x6d6f,0x6d72,0x6d72,0x6d74,0x6d74,0x6d77,0x6d79,0x6d7f,0x6d7f,0x6d82,0x6d82,0x6d85,0x6d85,0x6d87,0x6d89,0x6d8c,0x6d8f,0x6d91,0x6d91,0x6d93,0x6d97,0x6daa,0x6dac,0x6daf,0x6daf,0x6db2,0x6db2,0x6db4,0x6db5,0x6db7,0x6db8,0x6dbc,0x6dbc,0x6dbf,0x6dc0,0x6dc3,0x6dc8,0x6dcb,0x6dcc,0x6dcf,0x6dd2,0x6dd6,0x6dd6,0x6dd8,0x6dda,0x6ddd,0x6dde,0x6de0,0x6de6,0x6de8,0x6de8,0x6dea,0x6dec,0x6dee,0x6dee,0x6df1,0x6df1,0x6df3,0x6df3,0x6df5,0x6dfc,0x6e05,0x6e05,0x6e08,0x6e08,0x6e0a,0x6e0a,0x6e17,0x6e17,0x6e19,0x6e1b,0x6e1d,0x6e1d,0x6e1f,0x6e26,0x6e28,0x6e28,0x6e2b,0x6e2d,0x6e2f,0x6e2f,0x6e32,0x6e32,0x6e34,0x6e34,0x6e36,0x6e38,0x6e3a,0x6e3a,0x6e3c,0x6e3e,0x6e40,0x6e40,0x6e43,0x6e45,0x6e4a,0x6e4a,0x6e4d,0x6e4e,0x6e51,0x6e51,0x6e53,0x6e56,0x6e58,0x6e58,0x6e5b,0x6e5c,0x6e5e,0x6e5f,0x6e63,0x6e63,0x6e67,0x6e67,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e72,0x6e73,0x6e75,0x6e75,0x6e7a,0x6e7a,0x6e8f,0x6e90,0x6e95,0x6e96,0x6e98,0x6e98,0x6e9c,0x6e9d,0x6e9f,0x6e9f,0x6ea2,0x6ea2,0x6ea5,0x6ea5,0x6ea7,0x6ea8,0x6eaa,0x6eab,0x6eaf,0x6eaf,0x6eb1,0x6eb2,0x6eb5,0x6eb7,0x6eba,0x6eba,0x6ebd,0x6ebd,0x6ec2,0x6ec5,0x6ec8,0x6ec9,0x6ecb,0x6ecc,0x6ece,0x6ece,0x6ed1,0x6ed1,0x6ed3,0x6ed5,0x6ed9,0x6ed9,0x6eec,0x6eed,0x6eef,0x6eef,0x6ef2,0x6ef2,0x6ef4,0x6ef5,0x6ef7,0x6ef8,0x6efc,0x6efc,0x6efe,0x6eff,0x6f01,0x6f02,0x6f04,0x6f04,0x6f06,0x6f06,0x6f09,0x6f09,0x6f0c,0x6f0c,0x6f0f,0x6f0f,0x6f11,0x6f11,0x6f13,0x6f15,0x6f19,0x6f1a,0x6f20,0x6f20,0x6f22,0x6f24,0x6f26,0x6f28,0x6f2a,0x6f2d,0x6f30,0x6f33,0x6f38,0x6f38,0x6f3c,0x6f3c,0x6f3e,0x6f3f,0x6f41,0x6f41,0x6f4f,0x6f4f,0x6f51,0x6f52,0x6f54,0x6f54,0x6f57,0x6f5f,0x6f61,0x6f64,0x6f66,0x6f66,0x6f6d,0x6f71,0x6f74,0x6f74,0x6f78,0x6f78,0x6f7a,0x6f7a,0x6f7c,0x6f7e,0x6f81,0x6f82,0x6f84,0x6f84,0x6f86,0x6f89,0x6f8b,0x6f8e,0x6f90,0x6f90,0x6f92,0x6f92,0x6f94,0x6f98,0x6f9f,0x6f9f,0x6fa1,0x6fa1,0x6fa3,0x6fa5,0x6fa7,0x6fa8,0x6faa,0x6faa,0x6fae,0x6faf,0x6fb1,0x6fb1,0x6fb3,0x6fb3,0x6fb6,0x6fb6,0x6fb9,0x6fb9,0x6fbe,0x6fbe,0x6fc0,0x6fc3,0x6fc6,0x6fc7,0x6fc9,0x6fca,0x6fd4,0x6fd5,0x6fd8,0x6fd8,0x6fda,0x6fdb,0x6fde,0x6fe1,0x6fe4,0x6fe6,0x6fe9,0x6fe9,0x6feb,0x6fec,0x6fee,0x6fef,0x6ff1,0x6ff1,0x6ff3,0x6ff4,0x6ff6,0x6ff6,0x6ffa,0x6ffa,0x6ffe,0x6ffe,0x7001,0x7001,0x7005,0x7007,0x7009,0x7009,0x700b,0x700b,0x700f,0x700f,0x7011,0x7013,0x7015,0x7015,0x7018,0x7018,0x701a,0x701f,0x7023,0x7023,0x7026,0x7028,0x702f,0x7030,0x7032,0x7032,0x7037,0x7038,0x703c,0x703c,0x703e,0x703e,0x7044,0x7044,0x7046,0x7046,0x704c,0x704c,0x704e,0x704e,0x7050,0x7051,0x7053,0x7053,0x7058,0x7058,0x705d,0x705e,0x7063,0x7063,0x7066,0x7066,0x7069,0x7069,0x706b,0x706c,0x706f,0x7070,0x7078,0x7078,0x707c,0x707e,0x7081,0x7081,0x7085,0x7086,0x708a,0x708a,0x708e,0x708e,0x7092,0x7092,0x7095,0x7095,0x7098,0x709b,0x70a1,0x70a1,0x70a4,0x70a4,0x70a6,0x70a6,0x70ab,0x70b0,0x70b3,0x70b3,0x70b7,0x70ba,0x70c8,0x70c8,0x70ca,0x70cb,0x70cf,0x70cf,0x70d3,0x70d4,0x70d8,0x70d9,0x70dc,0x70dd,0x70df,0x70df,0x70ef,0x70ef,0x70f1,0x70f1,0x70f9,0x70fa,0x70fd,0x70fd,0x7103,0x7104,0x7106,0x7106,0x7109,0x7109,0x710c,0x710c,0x7119,0x711a,0x711c,0x711c,0x711e,0x711e,0x7120,0x7121,0x7126,0x7126,0x712d,0x7131,0x7136,0x7136,0x7143,0x7143,0x7146,0x7147,0x7149,0x714a,0x714c,0x714c,0x714e,0x714e,0x7150,0x7150,0x7152,0x7153,0x7155,0x7157,0x7159,0x7159,0x715c,0x715e,0x7162,0x7162,0x7164,0x7169,0x716c,0x716c,0x716e,0x716e,0x717d,0x717d,0x7180,0x7180,0x7184,0x7185,0x7187,0x718a,0x718f,0x718f,0x7192,0x7192,0x7194,0x7194,0x7199,0x7199,0x719b,0x719b,0x719f,0x71a2,0x71a4,0x71a4,0x71a8,0x71a9,0x71ac,0x71ac,0x71af,0x71af,0x71b1,0x71b2,0x71b9,0x71ba,0x71be,0x71be,0x71c1,0x71c1,0x71c3,0x71c3,0x71c8,0x71c9,0x71cb,0x71cb,0x71ce,0x71d0,0x71d2,0x71d2,0x71d4,0x71d6,0x71d9,0x71d9,0x71db,0x71db,0x71df,0x71e0,0x71e5,0x71e7,0x71ec,0x71ee,0x71f9,0x71f9,0x71fb,0x7201,0x7206,0x7207,0x720b,0x720d,0x7210,0x7210,0x7214,0x7214,0x7217,0x7217,0x721a,0x721b,0x721f,0x721f,0x7225,0x7225,0x7228,0x7228,0x722a,0x722a,0x722c,0x722d,0x7230,0x7230,0x7232,0x7232,0x7235,0x7236,0x7238,0x723b,0x723d,0x7240,0x7242,0x7242,0x7246,0x7248,0x724b,0x724c,0x7252,0x7254,0x7256,0x7256,0x7258,0x725b,0x725d,0x725d,0x725f,0x725f,0x7261,0x7263,0x7267,0x7267,0x7269,0x7269,0x726f,0x726f,0x7272,0x7272,0x7274,0x7274,0x7278,0x7279,0x727d,0x727d,0x7280,0x7282,0x7287,0x7287,0x728d,0x728d,0x7292,0x7292,0x7296,0x7296,0x72a2,0x72a2,0x72a7,0x72a7,0x72ac,0x72ad,0x72af,0x72af,0x72b3,0x72b5,0x72c0,0x72c0,0x72c2,0x72c2,0x72c4,0x72c4,0x72c9,0x72c9,0x72ce,0x72ce,0x72d0,0x72d0,0x72d2,0x72d2,0x72d7,0x72d7,0x72d9,0x72d9,0x72e1,0x72e2,0x72e5,0x72e5,0x72e8,0x72e9,0x72ec,0x72ec,0x72f4,0x72f4,0x72f7,0x72fd,0x7309,0x730a,0x7313,0x7313,0x7316,0x7319,0x731b,0x731d,0x7322,0x7322,0x7325,0x7325,0x7327,0x732b,0x7331,0x7331,0x7334,0x7334,0x7336,0x7337,0x733e,0x733f,0x7343,0x7345,0x734e,0x734e,0x7350,0x7350,0x7352,0x7352,0x7357,0x7358,0x735c,0x735c,0x7360,0x7360,0x7368,0x736c,0x736f,0x7370,0x7372,0x7372,0x7375,0x7375,0x7377,0x7378,0x737a,0x737c,0x7381,0x7381,0x7384,0x7384,0x7386,0x7389,0x738b,0x738b,0x738e,0x738e,0x7392,0x7392,0x7394,0x7398,0x739e,0x73a0,0x73a6,0x73a7,0x73a9,0x73ab,0x73ad,0x73ad,0x73b2,0x73b4,0x73b7,0x73b7,0x73b9,0x73b9,0x73bb,0x73bd,0x73bf,0x73c0,0x73c2,0x73c2,0x73c6,0x73c6,0x73c8,0x73ca,0x73cc,0x73cd,0x73cf,0x73cf,0x73d2,0x73d2,0x73d6,0x73d9,0x73dd,0x73de,0x73e0,0x73e0,0x73e2,0x73e6,0x73e9,0x73eb,0x73ed,0x73ee,0x73f5,0x73f5,0x73f7,0x73f9,0x73fd,0x73fe,0x7401,0x7401,0x7403,0x7407,0x7409,0x7409,0x7413,0x7413,0x7417,0x7418,0x741b,0x741b,0x741d,0x741d,0x741f,0x7422,0x7424,0x7426,0x7428,0x7428,0x742a,0x742c,0x742e,0x7436,0x7438,0x7438,0x743a,0x743a,0x743f,0x7446,0x7448,0x7449,0x744b,0x744c,0x744e,0x744e,0x7455,0x7455,0x7457,0x7457,0x7459,0x7460,0x7462,0x7465,0x7468,0x746a,0x746d,0x7473,0x747d,0x747e,0x7480,0x7480,0x7482,0x7487,0x7489,0x748c,0x7490,0x7490,0x7498,0x7498,0x749c,0x749f,0x74a1,0x74a1,0x74a3,0x74a3,0x74a5,0x74a5,0x74a7,0x74a8,0x74aa,0x74ab,0x74b0,0x74b2,0x74b5,0x74b6,0x74b8,0x74b9,0x74bc,0x74bd,0x74bf,0x74c0,0x74c6,0x74c6,0x74ca,0x74ca,0x74cd,0x74cd,0x74cf,0x74d0,0x74d3,0x74d4,0x74d8,0x74d8,0x74da,0x74dc,0x74e0,0x74e0,0x74e2,0x74e3,0x74e6,0x74e6,0x74e9,0x74e9,0x74ee,0x74ee,0x74f2,0x74f3,0x74f7,0x74f7,0x7501,0x7501,0x7503,0x7504,0x750c,0x750e,0x7511,0x7511,0x7513,0x7513,0x7515,0x7515,0x7518,0x7518,0x751a,0x751c,0x751e,0x751f,0x7522,0x7526,0x7528,0x7528,0x752b,0x752c,0x7530,0x7533,0x7537,0x7538,0x753a,0x753b,0x753f,0x753f,0x7543,0x7543,0x7547,0x7547,0x754a,0x754c,0x754e,0x754f,0x7551,0x7551,0x7553,0x7554,0x7559,0x755d,0x7560,0x7560,0x7562,0x7562,0x7564,0x7567,0x756a,0x756b,0x756f,0x7570,0x7575,0x7576,0x7578,0x7578,0x757a,0x757a,0x757f,0x757f,0x7586,0x7588,0x758a,0x758b,0x758e,0x758f,0x7591,0x7592,0x7594,0x7594,0x7599,0x759a,0x759d,0x759d,0x75a3,0x75a3,0x75a5,0x75a5,0x75a9,0x75a9,0x75ab,0x75ab,0x75b1,0x75b5,0x75b8,0x75b9,0x75bc,0x75be,0x75c0,0x75c0,0x75c2,0x75c3,0x75c5,0x75c5,0x75c7,0x75c7,0x75ca,0x75ca,0x75cd,0x75ce,0x75d2,0x75d5,0x75d8,0x75d9,0x75db,0x75db,0x75de,0x75de,0x75e2,0x75e4,0x75e7,0x75e7,0x75f0,0x75f0,0x75f2,0x75f4,0x75f9,0x75fa,0x75fc,0x75fc,0x75ff,0x7601,0x7607,0x7609,0x760b,0x760b,0x760d,0x760d,0x7610,0x7610,0x7615,0x7615,0x7619,0x7619,0x761f,0x7622,0x7624,0x7624,0x7626,0x7627,0x762f,0x7631,0x7633,0x7634,0x763b,0x763b,0x7642,0x7643,0x7646,0x7649,0x764c,0x764c,0x764e,0x764e,0x7652,0x7652,0x7655,0x7656,0x7658,0x7658,0x765c,0x765c,0x7661,0x7662,0x7664,0x7665,0x7667,0x7669,0x766c,0x7672,0x7676,0x7676,0x7678,0x7678,0x767a,0x767e,0x7680,0x7681,0x7683,0x7684,0x7686,0x7687,0x768b,0x768b,0x768e,0x768e,0x7690,0x7690,0x7692,0x7693,0x7696,0x7697,0x769a,0x769c,0x769e,0x769e,0x76a4,0x76a4,0x76ac,0x76ac,0x76ae,0x76ae,0x76b4,0x76b4,0x76b6,0x76b6,0x76b8,0x76b8,0x76ba,0x76ba,0x76bf,0x76bf,0x76c2,0x76c3,0x76c6,0x76c6,0x76c8,0x76c8,0x76ca,0x76ca,0x76cc,0x76ce,0x76d2,0x76d4,0x76d6,0x76d6,0x76d9,0x76d9,0x76db,0x76dc,0x76de,0x76df,0x76e1,0x76e1,0x76e3,0x76e5,0x76e7,0x76e7,0x76ea,0x76ea,0x76ec,0x76ec,0x76ee,0x76ee,0x76f1,0x76f2,0x76f4,0x76f4,0x76f8,0x76f9,0x76fb,0x76fc,0x76fe,0x7702,0x7704,0x7704,0x7707,0x770c,0x7710,0x7710,0x771a,0x771b,0x771e,0x7720,0x7725,0x7726,0x7728,0x7729,0x7734,0x7734,0x7737,0x773c,0x773e,0x773e,0x7740,0x7740,0x7743,0x7743,0x7746,0x7747,0x774d,0x774d,0x7752,0x7752,0x775a,0x775b,0x775f,0x7763,0x7765,0x7766,0x7768,0x7768,0x776b,0x776c,0x7777,0x7777,0x7779,0x7779,0x777d,0x777f,0x778b,0x778b,0x778d,0x778e,0x7791,0x7791,0x7796,0x7796,0x7799,0x7799,0x779e,0x779e,0x77a0,0x77a0,0x77a2,0x77a2,0x77a5,0x77a5,0x77aa,0x77aa,0x77ac,0x77ae,0x77b0,0x77b0,0x77b3,0x77b3,0x77b9,0x77b9,0x77bb,0x77bd,0x77bf,0x77bf,0x77c7,0x77c7,0x77c9,0x77c9,0x77cd,0x77cd,0x77d7,0x77d7,0x77d9,0x77dc,0x77de,0x77de,0x77e1,0x77e3,0x77e5,0x77e5,0x77e7,0x77e7,0x77e9,0x77e9,0x77ed,0x77f0,0x77f3,0x77f3,0x77f8,0x77f8,0x77fa,0x77fd,0x7802,0x7802,0x7807,0x7807,0x780c,0x780c,0x780f,0x780f,0x7811,0x7812,0x7814,0x7814,0x7822,0x7822,0x7825,0x7827,0x782c,0x782d,0x7830,0x7830,0x7832,0x7832,0x7834,0x7834,0x7843,0x7843,0x7845,0x7845,0x784f,0x784f,0x785c,0x785d,0x7860,0x7860,0x7867,0x7868,0x786a,0x786c,0x786e,0x786f,0x787c,0x787c,0x7881,0x7881,0x7884,0x7884,0x7887,0x7887,0x788c,0x788f,0x7891,0x7891,0x7893,0x7893,0x7897,0x7897,0x789f,0x789f,0x78a3,0x78a4,0x78a7,0x78a9,0x78ac,0x78ad,0x78ba,0x78bc,0x78be,0x78be,0x78c1,0x78c1,0x78c5,0x78c5,0x78c8,0x78c8,0x78ca,0x78cb,0x78ce,0x78d1,0x78d4,0x78d5,0x78da,0x78da,0x78e0,0x78e0,0x78e7,0x78e8,0x78ea,0x78ea,0x78ec,0x78ec,0x78ef,0x78ef,0x78f4,0x78f5,0x78f7,0x78f7,0x78fa,0x78fd,0x7901,0x7901,0x790c,0x790c,0x790e,0x790f,0x7911,0x7912,0x7916,0x7916,0x7919,0x7919,0x7927,0x7927,0x792a,0x792d,0x7931,0x7931,0x793a,0x793c,0x793e,0x793e,0x7940,0x7941,0x7944,0x794a,0x7950,0x7950,0x7953,0x7958,0x795a,0x7960,0x7962,0x7962,0x7965,0x7965,0x7967,0x7968,0x796d,0x796d,0x7979,0x797a,0x797c,0x797c,0x797f,0x7981,0x798a,0x798b,0x798d,0x798f,0x7991,0x7991,0x7994,0x7994,0x799b,0x799b,0x799d,0x799d,0x79a6,0x79a8,0x79aa,0x79ab,0x79ae,0x79ae,0x79b0,0x79b1,0x79b3,0x79b4,0x79b8,0x79c1,0x79c4,0x79c4,0x79c6,0x79c6,0x79c9,0x79cb,0x79d1,0x79d2,0x79d5,0x79d5,0x79d8,0x79d8,0x79de,0x79df,0x79e2,0x79e4,0x79e6,0x79e7,0x79e9,0x79ec,0x79f5,0x79f5,0x79f8,0x79f8,0x79fb,0x79fb,0x7a00,0x7a02,0x7a05,0x7a05,0x7a08,0x7a08,0x7a0a,0x7a0d,0x7a14,0x7a14,0x7a17,0x7a1a,0x7a1c,0x7a1c,0x7a1e,0x7a20,0x7a22,0x7a22,0x7a27,0x7a27,0x7a2e,0x7a2e,0x7a30,0x7a31,0x7a33,0x7a33,0x7a36,0x7a37,0x7a39,0x7a39,0x7a3b,0x7a3d,0x7a3f,0x7a40,0x7a42,0x7a42,0x7a45,0x7a46,0x7a49,0x7a49,0x7a4c,0x7a4e,0x7a57,0x7a57,0x7a60,0x7a62,0x7a66,0x7a66,0x7a69,0x7a69,0x7a6b,0x7a6b,0x7a70,0x7a70,0x7a74,0x7a76,0x7a79,0x7a7a,0x7a7d,0x7a86,0x7a88,0x7a88,0x7a8a,0x7a8a,0x7a92,0x7a93,0x7a95,0x7a99,0x7a9b,0x7a9b,0x7a9f,0x7aa0,0x7aa3,0x7aa3,0x7aa9,0x7aaa,0x7aac,0x7aac,0x7aae,0x7aaf,0x7ab3,0x7ab3,0x7ab6,0x7ab6,0x7ab9,0x7abb,0x7abe,0x7abf,0x7ac4,0x7ac5,0x7ac7,0x7ac8,0x7aca,0x7acb,0x7ad7,0x7ad7,0x7ad9,0x7ad9,0x7adc,0x7add,0x7adf,0x7ae0,0x7ae2,0x7ae3,0x7ae5,0x7ae6,0x7aea,0x7aea,0x7aed,0x7aed,0x7aef,0x7aef,0x7af4,0x7af4,0x7af6,0x7af6,0x7af8,0x7afa,0x7afd,0x7afd,0x7aff,0x7aff,0x7b06,0x7b06,0x7b08,0x7b08,0x7b0a,0x7b0a,0x7b0c,0x7b0c,0x7b0e,0x7b0f,0x7b11,0x7b12,0x7b18,0x7b19,0x7b1b,0x7b1b,0x7b1e,0x7b1e,0x7b20,0x7b20,0x7b25,0x7b28,0x7b2c,0x7b2d,0x7b2f,0x7b2f,0x7b33,0x7b33,0x7b35,0x7b35,0x7b39,0x7b39,0x7b45,0x7b46,0x7b48,0x7b49,0x7b4b,0x7b4d,0x7b4f,0x7b54,0x7b56,0x7b56,0x7b5f,0x7b60,0x7b65,0x7b67,0x7b69,0x7b69,0x7b6c,0x7b6c,0x7b6e,0x7b6e,0x7b71,0x7b71,0x7b73,0x7b73,0x7b75,0x7b75,0x7b7d,0x7b7d,0x7b87,0x7b87,0x7b8b,0x7b8b,0x7b8d,0x7b8f,0x7b92,0x7b92,0x7b94,0x7b95,0x7b97,0x7b97,0x7b99,0x7b9a,0x7b9c,0x7b9d,0x7ba0,0x7ba1,0x7bad,0x7bad,0x7bb1,0x7bb1,0x7bb4,0x7bb4,0x7bb8,0x7bb8,0x7bbe,0x7bbe,0x7bc0,0x7bc1,0x7bc4,0x7bc4,0x7bc6,0x7bc7,0x7bc9,0x7bcc,0x7bd2,0x7bd2,0x7bd4,0x7bd4,0x7bd9,0x7bd9,0x7bdb,0x7bdb,0x7bdd,0x7bdd,0x7be0,0x7be1,0x7be4,0x7be4,0x7be6,0x7be6,0x7be9,0x7bea,0x7bf3,0x7bf3,0x7bf7,0x7bf7,0x7bfe,0x7bfe,0x7c00,0x7c00,0x7c07,0x7c07,0x7c09,0x7c09,0x7c0b,0x7c0b,0x7c0f,0x7c0f,0x7c12,0x7c12,0x7c1e,0x7c21,0x7c27,0x7c27,0x7c2a,0x7c2b,0x7c37,0x7c38,0x7c3d,0x7c3f,0x7c43,0x7c43,0x7c4c,0x7c4d,0x7c50,0x7c50,0x7c52,0x7c52,0x7c54,0x7c54,0x7c5b,0x7c5c,0x7c5f,0x7c60,0x7c64,0x7c65,0x7c67,0x7c67,0x7c69,0x7c69,0x7c6c,0x7c6c,0x7c72,0x7c73,0x7c7e,0x7c7e,0x7c81,0x7c81,0x7c83,0x7c83,0x7c89,0x7c89,0x7c8d,0x7c8d,0x7c92,0x7c92,0x7c95,0x7c95,0x7c97,0x7c98,0x7c9f,0x7c9f,0x7ca2,0x7ca2,0x7ca4,0x7ca8,0x7cae,0x7cae,0x7cb1,0x7cb3,0x7cb9,0x7cb9,0x7cbc,0x7cbe,0x7cc5,0x7cc6,0x7cca,0x7cca,0x7cd5,0x7cd7,0x7cd9,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce5,0x7ce5,0x7ce7,0x7ce7,0x7cef,0x7cef,0x7cf1,0x7cf2,0x7cf4,0x7cf6,0x7cf8,0x7cfb,0x7cfe,0x7cfe,0x7d00,0x7d00,0x7d02,0x7d08,0x7d0a,0x7d0b,0x7d0d,0x7d0d,0x7d10,0x7d10,0x7d13,0x7d15,0x7d17,0x7d1c,0x7d20,0x7d22,0x7d2b,0x7d2c,0x7d2e,0x7d33,0x7d35,0x7d35,0x7d38,0x7d3a,0x7d41,0x7d46,0x7d49,0x7d49,0x7d4c,0x7d4d,0x7d50,0x7d51,0x7d55,0x7d56,0x7d59,0x7d59,0x7d5b,0x7d5c,0x7d5e,0x7d5e,0x7d61,0x7d63,0x7d66,0x7d66,0x7d68,0x7d6a,0x7d6e,0x7d6e,0x7d70,0x7d73,0x7d75,0x7d76,0x7d79,0x7d7a,0x7d7f,0x7d7f,0x7d83,0x7d83,0x7d86,0x7d86,0x7d8e,0x7d8f,0x7d93,0x7d93,0x7d98,0x7d98,0x7d9a,0x7d9a,0x7d9c,0x7d9c,0x7da0,0x7da0,0x7da2,0x7da3,0x7da5,0x7da7,0x7da9,0x7da9,0x7dab,0x7dae,0x7db0,0x7db2,0x7db4,0x7db5,0x7db8,0x7db8,0x7dba,0x7dbb,0x7dbd,0x7dbf,0x7dc4,0x7dc4,0x7dc7,0x7dc7,0x7dca,0x7dcd,0x7dcf,0x7dcf,0x7dd6,0x7dd8,0x7dda,0x7dda,0x7ddc,0x7dde,0x7de0,0x7de1,0x7de3,0x7de3,0x7de6,0x7de6,0x7de8,0x7de9,0x7dec,0x7dec,0x7def,0x7def,0x7df4,0x7df4,0x7df6,0x7df6,0x7df9,0x7df9,0x7dfb,0x7dfb,0x7e03,0x7e03,0x7e08,0x7e0b,0x7e10,0x7e11,0x7e15,0x7e15,0x7e17,0x7e18,0x7e1b,0x7e1b,0x7e1d,0x7e23,0x7e2b,0x7e2b,0x7e2e,0x7e2f,0x7e31,0x7e33,0x7e35,0x7e35,0x7e37,0x7e37,0x7e39,0x7e39,0x7e3b,0x7e3b,0x7e3d,0x7e3e,0x7e41,0x7e41,0x7e43,0x7e48,0x7e50,0x7e50,0x7e52,0x7e52,0x7e54,0x7e57,0x7e59,0x7e5a,0x7e5e,0x7e5e,0x7e61,0x7e62,0x7e69,0x7e6b,0x7e6d,0x7e6d,0x7e6f,0x7e70,0x7e76,0x7e76,0x7e79,0x7e79,0x7e7c,0x7e7e,0x7e81,0x7e82,0x7e87,0x7e88,0x7e8a,0x7e8a,0x7e8c,0x7e8d,0x7e8f,0x7e8f,0x7e93,0x7e94,0x7e96,0x7e96,0x7e98,0x7e98,0x7e9b,0x7e9c,0x7e9f,0x7e9f,0x7f36,0x7f38,0x7f3a,0x7f3a,0x7f3e,0x7f3f,0x7f43,0x7f45,0x7f47,0x7f47,0x7f4b,0x7f4e,0x7f50,0x7f55,0x7f58,0x7f58,0x7f5d,0x7f5d,0x7f5f,0x7f61,0x7f63,0x7f63,0x7f66,0x7f66,0x7f68,0x7f68,0x7f6a,0x7f6b,0x7f6e,0x7f6e,0x7f70,0x7f70,0x7f72,0x7f72,0x7f75,0x7f75,0x7f77,0x7f79,0x7f7c,0x7f7e,0x7f82,0x7f82,0x7f85,0x7f88,0x7f8a,0x7f8a,0x7f8c,0x7f8c,0x7f8e,0x7f8e,0x7f94,0x7f94,0x7f96,0x7f98,0x7f9a,0x7f9a,0x7f9d,0x7f9e,0x7fa1,0x7fa1,0x7fa4,0x7fa4,0x7fa8,0x7fa9,0x7fab,0x7fab,0x7faf,0x7faf,0x7fb2,0x7fb2,0x7fb6,0x7fb6,0x7fb8,0x7fb9,0x7fbd,0x7fbd,0x7fbf,0x7fbf,0x7fc1,0x7fc1,0x7fc5,0x7fc5,0x7fca,0x7fca,0x7fcc,0x7fcc,0x7fce,0x7fce,0x7fd2,0x7fd2,0x7fd4,0x7fd6,0x7fdb,0x7fdb,0x7fdf,0x7fe1,0x7fe3,0x7fe4,0x7fe6,0x7fe6,0x7fe9,0x7fe9,0x7feb,0x7fec,0x7fee,0x7fee,0x7ff0,0x7ff0,0x7ff3,0x7ff3,0x7ff9,0x7ffc,0x7ffe,0x7ffe,0x8000,0x8009,0x800c,0x800c,0x8010,0x8012,0x8014,0x8019,0x801e,0x801e,0x8021,0x8021,0x8026,0x8026,0x8028,0x8028,0x802c,0x802d,0x8030,0x8030,0x8033,0x8033,0x8036,0x8036,0x803d,0x803d,0x803f,0x803f,0x8043,0x8043,0x8046,0x8046,0x8048,0x8048,0x804a,0x804a,0x8052,0x8052,0x8055,0x8056,0x8058,0x8058,0x805a,0x805a,0x805e,0x805e,0x8061,0x8061,0x806f,0x8073,0x8075,0x8077,0x807d,0x8080,0x8084,0x8087,0x8089,0x8089,0x808b,0x808c,0x8093,0x8093,0x8096,0x8096,0x8098,0x8098,0x809a,0x809b,0x809d,0x809d,0x80a1,0x80a2,0x80a5,0x80a6,0x80a9,0x80ab,0x80ad,0x80ad,0x80af,0x80af,0x80b1,0x80b2,0x80b4,0x80b5,0x80ba,0x80ba,0x80c3,0x80c4,0x80c6,0x80c6,0x80ca,0x80ca,0x80cc,0x80cc,0x80ce,0x80ce,0x80d5,0x80d6,0x80d9,0x80dc,0x80de,0x80de,0x80e0,0x80e1,0x80e4,0x80e5,0x80ef,0x80ef,0x80f1,0x80f1,0x80f4,0x80f4,0x80f7,0x80f8,0x80fd,0x80fe,0x8102,0x8102,0x8105,0x810a,0x8116,0x8118,0x811a,0x811b,0x8123,0x8124,0x8127,0x8127,0x8129,0x8129,0x812b,0x812b,0x812f,0x8130,0x8139,0x813a,0x813e,0x813e,0x8141,0x8141,0x8146,0x8146,0x814a,0x814b,0x814e,0x814e,0x8150,0x8155,0x8160,0x8160,0x8164,0x8166,0x816b,0x816b,0x816d,0x816d,0x8170,0x8171,0x8174,0x8174,0x8176,0x817a,0x817f,0x8180,0x8182,0x8184,0x8186,0x8186,0x8188,0x8188,0x818a,0x818b,0x818f,0x818f,0x819a,0x819a,0x819c,0x819e,0x81a0,0x81a0,0x81a3,0x81a3,0x81a8,0x81a9,0x81b0,0x81b0,0x81b3,0x81b5,0x81b8,0x81ba,0x81bd,0x81c0,0x81c2,0x81c2,0x81c6,0x81c6,0x81ca,0x81ca,0x81cd,0x81cd,0x81cf,0x81cf,0x81d1,0x81d1,0x81d8,0x81da,0x81dd,0x81dd,0x81df,0x81e0,0x81e3,0x81e3,0x81e5,0x81e5,0x81e7,0x81e8,0x81ea,0x81ea,0x81ec,0x81ed,0x81f3,0x81f4,0x81f6,0x81f6,0x81fa,0x81fc,0x81fe,0x81fe,0x8201,0x8203,0x8205,0x8205,0x8207,0x8208,0x820a,0x820a,0x820c,0x820d,0x8210,0x8210,0x8212,0x8212,0x8216,0x8216,0x8218,0x8218,0x821b,0x821c,0x821e,0x821f,0x8221,0x8221,0x822a,0x822c,0x8233,0x8233,0x8235,0x8239,0x823d,0x823d,0x8240,0x8240,0x8245,0x8245,0x8247,0x8247,0x8251,0x8251,0x8258,0x825a,0x825f,0x825f,0x8264,0x8264,0x8266,0x8266,0x8268,0x8268,0x826a,0x826b,0x826e,0x826f,0x8271,0x8272,0x8274,0x8274,0x8276,0x8279,0x827d,0x827e,0x8283,0x8283,0x828a,0x828b,0x828d,0x828e,0x8290,0x8290,0x8292,0x8292,0x8294,0x8294,0x8298,0x829a,0x829d,0x829d,0x829f,0x829f,0x82a1,0x82a3,0x82a5,0x82b1,0x82b3,0x82b3,0x82b7,0x82b9,0x82bb,0x82bf,0x82c5,0x82c5,0x82d1,0x82d5,0x82d7,0x82d7,0x82db,0x82dc,0x82de,0x82e1,0x82e3,0x82e3,0x82e5,0x82e7,0x82e9,0x82e9,0x82eb,0x82eb,0x82f1,0x82f1,0x82f3,0x82f4,0x82f9,0x82fb,0x82fd,0x8305,0x8308,0x8309,0x8317,0x8317,0x831b,0x831d,0x8323,0x8325,0x8328,0x8328,0x832a,0x832b,0x832f,0x832f,0x8331,0x8336,0x8338,0x8339,0x833c,0x833c,0x8340,0x8340,0x8343,0x8343,0x8347,0x8347,0x8349,0x834a,0x834f,0x8352,0x8363,0x8363,0x8373,0x8373,0x8377,0x8377,0x837a,0x837b,0x8382,0x8382,0x8385,0x8385,0x8389,0x838a,0x838e,0x838e,0x8392,0x8393,0x8396,0x8396,0x8398,0x8398,0x839a,0x839b,0x839d,0x83a0,0x83a2,0x83a2,0x83a8,0x83ab,0x83bd,0x83c2,0x83c5,0x83c5,0x83c9,0x83ca,0x83cc,0x83cc,0x83d1,0x83d1,0x83d3,0x83d4,0x83d6,0x83d6,0x83d8,0x83d8,0x83dc,0x83dc,0x83df,0x83e1,0x83e9,0x83e9,0x83eb,0x83eb,0x83ef,0x83f2,0x83f4,0x83f4,0x83f6,0x83f6,0x83f9,0x83f9,0x83fb,0x83fb,0x83fd,0x83fd,0x8403,0x8404,0x8406,0x8407,0x840a,0x840e,0x8429,0x8429,0x842c,0x842c,0x8431,0x8431,0x8435,0x8435,0x8438,0x8439,0x843c,0x843d,0x8446,0x8446,0x8449,0x844a,0x8451,0x8451,0x8457,0x8457,0x845a,0x845b,0x8461,0x8461,0x8463,0x8463,0x8466,0x8466,0x8469,0x846d,0x846f,0x8471,0x8473,0x8473,0x8475,0x8475,0x8477,0x8477,0x847a,0x847a,0x8482,0x8482,0x8490,0x8491,0x8494,0x8494,0x8499,0x8499,0x849c,0x849c,0x849f,0x849f,0x84a1,0x84a1,0x84a8,0x84a8,0x84ad,0x84ad,0x84af,0x84af,0x84b2,0x84b2,0x84b4,0x84b4,0x84b8,0x84bd,0x84bf,0x84c2,0x84c4,0x84c4,0x84c6,0x84c6,0x84c9,0x84cb,0x84cd,0x84cd,0x84cf,0x84d1,0x84d3,0x84d3,0x84d6,0x84d6,0x84da,0x84da,0x84ec,0x84ef,0x84f1,0x84f1,0x84f4,0x84f4,0x84fa,0x84fa,0x84fc,0x84fd,0x8500,0x8500,0x8506,0x8506,0x850e,0x850e,0x8511,0x8511,0x8513,0x8515,0x8517,0x8518,0x851a,0x851a,0x851e,0x851f,0x8521,0x8521,0x8523,0x8523,0x8525,0x8526,0x852a,0x852a,0x852c,0x852d,0x852f,0x8530,0x853d,0x853d,0x853f,0x853f,0x8541,0x8541,0x8543,0x8543,0x8546,0x8546,0x8549,0x854b,0x854e,0x854e,0x8553,0x8553,0x8555,0x8559,0x855e,0x855e,0x8561,0x8561,0x8563,0x8564,0x8568,0x856b,0x856d,0x856d,0x8578,0x8578,0x857a,0x857a,0x857e,0x857e,0x8580,0x8580,0x8584,0x8584,0x8586,0x8587,0x8589,0x858a,0x858c,0x858c,0x858f,0x858f,0x8591,0x8591,0x8594,0x8594,0x8597,0x8597,0x8599,0x8599,0x859b,0x859b,0x859d,0x859d,0x85a4,0x85a6,0x85a8,0x85ab,0x85af,0x85b0,0x85ba,0x85ba,0x85c1,0x85c1,0x85c7,0x85c7,0x85c9,0x85c9,0x85cd,0x85d0,0x85d5,0x85d5,0x85dc,0x85dd,0x85e4,0x85e5,0x85e9,0x85ea,0x85f7,0x85f7,0x85f9,0x85fb,0x85fd,0x85fd,0x85ff,0x8600,0x8602,0x8602,0x8604,0x8604,0x8606,0x8607,0x860a,0x860b,0x8616,0x8618,0x861a,0x861a,0x861f,0x861f,0x8622,0x8622,0x8627,0x8627,0x8629,0x862a,0x862d,0x862d,0x862f,0x862f,0x863c,0x863c,0x863f,0x863f,0x8641,0x8641,0x864d,0x864e,0x8650,0x8650,0x8653,0x8655,0x865b,0x865c,0x865e,0x865f,0x8667,0x8667,0x866b,0x866c,0x866f,0x866f,0x8671,0x8671,0x8678,0x867b,0x868a,0x868d,0x8693,0x8693,0x8695,0x8695,0x86a3,0x86a4,0x86a8,0x86aa,0x86af,0x86b1,0x86b4,0x86b4,0x86c0,0x86c0,0x86c5,0x86c7,0x86c9,0x86c9,0x86cb,0x86cb,0x86d4,0x86d4,0x86d9,0x86d9,0x86db,0x86db,0x86de,0x86df,0x86e3,0x86e4,0x86e9,0x86e9,0x86ec,0x86ed,0x86f8,0x86f9,0x86fb,0x86fb,0x86fe,0x86fe,0x8700,0x8700,0x8702,0x8703,0x8706,0x8706,0x8708,0x870b,0x8711,0x8711,0x8718,0x8718,0x871a,0x871a,0x871c,0x871d,0x8721,0x8721,0x8725,0x8725,0x8728,0x8729,0x8734,0x8735,0x8737,0x8737,0x873a,0x873b,0x873f,0x8740,0x874c,0x874c,0x874e,0x874e,0x8755,0x8755,0x8757,0x8757,0x8759,0x8759,0x875f,0x8760,0x8764,0x8766,0x8768,0x8768,0x876e,0x876e,0x8774,0x8774,0x8776,0x8776,0x8778,0x8778,0x8782,0x8783,0x878c,0x878d,0x8798,0x8798,0x879e,0x879f,0x87a2,0x87a3,0x87ad,0x87ad,0x87b3,0x87b4,0x87ba,0x87bb,0x87bd,0x87bd,0x87c0,0x87c0,0x87c4,0x87c4,0x87c7,0x87c7,0x87ca,0x87cb,0x87d2,0x87d2,0x87da,0x87db,0x87e0,0x87e0,0x87e3,0x87e3,0x87ec,0x87ec,0x87ef,0x87ef,0x87f2,0x87f2,0x87f7,0x87f7,0x87f9,0x87f9,0x87fb,0x87fb,0x87fe,0x87fe,0x8805,0x8805,0x880d,0x880d,0x8811,0x8811,0x8815,0x8815,0x881f,0x881f,0x8821,0x8823,0x8831,0x8832,0x8836,0x8836,0x8839,0x8839,0x883b,0x883b,0x8840,0x8840,0x8844,0x8844,0x8846,0x8846,0x884a,0x884a,0x884c,0x884e,0x8852,0x8853,0x8857,0x8857,0x8859,0x8859,0x885b,0x885b,0x885d,0x885e,0x8861,0x8864,0x8868,0x8868,0x886b,0x886b,0x886e,0x886e,0x8870,0x8870,0x8872,0x8872,0x8877,0x8877,0x887d,0x887f,0x8881,0x8882,0x8888,0x8888,0x888b,0x888b,0x888d,0x888d,0x8892,0x8892,0x8896,0x8897,0x889b,0x889b,0x889d,0x889e,0x88a2,0x88a2,0x88aa,0x88ab,0x88b4,0x88b4,0x88c0,0x88c2,0x88c5,0x88c5,0x88ca,0x88ca,0x88cd,0x88cd,0x88cf,0x88cf,0x88d2,0x88d2,0x88d4,0x88d5,0x88d8,0x88d9,0x88dc,0x88dd,0x88df,0x88df,0x88e1,0x88e1,0x88e8,0x88e8,0x88ef,0x88ef,0x88f1,0x88f1,0x88f3,0x88f5,0x88f8,0x88f9,0x88fd,0x88fe,0x8904,0x8904,0x8907,0x8907,0x890a,0x890a,0x890c,0x890c,0x8910,0x8913,0x8915,0x8915,0x8918,0x891a,0x8925,0x8925,0x8927,0x8927,0x892a,0x892b,0x892f,0x8930,0x8936,0x8936,0x8938,0x8938,0x893a,0x893b,0x8941,0x8941,0x8944,0x8944,0x894d,0x894d,0x8952,0x8952,0x8956,0x8956,0x8958,0x8958,0x895c,0x895c,0x895e,0x8960,0x8964,0x8964,0x896a,0x896a,0x896d,0x896d,0x896f,0x896f,0x8972,0x8972,0x8974,0x8974,0x897e,0x8981,0x8983,0x8983,0x8986,0x8989,0x898b,0x898b,0x898f,0x898f,0x8993,0x8993,0x8996,0x8998,0x899a,0x899a,0x89a0,0x89a1,0x89a8,0x89aa,0x89ac,0x89ac,0x89af,0x89af,0x89b2,0x89b3,0x89b6,0x89b7,0x89ba,0x89ba,0x89bd,0x89bd,0x89bf,0x89c1,0x89d2,0x89d2,0x89d4,0x89d4,0x89d6,0x89d7,0x89da,0x89da,0x89dc,0x89dd,0x89e3,0x89e3,0x89e5,0x89e7,0x89f0,0x89f1,0x89f3,0x89f4,0x89f6,0x89f6,0x89f8,0x89f8,0x8a00,0x8a00,0x8a02,0x8a03,0x8a07,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a0e,0x8a10,0x8a18,0x8a1b,0x8a1b,0x8a1d,0x8a1d,0x8a1f,0x8a1f,0x8a22,0x8a23,0x8a25,0x8a25,0x8a2a,0x8a2a,0x8a2d,0x8a2d,0x8a31,0x8a31,0x8a33,0x8a34,0x8a36,0x8a36,0x8a3a,0x8a3c,0x8a3e,0x8a3e,0x8a41,0x8a41,0x8a46,0x8a46,0x8a4b,0x8a4b,0x8a50,0x8a51,0x8a54,0x8a58,0x8a5b,0x8a5b,0x8a5e,0x8a5e,0x8a60,0x8a63,0x8a66,0x8a66,0x8a69,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a73,0x8a75,0x8a75,0x8a79,0x8a79,0x8a7c,0x8a7c,0x8a7f,0x8a7f,0x8a82,0x8a82,0x8a84,0x8a87,0x8a8c,0x8a8d,0x8a91,0x8a91,0x8a93,0x8a93,0x8a95,0x8a95,0x8a98,0x8a98,0x8a9a,0x8a9a,0x8a9e,0x8a9e,0x8aa0,0x8aa8,0x8aaa,0x8aaa,0x8ab0,0x8ab0,0x8ab2,0x8ab2,0x8ab9,0x8ab9,0x8abc,0x8abc,0x8abe,0x8abf,0x8ac2,0x8ac2,0x8ac4,0x8ac4,0x8ac7,0x8ac7,0x8ac9,0x8ac9,0x8acb,0x8acb,0x8acd,0x8acd,0x8acf,0x8acf,0x8ad2,0x8ad2,0x8ad6,0x8ad7,0x8adb,0x8ae1,0x8ae4,0x8ae4,0x8ae6,0x8ae7,0x8aea,0x8aeb,0x8aed,0x8aee,0x8af0,0x8af4,0x8af6,0x8af8,0x8afa,0x8afa,0x8afc,0x8afc,0x8afe,0x8afe,0x8b00,0x8b02,0x8b04,0x8b04,0x8b07,0x8b07,0x8b0c,0x8b0c,0x8b0e,0x8b0e,0x8b10,0x8b11,0x8b14,0x8b14,0x8b16,0x8b17,0x8b19,0x8b1d,0x8b20,0x8b20,0x8b23,0x8b23,0x8b26,0x8b26,0x8b28,0x8b28,0x8b2b,0x8b2c,0x8b33,0x8b33,0x8b37,0x8b37,0x8b39,0x8b39,0x8b3c,0x8b3c,0x8b3e,0x8b3e,0x8b41,0x8b41,0x8b43,0x8b43,0x8b46,0x8b46,0x8b49,0x8b49,0x8b4c,0x8b4c,0x8b4e,0x8b4f,0x8b53,0x8b54,0x8b56,0x8b56,0x8b58,0x8b5a,0x8b5c,0x8b5c,0x8b5e,0x8b5f,0x8b66,0x8b66,0x8b6b,0x8b6c,0x8b6f,0x8b71,0x8b74,0x8b74,0x8b77,0x8b77,0x8b7d,0x8b7d,0x8b7f,0x8b80,0x8b83,0x8b83,0x8b89,0x8b8a,0x8b8c,0x8b8c,0x8b8e,0x8b8e,0x8b90,0x8b90,0x8b92,0x8b93,0x8b96,0x8b96,0x8b9a,0x8b9a,0x8b9c,0x8b9c,0x8b9e,0x8b9e,0x8ba0,0x8ba0,0x8c37,0x8c37,0x8c3f,0x8c3f,0x8c41,0x8c41,0x8c46,0x8c4a,0x8c4c,0x8c4c,0x8c4e,0x8c4e,0x8c50,0x8c50,0x8c55,0x8c56,0x8c5a,0x8c5a,0x8c61,0x8c62,0x8c68,0x8c68,0x8c6a,0x8c6c,0x8c73,0x8c73,0x8c78,0x8c7a,0x8c82,0x8c83,0x8c8a,0x8c8a,0x8c8c,0x8c8d,0x8c93,0x8c94,0x8c98,0x8c98,0x8c9d,0x8ca2,0x8ca7,0x8cac,0x8caf,0x8cb0,0x8cb2,0x8cb4,0x8cb6,0x8cbd,0x8cbf,0x8cc4,0x8cc6,0x8cc8,0x8cca,0x8cca,0x8cd1,0x8cd1,0x8cd3,0x8cd3,0x8cd9,0x8cdc,0x8cde,0x8cde,0x8ce0,0x8ce6,0x8cea,0x8cea,0x8cec,0x8ced,0x8cf0,0x8cf1,0x8cf3,0x8cf4,0x8cfb,0x8cfd,0x8d04,0x8d05,0x8d07,0x8d08,0x8d0a,0x8d0b,0x8d0d,0x8d0d,0x8d0f,0x8d10,0x8d13,0x8d14,0x8d16,0x8d16,0x8d1b,0x8d1b,0x8d1d,0x8d1d,0x8d64,0x8d64,0x8d66,0x8d67,0x8d6b,0x8d6b,0x8d6d,0x8d6e,0x8d70,0x8d70,0x8d73,0x8d74,0x8d76,0x8d77,0x8d81,0x8d81,0x8d85,0x8d85,0x8d8a,0x8d8a,0x8d8e,0x8d8e,0x8d90,0x8d90,0x8d99,0x8d99,0x8da0,0x8da0,0x8da3,0x8da3,0x8da8,0x8da8,0x8dab,0x8dab,0x8db2,0x8db3,0x8dba,0x8dba,0x8dbe,0x8dbe,0x8dc2,0x8dc2,0x8dc6,0x8dc6,0x8dcb,0x8dcc,0x8dce,0x8dcf,0x8dd5,0x8dd7,0x8ddb,0x8ddb,0x8ddd,0x8ddd,0x8ddf,0x8ddf,0x8de1,0x8de1,0x8de3,0x8de3,0x8de8,0x8de8,0x8dea,0x8ded,0x8def,0x8def,0x8df1,0x8df1,0x8df3,0x8df3,0x8dfc,0x8dfc,0x8e06,0x8e06,0x8e08,0x8e0a,0x8e0f,0x8e10,0x8e14,0x8e14,0x8e1d,0x8e1f,0x8e2a,0x8e2a,0x8e30,0x8e30,0x8e34,0x8e36,0x8e3a,0x8e3a,0x8e3d,0x8e3d,0x8e40,0x8e40,0x8e42,0x8e42,0x8e44,0x8e44,0x8e47,0x8e4a,0x8e4c,0x8e4c,0x8e4f,0x8e4f,0x8e55,0x8e55,0x8e59,0x8e59,0x8e5c,0x8e5c,0x8e5f,0x8e60,0x8e63,0x8e64,0x8e72,0x8e72,0x8e74,0x8e74,0x8e76,0x8e76,0x8e7b,0x8e7b,0x8e81,0x8e81,0x8e85,0x8e85,0x8e87,0x8e87,0x8e89,0x8e8b,0x8e8d,0x8e8d,0x8e90,0x8e91,0x8e93,0x8e94,0x8e99,0x8e99,0x8e9e,0x8e9e,0x8ea1,0x8ea1,0x8ea9,0x8eac,0x8eb1,0x8eb1,0x8eb3,0x8eb3,0x8ebe,0x8ebe,0x8ec0,0x8ec0,0x8ec6,0x8ec6,0x8eca,0x8ecd,0x8ed2,0x8ed2,0x8ede,0x8edf,0x8ee2,0x8ee2,0x8ee8,0x8ee8,0x8eeb,0x8eeb,0x8ef8,0x8efc,0x8efe,0x8efe,0x8f03,0x8f03,0x8f05,0x8f05,0x8f07,0x8f09,0x8f12,0x8f15,0x8f1b,0x8f1f,0x8f26,0x8f2a,0x8f2d,0x8f2d,0x8f2f,0x8f30,0x8f33,0x8f33,0x8f38,0x8f39,0x8f3b,0x8f3b,0x8f3e,0x8f40,0x8f42,0x8f42,0x8f44,0x8f46,0x8f49,0x8f49,0x8f4d,0x8f4e,0x8f52,0x8f52,0x8f54,0x8f54,0x8f57,0x8f58,0x8f5d,0x8f5f,0x8f61,0x8f64,0x8f66,0x8f66,0x8f9b,0x8f9c,0x8f9f,0x8f9f,0x8fa2,0x8fa3,0x8fa6,0x8fa6,0x8fa8,0x8fa8,0x8fad,0x8fb2,0x8fb5,0x8fb6,0x8fbb,0x8fbb,0x8fbf,0x8fc0,0x8fc2,0x8fc5,0x8fcd,0x8fce,0x8fd0,0x8fd1,0x8fd3,0x8fd5,0x8fe2,0x8fe2,0x8fe4,0x8fe6,0x8fe8,0x8fe8,0x8fea,0x8fed,0x8ff0,0x8ff0,0x8ff2,0x8ff2,0x8ff4,0x8ff4,0x8ff7,0x8ffa,0x8ffc,0x8ffd,0x8fff,0x9003,0x9005,0x9006,0x9008,0x9008,0x900b,0x9011,0x9014,0x9017,0x9019,0x901a,0x901d,0x9023,0x902e,0x902e,0x9031,0x9032,0x9034,0x9036,0x9038,0x9038,0x903c,0x903c,0x903e,0x903e,0x9041,0x9042,0x9047,0x9047,0x9049,0x904b,0x904d,0x9055,0x9058,0x9059,0x905b,0x905e,0x9060,0x9061,0x9063,0x9063,0x9068,0x9069,0x906c,0x906f,0x9072,0x9072,0x9075,0x9078,0x907a,0x907a,0x907c,0x9085,0x9087,0x9088,0x908a,0x908a,0x908c,0x908d,0x908f,0x9091,0x9095,0x9095,0x9097,0x9099,0x90a0,0x90a0,0x90a2,0x90a3,0x90a6,0x90a6,0x90a8,0x90a8,0x90aa,0x90aa,0x90af,0x90b1,0x90b3,0x90b3,0x90b5,0x90b5,0x90b8,0x90b8,0x90bd,0x90be,0x90c1,0x90c1,0x90c3,0x90c5,0x90ca,0x90ca,0x90ce,0x90ce,0x90dc,0x90de,0x90e1,0x90e2,0x90e8,0x90e8,0x90ea,0x90eb,0x90ed,0x90ed,0x90ef,0x90ef,0x90f3,0x90f5,0x90fd,0x90fd,0x9102,0x9102,0x9112,0x9112,0x9115,0x9117,0x9119,0x9119,0x911e,0x911e,0x9122,0x9123,0x9127,0x9127,0x912d,0x912d,0x9130,0x9132,0x9134,0x9134,0x913d,0x913d,0x9148,0x914e,0x9152,0x9152,0x9156,0x9157,0x9162,0x9165,0x9169,0x916a,0x916c,0x916c,0x9172,0x9172,0x9174,0x9179,0x9183,0x9183,0x9187,0x9187,0x9189,0x9189,0x918b,0x918b,0x918d,0x918d,0x9190,0x9190,0x9192,0x9192,0x919c,0x919c,0x919e,0x919e,0x91a2,0x91a2,0x91aa,0x91ac,0x91ae,0x91af,0x91b1,0x91b2,0x91b4,0x91b5,0x91bc,0x91bc,0x91c0,0x91c1,0x91c3,0x91c3,0x91c5,0x91c7,0x91c9,0x91c9,0x91cb,0x91d1,0x91d7,0x91d8,0x91dc,0x91dd,0x91e3,0x91e7,0x91e9,0x91ea,0x91ed,0x91ed,0x91f5,0x91f5,0x91ff,0x91ff,0x9207,0x9207,0x920d,0x920d,0x9210,0x9212,0x9214,0x9215,0x9217,0x9217,0x921c,0x921c,0x921e,0x921f,0x9226,0x9226,0x9231,0x9231,0x9234,0x9235,0x9237,0x9238,0x923a,0x923a,0x923f,0x9241,0x9244,0x9245,0x9249,0x9249,0x924b,0x924b,0x924d,0x9252,0x9257,0x9257,0x925b,0x925b,0x925e,0x925e,0x9262,0x9262,0x9264,0x9266,0x9277,0x9278,0x927c,0x927c,0x927e,0x927e,0x9280,0x9280,0x9283,0x9283,0x9285,0x9285,0x928b,0x928b,0x9291,0x9291,0x9293,0x9293,0x9295,0x9296,0x9298,0x929c,0x92b3,0x92b4,0x92b6,0x92b7,0x92b9,0x92b9,0x92c6,0x92c6,0x92cc,0x92cc,0x92cf,0x92cf,0x92d1,0x92d2,0x92d5,0x92d5,0x92d7,0x92d7,0x92df,0x92df,0x92e4,0x92e5,0x92ea,0x92ea,0x92f2,0x92f2,0x92f8,0x92fa,0x92fc,0x92fe,0x9300,0x9300,0x9304,0x9304,0x9306,0x9306,0x930f,0x9310,0x9315,0x9315,0x9318,0x931a,0x931e,0x9324,0x9326,0x9328,0x932a,0x932c,0x932e,0x932f,0x9348,0x934b,0x934d,0x934d,0x9351,0x9351,0x9354,0x9354,0x9357,0x9357,0x935b,0x935d,0x9364,0x9365,0x936b,0x936c,0x936e,0x936e,0x9370,0x9370,0x9372,0x9372,0x9375,0x9375,0x937c,0x937c,0x937e,0x937e,0x938a,0x938a,0x938c,0x938c,0x9394,0x9394,0x9396,0x9397,0x939a,0x939b,0x939f,0x93a1,0x93a3,0x93a4,0x93a7,0x93a7,0x93ac,0x93ad,0x93b0,0x93b0,0x93bb,0x93bb,0x93c3,0x93c3,0x93c7,0x93c8,0x93ca,0x93cc,0x93d1,0x93d1,0x93d6,0x93d8,0x93dc,0x93df,0x93e1,0x93e2,0x93e4,0x93e4,0x93e6,0x93e6,0x93e8,0x93e8,0x93f6,0x93f6,0x93f8,0x93f9,0x93fb,0x93fb,0x9403,0x9404,0x940f,0x9410,0x9413,0x9414,0x9418,0x9419,0x9425,0x9425,0x942a,0x942b,0x9435,0x9436,0x9438,0x9438,0x943a,0x943a,0x9442,0x9442,0x9444,0x9444,0x944a,0x944a,0x944c,0x944c,0x9451,0x9452,0x9455,0x9455,0x945b,0x945b,0x945e,0x945e,0x9460,0x9460,0x9462,0x9463,0x946a,0x946b,0x9470,0x9472,0x9475,0x9475,0x9477,0x9477,0x947c,0x947f,0x9485,0x9485,0x9577,0x9578,0x957f,0x9580,0x9583,0x9583,0x9588,0x958b,0x958e,0x958f,0x9591,0x9594,0x9598,0x9598,0x959c,0x959c,0x959f,0x95a0,0x95a2,0x95a5,0x95a8,0x95a9,0x95ab,0x95ad,0x95b1,0x95b1,0x95b6,0x95b6,0x95b9,0x95b9,0x95bb,0x95be,0x95c3,0x95c3,0x95c7,0x95c8,0x95ca,0x95cd,0x95d3,0x95d6,0x95da,0x95da,0x95dc,0x95dc,0x95de,0x95de,0x95e0,0x95e2,0x95e5,0x95e5,0x95e8,0x95e8,0x961c,0x961d,0x9621,0x9621,0x9624,0x9624,0x9627,0x962a,0x962d,0x962f,0x9632,0x9632,0x963b,0x963b,0x963f,0x9640,0x9642,0x9642,0x9644,0x9644,0x964b,0x964d,0x9650,0x9650,0x9654,0x9654,0x9656,0x9656,0x9658,0x9658,0x965b,0x965f,0x9661,0x9664,0x966a,0x966a,0x966c,0x966c,0x9670,0x9670,0x9672,0x9679,0x967c,0x967d,0x9684,0x9686,0x968a,0x968b,0x968d,0x968f,0x9691,0x9691,0x9694,0x9695,0x9697,0x9698,0x969b,0x969c,0x96a3,0x96a4,0x96a7,0x96aa,0x96b0,0x96b1,0x96b3,0x96b4,0x96b6,0x96b9,0x96bb,0x96bc,0x96c0,0x96c1,0x96c4,0x96c7,0x96c9,0x96c9,0x96cb,0x96ce,0x96d5,0x96d6,0x96d9,0x96de,0x96e2,0x96e3,0x96e8,0x96ea,0x96ef,0x96f0,0x96f2,0x96f2,0x96f6,0x96f7,0x96f9,0x96fb,0x9700,0x9700,0x9704,0x9709,0x970c,0x970f,0x9711,0x9711,0x9713,0x9714,0x9716,0x9716,0x9719,0x9719,0x971c,0x971c,0x971e,0x971e,0x9723,0x9723,0x9726,0x9727,0x972a,0x972a,0x9730,0x9730,0x9732,0x9732,0x9738,0x9739,0x973d,0x973d,0x9742,0x9742,0x9744,0x9744,0x9746,0x9746,0x9748,0x9749,0x974c,0x974c,0x9751,0x9752,0x9755,0x9756,0x9758,0x975e,0x9760,0x9762,0x9766,0x9766,0x9768,0x9769,0x976d,0x976d,0x9773,0x9775,0x9777,0x9777,0x977a,0x977a,0x977c,0x977c,0x9780,0x9781,0x9784,0x9785,0x978b,0x978b,0x978d,0x978d,0x978f,0x978f,0x9798,0x9798,0x97a0,0x97a0,0x97a3,0x97a3,0x97a6,0x97a6,0x97a8,0x97a8,0x97ab,0x97ad,0x97b1,0x97b1,0x97b4,0x97b4,0x97b8,0x97b9,0x97c1,0x97c1,0x97c3,0x97c3,0x97c6,0x97c6,0x97cb,0x97cd,0x97d0,0x97d0,0x97d3,0x97d3,0x97d9,0x97d9,0x97dc,0x97de,0x97e0,0x97e1,0x97e6,0x97e6,0x97ed,0x97ee,0x97f1,0x97f3,0x97f5,0x97f6,0x97fa,0x97fb,0x97fe,0x9803,0x9805,0x9806,0x9808,0x9808,0x980a,0x980a,0x980c,0x9813,0x9816,0x9818,0x981e,0x981e,0x9821,0x9821,0x9823,0x9824,0x9826,0x9826,0x982b,0x982b,0x982d,0x982e,0x9830,0x9830,0x9832,0x9832,0x9837,0x9839,0x983b,0x983c,0x983f,0x983f,0x9842,0x9842,0x9846,0x9848,0x984b,0x984e,0x9852,0x9855,0x9858,0x985a,0x985c,0x985c,0x985e,0x985e,0x9865,0x9867,0x986b,0x986b,0x986f,0x9871,0x9873,0x9875,0x98a8,0x98a8,0x98ad,0x98ad,0x98af,0x98af,0x98b1,0x98b2,0x98b6,0x98b6,0x98ba,0x98ba,0x98bc,0x98bc,0x98bf,0x98bf,0x98c2,0x98c2,0x98c4,0x98c4,0x98c6,0x98c7,0x98c9,0x98c9,0x98cb,0x98cb,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e2,0x98e6,0x98e7,0x98ea,0x98eb,0x98ed,0x98ef,0x98f1,0x98f1,0x98f4,0x98f4,0x98fb,0x98fe,0x9903,0x9903,0x9909,0x990a,0x990c,0x990c,0x9910,0x9910,0x9912,0x9915,0x9918,0x9918,0x991a,0x991a,0x991e,0x991e,0x9920,0x9920,0x9926,0x9928,0x992a,0x992a,0x992c,0x992c,0x992e,0x992e,0x9930,0x9931,0x9933,0x9933,0x9939,0x9939,0x993c,0x993d,0x9942,0x9942,0x9945,0x9945,0x9948,0x9949,0x994b,0x994d,0x9950,0x9952,0x9954,0x9955,0x9957,0x9957,0x995c,0x995c,0x995e,0x995e,0x9963,0x9963,0x9996,0x9999,0x999c,0x999d,0x999f,0x999f,0x99a1,0x99a1,0x99a3,0x99a3,0x99a5,0x99a5,0x99a7,0x99a8,0x99aa,0x99aa,0x99ac,0x99ae,0x99b0,0x99b1,0x99b3,0x99b4,0x99b6,0x99b6,0x99b9,0x99b9,0x99c1,0x99c1,0x99c4,0x99c5,0x99c8,0x99c9,0x99cf,0x99d2,0x99d5,0x99d5,0x99d8,0x99d9,0x99db,0x99df,0x99e2,0x99e2,0x99e8,0x99e8,0x99ea,0x99ea,0x99ed,0x99ee,0x99f1,0x99f1,0x99f8,0x99f8,0x99fa,0x99fb,0x99fd,0x99fd,0x99ff,0x99ff,0x9a01,0x9a05,0x9a08,0x9a08,0x9a0b,0x9a0b,0x9a0d,0x9a0f,0x9a11,0x9a11,0x9a16,0x9a16,0x9a18,0x9a19,0x9a1b,0x9a1b,0x9a2b,0x9a2b,0x9a2d,0x9a2d,0x9a30,0x9a30,0x9a35,0x9a38,0x9a3e,0x9a3e,0x9a40,0x9a45,0x9a4a,0x9a4a,0x9a4c,0x9a4f,0x9a52,0x9a52,0x9a55,0x9a55,0x9a57,0x9a58,0x9a5a,0x9a5b,0x9a5f,0x9a5f,0x9a62,0x9a62,0x9a64,0x9a65,0x9a69,0x9a6a,0x9a6c,0x9a6c,0x9aa8,0x9aa8,0x9aaa,0x9aaa,0x9ab0,0x9ab0,0x9ab8,0x9ab9,0x9abc,0x9abc,0x9abf,0x9ac0,0x9ac6,0x9ac6,0x9acf,0x9acf,0x9ad1,0x9ad1,0x9ad3,0x9ad4,0x9ad6,0x9ad8,0x9adf,0x9adf,0x9ae1,0x9ae1,0x9ae3,0x9ae3,0x9ae5,0x9ae6,0x9aeb,0x9aeb,0x9aed,0x9aee,0x9af0,0x9af0,0x9af2,0x9af2,0x9af4,0x9af4,0x9af9,0x9afb,0x9afd,0x9afd,0x9b02,0x9b02,0x9b05,0x9b06,0x9b0a,0x9b0b,0x9b0d,0x9b0d,0x9b10,0x9b10,0x9b12,0x9b12,0x9b16,0x9b16,0x9b18,0x9b1a,0x9b1f,0x9b1f,0x9b22,0x9b23,0x9b25,0x9b25,0x9b27,0x9b2a,0x9b2e,0x9b2f,0x9b31,0x9b32,0x9b3a,0x9b3a,0x9b3c,0x9b3c,0x9b41,0x9b45,0x9b48,0x9b48,0x9b4b,0x9b4b,0x9b4d,0x9b4f,0x9b51,0x9b51,0x9b54,0x9b54,0x9b58,0x9b58,0x9b5a,0x9b5a,0x9b66,0x9b66,0x9b6f,0x9b6f,0x9b74,0x9b74,0x9b80,0x9b80,0x9b83,0x9b83,0x9b8e,0x9b8e,0x9b90,0x9b93,0x9b97,0x9b97,0x9b9f,0x9b9f,0x9ba7,0x9ba8,0x9baa,0x9bab,0x9bad,0x9bae,0x9bb9,0x9bb9,0x9bc1,0x9bc1,0x9bc6,0x9bc6,0x9bc9,0x9bca,0x9bd4,0x9bd4,0x9bd6,0x9bd6,0x9bdb,0x9bdb,0x9be2,0x9be2,0x9be4,0x9be4,0x9be8,0x9be8,0x9bf7,0x9bf7,0x9c08,0x9c08,0x9c0a,0x9c0a,0x9c0c,0x9c0d,0x9c10,0x9c10,0x9c12,0x9c13,0x9c15,0x9c15,0x9c24,0x9c25,0x9c2d,0x9c2f,0x9c31,0x9c32,0x9c35,0x9c35,0x9c39,0x9c3b,0x9c3e,0x9c3e,0x9c47,0x9c47,0x9c49,0x9c49,0x9c4f,0x9c4f,0x9c52,0x9c53,0x9c57,0x9c57,0x9c60,0x9c60,0x9c63,0x9c63,0x9c67,0x9c67,0x9c78,0x9c78,0x9c7b,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9ce9,0x9cf3,0x9cf4,0x9cf6,0x9cf6,0x9d03,0x9d03,0x9d06,0x9d09,0x9d0c,0x9d0c,0x9d12,0x9d12,0x9d15,0x9d15,0x9d18,0x9d19,0x9d1b,0x9d1b,0x9d1e,0x9d1f,0x9d23,0x9d23,0x9d25,0x9d26,0x9d28,0x9d28,0x9d2f,0x9d30,0x9d36,0x9d36,0x9d3b,0x9d3b,0x9d41,0x9d42,0x9d44,0x9d44,0x9d51,0x9d51,0x9d53,0x9d54,0x9d5d,0x9d5e,0x9d60,0x9d61,0x9d66,0x9d66,0x9d69,0x9d69,0x9d6c,0x9d6c,0x9d6f,0x9d70,0x9d72,0x9d72,0x9d77,0x9d77,0x9d7b,0x9d7b,0x9d7e,0x9d7e,0x9d84,0x9d84,0x9d89,0x9d8a,0x9d96,0x9d96,0x9d9a,0x9d9a,0x9da1,0x9da1,0x9da4,0x9da4,0x9da9,0x9da9,0x9dac,0x9dac,0x9daf,0x9daf,0x9db4,0x9db5,0x9db8,0x9db9,0x9dbb,0x9dbb,0x9dbf,0x9dbf,0x9dc1,0x9dc2,0x9dc4,0x9dc4,0x9dc7,0x9dc7,0x9dd3,0x9dd3,0x9dd6,0x9dd7,0x9dd9,0x9dd9,0x9de6,0x9de6,0x9de9,0x9deb,0x9df0,0x9df3,0x9df8,0x9dfa,0x9dfd,0x9dfd,0x9dff,0x9dff,0x9e07,0x9e07,0x9e0f,0x9e0f,0x9e15,0x9e15,0x9e1a,0x9e1f,0x9e75,0x9e75,0x9e77,0x9e77,0x9e79,0x9e7b,0x9e7d,0x9e7d,0x9e7f,0x9e80,0x9e82,0x9e82,0x9e84,0x9e84,0x9e8b,0x9e8c,0x9e8f,0x9e8f,0x9e91,0x9e93,0x9e97,0x9e98,0x9e9d,0x9e9f,0x9ea4,0x9ea6,0x9ea9,0x9eaa,0x9eaf,0x9eaf,0x9eb4,0x9eb5,0x9ebb,0x9ebb,0x9ebd,0x9ebf,0x9ec3,0x9ec5,0x9ecc,0x9ed1,0x9ed4,0x9ed4,0x9ed6,0x9ed6,0x9ed8,0x9ed8,0x9eda,0x9ede,0x9ee0,0x9ee0,0x9ee5,0x9ee5,0x9ee8,0x9ee8,0x9eee,0x9eef,0x9ef2,0x9ef2,0x9ef4,0x9ef7,0x9ef9,0x9f00,0x9f02,0x9f02,0x9f04,0x9f04,0x9f07,0x9f0a,0x9f0e,0x9f0e,0x9f10,0x9f10,0x9f13,0x9f14,0x9f17,0x9f17,0x9f19,0x9f19,0x9f20,0x9f20,0x9f22,0x9f22,0x9f2b,0x9f2c,0x9f2f,0x9f2f,0x9f34,0x9f34,0x9f38,0x9f39,0x9f3b,0x9f3b,0x9f3e,0x9f3e,0x9f4a,0x9f4b,0x9f4e,0x9f4e,0x9f50,0x9f50,0x9f52,0x9f52,0x9f54,0x9f55,0x9f57,0x9f57,0x9f5f,0x9f61,0x9f66,0x9f67,0x9f69,0x9f6c,0x9f72,0x9f72,0x9f76,0x9f77,0x9f7f,0x9f7f,0x9f8d,0x9f8e,0x9f90,0x9f92,0x9f94,0x9f95,0x9f99,0x9f99,0x9f9c,0x9f9d,0x9f9f,0x9fa0,0x9fa2,0x9fa2,0x9fa5,0x9fa5,0xa960,0xa97c,0xac00,0xd7a3,0xd7b0,0xd7c6,0xd7cb,0xd7fb,0xf900,0xf95e,0xf960,0xf9a9,0xf9ab,0xfa0b,0xfa12,0xfa12,0xfa15,0xfa17,0xfa19,0xfa1e,0xfa22,0xfa22,0xfa26,0xfa26,0xfa2a,0xfa2c,0xfa2e,0xfa31,0xfa33,0xfa3d,0xfa3f,0xfa3f,0xfa41,0xfa41,0xfa43,0xfa55,0xfa57,0xfa57,0xfa59,0xfa68,0xfa6a,0xfa6a,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x200d7,0x200d7,0x2012c,0x2012c,0x205ca,0x205ca,0x20628,0x20628,0x20984,0x20984,0x21155,0x21155,0x2128d,0x2128d,0x21594,0x21594,0x21727,0x21727,0x21f5c,0x21f5c,0x224b0,0x224b0,0x224ed,0x224ed,0x2294f,0x2294f,0x22c6f,0x22c6f,0x22ee0,0x22ee0,0x230fd,0x230fd,0x23343,0x23343,0x2363b,0x2363b,0x23ad9,0x23ad9,0x242f1,0x242f1,0x2439d,0x2439d,0x248e9,0x248e9,0x248f0,0x248f0,0x24a01,0x24a01,0x24a12,0x24a12,0x25055,0x25055,0x2533e,0x2533e,0x253b5,0x253b5,0x253fe,0x253fe,0x25832,0x25832,0x2583a,0x2583a,0x25874,0x25874,0x25978,0x25978,0x25ad7,0x25ad7,0x25b97,0x25b97,0x25e44,0x25e44,0x26057,0x26057,0x265a4,0x265a4,0x267d8,0x267d8,0x26951,0x26951,0x27144,0x27144,0x275ff,0x275ff,0x27625,0x27625,0x278b2,0x278b2,0x27a51,0x27a51,0x27b02,0x27b02,0x27cef,0x27cef,0x27e7d,0x27e7d,0x27f1b,0x27f1b,0x27fb7,0x27fb7,0x283f6,0x283f6,0x284dc,0x284dc,0x28d8a,0x28d8a,0x28da1,0x28da1,0x28e0f,0x28e0f,0x291d5,0x291d5,0x291e3,0x291e3,0x294de,0x294de,0x29509,0x29509,0x2967f,0x2967f,0x29810,0x29810,0x2983b,0x2983b,0x2a2ad,0x2a2ad,0x2a4d0,0x2a4d0,0x2a664,0x2a664,0x2c115,0x2c115,0x2c7d3,0x2c7d3,0x2d544,0x2d544,0x2e569,0x2e569,0x2f815,0x2f815,0x2f818,0x2f818,0x2f81a,0x2f81a,0x2f82c,0x2f82c,0x2f833,0x2f833,0x2f852,0x2f852,0x2f862,0x2f862,0x2f877,0x2f877,0x2f884,0x2f884,0x2f8b2,0x2f8b2,0x2f8ed,0x2f8ed,0x2f8fc,0x2f8fc,0x2f920,0x2f920,0x2f96c,0x2f96c,0x2f9d0,0x2f9d0,0x2f9df,0x2f9df,0x30729,0x30729,0x30ede,0x30ede,]), + NotoFont.fromFlatRanges('Noto Sans Kaithi', 'http://fonts.gstatic.com/s/notosanskaithi/v15/buEtppS9f8_vkXadMBJJu0tWjLwjQi0KdoZIKlo.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x966,0x96f,0x200b,0x200d,0x2010,0x2010,0x25cc,0x25cc,0xa830,0xa839,0x11080,0x110c1,0x110cd,0x110cd,]), + NotoFont.fromFlatRanges('Noto Sans Kannada', 'http://fonts.gstatic.com/s/notosanskannada/v21/8vIs7xs32H97qzQKnzfeXycxXZyUmySvZWItmf1fe6TVmgop9ndpS-BqHEyGrDvNzSIMLsPKrkY.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xc80,0xc8c,0xc8e,0xc90,0xc92,0xca8,0xcaa,0xcb3,0xcb5,0xcb9,0xcbc,0xcc4,0xcc6,0xcc8,0xcca,0xccd,0xcd5,0xcd6,0xcde,0xcde,0xce0,0xce3,0xce6,0xcef,0xcf1,0xcf2,0x1cd0,0x1cd0,0x1cd2,0x1cd2,0x1cda,0x1cda,0x1cf2,0x1cf2,0x1cf4,0x1cf5,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa835,]), + NotoFont.fromFlatRanges('Noto Sans Kayah Li', 'http://fonts.gstatic.com/s/notosanskayahli/v18/B50nF61OpWTRcGrhOVJJwOMXdca6Yecki3E06x2jVTX3WCc3CZH4EXLuKVM.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x200c,0x200d,0x2010,0x2010,0x25cc,0x25cc,0xa900,0xa92f,]), + NotoFont.fromFlatRanges('Noto Sans Kharoshthi', 'http://fonts.gstatic.com/s/notosanskharoshthi/v15/Fh4qPiLjKS30-P4-pGMMXCCfvkc5Vd7KE5z4rFyx5mR1.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x200b,0x200d,0x2010,0x2010,0x25cc,0x25cc,0x10a00,0x10a03,0x10a05,0x10a06,0x10a0c,0x10a13,0x10a15,0x10a17,0x10a19,0x10a35,0x10a38,0x10a3a,0x10a3f,0x10a48,0x10a50,0x10a58,]), + NotoFont.fromFlatRanges('Noto Sans Khmer', 'http://fonts.gstatic.com/s/notosanskhmer/v18/ijw3s5roRME5LLRxjsRb-gssOenAyendxrgV2c-Zw-9vbVUti_Z_dWgtWYuNAJz4kAbrddiA.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1780,0x17dd,0x17e0,0x17e9,0x17f0,0x17f9,0x19e0,0x19ff,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Khojki', 'http://fonts.gstatic.com/s/notosanskhojki/v15/-nFnOHM29Oofr2wohFbTuPPKVWpmK_d709jy92k.ttf', [0x20,0x20,0xa0,0xa0,0xae6,0xaef,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11200,0x11211,0x11213,0x1123e,]), + NotoFont.fromFlatRanges('Noto Sans Khudawadi', 'http://fonts.gstatic.com/s/notosanskhudawadi/v15/fdNi9t6ZsWBZ2k5ltHN73zZ5hc8HANlHIjRnVVXz9MY.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x965,0x200c,0x200d,0x2013,0x2014,0x25cc,0x25cc,0xa830,0xa839,0x112b0,0x112ea,0x112f0,0x112f9,]), + NotoFont.fromFlatRanges('Noto Sans Lao', 'http://fonts.gstatic.com/s/notosanslao/v24/bx6lNx2Ol_ixgdYWLm9BwxM3NW6BOkuf763Clj73CiQ_J1Djx9pidOt4ccbdf5MK3riB2w.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0xe81,0xe82,0xe84,0xe84,0xe87,0xe88,0xe8a,0xe8a,0xe8d,0xe8d,0xe94,0xe97,0xe99,0xe9f,0xea1,0xea3,0xea5,0xea5,0xea7,0xea7,0xeaa,0xeab,0xead,0xeb9,0xebb,0xebd,0xec0,0xec4,0xec6,0xec6,0xec8,0xecd,0xed0,0xed9,0xedc,0xedf,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ad,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Lepcha', 'http://fonts.gstatic.com/s/notosanslepcha/v15/0QI7MWlB_JWgA166SKhu05TekNS32AJstqBXgd4.ttf', [0x20,0x20,0xa0,0xa0,0x1c00,0x1c37,0x1c3b,0x1c49,0x1c4d,0x1c4f,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Limbu', 'http://fonts.gstatic.com/s/notosanslimbu/v15/3JnlSDv90Gmq2mrzckOBBRRoNJVj0MF3OHRDnA.ttf', [0x20,0x20,0xa0,0xa0,0x965,0x965,0x1900,0x191e,0x1920,0x192b,0x1930,0x193b,0x1940,0x1940,0x1944,0x194f,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Linear A', 'http://fonts.gstatic.com/s/notosanslineara/v16/oPWS_l16kP4jCuhpgEGmwJOiA18FZj22zmHQAGQicw.ttf', [0x20,0x20,0xa0,0xa0,0x10600,0x10736,0x10740,0x10755,0x10760,0x10767,]), + NotoFont.fromFlatRanges('Noto Sans Linear B', 'http://fonts.gstatic.com/s/notosanslinearb/v15/HhyJU4wt9vSgfHoORYOiXOckKNB737IV3BkFTq4EPw.ttf', [0x20,0x20,0xa0,0xa0,0x10000,0x1000b,0x1000d,0x10026,0x10028,0x1003a,0x1003c,0x1003d,0x1003f,0x1004d,0x10050,0x1005d,0x10080,0x100fa,0x10100,0x10102,0x10107,0x10133,0x10137,0x1013f,]), + NotoFont.fromFlatRanges('Noto Sans Lisu', 'http://fonts.gstatic.com/s/notosanslisu/v21/uk-3EGO3o6EruUbnwovcYhz6kh57_nqbcTdjJnHP2Vwt29IlxkVdig.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2cd,0x2cd,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0x300a,0x300b,0xa4d0,0xa4ff,0x11fb0,0x11fb0,]), + NotoFont.fromFlatRanges('Noto Sans Lycian', 'http://fonts.gstatic.com/s/notosanslycian/v15/QldVNSNMqAsHtsJ7UmqxBQA9r8wA5_naCJwn00E.ttf', [0x20,0x20,0xa0,0xa0,0x10280,0x1029c,]), + NotoFont.fromFlatRanges('Noto Sans Lydian', 'http://fonts.gstatic.com/s/notosanslydian/v15/c4m71mVzGN7s8FmIukZJ1v4ZlcPReUPXMoIjEQI.ttf', [0x20,0x20,0xa0,0xa0,0x10920,0x10939,0x1093f,0x1093f,]), + NotoFont.fromFlatRanges('Noto Sans Mahajani', 'http://fonts.gstatic.com/s/notosansmahajani/v15/-F6sfiVqLzI2JPCgQBnw60Agp0JrvD5Fh8ARHNh4zg.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x96f,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11150,0x11176,]), + NotoFont.fromFlatRanges('Noto Sans Malayalam', 'http://fonts.gstatic.com/s/notosansmalayalam/v21/sJoi3K5XjsSdcnzn071rL37lpAOsUThnDZIfPdbeSNzVakglNM-Qw8EaeB8Nss-_RuD9BFzEr6HxEA.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x323,0x323,0x326,0x328,0x951,0x952,0x964,0x965,0xd00,0xd0c,0xd0e,0xd10,0xd12,0xd44,0xd46,0xd48,0xd4a,0xd4f,0xd54,0xd63,0xd66,0xd7f,0x1cda,0x1cda,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa830,0xa832,]), + NotoFont.fromFlatRanges('Noto Sans Mandaic', 'http://fonts.gstatic.com/s/notosansmandaic/v15/cIfnMbdWt1w_HgCcilqhKQBo_OsMI5_A_gMk0izH.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x840,0x85b,0x85e,0x85e,0x200c,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Manichaean', 'http://fonts.gstatic.com/s/notosansmanichaean/v15/taiVGntiC4--qtsfi4Jp9-_GkPZZCcrfekqCNTtFCtdX.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x200c,0x200d,0x25cc,0x25cc,0xfe00,0xfe00,0x10ac0,0x10ae6,0x10aeb,0x10af6,]), + NotoFont.fromFlatRanges('Noto Sans Marchen', 'http://fonts.gstatic.com/s/notosansmarchen/v15/aFTO7OZ_Y282EP-WyG6QTOX_C8WZMHhPk652ZaHk.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x11c70,0x11c8f,0x11c92,0x11ca7,0x11ca9,0x11cb6,]), + NotoFont.fromFlatRanges('Noto Sans Masaram Gondi', 'http://fonts.gstatic.com/s/notosansmasaramgondi/v15/6xK_dThFKcWIu4bpRBjRYRV7KZCbUq6n_1kPnuGe7RI9WSWX.ttf', [0x20,0x22,0x25,0x25,0x27,0x2f,0x3a,0x3f,0xa0,0xa0,0xd7,0xd7,0xf7,0xf7,0x964,0x965,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x2212,0x2212,0x25cc,0x25cc,0x11d00,0x11d06,0x11d08,0x11d09,0x11d0b,0x11d36,0x11d3a,0x11d3a,0x11d3c,0x11d3d,0x11d3f,0x11d47,0x11d50,0x11d59,]), + NotoFont.fromFlatRanges('Noto Sans Math', 'http://fonts.gstatic.com/s/notosansmath/v15/7Aump_cpkSecTWaHRlH2hyV5UHkG-V048PW0.ttf', [0x20,0x7e,0xa0,0xa0,0xa7,0xa7,0xac,0xac,0xb1,0xb1,0xd7,0xd7,0xf7,0xf7,0x302,0x303,0x305,0x305,0x307,0x308,0x330,0x330,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x3d1,0x3d1,0x3d5,0x3d6,0x3f0,0x3f1,0x3f4,0x3f5,0x2032,0x2037,0x2057,0x2057,0x20d0,0x20dc,0x20e1,0x20e1,0x20e5,0x20ef,0x2102,0x2102,0x210a,0x210e,0x2110,0x2112,0x2115,0x2115,0x2119,0x211d,0x2124,0x2124,0x2128,0x2128,0x212c,0x212d,0x212f,0x2131,0x2133,0x2138,0x213c,0x2140,0x2145,0x2149,0x2190,0x21ae,0x21b0,0x21e5,0x21f1,0x21f2,0x21f4,0x22ff,0x2308,0x230b,0x2310,0x2310,0x2319,0x2319,0x231c,0x2321,0x2336,0x237a,0x237c,0x237c,0x2395,0x2395,0x239b,0x23b6,0x23d0,0x23d0,0x23dc,0x23e1,0x2474,0x2475,0x25af,0x25af,0x25b3,0x25b3,0x25b7,0x25b7,0x25bd,0x25bd,0x25c1,0x25c1,0x25ca,0x25ca,0x25cc,0x25cc,0x25fb,0x25fb,0x266d,0x266f,0x27c0,0x27ff,0x2900,0x2aff,0x2b0e,0x2b11,0x2b30,0x2b4c,0x2bfe,0x2bfe,0xff5b,0xff5b,0xff5d,0xff5d,0x1d400,0x1d454,0x1d456,0x1d49c,0x1d49e,0x1d49f,0x1d4a2,0x1d4a2,0x1d4a5,0x1d4a6,0x1d4a9,0x1d4ac,0x1d4ae,0x1d4b9,0x1d4bb,0x1d4bb,0x1d4bd,0x1d4c3,0x1d4c5,0x1d505,0x1d507,0x1d50a,0x1d50d,0x1d514,0x1d516,0x1d51c,0x1d51e,0x1d539,0x1d53b,0x1d53e,0x1d540,0x1d544,0x1d546,0x1d546,0x1d54a,0x1d550,0x1d552,0x1d6a5,0x1d6a8,0x1d7cb,0x1d7ce,0x1d7ff,0x1ee00,0x1ee03,0x1ee05,0x1ee1f,0x1ee21,0x1ee22,0x1ee24,0x1ee24,0x1ee27,0x1ee27,0x1ee29,0x1ee32,0x1ee34,0x1ee37,0x1ee39,0x1ee39,0x1ee3b,0x1ee3b,0x1ee42,0x1ee42,0x1ee47,0x1ee47,0x1ee49,0x1ee49,0x1ee4b,0x1ee4b,0x1ee4d,0x1ee4f,0x1ee51,0x1ee52,0x1ee54,0x1ee54,0x1ee57,0x1ee57,0x1ee59,0x1ee59,0x1ee5b,0x1ee5b,0x1ee5d,0x1ee5d,0x1ee5f,0x1ee5f,0x1ee61,0x1ee62,0x1ee64,0x1ee64,0x1ee67,0x1ee6a,0x1ee6c,0x1ee72,0x1ee74,0x1ee77,0x1ee79,0x1ee7c,0x1ee7e,0x1ee7e,0x1ee80,0x1ee89,0x1ee8b,0x1ee9b,0x1eea1,0x1eea3,0x1eea5,0x1eea9,0x1eeab,0x1eebb,0x1eef0,0x1eef1,]), + NotoFont.fromFlatRanges('Noto Sans Mayan Numerals', 'http://fonts.gstatic.com/s/notosansmayannumerals/v15/PlIuFk25O6RzLfvNNVSivR09_KqYMwvvDKYjfIiE68oo6eepYQ.ttf', [0x20,0x20,0xa0,0xa0,0x1d2e0,0x1d2f3,]), + NotoFont.fromFlatRanges('Noto Sans Medefaidrin', 'http://fonts.gstatic.com/s/notosansmedefaidrin/v19/WwkzxOq6Dk-wranENynkfeVsNbRZtbOIdLb1exeM4ZeuabBfmErWlT318e5A3rw.ttf', [0x20,0x20,0xa0,0xa0,0x16e40,0x16e9a,]), + NotoFont.fromFlatRanges('Noto Sans Meetei Mayek', 'http://fonts.gstatic.com/s/notosansmeeteimayek/v10/HTxAL3QyKieByqY9eZPFweO0be7M21uSphSdhqILnmrRfJ8t_1TJ_vTW5PgeFYVa.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xaae0,0xaaf6,0xabc0,0xabed,0xabf0,0xabf9,]), + NotoFont.fromFlatRanges('Noto Sans Meroitic', 'http://fonts.gstatic.com/s/notosansmeroitic/v16/IFS5HfRJndhE3P4b5jnZ3ITPvC6i00UDgDhTiKY9KQ.ttf', [0x20,0x20,0x3a,0x3a,0xa0,0xa0,0x2026,0x2026,0x205d,0x205d,0x10980,0x109b7,0x109bc,0x109cf,0x109d2,0x109ff,]), + NotoFont.fromFlatRanges('Noto Sans Miao', 'http://fonts.gstatic.com/s/notosansmiao/v15/Dxxz8jmXMW75w3OmoDXVV4zyZUjgUYVslLhx.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x16f00,0x16f4a,0x16f4f,0x16f87,0x16f8f,0x16f9f,]), + NotoFont.fromFlatRanges('Noto Sans Modi', 'http://fonts.gstatic.com/s/notosansmodi/v15/pe03MIySN5pO62Z5YkFyT7jeav5qWVAgVol-.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11600,0x11644,0x11650,0x11659,]), + NotoFont.fromFlatRanges('Noto Sans Mongolian', 'http://fonts.gstatic.com/s/notosansmongolian/v15/VdGCAYADGIwE0EopZx8xQfHlgEAMsrToxLsg6-av1x0.ttf', [0x20,0x22,0x28,0x29,0x2d,0x2d,0x3f,0x3f,0xa0,0xa0,0x1800,0x180e,0x1810,0x1819,0x1820,0x1878,0x1880,0x18aa,0x200c,0x200d,0x2013,0x2014,0x201c,0x201d,0x202f,0x202f,0x2048,0x2049,0x2460,0x2473,0x25cc,0x25cc,0x3001,0x3002,0x300a,0x300f,0xfe3d,0xfe3e,0xfe41,0xfe44,0x11660,0x1166c,]), + NotoFont.fromFlatRanges('Noto Sans Mro', 'http://fonts.gstatic.com/s/notosansmro/v15/qWcsB6--pZv9TqnUQMhe9b39WDzRtjkho4M.ttf', [0x20,0x20,0xa0,0xa0,0x16a40,0x16a5e,0x16a60,0x16a69,0x16a6e,0x16a6f,]), + NotoFont.fromFlatRanges('Noto Sans Multani', 'http://fonts.gstatic.com/s/notosansmultani/v15/9Bty3ClF38_RfOpe1gCaZ8p30BOFO1A0pfCs5Kos.ttf', [0x20,0x20,0xa0,0xa0,0xa66,0xa6f,0x11280,0x11286,0x11288,0x11288,0x1128a,0x1128d,0x1128f,0x1129d,0x1129f,0x112a9,]), + NotoFont.fromFlatRanges('Noto Sans Myanmar', 'http://fonts.gstatic.com/s/notosansmyanmar/v19/AlZq_y1ZtY3ymOryg38hOCSdOnFq0En23OU4o1AC.ttf', [0x20,0x20,0x3f,0x3f,0xa0,0xa0,0x1000,0x109f,0x200b,0x200d,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x25cc,0x25cc,0xa92e,0xa92e,0xa9e0,0xa9fe,0xaa60,0xaa7f,0xfe00,0xfe00,]), + NotoFont.fromFlatRanges('Noto Sans N Ko', 'http://fonts.gstatic.com/s/notosansnko/v17/6NUP8FqDKBaKKjnr6P8v-sxPpvVBVNmme3gf.ttf', [0x20,0x20,0xa0,0xa0,0x60c,0x60c,0x61b,0x61b,0x61f,0x61f,0x66a,0x66a,0x7c0,0x7fa,0x7fd,0x7ff,0x200c,0x200f,0x25cc,0x25cc,0x2e1c,0x2e1d,0xfd3e,0xfd3f,]), + NotoFont.fromFlatRanges('Noto Sans Nabataean', 'http://fonts.gstatic.com/s/notosansnabataean/v15/IFS4HfVJndhE3P4b5jnZ34DfsjO330dNoBJ9hK8kMK4.ttf', [0x20,0x20,0xa0,0xa0,0x10880,0x1089e,0x108a7,0x108af,]), + NotoFont.fromFlatRanges('Noto Sans New Tai Lue', 'http://fonts.gstatic.com/s/notosansnewtailue/v15/H4c5BW-Pl9DZ0Xe_nHUapt7PovLXAhAnY7wwY55O4AS32A.ttf', [0x20,0x20,0xa0,0xa0,0x1980,0x19ab,0x19b0,0x19c9,0x19d0,0x19da,0x19de,0x19df,0x200c,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Newa', 'http://fonts.gstatic.com/s/notosansnewa/v15/7r3fqXp6utEsO9pI4f8ok8sWg8n_qN4R5lNU.ttf', [0x20,0x20,0xa0,0xa0,0xb7,0xb7,0x1dfb,0x1dfb,0x200c,0x200d,0x25cc,0x25cc,0x11400,0x1145b,0x1145d,0x11461,]), + NotoFont.fromFlatRanges('Noto Sans Nushu', 'http://fonts.gstatic.com/s/notosansnushu/v18/rnCw-xRQ3B7652emAbAe_Ai1IYaFWFAMArZKqQ.ttf', [0x20,0x20,0xa0,0xa0,0x16fe1,0x16fe1,0x1b170,0x1b2fb,]), + NotoFont.fromFlatRanges('Noto Sans Ogham', 'http://fonts.gstatic.com/s/notosansogham/v15/kmKlZqk1GBDGN0mY6k5lmEmww4hrt5laQxcoCA.ttf', [0x20,0x20,0xa0,0xa0,0x1680,0x169c,]), + NotoFont.fromFlatRanges('Noto Sans Ol Chiki', 'http://fonts.gstatic.com/s/notosansolchiki/v17/N0b92TJNOPt-eHmFZCdQbrL32r-4CvhzDzRwlxOQYuVALWk267I6gVrz5gQ.ttf', [0x20,0x20,0xa0,0xa0,0x1c50,0x1c7f,0x20b9,0x20b9,]), + NotoFont.fromFlatRanges('Noto Sans Old Hungarian', 'http://fonts.gstatic.com/s/notosansoldhungarian/v15/E213_cD6hP3GwCJPEUssHEM0KqLaHJXg2PiIgRfjbg5nCYXt.ttf', [0x20,0x20,0xa0,0xa0,0x200d,0x200d,0x10c80,0x10cb2,0x10cc0,0x10cf2,0x10cfa,0x10cff,]), + NotoFont.fromFlatRanges('Noto Sans Old Italic', 'http://fonts.gstatic.com/s/notosansolditalic/v15/TuGOUUFzXI5FBtUq5a8bh68BJxxEVam7tWlRdRhtCC4d.ttf', [0x20,0x20,0xa0,0xa0,0x10300,0x10323,0x1032d,0x1032f,]), + NotoFont.fromFlatRanges('Noto Sans Old North Arabian', 'http://fonts.gstatic.com/s/notosansoldnortharabian/v15/esDF30BdNv-KYGGJpKGk2tNiMt7Jar6olZDyNdr81zBQmUo_xw4ABw.ttf', [0x20,0x20,0xa0,0xa0,0x10a80,0x10a9f,]), + NotoFont.fromFlatRanges('Noto Sans Old Permic', 'http://fonts.gstatic.com/s/notosansoldpermic/v16/snf1s1q1-dF8pli1TesqcbUY4Mr-ElrwKLdXgv_dKYB5.ttf', [0x20,0x20,0xa0,0xa0,0x300,0x300,0x306,0x308,0x313,0x313,0x483,0x483,0x20db,0x20db,0x25cc,0x25cc,0x10350,0x1037a,]), + NotoFont.fromFlatRanges('Noto Sans Old Persian', 'http://fonts.gstatic.com/s/notosansoldpersian/v15/wEOjEAbNnc5caQTFG18FHrZr9Bp6-8CmIJ_tqOlQfx9CjA.ttf', [0x20,0x20,0xa0,0xa0,0x103a0,0x103c3,0x103c8,0x103d5,]), + NotoFont.fromFlatRanges('Noto Sans Old Sogdian', 'http://fonts.gstatic.com/s/notosansoldsogdian/v15/3JnjSCH90Gmq2mrzckOBBhFhdrMst48aURt7neIqM-9uyg.ttf', [0x20,0x20,0xa0,0xa0,0x10f00,0x10f27,]), + NotoFont.fromFlatRanges('Noto Sans Old South Arabian', 'http://fonts.gstatic.com/s/notosansoldsoutharabian/v15/3qT5oiOhnSyU8TNFIdhZTice3hB_HWKsEnF--0XCHiKx1OtDT9HwTA.ttf', [0x20,0x20,0xa0,0xa0,0x10a60,0x10a7f,]), + NotoFont.fromFlatRanges('Noto Sans Old Turkic', 'http://fonts.gstatic.com/s/notosansoldturkic/v15/yMJNMJVya43H0SUF_WmcGEQVqoEMKDKbsE2RjEw-Vyws.ttf', [0x20,0x20,0xa0,0xa0,0x10c00,0x10c48,]), + NotoFont.fromFlatRanges('Noto Sans Oriya', 'http://fonts.gstatic.com/s/notosansoriya/v16/AYCTpXfzfccDCstK_hrjDyADv5en5K3DZq1hIg.ttf', [0x20,0x23,0x25,0x25,0x27,0x2c,0x2e,0x3f,0x5b,0x5f,0x7b,0x7e,0xa0,0xa0,0xad,0xad,0xd7,0xd7,0xf7,0xf7,0x964,0x965,0xb01,0xb03,0xb05,0xb0c,0xb0f,0xb10,0xb13,0xb28,0xb2a,0xb30,0xb32,0xb33,0xb35,0xb39,0xb3c,0xb44,0xb47,0xb48,0xb4b,0xb4d,0xb56,0xb57,0xb5c,0xb5d,0xb5f,0xb63,0xb66,0xb77,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x20b9,0x20b9,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Osage', 'http://fonts.gstatic.com/s/notosansosage/v15/oPWX_kB6kP4jCuhpgEGmw4mtAVtXRlaSxkrMCQ.ttf', [0x20,0x20,0xa0,0xa0,0x301,0x301,0x304,0x304,0x30b,0x30b,0x358,0x358,0x25cc,0x25cc,0x104b0,0x104d3,0x104d8,0x104fb,]), + NotoFont.fromFlatRanges('Noto Sans Osmanya', 'http://fonts.gstatic.com/s/notosansosmanya/v15/8vIS7xs32H97qzQKnzfeWzUyUpOJmz6kR47NCV5Z.ttf', [0x20,0x20,0xa0,0xa0,0x10480,0x1049d,0x104a0,0x104a9,]), + NotoFont.fromFlatRanges('Noto Sans Pahawh Hmong', 'http://fonts.gstatic.com/s/notosanspahawhhmong/v15/bWtp7e_KfBziStx7lIzKKaMUOBEA3UPQDW7krzc_c48aMpM.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x16b00,0x16b45,0x16b50,0x16b59,0x16b5b,0x16b61,0x16b63,0x16b77,0x16b7d,0x16b8f,]), + NotoFont.fromFlatRanges('Noto Sans Palmyrene', 'http://fonts.gstatic.com/s/notosanspalmyrene/v15/ZgNPjOdKPa7CHqq0h37c_ASCWvH93SFCPnK5ZpdNtcA.ttf', [0x20,0x20,0xa0,0xa0,0x10860,0x1087f,]), + NotoFont.fromFlatRanges('Noto Sans Pau Cin Hau', 'http://fonts.gstatic.com/s/notosanspaucinhau/v16/x3d-cl3IZKmUqiMg_9wBLLtzl22EayN7ehIdjEWqKMxsKw.ttf', [0x20,0x20,0xa0,0xa0,0x11ac0,0x11af8,]), + NotoFont.fromFlatRanges('Noto Sans Phags Pa', 'http://fonts.gstatic.com/s/notosansphagspa/v15/pxiZyoo6v8ZYyWh5WuPeJzMkd4SrGChkqkSsrvNXiA.ttf', [0x20,0x20,0xa0,0xa0,0x1801,0x1803,0x1805,0x1805,0x200b,0x200f,0x2025,0x2026,0x25cc,0x25cc,0x3001,0x3002,0x3007,0x3011,0x3014,0x301b,0xa840,0xa877,0xfe00,0xfe00,]), + NotoFont.fromFlatRanges('Noto Sans Phoenician', 'http://fonts.gstatic.com/s/notosansphoenician/v15/jizFRF9Ksm4Bt9PvcTaEkIHiTVtxmFtS5X7Jot-p5561.ttf', [0x20,0x20,0xa0,0xa0,0x10900,0x1091b,0x1091f,0x1091f,]), + NotoFont.fromFlatRanges('Noto Sans Psalter Pahlavi', 'http://fonts.gstatic.com/s/notosanspsalterpahlavi/v15/rP2Vp3K65FkAtHfwd-eISGznYihzggmsicPfud3w1G3KsUQBct4.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x200c,0x200d,0x25cc,0x25cc,0x10b80,0x10b91,0x10b99,0x10b9c,0x10ba9,0x10baf,]), + NotoFont.fromFlatRanges('Noto Sans Rejang', 'http://fonts.gstatic.com/s/notosansrejang/v15/Ktk2AKuMeZjqPnXgyqrib7DIogqwN4O3WYZB_sU.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa930,0xa953,0xa95f,0xa95f,]), + NotoFont.fromFlatRanges('Noto Sans Runic', 'http://fonts.gstatic.com/s/notosansrunic/v15/H4c_BXWPl9DZ0Xe_nHUaus7W68WWaxpvHtgIYg.ttf', [0x20,0x20,0xa0,0xa0,0x16a0,0x16f8,]), + NotoFont.fromFlatRanges('Noto Sans SC', 'http://fonts.gstatic.com/s/notosanssc/v26/k3kXo84MPvpLmixcA63oeALhL4iJ-Q7m8w.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x4db5,0x4e00,0x9fef,0xf900,0xf903,0xf905,0xf906,0xf90b,0xf90c,0xf915,0xf915,0xf917,0xf91a,0xf921,0xf921,0xf92c,0xf92d,0xf92f,0xf92f,0xf931,0xf935,0xf937,0xf93a,0xf943,0xf943,0xf947,0xf94a,0xf94e,0xf94e,0xf952,0xf953,0xf95e,0xf95e,0xf962,0xf967,0xf96e,0xf96e,0xf972,0xf972,0xf974,0xf974,0xf976,0xf976,0xf979,0xf97b,0xf97e,0xf980,0xf984,0xf985,0xf98a,0xf98c,0xf98e,0xf98e,0xf993,0xf993,0xf995,0xf995,0xf998,0xf998,0xf9ae,0xf9ae,0xf9b3,0xf9b3,0xf9b7,0xf9b7,0xf9bb,0xf9bb,0xf9bd,0xf9be,0xf9c0,0xf9c0,0xf9c5,0xf9c6,0xf9d0,0xf9d0,0xf9d8,0xf9d9,0xf9dc,0xf9e0,0xf9e2,0xf9e4,0xf9e7,0xf9e7,0xf9e9,0xf9e9,0xf9f1,0xf9f1,0xf9f4,0xf9f5,0xf9fa,0xf9fa,0xf9fd,0xf9fd,0xf9ff,0xf9ff,0xfa02,0xfa02,0xfa05,0xfa08,0xfa0a,0xfa0a,0xfa0c,0xfa0f,0xfa11,0xfa11,0xfa13,0xfa14,0xfa18,0xfa18,0xfa1f,0xfa21,0xfa23,0xfa24,0xfa27,0xfa29,0xfa2f,0xfa2f,0xfa33,0xfa35,0xfa37,0xfa38,0xfa3a,0xfa3a,0xfa47,0xfa47,0xfa49,0xfa49,0xfa4b,0xfa4b,0xfa5d,0xfa5e,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x20087,0x20087,0x20089,0x20089,0x200cc,0x200cc,0x20164,0x20164,0x20628,0x20628,0x20676,0x20676,0x20cd0,0x20cd0,0x2139a,0x2139a,0x21413,0x21413,0x215d7,0x215d7,0x2298f,0x2298f,0x235cb,0x235cb,0x23c97,0x23c98,0x23e23,0x23e23,0x241fe,0x241fe,0x2420e,0x2420e,0x248e9,0x248e9,0x249db,0x249db,0x24a01,0x24a01,0x24a7d,0x24a7d,0x24ac9,0x24ac9,0x25532,0x25532,0x25562,0x25562,0x255a8,0x255a8,0x25ad7,0x25ad7,0x25ed7,0x25ed7,0x26221,0x26221,0x2648d,0x2648d,0x26676,0x26676,0x2677c,0x2677c,0x26951,0x26951,0x26b5c,0x26b5c,0x26c21,0x26c21,0x278b2,0x278b2,0x27eaf,0x27eaf,0x27fb7,0x27fb7,0x27ff9,0x27ff9,0x28408,0x28408,0x28678,0x28678,0x28695,0x28695,0x287e0,0x287e0,0x28b49,0x28b49,0x28c47,0x28c47,0x28c4f,0x28c4f,0x28c51,0x28c51,0x28c54,0x28c54,0x28e0f,0x28e0f,0x28e99,0x28e99,0x2967f,0x2967f,0x29810,0x29810,0x29f7e,0x29f7e,0x29f83,0x29f83,0x29f8c,0x29f8c,0x2a7dd,0x2a7dd,0x2a8fb,0x2a8fb,0x2a917,0x2a917,0x2aa30,0x2aa30,0x2aa36,0x2aa36,0x2aa58,0x2aa58,0x2afa2,0x2afa2,0x2b127,0x2b128,0x2b137,0x2b138,0x2b1ed,0x2b1ed,0x2b300,0x2b300,0x2b363,0x2b363,0x2b36f,0x2b36f,0x2b372,0x2b372,0x2b37d,0x2b37d,0x2b404,0x2b404,0x2b410,0x2b410,0x2b413,0x2b413,0x2b461,0x2b461,0x2b4e7,0x2b4e7,0x2b4ef,0x2b4ef,0x2b4f6,0x2b4f6,0x2b4f9,0x2b4f9,0x2b50d,0x2b50e,0x2b536,0x2b536,0x2b5ae,0x2b5af,0x2b5b3,0x2b5b3,0x2b5e7,0x2b5e7,0x2b5f4,0x2b5f4,0x2b61c,0x2b61d,0x2b626,0x2b628,0x2b62a,0x2b62a,0x2b62c,0x2b62c,0x2b695,0x2b696,0x2b6ad,0x2b6ad,0x2b6ed,0x2b6ed,0x2b7a9,0x2b7a9,0x2b7c5,0x2b7c5,0x2b7e6,0x2b7e6,0x2b7f9,0x2b7f9,0x2b7fc,0x2b7fc,0x2b806,0x2b806,0x2b80a,0x2b80a,0x2b81c,0x2b81c,0x2b8b8,0x2b8b8,0x2bac7,0x2bac7,0x2bb5f,0x2bb5f,0x2bb62,0x2bb62,0x2bb7c,0x2bb7c,0x2bb83,0x2bb83,0x2bc1b,0x2bc1b,0x2bd77,0x2bd77,0x2bd87,0x2bd87,0x2bdf7,0x2bdf7,0x2be29,0x2be29,0x2c029,0x2c02a,0x2c0a9,0x2c0a9,0x2c0ca,0x2c0ca,0x2c1d5,0x2c1d5,0x2c1d9,0x2c1d9,0x2c1f9,0x2c1f9,0x2c27c,0x2c27c,0x2c288,0x2c288,0x2c2a4,0x2c2a4,0x2c317,0x2c317,0x2c35b,0x2c35b,0x2c361,0x2c361,0x2c364,0x2c364,0x2c488,0x2c488,0x2c494,0x2c494,0x2c497,0x2c497,0x2c542,0x2c542,0x2c613,0x2c613,0x2c618,0x2c618,0x2c621,0x2c621,0x2c629,0x2c629,0x2c62b,0x2c62d,0x2c62f,0x2c62f,0x2c642,0x2c642,0x2c64a,0x2c64b,0x2c72c,0x2c72c,0x2c72f,0x2c72f,0x2c79f,0x2c79f,0x2c7c1,0x2c7c1,0x2c7fd,0x2c7fd,0x2c8d9,0x2c8d9,0x2c8de,0x2c8de,0x2c8e1,0x2c8e1,0x2c8f3,0x2c8f3,0x2c907,0x2c907,0x2c90a,0x2c90a,0x2c91d,0x2c91d,0x2ca02,0x2ca02,0x2ca0e,0x2ca0e,0x2ca7d,0x2ca7d,0x2caa9,0x2caa9,0x2cb29,0x2cb29,0x2cb2d,0x2cb2e,0x2cb31,0x2cb31,0x2cb38,0x2cb39,0x2cb3b,0x2cb3b,0x2cb3f,0x2cb3f,0x2cb41,0x2cb41,0x2cb4a,0x2cb4a,0x2cb4e,0x2cb4e,0x2cb5a,0x2cb5b,0x2cb64,0x2cb64,0x2cb69,0x2cb69,0x2cb6c,0x2cb6c,0x2cb6f,0x2cb6f,0x2cb73,0x2cb73,0x2cb76,0x2cb76,0x2cb78,0x2cb78,0x2cb7c,0x2cb7c,0x2cbb1,0x2cbb1,0x2cbbf,0x2cbc0,0x2cbce,0x2cbce,0x2cc56,0x2cc56,0x2cc5f,0x2cc5f,0x2ccf5,0x2ccf6,0x2ccfd,0x2ccfd,0x2ccff,0x2ccff,0x2cd02,0x2cd03,0x2cd0a,0x2cd0a,0x2cd8b,0x2cd8b,0x2cd8d,0x2cd8d,0x2cd8f,0x2cd90,0x2cd9f,0x2cda0,0x2cda8,0x2cda8,0x2cdad,0x2cdae,0x2cdd5,0x2cdd5,0x2ce18,0x2ce18,0x2ce1a,0x2ce1a,0x2ce23,0x2ce23,0x2ce26,0x2ce26,0x2ce2a,0x2ce2a,0x2ce7c,0x2ce7c,0x2ce88,0x2ce88,0x2ce93,0x2ce93,0x2d544,0x2d544,0x2f884,0x2f884,0x2f8b6,0x2f8b6,0x30edd,0x30ede,0x3106c,0x3106c,]), + NotoFont.fromFlatRanges('Noto Sans Saurashtra', 'http://fonts.gstatic.com/s/notosanssaurashtra/v15/ea8GacQ0Wfz_XKWXe6OtoA8w8zvmYwTef9ndjhPTSIx9.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa880,0xa8c5,0xa8ce,0xa8d9,]), + NotoFont.fromFlatRanges('Noto Sans Sharada', 'http://fonts.gstatic.com/s/notosanssharada/v15/gok0H7rwAEdtF9N8-mdTGALG6p0kwoXLPOwr4H8a.ttf', [0x20,0x20,0xa0,0xa0,0x951,0x951,0x1cd7,0x1cd7,0x1cd9,0x1cd9,0x1cdc,0x1cdd,0x1ce0,0x1ce0,0x200c,0x200d,0x25cc,0x25cc,0x11180,0x111df,]), + NotoFont.fromFlatRanges('Noto Sans Shavian', 'http://fonts.gstatic.com/s/notosansshavian/v15/CHy5V_HZE0jxJBQlqAeCKjJvQBNF4EFQSplv2Cwg.ttf', [0x20,0x20,0xa0,0xa0,0x10450,0x1047f,]), + NotoFont.fromFlatRanges('Noto Sans Siddham', 'http://fonts.gstatic.com/s/notosanssiddham/v15/OZpZg-FwqiNLe9PELUikxTWDoCCeGqndk3Ic92ZH.ttf', [0x20,0x20,0xa0,0xa0,0x200c,0x200d,0x25cc,0x25cc,0x11580,0x115b5,0x115b8,0x115dd,]), + NotoFont.fromFlatRanges('Noto Sans Sinhala', 'http://fonts.gstatic.com/s/notosanssinhala/v25/yMJ2MJBya43H0SUF_WmcBEEf4rQVO2P524V5N_MxQzQtb-tf5dJbC30Fu9zUwg2a5lgLpJwbQRM.ttf', [0x20,0x23,0x25,0x25,0x27,0x3f,0x5b,0x5f,0x7b,0x7e,0xa0,0xa0,0xad,0xad,0xd7,0xd7,0xf7,0xf7,0x964,0x965,0xd81,0xd83,0xd85,0xd96,0xd9a,0xdb1,0xdb3,0xdbb,0xdbd,0xdbd,0xdc0,0xdc6,0xdca,0xdca,0xdcf,0xdd4,0xdd6,0xdd6,0xdd8,0xddf,0xde6,0xdef,0xdf2,0xdf4,0x200b,0x200d,0x2013,0x2014,0x2018,0x2019,0x201c,0x201d,0x2026,0x2026,0x2212,0x2212,0x25cc,0x25cc,0x111e1,0x111f4,]), + NotoFont.fromFlatRanges('Noto Sans Sogdian', 'http://fonts.gstatic.com/s/notosanssogdian/v15/taiQGn5iC4--qtsfi4Jp6eHPnfxQBo--Pm6KHidM.ttf', [0x20,0x20,0xa0,0xa0,0x640,0x640,0x200c,0x200c,0x25cc,0x25cc,0x10f30,0x10f59,]), + NotoFont.fromFlatRanges('Noto Sans Sora Sompeng', 'http://fonts.gstatic.com/s/notosanssorasompeng/v17/PlIRFkO5O6RzLfvNNVSioxM2_OTrEhPyDLolKvCsHzCxWuGkYHR818DpZXJQd4Mu.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x2010,0x2010,0x110d0,0x110e8,0x110f0,0x110f9,]), + NotoFont.fromFlatRanges('Noto Sans Soyombo', 'http://fonts.gstatic.com/s/notosanssoyombo/v15/RWmSoL-Y6-8q5LTtXs6MF6q7xsxgY0FrIFOcK25W.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x11a50,0x11aa2,]), + NotoFont.fromFlatRanges('Noto Sans Sundanese', 'http://fonts.gstatic.com/s/notosanssundanese/v17/FwZw7_84xUkosG2xJo2gm7nFwSLQkdymq2mkz3Gz1_b6ctxpNNHCizv7fQES.ttf', [0x20,0x20,0x2d,0x2d,0xa0,0xa0,0x1b80,0x1bbf,0x1cc0,0x1cc7,0x200b,0x200d,0x2010,0x2010,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Syloti Nagri', 'http://fonts.gstatic.com/s/notosanssylotinagri/v15/uU9eCAQZ75uhfF9UoWDRiY3q7Sf_VFV3m4dGFVfxN87gsj0.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x965,0x9e6,0x9ef,0x200b,0x200d,0x2010,0x2011,0x2055,0x2055,0x25cc,0x25cc,0xa800,0xa82c,]), + NotoFont.fromFlatRanges('Noto Sans Syriac', 'http://fonts.gstatic.com/s/notosanssyriac/v15/Ktk2AKuMeZjqPnXgyqribqzQqgW0N4O3WYZB_sU.ttf', [0x20,0x21,0x28,0x2b,0x2d,0x2f,0x3a,0x3a,0x3d,0x3d,0x5b,0x5d,0xa0,0xa0,0xab,0xab,0xb0,0xb0,0xbb,0xbb,0x303,0x304,0x307,0x308,0x30a,0x30a,0x320,0x320,0x323,0x325,0x32d,0x32e,0x330,0x331,0x60c,0x60c,0x61b,0x61b,0x61f,0x61f,0x621,0x621,0x640,0x640,0x64b,0x655,0x660,0x66c,0x670,0x670,0x700,0x70d,0x70f,0x74a,0x74d,0x74f,0x200c,0x200f,0x2026,0x2026,0x2044,0x2044,0x2212,0x2212,0x25cc,0x25cc,0x2670,0x2671,]), + NotoFont.fromFlatRanges('Noto Sans TC', 'http://fonts.gstatic.com/s/notosanstc/v26/-nF7OG829Oofr2wohFbTp9iFOSsLA_ZJ1g.otf', [0x20,0x7e,0xa0,0x103,0x110,0x113,0x11a,0x11b,0x128,0x12b,0x143,0x144,0x147,0x148,0x14c,0x14f,0x152,0x153,0x168,0x16d,0x192,0x192,0x1a0,0x1a1,0x1af,0x1b0,0x1cd,0x1dc,0x1f8,0x1f9,0x251,0x251,0x261,0x261,0x2bb,0x2bb,0x2c7,0x2c7,0x2c9,0x2cb,0x2d9,0x2d9,0x2ea,0x2eb,0x300,0x301,0x304,0x304,0x307,0x307,0x30c,0x30c,0x391,0x3a1,0x3a3,0x3a9,0x3b1,0x3c9,0x401,0x401,0x410,0x44f,0x451,0x451,0x1e3e,0x1e3f,0x1ea0,0x1ef9,0x2002,0x2003,0x2010,0x2016,0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x2025,0x2027,0x2030,0x2030,0x2032,0x2033,0x2035,0x2035,0x2039,0x203c,0x2042,0x2042,0x2047,0x2049,0x2051,0x2051,0x2074,0x2074,0x20a9,0x20a9,0x20ab,0x20ac,0x20dd,0x20de,0x2100,0x2100,0x2103,0x2103,0x2105,0x2105,0x2109,0x210a,0x210f,0x210f,0x2113,0x2113,0x2116,0x2116,0x2121,0x2122,0x2126,0x2127,0x212b,0x212b,0x212e,0x212e,0x2135,0x2135,0x213b,0x213b,0x2160,0x216b,0x2170,0x217b,0x2190,0x2199,0x21b8,0x21b9,0x21c4,0x21c6,0x21cb,0x21cc,0x21d0,0x21d0,0x21d2,0x21d2,0x21d4,0x21d4,0x21e6,0x21e9,0x21f5,0x21f5,0x2200,0x2200,0x2202,0x2203,0x2205,0x220b,0x220f,0x220f,0x2211,0x2213,0x2215,0x2215,0x221a,0x221a,0x221d,0x2220,0x2223,0x2223,0x2225,0x222e,0x2234,0x2237,0x223d,0x223d,0x2243,0x2243,0x2245,0x2245,0x2248,0x2248,0x224c,0x224c,0x2252,0x2252,0x2260,0x2262,0x2264,0x2267,0x226a,0x226b,0x226e,0x226f,0x2272,0x2273,0x2276,0x2277,0x2282,0x2287,0x228a,0x228b,0x2295,0x2299,0x22a0,0x22a0,0x22a5,0x22a5,0x22bf,0x22bf,0x22da,0x22db,0x22ef,0x22ef,0x2305,0x2307,0x2312,0x2312,0x2318,0x2318,0x2329,0x232a,0x23b0,0x23b1,0x23be,0x23cc,0x23ce,0x23ce,0x23da,0x23db,0x2423,0x2423,0x2460,0x25ab,0x25b1,0x25b3,0x25b6,0x25b7,0x25bc,0x25bd,0x25c0,0x25c1,0x25c6,0x25cc,0x25ce,0x25d3,0x25e2,0x25e6,0x25ef,0x25ef,0x2600,0x2603,0x2605,0x2606,0x2609,0x2609,0x260e,0x260f,0x2616,0x2617,0x261c,0x261f,0x262f,0x262f,0x2640,0x2642,0x2660,0x266f,0x2672,0x267d,0x26a0,0x26a0,0x26bd,0x26be,0x2702,0x2702,0x2713,0x2713,0x271a,0x271a,0x273d,0x273d,0x273f,0x2740,0x2756,0x2756,0x2776,0x2793,0x27a1,0x27a1,0x2934,0x2935,0x29bf,0x29bf,0x29fa,0x29fb,0x2b05,0x2b07,0x2b1a,0x2b1a,0x2b95,0x2b95,0x2e3a,0x2e3b,0x2e80,0x2e99,0x2e9b,0x2ef3,0x2f00,0x2fd5,0x2ff0,0x2ffb,0x3000,0x303f,0x3041,0x3096,0x3099,0x30ff,0x3105,0x312f,0x3131,0x3163,0x3165,0x318e,0x3190,0x31bb,0x31c0,0x31e3,0x31f0,0x321e,0x3220,0x332b,0x332d,0x33ff,0x3435,0x3435,0x3440,0x3440,0x344a,0x344a,0x344c,0x344c,0x3464,0x3464,0x3473,0x3473,0x347a,0x347a,0x347d,0x347e,0x3493,0x3493,0x3496,0x3496,0x34a5,0x34a5,0x34af,0x34af,0x34bc,0x34bc,0x34c1,0x34c1,0x34c8,0x34c8,0x34df,0x34df,0x34e4,0x34e4,0x34e6,0x34e6,0x34fb,0x34fb,0x3506,0x3506,0x353e,0x353e,0x3551,0x3551,0x3553,0x3553,0x3559,0x3559,0x3561,0x3561,0x356d,0x356d,0x3570,0x3570,0x3572,0x3572,0x3577,0x3578,0x3584,0x3584,0x3597,0x3598,0x35a1,0x35a1,0x35a5,0x35a5,0x35ad,0x35ad,0x35bf,0x35bf,0x35c1,0x35c1,0x35c5,0x35c5,0x35c7,0x35c7,0x35ca,0x35ca,0x35ce,0x35ce,0x35d2,0x35d2,0x35d6,0x35d6,0x35db,0x35db,0x35dd,0x35dd,0x35f1,0x35f3,0x35fb,0x35fb,0x35fe,0x35fe,0x3609,0x3609,0x3618,0x3618,0x361a,0x361a,0x3623,0x3623,0x3625,0x3625,0x362d,0x362d,0x3635,0x3635,0x3639,0x3639,0x363e,0x363e,0x3647,0x3649,0x364e,0x364e,0x365f,0x365f,0x3661,0x3661,0x367a,0x367a,0x3681,0x3681,0x369a,0x369a,0x36a5,0x36a5,0x36aa,0x36aa,0x36ac,0x36ac,0x36b0,0x36b1,0x36b5,0x36b5,0x36b9,0x36b9,0x36bc,0x36bc,0x36c1,0x36c1,0x36c3,0x36c5,0x36c7,0x36c8,0x36d3,0x36d4,0x36d6,0x36d6,0x36dd,0x36dd,0x36e1,0x36e2,0x36e5,0x36e6,0x36f5,0x36f5,0x3701,0x3701,0x3703,0x3703,0x3708,0x3708,0x370a,0x370a,0x370d,0x370d,0x371c,0x371c,0x3722,0x3723,0x3725,0x3725,0x372c,0x372d,0x3730,0x3730,0x3732,0x3733,0x373a,0x373a,0x3740,0x3740,0x3743,0x3743,0x3762,0x3762,0x376f,0x376f,0x3797,0x3797,0x37a0,0x37a0,0x37b9,0x37b9,0x37be,0x37be,0x37d6,0x37d6,0x37f2,0x37f2,0x37f8,0x37f8,0x37fb,0x37fb,0x380f,0x380f,0x3819,0x3819,0x3820,0x3820,0x382d,0x382d,0x3836,0x3836,0x3838,0x3838,0x3863,0x3863,0x3875,0x3875,0x38a0,0x38a0,0x38c3,0x38c3,0x38cc,0x38cc,0x38d1,0x38d1,0x38d4,0x38d4,0x38fa,0x38fa,0x3908,0x3908,0x3914,0x3914,0x3927,0x3927,0x3932,0x3932,0x393f,0x393f,0x394d,0x394d,0x3963,0x3963,0x3978,0x3978,0x3980,0x3980,0x3989,0x398a,0x3992,0x3992,0x3999,0x3999,0x399b,0x399b,0x39a1,0x39a1,0x39a4,0x39a4,0x39b8,0x39b8,0x39dc,0x39dc,0x39e2,0x39e2,0x39e5,0x39e5,0x39ec,0x39ec,0x39f8,0x39f8,0x39fb,0x39fb,0x39fe,0x39fe,0x3a01,0x3a01,0x3a03,0x3a03,0x3a06,0x3a06,0x3a17,0x3a18,0x3a29,0x3a2a,0x3a34,0x3a34,0x3a4b,0x3a4b,0x3a52,0x3a52,0x3a57,0x3a57,0x3a5c,0x3a5c,0x3a5e,0x3a5e,0x3a66,0x3a67,0x3a97,0x3a97,0x3aab,0x3aab,0x3abd,0x3abd,0x3ada,0x3ada,0x3ade,0x3ade,0x3ae0,0x3ae0,0x3af0,0x3af0,0x3af2,0x3af2,0x3af5,0x3af5,0x3afb,0x3afb,0x3b0e,0x3b0e,0x3b19,0x3b19,0x3b22,0x3b22,0x3b2b,0x3b2b,0x3b39,0x3b39,0x3b42,0x3b42,0x3b58,0x3b58,0x3b60,0x3b60,0x3b71,0x3b72,0x3b7b,0x3b7c,0x3b80,0x3b80,0x3b95,0x3b96,0x3b99,0x3b99,0x3ba1,0x3ba1,0x3bbc,0x3bbc,0x3bbe,0x3bbe,0x3bc2,0x3bc2,0x3bc4,0x3bc4,0x3bd7,0x3bd7,0x3bdd,0x3bdd,0x3bec,0x3bec,0x3bf2,0x3bf4,0x3c0d,0x3c0d,0x3c11,0x3c11,0x3c15,0x3c15,0x3c18,0x3c18,0x3c54,0x3c54,0x3c8b,0x3c8b,0x3ccb,0x3ccb,0x3ccd,0x3ccd,0x3cd1,0x3cd1,0x3cd6,0x3cd6,0x3cdc,0x3cdc,0x3ceb,0x3ceb,0x3cef,0x3cef,0x3d12,0x3d13,0x3d1d,0x3d1d,0x3d32,0x3d32,0x3d3b,0x3d3b,0x3d46,0x3d46,0x3d4c,0x3d4c,0x3d4e,0x3d4e,0x3d51,0x3d51,0x3d5f,0x3d5f,0x3d62,0x3d62,0x3d69,0x3d6a,0x3d6f,0x3d6f,0x3d75,0x3d75,0x3d7d,0x3d7d,0x3d85,0x3d85,0x3d88,0x3d88,0x3d8a,0x3d8a,0x3d8f,0x3d8f,0x3d91,0x3d91,0x3da5,0x3da5,0x3dad,0x3dad,0x3db4,0x3db4,0x3dbf,0x3dbf,0x3dc6,0x3dc7,0x3dc9,0x3dc9,0x3dcc,0x3dcd,0x3dd3,0x3dd3,0x3ddb,0x3ddb,0x3de7,0x3de8,0x3deb,0x3deb,0x3df3,0x3df4,0x3df7,0x3df7,0x3dfc,0x3dfd,0x3e06,0x3e06,0x3e40,0x3e40,0x3e43,0x3e43,0x3e48,0x3e48,0x3e55,0x3e55,0x3e74,0x3e74,0x3ea8,0x3eaa,0x3ead,0x3ead,0x3eb1,0x3eb1,0x3eb8,0x3eb8,0x3ebf,0x3ebf,0x3ec2,0x3ec2,0x3ec7,0x3ec7,0x3eca,0x3eca,0x3ecc,0x3ecc,0x3ed0,0x3ed1,0x3ed6,0x3ed7,0x3eda,0x3edb,0x3ede,0x3ede,0x3ee1,0x3ee2,0x3ee7,0x3ee7,0x3ee9,0x3ee9,0x3eeb,0x3eec,0x3ef0,0x3ef0,0x3ef3,0x3ef4,0x3efa,0x3efa,0x3efc,0x3efc,0x3eff,0x3f00,0x3f04,0x3f04,0x3f06,0x3f07,0x3f0e,0x3f0e,0x3f53,0x3f53,0x3f58,0x3f59,0x3f63,0x3f63,0x3f7c,0x3f7c,0x3f93,0x3f93,0x3fc0,0x3fc0,0x3fc8,0x3fc8,0x3fd7,0x3fd7,0x3fdc,0x3fdc,0x3fe5,0x3fe5,0x3fed,0x3fed,0x3ff9,0x3ffa,0x4004,0x4004,0x4009,0x4009,0x401d,0x401d,0x4039,0x4039,0x4045,0x4045,0x4053,0x4053,0x4057,0x4057,0x4062,0x4062,0x4065,0x4065,0x406a,0x406a,0x406f,0x406f,0x4071,0x4071,0x40a8,0x40a8,0x40b4,0x40b4,0x40bb,0x40bb,0x40bf,0x40bf,0x40c8,0x40c8,0x40d8,0x40d8,0x40df,0x40df,0x40f8,0x40f8,0x40fa,0x40fa,0x4102,0x4104,0x4109,0x4109,0x410e,0x410e,0x4131,0x4132,0x4167,0x4167,0x416c,0x416c,0x416e,0x416e,0x417c,0x417c,0x417f,0x417f,0x4181,0x4181,0x4190,0x4190,0x41b2,0x41b2,0x41c4,0x41c4,0x41ca,0x41ca,0x41cf,0x41cf,0x41db,0x41db,0x41ed,0x41ed,0x41ef,0x41ef,0x41f9,0x41f9,0x4211,0x4211,0x4223,0x4223,0x4240,0x4240,0x4260,0x4260,0x426a,0x426a,0x4276,0x4276,0x427a,0x427a,0x428c,0x428c,0x4294,0x4294,0x42a2,0x42a2,0x42b5,0x42b5,0x42b9,0x42b9,0x42bc,0x42bc,0x42f4,0x42f4,0x42fb,0x42fc,0x430a,0x430a,0x432b,0x432b,0x436e,0x436e,0x4397,0x4397,0x439a,0x439a,0x43ba,0x43ba,0x43c1,0x43c1,0x43d9,0x43d9,0x43df,0x43df,0x43ed,0x43ed,0x43f0,0x43f0,0x43f2,0x43f2,0x4401,0x4402,0x4413,0x4413,0x4425,0x4425,0x442d,0x442d,0x447a,0x447a,0x448f,0x448f,0x4491,0x4491,0x449f,0x44a0,0x44a2,0x44a2,0x44b0,0x44b0,0x44b7,0x44b7,0x44bd,0x44bd,0x44c0,0x44c0,0x44c3,0x44c3,0x44c5,0x44c5,0x44ce,0x44ce,0x44dd,0x44df,0x44e1,0x44e1,0x44e4,0x44e4,0x44e9,0x44ec,0x44f4,0x44f4,0x4503,0x4504,0x4509,0x4509,0x450b,0x450b,0x4516,0x4516,0x451b,0x451b,0x451d,0x451d,0x4527,0x4527,0x452e,0x452e,0x4533,0x4533,0x4536,0x4536,0x453b,0x453b,0x453d,0x453d,0x453f,0x453f,0x4543,0x4543,0x4551,0x4552,0x4555,0x4555,0x4558,0x4558,0x455c,0x455c,0x4561,0x4562,0x456a,0x456a,0x456d,0x456d,0x4577,0x4578,0x4585,0x4585,0x45a6,0x45a6,0x45b3,0x45b3,0x45da,0x45da,0x45e9,0x45ea,0x4603,0x4603,0x4606,0x4606,0x460f,0x460f,0x4615,0x4615,0x4617,0x4617,0x465b,0x465b,0x467a,0x467a,0x4680,0x4680,0x46a1,0x46a1,0x46ae,0x46ae,0x46bb,0x46bb,0x46cf,0x46d0,0x46f5,0x46f5,0x46f7,0x46f7,0x4713,0x4713,0x4718,0x4718,0x4736,0x4736,0x4744,0x4744,0x474e,0x474f,0x477c,0x477c,0x4798,0x4798,0x47a6,0x47a6,0x47d5,0x47d5,0x47ed,0x47ed,0x47f4,0x47f4,0x4800,0x4800,0x480b,0x480b,0x4837,0x4837,0x485d,0x485d,0x4871,0x4871,0x489b,0x489b,0x48ad,0x48ae,0x48d0,0x48d0,0x48dd,0x48dd,0x48ed,0x48ed,0x48f3,0x48f3,0x48fa,0x48fa,0x4906,0x4906,0x4911,0x4911,0x491e,0x491e,0x4925,0x4925,0x492a,0x492a,0x492d,0x492d,0x492f,0x4930,0x4935,0x4935,0x493c,0x493c,0x493e,0x493e,0x4945,0x4945,0x4951,0x4951,0x4953,0x4953,0x4965,0x4965,0x496a,0x496a,0x4972,0x4972,0x4989,0x4989,0x49a1,0x49a1,0x49a7,0x49a7,0x49df,0x49df,0x49e5,0x49e5,0x49e7,0x49e7,0x4a0f,0x4a0f,0x4a1d,0x4a1d,0x4a24,0x4a24,0x4a35,0x4a35,0x4a96,0x4a96,0x4aa4,0x4aa4,0x4ab4,0x4ab4,0x4ab8,0x4ab8,0x4ad1,0x4ad1,0x4ae4,0x4ae4,0x4aff,0x4aff,0x4b10,0x4b10,0x4b19,0x4b19,0x4b20,0x4b20,0x4b2c,0x4b2c,0x4b37,0x4b37,0x4b6f,0x4b70,0x4b72,0x4b72,0x4b7b,0x4b7b,0x4b7e,0x4b7e,0x4b8e,0x4b8e,0x4b90,0x4b90,0x4b93,0x4b93,0x4b96,0x4b97,0x4b9d,0x4b9d,0x4bbd,0x4bbe,0x4bc0,0x4bc0,0x4c04,0x4c04,0x4c07,0x4c07,0x4c0e,0x4c0e,0x4c32,0x4c32,0x4c3b,0x4c3b,0x4c3e,0x4c3e,0x4c40,0x4c40,0x4c47,0x4c47,0x4c57,0x4c57,0x4c5b,0x4c5b,0x4c6d,0x4c6d,0x4c77,0x4c77,0x4c7b,0x4c7b,0x4c7d,0x4c7d,0x4c81,0x4c81,0x4c85,0x4c85,0x4ca4,0x4ca4,0x4cae,0x4cae,0x4cb0,0x4cb0,0x4cb7,0x4cb7,0x4ccd,0x4ccd,0x4ce1,0x4ce2,0x4ced,0x4ced,0x4d07,0x4d07,0x4d09,0x4d09,0x4d10,0x4d10,0x4d34,0x4d34,0x4d76,0x4d77,0x4d89,0x4d89,0x4d91,0x4d91,0x4d9c,0x4d9c,0x4e00,0x4e01,0x4e03,0x4e04,0x4e07,0x4e11,0x4e14,0x4e16,0x4e18,0x4e1a,0x4e1c,0x4e1c,0x4e1e,0x4e1f,0x4e21,0x4e22,0x4e24,0x4e24,0x4e26,0x4e26,0x4e28,0x4e28,0x4e2a,0x4e33,0x4e36,0x4e39,0x4e3b,0x4e3d,0x4e3f,0x4e3f,0x4e42,0x4e43,0x4e45,0x4e45,0x4e47,0x4e49,0x4e4b,0x4e4b,0x4e4d,0x4e4f,0x4e52,0x4e53,0x4e56,0x4e56,0x4e58,0x4e5f,0x4e69,0x4e6a,0x4e73,0x4e73,0x4e78,0x4e78,0x4e7e,0x4e89,0x4e8b,0x4e8e,0x4e91,0x4e95,0x4e98,0x4e9b,0x4e9e,0x4ea6,0x4ea8,0x4ea8,0x4eab,0x4eae,0x4eb3,0x4eb3,0x4eb6,0x4eb7,0x4eb9,0x4ebc,0x4ebf,0x4ec4,0x4ec6,0x4ecb,0x4ecd,0x4ece,0x4ed4,0x4eda,0x4edc,0x4edf,0x4ee1,0x4ee1,0x4ee3,0x4ee5,0x4ee8,0x4eeb,0x4eee,0x4eee,0x4ef0,0x4ef8,0x4efb,0x4efb,0x4efd,0x4efd,0x4eff,0x4f05,0x4f08,0x4f0b,0x4f0d,0x4f15,0x4f17,0x4f1a,0x4f1d,0x4f1d,0x4f22,0x4f22,0x4f28,0x4f29,0x4f2c,0x4f2d,0x4f2f,0x4f30,0x4f32,0x4f34,0x4f36,0x4f3f,0x4f41,0x4f43,0x4f45,0x4f49,0x4f4b,0x4f64,0x4f67,0x4f67,0x4f69,0x4f6c,0x4f6e,0x4f70,0x4f72,0x4f8b,0x4f8d,0x4f8d,0x4f8f,0x4f92,0x4f94,0x4f98,0x4f9a,0x4f9e,0x4fa2,0x4fa2,0x4fa8,0x4fa8,0x4fab,0x4fab,0x4fae,0x4fb0,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbd,0x4fbd,0x4fbf,0x4fc5,0x4fc7,0x4fd1,0x4fd3,0x4fd4,0x4fd6,0x4fe1,0x4fe4,0x4fe5,0x4fec,0x4fec,0x4fee,0x4ffa,0x4ffd,0x4ffe,0x5000,0x5000,0x5003,0x5003,0x5005,0x5009,0x500b,0x500f,0x5011,0x501c,0x501e,0x5023,0x5025,0x5031,0x5033,0x5035,0x5037,0x5037,0x503b,0x503c,0x5040,0x5041,0x5043,0x5043,0x5045,0x504f,0x5051,0x5051,0x5053,0x5053,0x5055,0x5058,0x505a,0x5066,0x5068,0x5070,0x5072,0x5077,0x507a,0x507a,0x507d,0x507d,0x5080,0x5083,0x5085,0x5085,0x5087,0x5088,0x508b,0x508e,0x5090,0x5092,0x5094,0x5096,0x5098,0x509e,0x50a2,0x50a3,0x50a6,0x50a6,0x50ac,0x50b8,0x50ba,0x50bf,0x50c1,0x50c2,0x50c4,0x50cb,0x50cd,0x50d1,0x50d3,0x50d7,0x50d9,0x50db,0x50dd,0x50dd,0x50df,0x50e1,0x50e3,0x50ea,0x50ec,0x50f1,0x50f3,0x50f6,0x50f8,0x50f9,0x50fb,0x510e,0x5110,0x5115,0x5117,0x5118,0x511a,0x511a,0x511c,0x511c,0x511f,0x5122,0x5124,0x5126,0x5129,0x512b,0x512d,0x512e,0x5130,0x5135,0x5137,0x513d,0x513f,0x5141,0x5143,0x5149,0x514b,0x514d,0x5151,0x5152,0x5154,0x5157,0x5159,0x5163,0x5165,0x5165,0x5167,0x516e,0x5171,0x5171,0x5174,0x5179,0x517c,0x517c,0x5180,0x5180,0x5182,0x5182,0x5186,0x518a,0x518d,0x518d,0x518f,0x518f,0x5191,0x5198,0x519a,0x519a,0x519c,0x519c,0x519e,0x519e,0x51a0,0x51a0,0x51a2,0x51a2,0x51a4,0x51a5,0x51a7,0x51a8,0x51aa,0x51ac,0x51ae,0x51ae,0x51b0,0x51b9,0x51bc,0x51be,0x51c3,0x51d4,0x51d7,0x51d8,0x51db,0x51e2,0x51e4,0x51e4,0x51ed,0x51ed,0x51f0,0x51f1,0x51f3,0x51f6,0x51f8,0x51fa,0x51fc,0x51fe,0x5200,0x5203,0x5205,0x520c,0x520e,0x520e,0x5210,0x5213,0x5216,0x5217,0x521c,0x5221,0x5224,0x522a,0x522e,0x522e,0x5230,0x5238,0x523a,0x523c,0x5241,0x5241,0x5243,0x5244,0x5246,0x5247,0x5249,0x524f,0x5252,0x5252,0x5254,0x5257,0x5259,0x5262,0x5268,0x526f,0x5272,0x5275,0x5277,0x527d,0x527f,0x5284,0x5287,0x528d,0x528f,0x5291,0x5293,0x5294,0x5296,0x529b,0x529f,0x52a1,0x52a3,0x52a4,0x52a6,0x52a6,0x52a8,0x52ae,0x52b5,0x52b5,0x52b9,0x52b9,0x52bb,0x52bc,0x52be,0x52be,0x52c0,0x52c3,0x52c5,0x52c5,0x52c7,0x52c7,0x52c9,0x52c9,0x52cc,0x52cd,0x52d0,0x52d3,0x52d5,0x52d9,0x52db,0x52db,0x52dd,0x52e4,0x52e6,0x52e6,0x52e9,0x52e9,0x52eb,0x52eb,0x52ef,0x52f1,0x52f3,0x52f5,0x52f7,0x52fc,0x52fe,0x52ff,0x5301,0x5301,0x5305,0x5306,0x5308,0x530b,0x530d,0x5312,0x5315,0x5317,0x5319,0x531a,0x531c,0x531d,0x531f,0x5324,0x5327,0x5327,0x532a,0x532a,0x532c,0x532d,0x532f,0x5334,0x5337,0x5339,0x533b,0x5345,0x5347,0x534a,0x534c,0x534e,0x5351,0x5354,0x5357,0x5357,0x535a,0x535a,0x535c,0x5361,0x5363,0x5364,0x5366,0x5367,0x5369,0x5369,0x536c,0x5375,0x5377,0x5379,0x537b,0x537f,0x5382,0x5382,0x5384,0x5384,0x538a,0x538a,0x538e,0x538f,0x5392,0x5394,0x5396,0x539a,0x539c,0x53a0,0x53a2,0x53a2,0x53a4,0x53ae,0x53b0,0x53b0,0x53b2,0x53b2,0x53b4,0x53b4,0x53b6,0x53b6,0x53b9,0x53b9,0x53bb,0x53bb,0x53c1,0x53c3,0x53c5,0x53c5,0x53c8,0x53cd,0x53d0,0x53d2,0x53d4,0x53d4,0x53d6,0x53db,0x53df,0x53e6,0x53e8,0x53f3,0x53f5,0x53f8,0x53fb,0x53fc,0x53fe,0x53fe,0x5401,0x5401,0x5403,0x5404,0x5406,0x5414,0x5416,0x5416,0x5418,0x5421,0x5423,0x5439,0x543b,0x5443,0x5445,0x5448,0x544a,0x544f,0x5454,0x5454,0x5460,0x546d,0x546f,0x5478,0x547a,0x5482,0x5484,0x5488,0x548b,0x5498,0x549a,0x549a,0x549c,0x549c,0x549e,0x549e,0x54a0,0x54b4,0x54b6,0x54c9,0x54cb,0x54d0,0x54d6,0x54d6,0x54da,0x54da,0x54de,0x54de,0x54e0,0x54eb,0x54ed,0x54ef,0x54f1,0x54f3,0x54f7,0x54f8,0x54fa,0x54fd,0x54ff,0x54ff,0x5501,0x5514,0x5517,0x5518,0x551a,0x551a,0x551e,0x551e,0x5523,0x5523,0x5525,0x5528,0x552a,0x5539,0x553b,0x553c,0x553e,0x5541,0x5543,0x554b,0x554d,0x5553,0x5555,0x5557,0x555c,0x555f,0x5561,0x5566,0x5569,0x556b,0x5571,0x5573,0x5575,0x5577,0x5579,0x5579,0x557b,0x5584,0x5586,0x5595,0x5598,0x559a,0x559c,0x559d,0x559f,0x559f,0x55a1,0x55ae,0x55b0,0x55b5,0x55b9,0x55bc,0x55bf,0x55df,0x55e1,0x55ea,0x55ec,0x55ec,0x55ee,0x55f2,0x55f5,0x55f7,0x55f9,0x5602,0x5604,0x5606,0x5608,0x5609,0x560c,0x5617,0x561b,0x5623,0x5625,0x5625,0x5627,0x5627,0x5629,0x562a,0x562c,0x5630,0x5632,0x563b,0x563d,0x5643,0x5645,0x5646,0x5648,0x564a,0x564c,0x5650,0x5652,0x5654,0x5657,0x565a,0x565d,0x565e,0x5660,0x5666,0x5668,0x5674,0x5676,0x567c,0x567e,0x5687,0x5689,0x5690,0x5692,0x5693,0x5695,0x5695,0x5697,0x569a,0x569c,0x569f,0x56a1,0x56a1,0x56a4,0x56a8,0x56aa,0x56af,0x56b1,0x56b7,0x56b9,0x56b9,0x56bc,0x56c3,0x56c5,0x56c6,0x56c8,0x56cd,0x56d1,0x56d1,0x56d3,0x56d4,0x56d6,0x56d7,0x56da,0x56db,0x56dd,0x56e2,0x56e4,0x56e5,0x56e7,0x56e7,0x56ea,0x56eb,0x56ed,0x56f1,0x56f7,0x56f7,0x56f9,0x56fb,0x56fd,0x56fd,0x56ff,0x5704,0x5707,0x570d,0x5712,0x5716,0x5718,0x5718,0x571a,0x5720,0x5722,0x5723,0x5728,0x572a,0x572c,0x5730,0x5732,0x5734,0x573b,0x573b,0x573d,0x5743,0x5745,0x5747,0x5749,0x5752,0x5754,0x5754,0x5757,0x5757,0x575b,0x575b,0x575f,0x575f,0x5761,0x5762,0x5764,0x5764,0x5766,0x576b,0x576d,0x576d,0x576f,0x5777,0x577a,0x5780,0x5782,0x5783,0x5788,0x5788,0x578a,0x578d,0x578f,0x5790,0x5793,0x5795,0x5797,0x57a5,0x57a7,0x57a7,0x57aa,0x57aa,0x57ae,0x57ae,0x57b3,0x57b6,0x57b8,0x57bf,0x57c1,0x57c4,0x57c6,0x57c8,0x57cb,0x57cc,0x57ce,0x57d0,0x57d2,0x57d2,0x57d4,0x57d5,0x57d7,0x57d7,0x57dc,0x57e7,0x57e9,0x57e9,0x57ec,0x57fe,0x5800,0x580e,0x5810,0x5810,0x5812,0x5812,0x5814,0x5814,0x5818,0x5819,0x581b,0x581e,0x5820,0x582a,0x582c,0x583b,0x583d,0x583d,0x583f,0x5840,0x5844,0x5844,0x5847,0x584f,0x5851,0x5855,0x5857,0x585f,0x5862,0x5865,0x5868,0x5869,0x586b,0x586d,0x586f,0x586f,0x5871,0x5876,0x5879,0x5883,0x5885,0x588b,0x588e,0x5894,0x5896,0x5896,0x5898,0x589a,0x589c,0x58a1,0x58a3,0x58a3,0x58a5,0x58ac,0x58ae,0x58b1,0x58b3,0x58b3,0x58b5,0x58b6,0x58ba,0x58bf,0x58c1,0x58c2,0x58c5,0x58c9,0x58cb,0x58cb,0x58ce,0x58d6,0x58d8,0x58e0,0x58e2,0x58e4,0x58e7,0x58e9,0x58eb,0x58ec,0x58ef,0x58f0,0x58f2,0x58f4,0x58f9,0x58ff,0x5902,0x5907,0x590a,0x590a,0x590c,0x590f,0x5911,0x5912,0x5914,0x5917,0x5919,0x591a,0x591c,0x591d,0x591f,0x5920,0x5922,0x5922,0x5924,0x5925,0x5927,0x5927,0x5929,0x592f,0x5931,0x5932,0x5934,0x5934,0x5937,0x5938,0x593c,0x593c,0x593e,0x593e,0x5940,0x5940,0x5944,0x5945,0x5947,0x594a,0x594e,0x5951,0x5953,0x5955,0x5957,0x5958,0x595a,0x595a,0x595c,0x595c,0x5960,0x5962,0x5965,0x5965,0x5967,0x5967,0x5969,0x596e,0x5970,0x5979,0x597b,0x5985,0x5989,0x598a,0x598d,0x5990,0x5992,0x5994,0x5996,0x599a,0x599d,0x59a8,0x59ac,0x59ac,0x59ae,0x59c1,0x59c3,0x59d4,0x59d6,0x59d6,0x59d8,0x59de,0x59e0,0x59e1,0x59e3,0x59e6,0x59e8,0x5a03,0x5a09,0x5a0d,0x5a0f,0x5a0f,0x5a11,0x5a13,0x5a15,0x5a1c,0x5a1e,0x5a21,0x5a23,0x5a25,0x5a27,0x5a27,0x5a29,0x5a2e,0x5a33,0x5a33,0x5a35,0x5a39,0x5a3c,0x5a3e,0x5a40,0x5a4a,0x5a4c,0x5a4d,0x5a50,0x5a6e,0x5a70,0x5a71,0x5a77,0x5a7f,0x5a81,0x5a84,0x5a86,0x5a86,0x5a88,0x5a88,0x5a8a,0x5a8c,0x5a8e,0x5a97,0x5a99,0x5aa2,0x5aa4,0x5aa7,0x5aa9,0x5aac,0x5aae,0x5ac4,0x5ac6,0x5acf,0x5ad1,0x5ad1,0x5ad3,0x5ad3,0x5ad5,0x5ae6,0x5ae8,0x5aee,0x5af0,0x5af0,0x5af2,0x5afb,0x5afd,0x5aff,0x5b01,0x5b03,0x5b05,0x5b05,0x5b07,0x5b09,0x5b0b,0x5b0d,0x5b0f,0x5b11,0x5b13,0x5b17,0x5b19,0x5b1b,0x5b1d,0x5b21,0x5b23,0x5b28,0x5b2a,0x5b30,0x5b32,0x5b32,0x5b34,0x5b34,0x5b38,0x5b38,0x5b3c,0x5b41,0x5b43,0x5b48,0x5b4a,0x5b51,0x5b53,0x5b58,0x5b5a,0x5b5d,0x5b5f,0x5b5f,0x5b62,0x5b66,0x5b68,0x5b69,0x5b6b,0x5b6e,0x5b70,0x5b78,0x5b7a,0x5b7d,0x5b7f,0x5b85,0x5b87,0x5b89,0x5b8b,0x5b8c,0x5b8e,0x5b90,0x5b92,0x5b93,0x5b95,0x5b9f,0x5ba2,0x5ba8,0x5baa,0x5baa,0x5bac,0x5bae,0x5bb0,0x5bb0,0x5bb3,0x5bb9,0x5bbf,0x5bc7,0x5bca,0x5bce,0x5bd0,0x5bd9,0x5bdb,0x5bdb,0x5bde,0x5bec,0x5bee,0x5bf3,0x5bf5,0x5bf6,0x5bf8,0x5bf8,0x5bfa,0x5bfa,0x5bff,0x5bff,0x5c01,0x5c01,0x5c03,0x5c05,0x5c07,0x5c16,0x5c1a,0x5c1a,0x5c1c,0x5c1c,0x5c1e,0x5c20,0x5c22,0x5c25,0x5c28,0x5c28,0x5c2a,0x5c2a,0x5c2c,0x5c2c,0x5c30,0x5c31,0x5c33,0x5c33,0x5c37,0x5c3c,0x5c3e,0x5c41,0x5c44,0x5c51,0x5c53,0x5c56,0x5c58,0x5c59,0x5c5c,0x5c5e,0x5c60,0x5c60,0x5c62,0x5c65,0x5c67,0x5c6a,0x5c6c,0x5c6f,0x5c71,0x5c71,0x5c73,0x5c74,0x5c78,0x5c7c,0x5c7e,0x5c7e,0x5c85,0x5c86,0x5c88,0x5c8d,0x5c8f,0x5c95,0x5c99,0x5c9a,0x5c9c,0x5cb1,0x5cb3,0x5cb3,0x5cb5,0x5cb8,0x5cba,0x5cba,0x5cc1,0x5cc2,0x5cc6,0x5ccc,0x5cce,0x5cdb,0x5cde,0x5cdf,0x5ce5,0x5ce5,0x5ce8,0x5cea,0x5cec,0x5cf1,0x5cf4,0x5cf9,0x5cfb,0x5cfd,0x5cff,0x5d01,0x5d06,0x5d07,0x5d0b,0x5d12,0x5d14,0x5d1b,0x5d1d,0x5d20,0x5d22,0x5d29,0x5d2c,0x5d2c,0x5d2e,0x5d3a,0x5d3c,0x5d43,0x5d45,0x5d4c,0x5d4e,0x5d4e,0x5d50,0x5d52,0x5d55,0x5d57,0x5d59,0x5d59,0x5d5b,0x5d5b,0x5d5e,0x5d5e,0x5d62,0x5d63,0x5d65,0x5d65,0x5d67,0x5d69,0x5d6b,0x5d6c,0x5d6f,0x5d72,0x5d74,0x5d74,0x5d77,0x5d82,0x5d84,0x5d8b,0x5d8d,0x5d8e,0x5d92,0x5d95,0x5d97,0x5d97,0x5d99,0x5d9a,0x5d9c,0x5da2,0x5da4,0x5da4,0x5da7,0x5db2,0x5db4,0x5dba,0x5dbc,0x5dbd,0x5dc0,0x5dc3,0x5dc6,0x5dc7,0x5dc9,0x5dc9,0x5dcb,0x5dcb,0x5dcd,0x5dcd,0x5dcf,0x5dcf,0x5dd1,0x5dd2,0x5dd4,0x5dd8,0x5ddb,0x5ddb,0x5ddd,0x5de2,0x5de5,0x5de8,0x5deb,0x5deb,0x5dee,0x5dee,0x5df0,0x5df5,0x5df7,0x5df7,0x5df9,0x5df9,0x5dfd,0x5dff,0x5e02,0x5e04,0x5e06,0x5e06,0x5e09,0x5e0c,0x5e0e,0x5e0e,0x5e11,0x5e12,0x5e14,0x5e1b,0x5e1d,0x5e1d,0x5e1f,0x5e25,0x5e28,0x5e29,0x5e2b,0x5e2b,0x5e2d,0x5e2e,0x5e33,0x5e34,0x5e36,0x5e38,0x5e3d,0x5e3e,0x5e40,0x5e45,0x5e48,0x5e48,0x5e4a,0x5e4f,0x5e53,0x5e55,0x5e57,0x5e59,0x5e5b,0x5e63,0x5e66,0x5e70,0x5e72,0x5e76,0x5e78,0x5e80,0x5e82,0x5e84,0x5e86,0x5e8d,0x5e8f,0x5e8f,0x5e92,0x5e92,0x5e95,0x5e97,0x5e99,0x5e9c,0x5ea0,0x5ea0,0x5ea2,0x5ea8,0x5eaa,0x5eae,0x5eb0,0x5eb9,0x5ebd,0x5ebe,0x5ec1,0x5ec2,0x5ec4,0x5ece,0x5ed0,0x5ee3,0x5ee5,0x5ee9,0x5eec,0x5eec,0x5eee,0x5eef,0x5ef1,0x5ef4,0x5ef6,0x5efc,0x5efe,0x5eff,0x5f01,0x5f02,0x5f04,0x5f05,0x5f07,0x5f08,0x5f0a,0x5f0f,0x5f12,0x5f15,0x5f17,0x5f18,0x5f1a,0x5f1b,0x5f1d,0x5f1d,0x5f1f,0x5f1f,0x5f22,0x5f29,0x5f2d,0x5f2e,0x5f30,0x5f31,0x5f33,0x5f33,0x5f35,0x5f38,0x5f3a,0x5f3c,0x5f40,0x5f40,0x5f43,0x5f46,0x5f48,0x5f51,0x5f54,0x5f54,0x5f56,0x5f59,0x5f5c,0x5f5e,0x5f61,0x5f65,0x5f67,0x5f67,0x5f69,0x5f6d,0x5f6f,0x5f74,0x5f76,0x5f79,0x5f7b,0x5f83,0x5f85,0x5f8c,0x5f90,0x5f92,0x5f96,0x5f99,0x5f9b,0x5f9c,0x5f9e,0x5fa1,0x5fa4,0x5faf,0x5fb1,0x5fb2,0x5fb5,0x5fb7,0x5fb9,0x5fc5,0x5fc9,0x5fc9,0x5fcc,0x5fcd,0x5fcf,0x5fd2,0x5fd4,0x5fd9,0x5fdb,0x5fdb,0x5fdd,0x5fe1,0x5fe3,0x5fe5,0x5fe8,0x5fe8,0x5fea,0x5feb,0x5fed,0x5fef,0x5ff1,0x5ff1,0x5ff3,0x5ff5,0x5ff7,0x5ff8,0x5ffa,0x5ffb,0x5ffd,0x5ffd,0x5fff,0x6000,0x6009,0x6017,0x6019,0x601e,0x6020,0x602f,0x6031,0x6035,0x6037,0x6037,0x6039,0x6039,0x603b,0x603b,0x6040,0x6047,0x6049,0x604d,0x6050,0x6050,0x6052,0x6055,0x6058,0x605b,0x605d,0x605f,0x6062,0x6070,0x6072,0x6072,0x6075,0x6075,0x6077,0x6077,0x607e,0x6081,0x6083,0x608a,0x608c,0x608e,0x6090,0x6090,0x6092,0x6092,0x6094,0x6097,0x609a,0x60a0,0x60a2,0x60a4,0x60a6,0x60a8,0x60b0,0x60c1,0x60c3,0x60cf,0x60d1,0x60d1,0x60d3,0x60d5,0x60d7,0x60e4,0x60e6,0x60e9,0x60f0,0x6101,0x6103,0x6110,0x6112,0x6116,0x6118,0x611d,0x611f,0x6120,0x6122,0x6123,0x6127,0x6129,0x612b,0x612c,0x612e,0x6130,0x6132,0x6132,0x6134,0x6134,0x6136,0x6137,0x613b,0x613b,0x613d,0x6142,0x6144,0x6150,0x6152,0x6156,0x6158,0x6168,0x616a,0x616c,0x616e,0x6177,0x6179,0x617a,0x617c,0x617e,0x6180,0x6183,0x6187,0x6187,0x6189,0x618e,0x6190,0x6196,0x6198,0x619d,0x619f,0x619f,0x61a1,0x61a2,0x61a4,0x61a4,0x61a7,0x61ba,0x61bc,0x61bc,0x61be,0x61c3,0x61c5,0x61cd,0x61cf,0x61d0,0x61d3,0x61d3,0x61d6,0x61d6,0x61d8,0x61d8,0x61da,0x61da,0x61de,0x61e0,0x61e2,0x61eb,0x61ed,0x61ee,0x61f0,0x61f2,0x61f5,0x6201,0x6203,0x6204,0x6207,0x620a,0x620c,0x620e,0x6210,0x6212,0x6214,0x6216,0x6219,0x621b,0x621f,0x6225,0x6227,0x6227,0x6229,0x622e,0x6230,0x6230,0x6232,0x6234,0x6236,0x6237,0x6239,0x623a,0x623d,0x6243,0x6246,0x624e,0x6250,0x6254,0x6258,0x625c,0x625e,0x625e,0x6260,0x6266,0x6268,0x6268,0x626d,0x6274,0x6276,0x6277,0x6279,0x628a,0x628c,0x628c,0x628e,0x6298,0x629d,0x629d,0x62a4,0x62a4,0x62a6,0x62a6,0x62a8,0x62b1,0x62b3,0x62b6,0x62b8,0x62b9,0x62bb,0x62bf,0x62c1,0x62dc,0x62df,0x62df,0x62e5,0x62e5,0x62eb,0x6303,0x6307,0x6309,0x630b,0x6311,0x6313,0x6316,0x6318,0x6318,0x6328,0x632f,0x6331,0x633e,0x6340,0x6351,0x6354,0x635a,0x635d,0x635d,0x6364,0x6365,0x6367,0x6369,0x636b,0x6372,0x6375,0x637d,0x637f,0x6385,0x6387,0x6392,0x6394,0x6394,0x6396,0x6399,0x639b,0x63a5,0x63a7,0x63b1,0x63b9,0x63b9,0x63bd,0x63be,0x63c0,0x63d3,0x63d5,0x63eb,0x63ed,0x63f6,0x63f8,0x63f9,0x63fb,0x63fc,0x63fe,0x63fe,0x6406,0x6407,0x6409,0x6410,0x6412,0x6418,0x641a,0x641c,0x641e,0x6428,0x642a,0x6430,0x6432,0x643b,0x643d,0x6441,0x6443,0x6443,0x644b,0x644b,0x644d,0x644e,0x6450,0x6454,0x6458,0x6461,0x6465,0x6469,0x646b,0x647d,0x647f,0x647f,0x6482,0x6482,0x6485,0x6485,0x6487,0x648d,0x648f,0x6493,0x6495,0x649a,0x649c,0x64a0,0x64a2,0x64a6,0x64a9,0x64a9,0x64ab,0x64b4,0x64b6,0x64b6,0x64bb,0x64c5,0x64c7,0x64c7,0x64c9,0x64cb,0x64cd,0x64d0,0x64d2,0x64d4,0x64d6,0x64db,0x64dd,0x64dd,0x64e0,0x64ed,0x64ef,0x64f4,0x64f7,0x64f8,0x64fa,0x6501,0x6503,0x6504,0x6506,0x6507,0x6509,0x650a,0x650c,0x6511,0x6513,0x6519,0x651b,0x6526,0x6529,0x6530,0x6532,0x6539,0x653b,0x653b,0x653d,0x653f,0x6541,0x6541,0x6543,0x6543,0x6545,0x6546,0x6548,0x654a,0x654d,0x654d,0x654f,0x654f,0x6551,0x6551,0x6553,0x655a,0x655c,0x655f,0x6562,0x6568,0x656a,0x656d,0x656f,0x656f,0x6572,0x657c,0x657f,0x6589,0x658b,0x658c,0x6590,0x6592,0x6594,0x6597,0x6599,0x6599,0x659b,0x65a2,0x65a4,0x65a5,0x65a7,0x65a8,0x65aa,0x65ac,0x65ae,0x65b0,0x65b2,0x65b3,0x65b5,0x65b9,0x65bb,0x65bf,0x65c1,0x65c6,0x65cb,0x65d4,0x65d6,0x65d7,0x65da,0x65db,0x65dd,0x65e3,0x65e5,0x65e6,0x65e8,0x65e9,0x65ec,0x65f5,0x65fa,0x65fd,0x65ff,0x6600,0x6602,0x6615,0x6618,0x6618,0x661c,0x6628,0x662b,0x662b,0x662d,0x6636,0x6639,0x663a,0x6641,0x6645,0x6647,0x664d,0x664f,0x664f,0x6651,0x6653,0x6657,0x6657,0x6659,0x6668,0x666a,0x666c,0x666e,0x6674,0x6676,0x667e,0x6680,0x6680,0x6684,0x668e,0x6690,0x6692,0x6694,0x669a,0x669d,0x669d,0x669f,0x66a2,0x66a4,0x66a4,0x66a8,0x66ab,0x66ad,0x66bb,0x66bd,0x66c0,0x66c4,0x66c4,0x66c6,0x66cf,0x66d2,0x66d2,0x66d6,0x66d6,0x66d8,0x66de,0x66e0,0x66e0,0x66e3,0x66e4,0x66e6,0x66e9,0x66eb,0x66ee,0x66f0,0x66f4,0x66f6,0x66f9,0x66fc,0x66fc,0x66fe,0x6705,0x6708,0x6710,0x6712,0x6719,0x671b,0x671b,0x671d,0x6723,0x6725,0x6728,0x672a,0x672e,0x6731,0x6731,0x6733,0x6736,0x6738,0x673f,0x6744,0x6749,0x674b,0x6751,0x6753,0x6753,0x6755,0x6757,0x6759,0x675a,0x675c,0x6762,0x6767,0x6767,0x676a,0x677f,0x6781,0x6787,0x6789,0x6789,0x678b,0x6795,0x6797,0x679a,0x679c,0x679d,0x679f,0x67a0,0x67a4,0x67a4,0x67ac,0x67ac,0x67ae,0x67bb,0x67bf,0x67c6,0x67c8,0x67d4,0x67d6,0x67df,0x67e2,0x67e7,0x67e9,0x67fa,0x67fc,0x67fc,0x67fe,0x6804,0x680d,0x680d,0x6810,0x6810,0x6812,0x6814,0x6816,0x6818,0x681a,0x6822,0x6825,0x6826,0x6828,0x682b,0x682d,0x682f,0x6831,0x683e,0x6840,0x6851,0x6853,0x6856,0x685d,0x685d,0x6865,0x6865,0x686b,0x686b,0x686d,0x686f,0x6871,0x6872,0x6874,0x6879,0x687b,0x688c,0x688f,0x6894,0x6896,0x6898,0x689b,0x689d,0x689f,0x68a4,0x68a6,0x68b6,0x68b9,0x68b9,0x68bd,0x68bd,0x68c1,0x68c1,0x68c3,0x68ce,0x68d0,0x68d8,0x68da,0x68da,0x68dc,0x68e1,0x68e3,0x68e4,0x68e6,0x68ec,0x68ee,0x68fd,0x6900,0x6915,0x6917,0x691b,0x6925,0x6925,0x692a,0x692a,0x692c,0x692c,0x692f,0x6930,0x6932,0x6939,0x693b,0x6946,0x6948,0x694c,0x694e,0x694f,0x6951,0x697b,0x6980,0x6980,0x6982,0x6983,0x6985,0x6986,0x698a,0x698a,0x698d,0x698e,0x6990,0x6991,0x6993,0x699c,0x699e,0x69b7,0x69b9,0x69b9,0x69bb,0x69c4,0x69c6,0x69c6,0x69c9,0x69d1,0x69d3,0x69d6,0x69d9,0x69d9,0x69e1,0x69e2,0x69e4,0x69e9,0x69eb,0x69ee,0x69f1,0x69f4,0x69f6,0x6a0d,0x6a0f,0x6a0f,0x6a11,0x6a11,0x6a13,0x6a21,0x6a23,0x6a23,0x6a25,0x6a29,0x6a2b,0x6a2d,0x6a32,0x6a35,0x6a38,0x6a41,0x6a43,0x6a49,0x6a4b,0x6a5b,0x6a5d,0x6a6b,0x6a6d,0x6a6d,0x6a6f,0x6a6f,0x6a71,0x6a71,0x6a74,0x6a74,0x6a76,0x6a76,0x6a7a,0x6a7a,0x6a7e,0x6a85,0x6a87,0x6a87,0x6a89,0x6a8a,0x6a8c,0x6a97,0x6a99,0x6aa8,0x6aab,0x6aaf,0x6ab1,0x6abb,0x6abd,0x6abe,0x6ac2,0x6ac3,0x6ac5,0x6acd,0x6acf,0x6ad1,0x6ad3,0x6ad4,0x6ad8,0x6ae1,0x6ae5,0x6ae5,0x6ae7,0x6ae8,0x6aea,0x6aec,0x6aee,0x6af1,0x6af3,0x6af3,0x6af6,0x6af6,0x6af8,0x6afc,0x6b00,0x6b00,0x6b02,0x6b05,0x6b08,0x6b0b,0x6b0f,0x6b13,0x6b16,0x6b1a,0x6b1d,0x6b1e,0x6b20,0x6b21,0x6b23,0x6b23,0x6b25,0x6b25,0x6b28,0x6b28,0x6b2c,0x6b2d,0x6b2f,0x6b2f,0x6b31,0x6b3f,0x6b41,0x6b43,0x6b45,0x6b4e,0x6b50,0x6b52,0x6b54,0x6b57,0x6b59,0x6b59,0x6b5b,0x6b5c,0x6b5e,0x6b67,0x6b6a,0x6b6a,0x6b6d,0x6b6d,0x6b6f,0x6b6f,0x6b72,0x6b72,0x6b74,0x6b74,0x6b76,0x6b7b,0x6b7e,0x6b84,0x6b86,0x6b86,0x6b88,0x6b8a,0x6b8c,0x6b8f,0x6b91,0x6b91,0x6b94,0x6b99,0x6b9b,0x6b9b,0x6b9e,0x6ba0,0x6ba2,0x6ba7,0x6baa,0x6bab,0x6bad,0x6bb0,0x6bb2,0x6bb3,0x6bb5,0x6bb7,0x6bba,0x6bba,0x6bbc,0x6bbd,0x6bbf,0x6bc1,0x6bc3,0x6bcd,0x6bcf,0x6bd0,0x6bd2,0x6bd4,0x6bd6,0x6bd8,0x6bda,0x6bdc,0x6bde,0x6bde,0x6be0,0x6be4,0x6be6,0x6be8,0x6bea,0x6bec,0x6bef,0x6bf0,0x6bf2,0x6bf3,0x6bf7,0x6c06,0x6c08,0x6c09,0x6c0b,0x6c0d,0x6c0f,0x6c11,0x6c13,0x6c16,0x6c18,0x6c1d,0x6c1f,0x6c21,0x6c23,0x6c28,0x6c2a,0x6c2c,0x6c2e,0x6c3b,0x6c3d,0x6c43,0x6c46,0x6c46,0x6c49,0x6c50,0x6c52,0x6c52,0x6c54,0x6c55,0x6c57,0x6c61,0x6c65,0x6c6b,0x6c6d,0x6c76,0x6c78,0x6c7b,0x6c7d,0x6c90,0x6c92,0x6c96,0x6c98,0x6c9d,0x6c9f,0x6c9f,0x6ca2,0x6ca2,0x6caa,0x6cb4,0x6cb6,0x6cc7,0x6cc9,0x6cd7,0x6cd9,0x6ce3,0x6ce5,0x6ce5,0x6ce7,0x6cf3,0x6cf5,0x6cf5,0x6cf9,0x6cf9,0x6cff,0x6d12,0x6d16,0x6d1b,0x6d1d,0x6d20,0x6d22,0x6d22,0x6d24,0x6d42,0x6d4e,0x6d4e,0x6d57,0x6d5c,0x6d5e,0x6d6a,0x6d6c,0x6d72,0x6d74,0x6d98,0x6d9a,0x6d9a,0x6da4,0x6da5,0x6daa,0x6dac,0x6dae,0x6daf,0x6db1,0x6db5,0x6db7,0x6dc0,0x6dc2,0x6dc2,0x6dc4,0x6dcd,0x6dcf,0x6de6,0x6de8,0x6df7,0x6df9,0x6dfe,0x6e00,0x6e00,0x6e02,0x6e05,0x6e0a,0x6e0a,0x6e0f,0x6e0f,0x6e15,0x6e15,0x6e18,0x6e1d,0x6e1f,0x6e36,0x6e38,0x6e41,0x6e43,0x6e47,0x6e49,0x6e4b,0x6e4d,0x6e69,0x6e6b,0x6e6b,0x6e6e,0x6e6f,0x6e71,0x6e74,0x6e76,0x6e79,0x6e7c,0x6e7c,0x6e86,0x6e86,0x6e88,0x6e89,0x6e8b,0x6e8b,0x6e8d,0x6e90,0x6e92,0x6e94,0x6e96,0x6ea7,0x6eaa,0x6eab,0x6eae,0x6ed6,0x6ed8,0x6edd,0x6ee2,0x6ee2,0x6ee8,0x6ee9,0x6eeb,0x6eef,0x6ef1,0x6ef2,0x6ef4,0x6f0f,0x6f12,0x6f1a,0x6f1c,0x6f1c,0x6f1e,0x6f27,0x6f29,0x6f41,0x6f43,0x6f44,0x6f4e,0x6f58,0x6f5a,0x6f64,0x6f66,0x6f67,0x6f69,0x6f70,0x6f72,0x6f74,0x6f76,0x6f82,0x6f84,0x6f8e,0x6f90,0x6f90,0x6f92,0x6f97,0x6f9d,0x6fb6,0x6fb8,0x6fc4,0x6fc6,0x6fcf,0x6fd3,0x6fd5,0x6fd8,0x6fe4,0x6fe6,0x6fe9,0x6feb,0x6ff2,0x6ff4,0x6ff4,0x6ff6,0x6ff8,0x6ffa,0x6ffc,0x6ffe,0x7001,0x7003,0x7007,0x7009,0x700f,0x7011,0x7011,0x7014,0x7024,0x7026,0x702c,0x702f,0x7035,0x7037,0x703c,0x703e,0x7046,0x7048,0x704d,0x7050,0x7052,0x7054,0x7058,0x705a,0x706c,0x706e,0x7071,0x7074,0x707a,0x707c,0x707f,0x7081,0x7086,0x7089,0x708b,0x708e,0x708f,0x7091,0x7096,0x7098,0x709a,0x709f,0x70a1,0x70a3,0x70a7,0x70a9,0x70a9,0x70ab,0x70b1,0x70b3,0x70b5,0x70b7,0x70be,0x70c0,0x70c0,0x70c4,0x70c8,0x70ca,0x70da,0x70dc,0x70e2,0x70e4,0x70e4,0x70ef,0x70f1,0x70f3,0x7100,0x7102,0x7102,0x7104,0x7106,0x7109,0x710e,0x7110,0x7110,0x7113,0x7113,0x7117,0x7117,0x7119,0x7123,0x7125,0x7126,0x7128,0x7129,0x712b,0x712c,0x712e,0x7136,0x713a,0x713b,0x713e,0x713e,0x7140,0x7147,0x7149,0x7154,0x7156,0x715a,0x715c,0x716c,0x716e,0x716e,0x7170,0x7178,0x717a,0x717e,0x7180,0x7182,0x7184,0x718a,0x718c,0x718c,0x718e,0x7192,0x7194,0x7194,0x7196,0x71a5,0x71a7,0x71aa,0x71ac,0x71ad,0x71af,0x71b5,0x71b7,0x71ba,0x71bc,0x71cb,0x71ce,0x71d2,0x71d4,0x71d6,0x71d8,0x71dd,0x71df,0x71e2,0x71e4,0x71e8,0x71eb,0x71ee,0x71f0,0x71f2,0x71f4,0x71f6,0x71f8,0x71f9,0x71fb,0x7203,0x7205,0x7207,0x7209,0x720a,0x720c,0x7210,0x7213,0x7217,0x7219,0x721b,0x721d,0x721f,0x7222,0x722e,0x7230,0x7230,0x7235,0x7236,0x7238,0x723b,0x723d,0x7242,0x7244,0x7244,0x7246,0x724c,0x724f,0x7250,0x7252,0x7253,0x7255,0x7263,0x7266,0x7267,0x7269,0x726a,0x726c,0x726c,0x726e,0x7270,0x7272,0x7274,0x7276,0x7279,0x727b,0x7282,0x7284,0x7289,0x728b,0x7298,0x729a,0x729b,0x729d,0x729f,0x72a1,0x72aa,0x72ac,0x72b0,0x72b2,0x72b2,0x72b4,0x72b5,0x72ba,0x72ba,0x72bd,0x72bd,0x72bf,0x72c6,0x72c9,0x72ce,0x72d0,0x72d2,0x72d4,0x72d4,0x72d6,0x72da,0x72dc,0x72dc,0x72df,0x72e4,0x72e6,0x72e6,0x72e8,0x72eb,0x72f3,0x72f4,0x72f6,0x7302,0x7304,0x7304,0x7307,0x7308,0x730a,0x730c,0x730f,0x7313,0x7316,0x7319,0x731b,0x731e,0x7322,0x7323,0x7325,0x732e,0x7330,0x733c,0x733e,0x7345,0x7348,0x734a,0x734c,0x7352,0x7357,0x735b,0x735d,0x7362,0x7365,0x736c,0x736e,0x7378,0x737a,0x738c,0x738e,0x738f,0x7392,0x7398,0x739c,0x73a2,0x73a4,0x73ad,0x73b2,0x73bc,0x73be,0x73c0,0x73c2,0x73d0,0x73d2,0x73de,0x73e0,0x73eb,0x73ed,0x73ef,0x73f3,0x740d,0x7411,0x7412,0x7414,0x7417,0x7419,0x7426,0x7428,0x743a,0x743c,0x743c,0x743f,0x7457,0x7459,0x7465,0x7467,0x7476,0x7479,0x747a,0x747c,0x7483,0x7485,0x748d,0x7490,0x7490,0x7492,0x7492,0x7494,0x7495,0x7497,0x74a1,0x74a3,0x74ab,0x74ad,0x74ad,0x74af,0x74b2,0x74b4,0x74bb,0x74bd,0x74c3,0x74c5,0x74c6,0x74c8,0x74c8,0x74ca,0x74cc,0x74cf,0x74d0,0x74d3,0x74e9,0x74ec,0x74ec,0x74ee,0x74ee,0x74f0,0x74f2,0x74f4,0x74f8,0x74fb,0x74fb,0x74fd,0x7500,0x7502,0x7505,0x7507,0x7508,0x750b,0x751a,0x751c,0x751f,0x7521,0x7522,0x7525,0x7526,0x7528,0x7535,0x7537,0x753b,0x753d,0x7540,0x7542,0x7542,0x7546,0x7548,0x754a,0x754f,0x7551,0x7551,0x7553,0x7555,0x7559,0x755d,0x755f,0x7560,0x7562,0x7567,0x756a,0x7570,0x7572,0x7572,0x7576,0x757a,0x757d,0x7580,0x7583,0x7584,0x7586,0x7587,0x758a,0x7592,0x7594,0x7595,0x7598,0x759a,0x759d,0x759e,0x75a2,0x75a5,0x75a7,0x75a7,0x75aa,0x75ab,0x75b0,0x75b6,0x75b8,0x75c5,0x75c7,0x75c8,0x75ca,0x75d2,0x75d4,0x75d5,0x75d7,0x75e4,0x75e6,0x75e7,0x75ed,0x75ed,0x75ef,0x7603,0x7607,0x760d,0x760f,0x7611,0x7613,0x7616,0x7619,0x7629,0x762c,0x762d,0x762f,0x7635,0x7638,0x7638,0x763a,0x763d,0x7640,0x7640,0x7642,0x7643,0x7646,0x7649,0x764c,0x7654,0x7656,0x765a,0x765c,0x765c,0x765f,0x7662,0x7664,0x7667,0x7669,0x766a,0x766c,0x7676,0x7678,0x767f,0x7681,0x7682,0x7684,0x7684,0x7686,0x768b,0x768e,0x7690,0x7692,0x7693,0x7695,0x7696,0x7699,0x769e,0x76a1,0x76a1,0x76a4,0x76a6,0x76aa,0x76ab,0x76ad,0x76b0,0x76b4,0x76b5,0x76b7,0x76b8,0x76ba,0x76bb,0x76bd,0x76bf,0x76c2,0x76c6,0x76c8,0x76ca,0x76cc,0x76ce,0x76d2,0x76d4,0x76d6,0x76d6,0x76d9,0x76df,0x76e1,0x76e1,0x76e3,0x76e7,0x76e9,0x76ea,0x76ec,0x76f5,0x76f7,0x76fc,0x76fe,0x76fe,0x7701,0x7701,0x7703,0x7705,0x7707,0x770c,0x770e,0x7713,0x7715,0x7715,0x7719,0x771b,0x771d,0x7720,0x7722,0x7729,0x772b,0x772b,0x772d,0x772d,0x772f,0x772f,0x7731,0x773e,0x7740,0x7740,0x7743,0x7747,0x774a,0x774f,0x7752,0x7752,0x7754,0x7756,0x7758,0x775c,0x775e,0x7763,0x7765,0x776f,0x7772,0x7772,0x7777,0x7785,0x7787,0x7789,0x778b,0x778f,0x7791,0x7791,0x7793,0x7793,0x7795,0x7795,0x7797,0x77a3,0x77a5,0x77a5,0x77a7,0x77a8,0x77aa,0x77ad,0x77af,0x77b7,0x77b9,0x77bf,0x77c2,0x77c5,0x77c7,0x77c7,0x77c9,0x77d0,0x77d3,0x77d5,0x77d7,0x77de,0x77e0,0x77e0,0x77e2,0x77e3,0x77e5,0x77e9,0x77ec,0x77f4,0x77f7,0x77fe,0x7802,0x7803,0x7805,0x7806,0x7808,0x7809,0x780c,0x7814,0x7818,0x7818,0x781c,0x7823,0x7825,0x7835,0x7837,0x7839,0x783c,0x783d,0x7842,0x7845,0x7847,0x784e,0x7850,0x7854,0x785c,0x785e,0x7860,0x7860,0x7862,0x7862,0x7864,0x7866,0x7868,0x7871,0x7879,0x787c,0x787e,0x7881,0x7883,0x7889,0x788c,0x788f,0x7891,0x7891,0x7893,0x789a,0x789e,0x78a5,0x78a7,0x78ad,0x78af,0x78b4,0x78b6,0x78b6,0x78b8,0x78bc,0x78be,0x78be,0x78c1,0x78c1,0x78c3,0x78c5,0x78c7,0x78d5,0x78d7,0x78d8,0x78da,0x78db,0x78dd,0x78e5,0x78e7,0x78ea,0x78ec,0x78f5,0x78f7,0x78f7,0x78f9,0x78ff,0x7901,0x7902,0x7904,0x7906,0x7909,0x7909,0x790c,0x790c,0x790e,0x790e,0x7910,0x7914,0x7917,0x7917,0x7919,0x7919,0x791b,0x791e,0x7921,0x7921,0x7923,0x792f,0x7931,0x7936,0x7938,0x7942,0x7944,0x794c,0x794f,0x7965,0x7967,0x796b,0x796d,0x796d,0x7970,0x7974,0x7979,0x797a,0x797c,0x7983,0x7986,0x7988,0x798a,0x798b,0x798d,0x799d,0x799f,0x79a2,0x79a4,0x79ae,0x79b0,0x79b4,0x79b6,0x79bb,0x79bd,0x79c1,0x79c4,0x79c6,0x79c8,0x79d2,0x79d4,0x79d6,0x79d8,0x79d8,0x79dc,0x79e0,0x79e2,0x79e4,0x79e6,0x79e7,0x79e9,0x79ee,0x79f1,0x79f1,0x79f4,0x79f4,0x79f6,0x79f8,0x79fa,0x79fb,0x7a00,0x7a00,0x7a02,0x7a06,0x7a08,0x7a08,0x7a0a,0x7a0e,0x7a10,0x7a15,0x7a17,0x7a1c,0x7a1e,0x7a20,0x7a22,0x7a22,0x7a26,0x7a26,0x7a28,0x7a28,0x7a2a,0x7a32,0x7a37,0x7a37,0x7a39,0x7a40,0x7a43,0x7a4e,0x7a54,0x7a54,0x7a56,0x7a58,0x7a5a,0x7a5c,0x7a5f,0x7a62,0x7a65,0x7a65,0x7a67,0x7a69,0x7a6b,0x7a6e,0x7a70,0x7a72,0x7a74,0x7a76,0x7a78,0x7a7b,0x7a7d,0x7a81,0x7a83,0x7a8c,0x7a8f,0x7a99,0x7a9e,0x7aa0,0x7aa2,0x7aa3,0x7aa8,0x7aac,0x7aae,0x7ab8,0x7aba,0x7abc,0x7abe,0x7ac5,0x7ac7,0x7acb,0x7acf,0x7acf,0x7ad1,0x7ad1,0x7ad3,0x7ad3,0x7ad8,0x7add,0x7adf,0x7ae0,0x7ae2,0x7ae7,0x7ae9,0x7aeb,0x7aed,0x7aef,0x7af6,0x7af7,0x7af9,0x7b01,0x7b04,0x7b06,0x7b08,0x7b0c,0x7b0e,0x7b14,0x7b18,0x7b1b,0x7b1d,0x7b20,0x7b22,0x7b35,0x7b38,0x7b39,0x7b3b,0x7b3b,0x7b40,0x7b40,0x7b42,0x7b52,0x7b54,0x7b56,0x7b58,0x7b58,0x7b60,0x7b67,0x7b69,0x7b69,0x7b6c,0x7b78,0x7b7b,0x7b7b,0x7b82,0x7b82,0x7b84,0x7b85,0x7b87,0x7b88,0x7b8a,0x7b92,0x7b94,0x7b9d,0x7ba0,0x7ba4,0x7bac,0x7baf,0x7bb1,0x7bb2,0x7bb4,0x7bb5,0x7bb7,0x7bb9,0x7bbe,0x7bbe,0x7bc0,0x7bc1,0x7bc4,0x7bc7,0x7bc9,0x7bcc,0x7bce,0x7bd0,0x7bd4,0x7bd5,0x7bd8,0x7bec,0x7bf0,0x7bf4,0x7bf7,0x7c03,0x7c05,0x7c07,0x7c09,0x7c12,0x7c15,0x7c15,0x7c19,0x7c19,0x7c1b,0x7c23,0x7c25,0x7c2d,0x7c30,0x7c30,0x7c33,0x7c33,0x7c35,0x7c35,0x7c37,0x7c39,0x7c3b,0x7c40,0x7c42,0x7c45,0x7c47,0x7c4a,0x7c4c,0x7c4d,0x7c50,0x7c51,0x7c53,0x7c54,0x7c56,0x7c57,0x7c59,0x7c5d,0x7c5f,0x7c60,0x7c63,0x7c67,0x7c69,0x7c70,0x7c72,0x7c75,0x7c78,0x7c81,0x7c83,0x7c86,0x7c88,0x7c8a,0x7c8c,0x7c8e,0x7c91,0x7c92,0x7c94,0x7c98,0x7c9c,0x7c9c,0x7c9e,0x7c9f,0x7ca1,0x7ca3,0x7ca5,0x7ca8,0x7cac,0x7cac,0x7cae,0x7caf,0x7cb1,0x7cb5,0x7cb8,0x7cbf,0x7cc2,0x7cc3,0x7cc5,0x7cc5,0x7cc7,0x7cce,0x7cd0,0x7cd7,0x7cd9,0x7cda,0x7cdc,0x7ce0,0x7ce2,0x7ce2,0x7ce6,0x7ce8,0x7cea,0x7cea,0x7cec,0x7cf9,0x7cfb,0x7cfe,0x7d00,0x7d22,0x7d25,0x7d25,0x7d28,0x7d29,0x7d2b,0x7d2c,0x7d2e,0x7d33,0x7d35,0x7d36,0x7d38,0x7d47,0x7d4a,0x7d4a,0x7d4d,0x7d56,0x7d58,0x7d58,0x7d5a,0x7d5f,0x7d61,0x7d63,0x7d66,0x7d6b,0x7d6d,0x7d73,0x7d79,0x7d7d,0x7d7f,0x7d81,0x7d83,0x7d86,0x7d88,0x7d89,0x7d8b,0x7d8f,0x7d91,0x7d97,0x7d9c,0x7da4,0x7da6,0x7db5,0x7db7,0x7dc2,0x7dc4,0x7dc7,0x7dc9,0x7dd0,0x7dd2,0x7dd4,0x7dd7,0x7de1,0x7de3,0x7dea,0x7dec,0x7dec,0x7dee,0x7df7,0x7df9,0x7dfe,0x7e03,0x7e03,0x7e07,0x7e17,0x7e1a,0x7e25,0x7e27,0x7e27,0x7e29,0x7e2b,0x7e2d,0x7e49,0x7e4c,0x7e4c,0x7e50,0x7e5c,0x7e5e,0x7e63,0x7e65,0x7e65,0x7e67,0x7e70,0x7e72,0x7e82,0x7e86,0x7e88,0x7e8a,0x7e8f,0x7e91,0x7e9c,0x7e9f,0x7e9f,0x7ea4,0x7ea4,0x7eac,0x7eac,0x7eba,0x7eba,0x7ec7,0x7ec7,0x7ecf,0x7ecf,0x7edf,0x7edf,0x7f06,0x7f06,0x7f36,0x7f3a,0x7f3d,0x7f41,0x7f43,0x7f45,0x7f47,0x7f55,0x7f58,0x7f58,0x7f5b,0x7f61,0x7f63,0x7f63,0x7f65,0x7f6e,0x7f70,0x7f73,0x7f75,0x7f7f,0x7f83,0x7f83,0x7f85,0x7f8f,0x7f91,0x7f97,0x7f9a,0x7f9e,0x7fa0,0x7fa9,0x7fac,0x7fc3,0x7fc5,0x7fc5,0x7fc7,0x7fc7,0x7fc9,0x7fd2,0x7fd4,0x7fd5,0x7fd7,0x7fd7,0x7fdb,0x7fe3,0x7fe5,0x7ff5,0x7ff7,0x8008,0x800b,0x8012,0x8014,0x8019,0x801b,0x8021,0x8024,0x8026,0x8028,0x802a,0x802c,0x802c,0x802e,0x8031,0x8033,0x8037,0x8039,0x8039,0x803b,0x803f,0x8043,0x8043,0x8046,0x8048,0x804a,0x804a,0x804f,0x8052,0x8054,0x8054,0x8056,0x8056,0x8058,0x8058,0x805a,0x805e,0x8061,0x8064,0x8066,0x8067,0x806c,0x806c,0x806f,0x8073,0x8075,0x8079,0x807d,0x8080,0x8082,0x8082,0x8084,0x8087,0x8089,0x808c,0x808f,0x8090,0x8092,0x8093,0x8095,0x8096,0x8098,0x809d,0x809f,0x809f,0x80a1,0x80a3,0x80a5,0x80a5,0x80a7,0x80a7,0x80a9,0x80ab,0x80ad,0x80af,0x80b1,0x80b2,0x80b4,0x80b8,0x80ba,0x80ba,0x80bc,0x80bd,0x80c2,0x80ca,0x80cc,0x80d1,0x80d4,0x80de,0x80e0,0x80e1,0x80e3,0x80e6,0x80e9,0x80e9,0x80ec,0x80ed,0x80ef,0x80f6,0x80f8,0x80fe,0x8100,0x8103,0x8105,0x810a,0x810c,0x810c,0x810e,0x810e,0x8112,0x8112,0x8114,0x811b,0x811d,0x811f,0x8121,0x8125,0x8127,0x8127,0x8129,0x812d,0x812f,0x8132,0x8134,0x8134,0x8137,0x8137,0x8139,0x813a,0x813d,0x813e,0x8142,0x8144,0x8146,0x8148,0x814a,0x8156,0x8159,0x815c,0x815e,0x815e,0x8160,0x8162,0x8164,0x8167,0x8169,0x8169,0x816b,0x8174,0x8176,0x817a,0x817c,0x817d,0x817f,0x8180,0x8182,0x8184,0x8186,0x818d,0x818f,0x818f,0x8193,0x8193,0x8195,0x8195,0x8197,0x81a0,0x81a2,0x81a3,0x81a5,0x81ac,0x81ae,0x81ae,0x81b0,0x81b7,0x81b9,0x81ca,0x81cc,0x81cd,0x81cf,0x81d2,0x81d5,0x81d5,0x81d7,0x81db,0x81dd,0x81ea,0x81ec,0x81ef,0x81f2,0x81f4,0x81f6,0x81fc,0x81fe,0x8202,0x8204,0x8205,0x8207,0x820d,0x8210,0x8212,0x8214,0x8216,0x8218,0x8218,0x821a,0x8222,0x8225,0x8226,0x8228,0x822d,0x822f,0x822f,0x8232,0x823a,0x823c,0x8240,0x8242,0x8242,0x8244,0x8245,0x8247,0x8247,0x8249,0x8249,0x824b,0x824b,0x824e,0x825c,0x825e,0x825f,0x8261,0x8266,0x8268,0x8269,0x826b,0x826f,0x8271,0x8272,0x8274,0x8280,0x8283,0x8285,0x8287,0x8287,0x828a,0x828b,0x828d,0x8294,0x8298,0x829b,0x829d,0x82b1,0x82b3,0x82c0,0x82c2,0x82c4,0x82ca,0x82ca,0x82cf,0x82d9,0x82db,0x82dc,0x82de,0x82e8,0x82ea,0x8309,0x830b,0x830d,0x8316,0x831e,0x8320,0x8320,0x8322,0x8322,0x8324,0x832d,0x832f,0x832f,0x8331,0x833d,0x833f,0x8345,0x8347,0x8354,0x8356,0x8357,0x8362,0x8363,0x8366,0x8366,0x836f,0x836f,0x8373,0x8378,0x837a,0x837f,0x8381,0x8381,0x8383,0x8383,0x8385,0x839e,0x83a0,0x83a0,0x83a2,0x83ac,0x83ae,0x83b0,0x83b9,0x83b9,0x83bd,0x83cf,0x83d1,0x83d1,0x83d3,0x83d9,0x83db,0x83e5,0x83e7,0x83f6,0x83f8,0x83ff,0x8401,0x8401,0x8403,0x8407,0x8409,0x8414,0x8416,0x8416,0x8418,0x8418,0x841b,0x841c,0x8420,0x8421,0x8423,0x8424,0x8426,0x8426,0x8429,0x8429,0x842b,0x8440,0x8442,0x844e,0x8450,0x8469,0x846b,0x847a,0x847d,0x8480,0x8482,0x8482,0x8484,0x8484,0x8486,0x8486,0x8488,0x8488,0x848d,0x8494,0x8496,0x84a4,0x84a7,0x84b2,0x84b4,0x84b4,0x84b6,0x84b6,0x84b8,0x84c2,0x84c4,0x84c7,0x84c9,0x84d4,0x84d6,0x84d7,0x84da,0x84db,0x84de,0x84de,0x84e1,0x84e2,0x84e4,0x84e5,0x84e7,0x84ec,0x84ee,0x84f4,0x84f6,0x8500,0x8502,0x851a,0x851c,0x8521,0x8523,0x8531,0x8533,0x8534,0x8538,0x8538,0x853b,0x853b,0x853d,0x853e,0x8540,0x854e,0x8551,0x855b,0x855d,0x8571,0x8573,0x8573,0x8575,0x857c,0x857e,0x857e,0x8580,0x8591,0x8593,0x85a4,0x85a6,0x85aa,0x85af,0x85b1,0x85b3,0x85ba,0x85bd,0x85c9,0x85cb,0x85cb,0x85cd,0x85d2,0x85d5,0x85da,0x85dc,0x85e6,0x85e8,0x85f2,0x85f4,0x85f4,0x85f6,0x8602,0x8604,0x8607,0x8609,0x860d,0x860f,0x8611,0x8613,0x8614,0x8616,0x861c,0x861e,0x862a,0x862c,0x862f,0x8631,0x8636,0x8638,0x863c,0x863e,0x8640,0x8642,0x8643,0x8645,0x8648,0x864b,0x864e,0x8650,0x8650,0x8652,0x8656,0x8659,0x8659,0x865b,0x865c,0x865e,0x865f,0x8661,0x8665,0x8667,0x8674,0x8677,0x8677,0x8679,0x867c,0x867e,0x867e,0x8685,0x8687,0x868a,0x868e,0x8690,0x869a,0x869c,0x869e,0x86a0,0x86a5,0x86a7,0x86aa,0x86ad,0x86ad,0x86af,0x86c9,0x86cb,0x86cc,0x86d0,0x86d1,0x86d3,0x86d4,0x86d6,0x86df,0x86e2,0x86e4,0x86e6,0x86e6,0x86e8,0x86ed,0x86ef,0x86ef,0x86f5,0x86fb,0x86fe,0x86fe,0x8700,0x870e,0x8711,0x8713,0x8715,0x8715,0x8718,0x871c,0x871e,0x871e,0x8720,0x872a,0x872c,0x872e,0x8730,0x8735,0x8737,0x8738,0x873a,0x873c,0x873e,0x8743,0x8746,0x8746,0x874c,0x8771,0x8773,0x877b,0x877d,0x877d,0x8781,0x8789,0x878b,0x878d,0x878f,0x8794,0x8796,0x8798,0x879a,0x879f,0x87a2,0x87a5,0x87a9,0x87c6,0x87c8,0x87cc,0x87ce,0x87ce,0x87d1,0x87d4,0x87d6,0x87e8,0x87ea,0x87ef,0x87f2,0x87f7,0x87f9,0x87fc,0x87fe,0x8806,0x8808,0x880d,0x880f,0x8811,0x8813,0x8819,0x881b,0x881d,0x881f,0x8833,0x8835,0x8839,0x883b,0x8846,0x8848,0x8848,0x884a,0x884f,0x8852,0x8853,0x8855,0x8857,0x8859,0x885b,0x885d,0x885e,0x8860,0x8865,0x8867,0x886b,0x886d,0x8872,0x8874,0x8877,0x8879,0x8879,0x887c,0x8884,0x8887,0x8889,0x888b,0x8893,0x8895,0x88a2,0x88a4,0x88a4,0x88a7,0x88a8,0x88aa,0x88ac,0x88ae,0x88ae,0x88b1,0x88b2,0x88b4,0x88ba,0x88bc,0x88c2,0x88c5,0x88c5,0x88c7,0x88c7,0x88c9,0x88d0,0x88d2,0x88d2,0x88d4,0x88df,0x88e1,0x88e1,0x88e6,0x88e8,0x88eb,0x88ec,0x88ee,0x8902,0x8905,0x8907,0x8909,0x890c,0x890e,0x890e,0x8910,0x891a,0x891e,0x891f,0x8921,0x8927,0x8929,0x8933,0x8935,0x8938,0x893b,0x893e,0x8941,0x8944,0x8946,0x8947,0x8949,0x8949,0x894b,0x894d,0x894f,0x8954,0x8956,0x8966,0x8969,0x896f,0x8971,0x8974,0x8976,0x8977,0x8979,0x897c,0x897e,0x8983,0x8985,0x898b,0x898f,0x898f,0x8991,0x8991,0x8993,0x8998,0x899b,0x899f,0x89a1,0x89a7,0x89a9,0x89aa,0x89ac,0x89af,0x89b2,0x89b2,0x89b6,0x89b7,0x89b9,0x89ba,0x89bc,0x89c1,0x89c6,0x89c6,0x89d2,0x89d6,0x89d9,0x89dd,0x89df,0x89e9,0x89eb,0x89ed,0x89f0,0x89f4,0x89f6,0x89f8,0x89fa,0x89fc,0x89fe,0x8a00,0x8a02,0x8a04,0x8a07,0x8a08,0x8a0a,0x8a0a,0x8a0c,0x8a0c,0x8a0e,0x8a13,0x8a15,0x8a18,0x8a1b,0x8a1f,0x8a22,0x8a23,0x8a25,0x8a25,0x8a27,0x8a27,0x8a29,0x8a2d,0x8a30,0x8a31,0x8a34,0x8a34,0x8a36,0x8a36,0x8a38,0x8a41,0x8a44,0x8a46,0x8a48,0x8a4a,0x8a4c,0x8a52,0x8a54,0x8a59,0x8a5b,0x8a5b,0x8a5e,0x8a5e,0x8a60,0x8a63,0x8a66,0x8a69,0x8a6b,0x8a6e,0x8a70,0x8a77,0x8a79,0x8a7c,0x8a7e,0x8a7f,0x8a81,0x8a87,0x8a8b,0x8a8d,0x8a8f,0x8a96,0x8a98,0x8a9a,0x8a9c,0x8a9c,0x8a9e,0x8a9e,0x8aa0,0x8aa1,0x8aa3,0x8aac,0x8aaf,0x8ab0,0x8ab2,0x8ab2,0x8ab4,0x8ab4,0x8ab6,0x8ab6,0x8ab8,0x8ac0,0x8ac2,0x8ac9,0x8acb,0x8acd,0x8acf,0x8acf,0x8ad1,0x8ae2,0x8ae4,0x8ae4,0x8ae6,0x8ae8,0x8aea,0x8aeb,0x8aed,0x8afc,0x8afe,0x8b02,0x8b04,0x8b08,0x8b0a,0x8b20,0x8b22,0x8b28,0x8b2a,0x8b31,0x8b33,0x8b33,0x8b35,0x8b37,0x8b39,0x8b43,0x8b45,0x8b5a,0x8b5c,0x8b60,0x8b62,0x8b63,0x8b65,0x8b6d,0x8b6f,0x8b70,0x8b74,0x8b74,0x8b77,0x8b7b,0x8b7d,0x8b86,0x8b88,0x8b88,0x8b8a,0x8b8c,0x8b8e,0x8b90,0x8b92,0x8b96,0x8b98,0x8b9c,0x8b9e,0x8ba0,0x8bbe,0x8bbe,0x8be2,0x8be2,0x8c37,0x8c37,0x8c39,0x8c39,0x8c3b,0x8c3f,0x8c41,0x8c43,0x8c45,0x8c51,0x8c54,0x8c57,0x8c5a,0x8c5a,0x8c5c,0x8c5d,0x8c5f,0x8c5f,0x8c61,0x8c62,0x8c64,0x8c66,0x8c68,0x8c6d,0x8c6f,0x8c73,0x8c75,0x8c7b,0x8c7d,0x8c7d,0x8c80,0x8c82,0x8c84,0x8c86,0x8c89,0x8c8a,0x8c8c,0x8c8d,0x8c8f,0x8c95,0x8c97,0x8ca5,0x8ca7,0x8cad,0x8caf,0x8cb0,0x8cb2,0x8cc5,0x8cc7,0x8cc8,0x8cca,0x8cca,0x8ccc,0x8ccd,0x8ccf,0x8ccf,0x8cd1,0x8cd7,0x8cd9,0x8cee,0x8cf0,0x8cf5,0x8cf7,0x8cfe,0x8d00,0x8d00,0x8d02,0x8d0d,0x8d0f,0x8d19,0x8d1b,0x8d1d,0x8d64,0x8d64,0x8d66,0x8d69,0x8d6b,0x8d70,0x8d72,0x8d74,0x8d76,0x8d7b,0x8d7d,0x8d7d,0x8d80,0x8d82,0x8d84,0x8d85,0x8d89,0x8d8a,0x8d8c,0x8d96,0x8d99,0x8d99,0x8d9b,0x8d9c,0x8d9f,0x8da1,0x8da3,0x8da3,0x8da5,0x8daf,0x8db2,0x8db7,0x8db9,0x8dba,0x8dbc,0x8dbc,0x8dbe,0x8dc3,0x8dc5,0x8dc8,0x8dcb,0x8dd1,0x8dd3,0x8ddd,0x8ddf,0x8de4,0x8de6,0x8dec,0x8dee,0x8df4,0x8dfa,0x8dfa,0x8dfc,0x8e07,0x8e09,0x8e0a,0x8e0d,0x8e2b,0x8e2d,0x8e2e,0x8e30,0x8e31,0x8e33,0x8e36,0x8e38,0x8e3a,0x8e3c,0x8e42,0x8e44,0x8e50,0x8e53,0x8e57,0x8e59,0x8e6a,0x8e6c,0x8e6d,0x8e6f,0x8e6f,0x8e71,0x8e78,0x8e7a,0x8e7c,0x8e7e,0x8e7e,0x8e80,0x8e82,0x8e84,0x8e8e,0x8e90,0x8e98,0x8e9a,0x8e9a,0x8e9d,0x8ea1,0x8ea3,0x8ead,0x8eb0,0x8eb0,0x8eb2,0x8eb2,0x8eb6,0x8eb6,0x8eb9,0x8eba,0x8ebc,0x8ebd,0x8ec0,0x8ec0,0x8ec2,0x8ec3,0x8ec9,0x8ecf,0x8ed1,0x8ed4,0x8ed7,0x8ed8,0x8eda,0x8ee2,0x8ee4,0x8ee9,0x8eeb,0x8eef,0x8ef1,0x8ef2,0x8ef4,0x8efc,0x8efe,0x8f03,0x8f05,0x8f0b,0x8f0d,0x8f0e,0x8f10,0x8f20,0x8f23,0x8f26,0x8f29,0x8f2a,0x8f2c,0x8f30,0x8f32,0x8f39,0x8f3b,0x8f3c,0x8f3e,0x8f4b,0x8f4d,0x8f64,0x8f66,0x8f67,0x8f6e,0x8f6e,0x8f93,0x8f93,0x8f9b,0x8f9c,0x8f9f,0x8fa0,0x8fa3,0x8fa3,0x8fa5,0x8fa8,0x8fad,0x8fbc,0x8fbe,0x8fbf,0x8fc1,0x8fc2,0x8fc4,0x8fc6,0x8fc9,0x8fd7,0x8fda,0x8fda,0x8fe0,0x8fe6,0x8fe8,0x8fe8,0x8fea,0x8feb,0x8fed,0x8fee,0x8ff0,0x8ff0,0x8ff4,0x9006,0x9008,0x9008,0x900b,0x900d,0x900f,0x9012,0x9014,0x9017,0x9019,0x9024,0x902d,0x902f,0x9031,0x9038,0x903c,0x903f,0x9041,0x9042,0x9044,0x9044,0x9046,0x9047,0x9049,0x9056,0x9058,0x9059,0x905b,0x905e,0x9060,0x9064,0x9067,0x9069,0x906b,0x9070,0x9072,0x9088,0x908a,0x908b,0x908d,0x908d,0x908f,0x9091,0x9094,0x9095,0x9097,0x9099,0x909b,0x909b,0x909e,0x90a3,0x90a5,0x90a8,0x90aa,0x90aa,0x90ae,0x90b6,0x90b8,0x90b8,0x90bb,0x90bb,0x90bd,0x90bf,0x90c1,0x90c1,0x90c3,0x90c5,0x90c7,0x90c8,0x90ca,0x90cb,0x90ce,0x90ce,0x90d4,0x90dd,0x90df,0x90e5,0x90e8,0x90ed,0x90ef,0x90f5,0x90f9,0x9109,0x910b,0x910b,0x910d,0x9112,0x9114,0x9114,0x9116,0x9124,0x9126,0x9136,0x9138,0x913b,0x913e,0x9141,0x9143,0x9153,0x9155,0x915a,0x915c,0x915c,0x915e,0x9165,0x9167,0x916a,0x916c,0x916c,0x916e,0x9170,0x9172,0x917a,0x917c,0x917c,0x9180,0x9187,0x9189,0x9193,0x9196,0x9196,0x9199,0x91a3,0x91a5,0x91a5,0x91a7,0x91b7,0x91b9,0x91be,0x91c0,0x91c7,0x91c9,0x91c9,0x91cb,0x91d1,0x91d3,0x91da,0x91dc,0x91dd,0x91df,0x91df,0x91e2,0x91ee,0x91f1,0x91f1,0x91f3,0x91fa,0x91fd,0x920a,0x920c,0x921a,0x921c,0x921c,0x921e,0x921e,0x9221,0x9221,0x9223,0x9228,0x922a,0x922b,0x922d,0x922e,0x9230,0x923a,0x923c,0x9241,0x9244,0x9246,0x9248,0x9258,0x925a,0x925b,0x925d,0x9267,0x926b,0x9270,0x9272,0x9272,0x9276,0x928f,0x9291,0x9291,0x9293,0x929d,0x92a0,0x92ac,0x92ae,0x92ae,0x92b1,0x92b7,0x92b9,0x92bc,0x92be,0x92d5,0x92d7,0x92d9,0x92db,0x92db,0x92dd,0x92e1,0x92e3,0x92f4,0x92f6,0x9304,0x9306,0x9309,0x930b,0x9310,0x9312,0x9316,0x9318,0x931b,0x931d,0x9331,0x9333,0x9336,0x9338,0x9339,0x933c,0x933c,0x9340,0x9352,0x9354,0x935c,0x935e,0x936e,0x9370,0x9371,0x9373,0x937e,0x9380,0x938a,0x938c,0x9392,0x9394,0x93aa,0x93ac,0x93b5,0x93b7,0x93b8,0x93bb,0x93bb,0x93bd,0x93bd,0x93bf,0x93c0,0x93c2,0x93c4,0x93c6,0x93c8,0x93ca,0x93e4,0x93e6,0x93e8,0x93ec,0x93ec,0x93ee,0x93ee,0x93f0,0x93f1,0x93f3,0x9401,0x9403,0x9404,0x9406,0x9419,0x941b,0x941b,0x941d,0x941d,0x9420,0x9420,0x9424,0x9433,0x9435,0x9440,0x9442,0x944d,0x944f,0x9452,0x9454,0x9455,0x9457,0x9458,0x945b,0x945b,0x945d,0x945e,0x9460,0x9460,0x9462,0x9465,0x9467,0x9479,0x947b,0x9483,0x9485,0x9485,0x949f,0x949f,0x94a2,0x94a2,0x94c1,0x94c1,0x94c3,0x94c3,0x94dc,0x94dc,0x94f6,0x94f6,0x952d,0x952d,0x9547,0x9547,0x9577,0x9578,0x957a,0x957d,0x957f,0x9580,0x9582,0x9583,0x9585,0x9586,0x9588,0x9589,0x958b,0x9594,0x9596,0x9599,0x959b,0x959c,0x959e,0x95ae,0x95b0,0x95b2,0x95b5,0x95b7,0x95b9,0x95c0,0x95c3,0x95c3,0x95c5,0x95cd,0x95d0,0x95d6,0x95da,0x95dc,0x95de,0x95e5,0x95e8,0x95e8,0x95f4,0x95f4,0x961c,0x961e,0x9620,0x9624,0x9628,0x9628,0x962a,0x962a,0x962c,0x9633,0x9638,0x963d,0x963f,0x9645,0x964a,0x9651,0x9653,0x9654,0x9656,0x9656,0x9658,0x9658,0x965b,0x965f,0x9661,0x9664,0x9669,0x966d,0x966f,0x9678,0x967b,0x967e,0x9680,0x9681,0x9683,0x968b,0x968d,0x968f,0x9691,0x9699,0x969b,0x969c,0x969e,0x969e,0x96a1,0x96a5,0x96a7,0x96aa,0x96ac,0x96ac,0x96ae,0x96ae,0x96b0,0x96b1,0x96b3,0x96b4,0x96b6,0x96b6,0x96b8,0x96b9,0x96bb,0x96bd,0x96bf,0x96ce,0x96d2,0x96df,0x96e1,0x96e3,0x96e5,0x96e5,0x96e8,0x96ea,0x96ef,0x96f2,0x96f4,0x96fb,0x96fd,0x96fd,0x96ff,0x9700,0x9702,0x9709,0x970b,0x970b,0x970d,0x9713,0x9716,0x9716,0x9718,0x9719,0x971b,0x972c,0x972e,0x9732,0x9734,0x9736,0x9738,0x973a,0x973d,0x9744,0x9746,0x974b,0x9751,0x9752,0x9755,0x9758,0x975a,0x9762,0x9766,0x9766,0x9768,0x976a,0x976c,0x976e,0x9770,0x9774,0x9776,0x9778,0x977a,0x9785,0x9787,0x978b,0x978d,0x978f,0x9794,0x9794,0x9797,0x97a6,0x97a8,0x97a8,0x97aa,0x97ae,0x97b1,0x97b4,0x97b6,0x97bb,0x97bd,0x97c9,0x97cb,0x97d0,0x97d2,0x97d9,0x97dc,0x97e1,0x97e3,0x97e3,0x97e5,0x97e6,0x97ed,0x97ee,0x97f0,0x97f3,0x97f5,0x97f6,0x97f8,0x97fb,0x97fd,0x9808,0x980a,0x980a,0x980c,0x9818,0x981b,0x9821,0x9823,0x9824,0x9826,0x9829,0x982b,0x982b,0x982d,0x9830,0x9832,0x9835,0x9837,0x9839,0x983b,0x983b,0x9841,0x9841,0x9843,0x9853,0x9856,0x9859,0x985b,0x9860,0x9862,0x986c,0x986f,0x9875,0x98a8,0x98a9,0x98ac,0x98af,0x98b1,0x98b4,0x98b6,0x98c4,0x98c6,0x98cc,0x98ce,0x98ce,0x98db,0x98dc,0x98de,0x98e3,0x98e5,0x98e7,0x98e9,0x98ed,0x98ef,0x98ef,0x98f1,0x98f2,0x98f4,0x98f6,0x98f9,0x98fa,0x98fc,0x98fe,0x9900,0x9900,0x9902,0x9903,0x9905,0x9905,0x9907,0x990a,0x990c,0x990c,0x990e,0x990e,0x9910,0x991c,0x991e,0x991f,0x9921,0x9921,0x9924,0x9925,0x9927,0x9933,0x9935,0x9935,0x9937,0x9943,0x9945,0x9945,0x9947,0x994e,0x9950,0x9959,0x995b,0x995f,0x9961,0x9963,0x9996,0x9999,0x999b,0x999e,0x99a1,0x99a1,0x99a3,0x99a8,0x99aa,0x99b5,0x99b8,0x99bd,0x99c1,0x99c5,0x99c7,0x99c7,0x99c9,0x99c9,0x99cb,0x99dd,0x99df,0x99e7,0x99e9,0x99ea,0x99ec,0x99ee,0x99f0,0x99f1,0x99f4,0x99ff,0x9a01,0x9a07,0x9a09,0x9a11,0x9a14,0x9a16,0x9a19,0x9a27,0x9a29,0x9a32,0x9a34,0x9a46,0x9a48,0x9a4a,0x9a4c,0x9a50,0x9a52,0x9a5c,0x9a5e,0x9a60,0x9a62,0x9a6c,0x9a8f,0x9a8f,0x9aa8,0x9aa8,0x9aab,0x9aab,0x9aad,0x9aad,0x9aaf,0x9ab4,0x9ab6,0x9ac2,0x9ac6,0x9ac7,0x9aca,0x9aca,0x9acd,0x9acd,0x9acf,0x9ad8,0x9adc,0x9adc,0x9adf,0x9ae3,0x9ae6,0x9ae7,0x9aeb,0x9aef,0x9af1,0x9af4,0x9af6,0x9af7,0x9af9,0x9aff,0x9b01,0x9b06,0x9b08,0x9b12,0x9b14,0x9b1a,0x9b1e,0x9b20,0x9b22,0x9b25,0x9b27,0x9b2b,0x9b2d,0x9b2f,0x9b31,0x9b35,0x9b37,0x9b37,0x9b39,0x9b3c,0x9b3e,0x9b46,0x9b48,0x9b48,0x9b4a,0x9b52,0x9b54,0x9b56,0x9b58,0x9b5b,0x9b5f,0x9b61,0x9b64,0x9b64,0x9b66,0x9b69,0x9b6c,0x9b6c,0x9b6f,0x9b71,0x9b74,0x9b77,0x9b7a,0x9b83,0x9b85,0x9b88,0x9b8b,0x9b8b,0x9b8d,0x9b93,0x9b95,0x9b95,0x9b97,0x9b97,0x9b9a,0x9b9b,0x9b9d,0x9ba2,0x9ba4,0x9ba6,0x9ba8,0x9ba8,0x9baa,0x9bab,0x9bad,0x9bb0,0x9bb5,0x9bb6,0x9bb8,0x9bb9,0x9bbd,0x9bbd,0x9bbf,0x9bc1,0x9bc3,0x9bc4,0x9bc6,0x9bca,0x9bcf,0x9bcf,0x9bd3,0x9bd7,0x9bd9,0x9bde,0x9be0,0x9be2,0x9be4,0x9bed,0x9bf0,0x9bf1,0x9bf4,0x9bf4,0x9bf7,0x9bf8,0x9bfd,0x9bfd,0x9bff,0x9bff,0x9c02,0x9c02,0x9c05,0x9c0e,0x9c10,0x9c10,0x9c12,0x9c15,0x9c17,0x9c17,0x9c1b,0x9c1d,0x9c1f,0x9c21,0x9c23,0x9c26,0x9c28,0x9c29,0x9c2b,0x9c2d,0x9c2f,0x9c2f,0x9c31,0x9c37,0x9c39,0x9c41,0x9c44,0x9c50,0x9c52,0x9c59,0x9c5d,0x9c60,0x9c62,0x9c63,0x9c66,0x9c68,0x9c6d,0x9c6e,0x9c71,0x9c75,0x9c77,0x9c7c,0x9ce5,0x9ce7,0x9ce9,0x9cea,0x9ced,0x9ced,0x9cf1,0x9cf7,0x9cf9,0x9cfd,0x9cff,0x9d00,0x9d02,0x9d09,0x9d0c,0x9d0c,0x9d10,0x9d10,0x9d12,0x9d12,0x9d14,0x9d19,0x9d1b,0x9d1b,0x9d1d,0x9d23,0x9d25,0x9d26,0x9d28,0x9d29,0x9d2d,0x9d31,0x9d33,0x9d34,0x9d36,0x9d39,0x9d3b,0x9d3b,0x9d3d,0x9d45,0x9d49,0x9d4c,0x9d4e,0x9d54,0x9d56,0x9d61,0x9d67,0x9d75,0x9d77,0x9d79,0x9d7b,0x9d8c,0x9d90,0x9d90,0x9d92,0x9d94,0x9d96,0x9dad,0x9daf,0x9daf,0x9db1,0x9dc5,0x9dc7,0x9ddf,0x9de1,0x9de6,0x9de8,0x9de9,0x9deb,0x9df0,0x9df2,0x9e07,0x9e09,0x9e15,0x9e17,0x9e1f,0x9e75,0x9e75,0x9e79,0x9e7d,0x9e7f,0x9e8e,0x9e90,0x9ea2,0x9ea4,0x9eb1,0x9eb4,0x9eb7,0x9ebb,0x9ec4,0x9ec6,0x9ec8,0x9ecc,0x9ed1,0x9ed3,0x9ed6,0x9ed8,0x9ed8,0x9eda,0x9ee0,0x9ee2,0x9ee2,0x9ee4,0x9ee8,0x9eeb,0x9eeb,0x9eed,0x9f02,0x9f06,0x9f0a,0x9f0e,0x9f10,0x9f12,0x9f13,0x9f15,0x9f1c,0x9f1e,0x9f1e,0x9f20,0x9f20,0x9f22,0x9f39,0x9f3b,0x9f3b,0x9f3d,0x9f3e,0x9f40,0x9f50,0x9f52,0x9f67,0x9f69,0x9f6c,0x9f6e,0x9f72,0x9f74,0x9f7b,0x9f7e,0x9f7f,0x9f8d,0x9f8e,0x9f90,0x9f92,0x9f94,0x9f99,0x9f9c,0x9f9c,0x9f9f,0x9fa0,0x9fa2,0x9fa2,0x9fa4,0x9fb3,0x9fc7,0x9fcb,0x9fd0,0x9fd0,0xf900,0xf903,0xf905,0xf907,0xf90b,0xf90b,0xf90d,0xf90d,0xf915,0xf915,0xf917,0xf917,0xf91a,0xf91a,0xf922,0xf922,0xf92d,0xf92d,0xf931,0xf931,0xf937,0xf937,0xf939,0xf93a,0xf943,0xf943,0xf947,0xf948,0xf94a,0xf94a,0xf952,0xf952,0xf95e,0xf95e,0xf962,0xf962,0xf965,0xf965,0xf967,0xf967,0xf972,0xf972,0xf976,0xf976,0xf978,0xf979,0xf97e,0xf97e,0xf980,0xf980,0xf986,0xf986,0xf98a,0xf98a,0xf98e,0xf98e,0xf995,0xf995,0xf99c,0xf99c,0xf99f,0xf99f,0xf9b5,0xf9b5,0xf9bb,0xf9bb,0xf9bd,0xf9bd,0xf9c5,0xf9c6,0xf9c8,0xf9c8,0xf9d8,0xf9d8,0xf9dc,0xf9de,0xf9e0,0xf9e0,0xf9e4,0xf9e4,0xf9e7,0xf9e7,0xf9e9,0xf9e9,0xf9f4,0xf9f5,0xf9fa,0xf9fa,0xf9fd,0xf9fd,0xf9ff,0xf9ff,0xfa02,0xfa02,0xfa05,0xfa08,0xfa0a,0xfa0a,0xfa0c,0xfa0d,0xfa33,0xfa35,0xfa3a,0xfa3a,0xfa49,0xfa49,0xfa4b,0xfa4b,0xfa5d,0xfa5e,0xfb00,0xfb04,0xfe10,0xfe19,0xfe30,0xfe52,0xfe54,0xfe66,0xfe68,0xfe6b,0xff01,0xff9f,0xffa1,0xffbe,0xffc2,0xffc7,0xffca,0xffcf,0xffd2,0xffd7,0xffda,0xffdc,0xffe0,0xffe6,0xffe8,0xffee,0x1f100,0x1f10c,0x1f110,0x1f16c,0x1f170,0x1f1ac,0x1f200,0x1f202,0x1f210,0x1f23b,0x1f240,0x1f248,0x1f250,0x1f251,0x20021,0x20021,0x2003e,0x2003e,0x20046,0x20046,0x2004e,0x2004e,0x20068,0x20068,0x20086,0x20087,0x2008a,0x2008a,0x20094,0x20094,0x200ca,0x200cd,0x200d1,0x200d1,0x200ee,0x200ee,0x2010c,0x2010c,0x2010e,0x2010e,0x20118,0x20118,0x201a4,0x201a4,0x201a9,0x201a9,0x201ab,0x201ab,0x201c1,0x201c1,0x201d4,0x201d4,0x201f2,0x201f2,0x20204,0x20204,0x2020c,0x2020c,0x20214,0x20214,0x20239,0x20239,0x2025b,0x2025b,0x20274,0x20275,0x20299,0x20299,0x2029e,0x2029e,0x202a0,0x202a0,0x202b7,0x202b7,0x202bf,0x202c0,0x202e5,0x202e5,0x2030a,0x2030a,0x20325,0x20325,0x20341,0x20341,0x20345,0x20347,0x2037e,0x20380,0x203a0,0x203a0,0x203a7,0x203a7,0x203b5,0x203b5,0x203c9,0x203c9,0x203cb,0x203cb,0x203f5,0x203f5,0x203fc,0x203fc,0x20413,0x20414,0x2041f,0x2041f,0x20465,0x20465,0x20487,0x20487,0x2048e,0x2048e,0x20491,0x20492,0x204a3,0x204a3,0x204d7,0x204d7,0x204fc,0x204fc,0x204fe,0x204fe,0x20547,0x20547,0x2058e,0x2058e,0x205a5,0x205a5,0x205b3,0x205b3,0x205c3,0x205c3,0x205ca,0x205ca,0x205d0,0x205d0,0x205d5,0x205d5,0x205df,0x205e0,0x205eb,0x205eb,0x20611,0x20611,0x20615,0x20615,0x20619,0x2061a,0x20628,0x20628,0x20630,0x20630,0x20656,0x20656,0x20676,0x20676,0x2070e,0x2070e,0x20731,0x20731,0x20779,0x20779,0x2082c,0x2082c,0x20873,0x20873,0x208d5,0x208d5,0x20916,0x20916,0x20923,0x20923,0x20954,0x20954,0x20979,0x20979,0x209e7,0x209e7,0x20a11,0x20a11,0x20a50,0x20a50,0x20a6f,0x20a6f,0x20a8a,0x20a8a,0x20ab4,0x20ab4,0x20ac2,0x20ac2,0x20acd,0x20acd,0x20b0d,0x20b0d,0x20b8f,0x20b8f,0x20b9f,0x20b9f,0x20ba8,0x20ba9,0x20bbf,0x20bbf,0x20bc6,0x20bc6,0x20bcb,0x20bcb,0x20be2,0x20be2,0x20beb,0x20beb,0x20bfb,0x20bfb,0x20bff,0x20bff,0x20c0b,0x20c0b,0x20c0d,0x20c0d,0x20c20,0x20c20,0x20c34,0x20c34,0x20c3a,0x20c3b,0x20c41,0x20c43,0x20c53,0x20c53,0x20c65,0x20c65,0x20c77,0x20c78,0x20c7c,0x20c7c,0x20c8d,0x20c8d,0x20c96,0x20c96,0x20c9c,0x20c9c,0x20cb5,0x20cb5,0x20cb8,0x20cb8,0x20ccf,0x20ccf,0x20cd3,0x20cd6,0x20cdd,0x20cdd,0x20ced,0x20ced,0x20cff,0x20cff,0x20d15,0x20d15,0x20d28,0x20d28,0x20d31,0x20d32,0x20d46,0x20d49,0x20d4c,0x20d4e,0x20d6f,0x20d6f,0x20d71,0x20d71,0x20d74,0x20d74,0x20d7c,0x20d7c,0x20d7e,0x20d7f,0x20d96,0x20d96,0x20d9c,0x20d9c,0x20da7,0x20da7,0x20db2,0x20db2,0x20dc8,0x20dc8,0x20e04,0x20e04,0x20e09,0x20e0a,0x20e0d,0x20e11,0x20e16,0x20e16,0x20e1d,0x20e1d,0x20e4c,0x20e4c,0x20e6d,0x20e6d,0x20e73,0x20e73,0x20e75,0x20e7b,0x20e8c,0x20e8c,0x20e96,0x20e96,0x20e98,0x20e98,0x20e9d,0x20e9d,0x20ea2,0x20ea2,0x20eaa,0x20eac,0x20eb6,0x20eb6,0x20ed7,0x20ed8,0x20edd,0x20edd,0x20ef8,0x20efb,0x20f1d,0x20f1d,0x20f26,0x20f26,0x20f2d,0x20f2e,0x20f30,0x20f31,0x20f3b,0x20f3b,0x20f4c,0x20f4c,0x20f64,0x20f64,0x20f8d,0x20f8d,0x20f90,0x20f90,0x20fad,0x20fad,0x20fb4,0x20fb6,0x20fbc,0x20fbc,0x20fdf,0x20fdf,0x20fea,0x20fed,0x21014,0x21014,0x2101d,0x2101e,0x2104f,0x2104f,0x2105c,0x2105c,0x2106f,0x2106f,0x21075,0x21078,0x2107b,0x2107b,0x21088,0x21088,0x21096,0x21096,0x2109d,0x2109d,0x210b4,0x210b4,0x210bf,0x210c1,0x210c7,0x210c9,0x210cf,0x210cf,0x210d3,0x210d3,0x210e4,0x210e4,0x210f4,0x210f6,0x2112f,0x2112f,0x2113b,0x2113b,0x2113d,0x2113d,0x21145,0x21145,0x21148,0x21148,0x2114f,0x2114f,0x21180,0x21180,0x21187,0x21187,0x211d9,0x211d9,0x2123c,0x2123c,0x2124f,0x2124f,0x2127c,0x2127c,0x212a8,0x212a9,0x212b0,0x212b0,0x212e3,0x212e3,0x212fe,0x212fe,0x21302,0x21305,0x21336,0x21336,0x2133a,0x2133a,0x21375,0x21376,0x2138e,0x2138e,0x21398,0x21398,0x2139c,0x2139c,0x213c5,0x213c6,0x213ed,0x213ed,0x213fe,0x213fe,0x21413,0x21413,0x21416,0x21416,0x21424,0x21424,0x2143f,0x2143f,0x21452,0x21452,0x21454,0x21455,0x2148a,0x2148a,0x21497,0x21497,0x214b6,0x214b6,0x214e8,0x214e8,0x214fd,0x214fd,0x21577,0x21577,0x21582,0x21582,0x21596,0x21596,0x2160a,0x2160a,0x21613,0x21613,0x21619,0x21619,0x2163e,0x2163e,0x21661,0x21661,0x21692,0x21692,0x216b8,0x216b8,0x216ba,0x216ba,0x216c0,0x216c2,0x216d3,0x216d3,0x216d5,0x216d5,0x216df,0x216df,0x216e6,0x216e8,0x216fa,0x216fc,0x216fe,0x216fe,0x2170d,0x2170d,0x21710,0x21710,0x21726,0x21726,0x2173a,0x2173c,0x21757,0x21757,0x2176c,0x21771,0x21773,0x21774,0x217ab,0x217ab,0x217b0,0x217b5,0x217c3,0x217c3,0x217c7,0x217c7,0x217d9,0x217dc,0x217df,0x217df,0x217ef,0x217ef,0x217f5,0x217f6,0x217f8,0x217fc,0x21820,0x21820,0x21828,0x2182a,0x2182d,0x2182d,0x21839,0x2183b,0x21840,0x21840,0x21845,0x21845,0x21852,0x21852,0x2185e,0x2185e,0x21861,0x21864,0x21877,0x21877,0x2187b,0x2187b,0x21883,0x21885,0x2189e,0x218a2,0x218be,0x218bf,0x218d1,0x218d1,0x218d6,0x218d9,0x218fa,0x218fa,0x21903,0x21905,0x21910,0x21912,0x21915,0x21915,0x2191c,0x2191c,0x21922,0x21922,0x21927,0x21927,0x2193b,0x2193b,0x21944,0x21944,0x21958,0x21958,0x2196a,0x2196a,0x2197c,0x2197c,0x21980,0x21980,0x21983,0x21983,0x21988,0x21988,0x21996,0x21996,0x219db,0x219db,0x219f3,0x219f3,0x21a2d,0x21a2d,0x21a34,0x21a34,0x21a45,0x21a45,0x21a4b,0x21a4b,0x21a63,0x21a63,0x21b44,0x21b44,0x21bc1,0x21bc2,0x21c2a,0x21c2a,0x21c70,0x21c70,0x21ca2,0x21ca2,0x21ca5,0x21ca5,0x21cac,0x21cac,0x21d46,0x21d46,0x21d53,0x21d53,0x21d5e,0x21d5e,0x21d90,0x21d90,0x21db6,0x21db6,0x21dba,0x21dba,0x21dca,0x21dca,0x21dd1,0x21dd1,0x21deb,0x21deb,0x21df9,0x21df9,0x21e1c,0x21e1c,0x21e23,0x21e23,0x21e37,0x21e37,0x21e3d,0x21e3d,0x21e89,0x21e89,0x21ea4,0x21ea4,0x21ea8,0x21ea8,0x21ec8,0x21ec8,0x21ed5,0x21ed5,0x21f0f,0x21f0f,0x21f15,0x21f15,0x21f6a,0x21f6a,0x21f9e,0x21f9e,0x21fa1,0x21fa1,0x21fe8,0x21fe8,0x22045,0x22045,0x22049,0x22049,0x2207e,0x2207e,0x2209a,0x2209a,0x220c7,0x220c7,0x220fc,0x220fc,0x2212a,0x2212a,0x2215b,0x2215b,0x22173,0x22173,0x2217a,0x2217a,0x221a1,0x221a1,0x221c1,0x221c1,0x221c3,0x221c3,0x22208,0x22208,0x2227c,0x2227c,0x22321,0x22321,0x22325,0x22325,0x223bd,0x223bd,0x223d0,0x223d0,0x223d7,0x223d7,0x223fa,0x223fa,0x22465,0x22465,0x22471,0x22471,0x2248b,0x2248b,0x22491,0x22491,0x224b0,0x224b0,0x224bc,0x224bc,0x224c1,0x224c1,0x224c9,0x224c9,0x224cc,0x224cc,0x224ed,0x224ed,0x22513,0x22513,0x2251b,0x2251b,0x22530,0x22530,0x22554,0x22554,0x2258d,0x2258d,0x225af,0x225af,0x225be,0x225be,0x2261b,0x2261c,0x2262b,0x2262b,0x22668,0x22668,0x2267a,0x2267a,0x22696,0x22696,0x22698,0x22698,0x226f4,0x226f6,0x22712,0x22712,0x22714,0x22714,0x2271b,0x2271b,0x2271f,0x2271f,0x2272a,0x2272a,0x22775,0x22775,0x22781,0x22781,0x22796,0x22796,0x227b4,0x227b5,0x227cd,0x227cd,0x22803,0x22803,0x2285f,0x22860,0x22871,0x22871,0x228ad,0x228ad,0x228c1,0x228c1,0x228f7,0x228f7,0x22926,0x22926,0x22939,0x22939,0x2294f,0x2294f,0x22967,0x22967,0x2296b,0x2296b,0x22980,0x22980,0x22993,0x22993,0x22a66,0x22a66,0x22acf,0x22acf,0x22ad5,0x22ad5,0x22ae6,0x22ae6,0x22ae8,0x22ae8,0x22b0e,0x22b0e,0x22b22,0x22b22,0x22b3f,0x22b3f,0x22b43,0x22b43,0x22b6a,0x22b6a,0x22bca,0x22bca,0x22bce,0x22bce,0x22c26,0x22c27,0x22c38,0x22c38,0x22c4c,0x22c4c,0x22c51,0x22c51,0x22c55,0x22c55,0x22c62,0x22c62,0x22c88,0x22c88,0x22c9b,0x22c9b,0x22ca1,0x22ca1,0x22ca9,0x22ca9,0x22cb2,0x22cb2,0x22cb7,0x22cb7,0x22cc2,0x22cc2,0x22cc6,0x22cc6,0x22cc9,0x22cc9,0x22d07,0x22d08,0x22d12,0x22d12,0x22d44,0x22d44,0x22d4c,0x22d4c,0x22d67,0x22d67,0x22d8d,0x22d8d,0x22d95,0x22d95,0x22da0,0x22da0,0x22da3,0x22da4,0x22db7,0x22db7,0x22dee,0x22dee,0x22e0d,0x22e0d,0x22e36,0x22e36,0x22e42,0x22e42,0x22e78,0x22e78,0x22e8b,0x22e8b,0x22eb3,0x22eb3,0x22eef,0x22eef,0x22f74,0x22f74,0x22fcc,0x22fcc,0x22fe3,0x22fe3,0x23033,0x23033,0x23044,0x23044,0x2304b,0x2304b,0x23066,0x23066,0x2307d,0x2307e,0x2308e,0x2308e,0x230b7,0x230b7,0x230bc,0x230bc,0x230da,0x230da,0x23103,0x23103,0x2313d,0x2313d,0x2317d,0x2317d,0x23182,0x23182,0x231a4,0x231a5,0x231b3,0x231b3,0x231c8,0x231c9,0x231ea,0x231ea,0x231f7,0x231f9,0x2320f,0x2320f,0x23225,0x23225,0x2322f,0x2322f,0x23231,0x23234,0x23256,0x23256,0x2325e,0x2325e,0x23262,0x23262,0x23281,0x23281,0x23289,0x2328a,0x232ab,0x232ad,0x232d2,0x232d2,0x232e0,0x232e1,0x23300,0x23300,0x2330a,0x2330a,0x2331f,0x2331f,0x233b4,0x233b4,0x233cc,0x233cc,0x233de,0x233de,0x233e6,0x233e6,0x233f4,0x233f5,0x233f9,0x233fa,0x233fe,0x233fe,0x23400,0x23400,0x2343f,0x2343f,0x23450,0x23450,0x2346f,0x2346f,0x23472,0x23472,0x234e5,0x234e5,0x23519,0x23519,0x23530,0x23530,0x23551,0x23551,0x2355a,0x2355a,0x23567,0x23567,0x23595,0x23595,0x23599,0x23599,0x2359c,0x2359c,0x235bb,0x235bb,0x235cd,0x235cf,0x235f3,0x235f3,0x23600,0x23600,0x23617,0x23617,0x2361a,0x2361a,0x2363c,0x2363c,0x23640,0x23640,0x23659,0x23659,0x2365f,0x2365f,0x23677,0x23677,0x2368e,0x2368e,0x2369e,0x2369e,0x236a6,0x236a6,0x236ad,0x236ad,0x236ba,0x236ba,0x236df,0x236df,0x236ee,0x236ee,0x23703,0x23703,0x23716,0x23716,0x23720,0x23720,0x2372d,0x2372d,0x2372f,0x2372f,0x2373f,0x2373f,0x23766,0x23766,0x23781,0x23781,0x237a2,0x237a2,0x237bc,0x237bc,0x237c2,0x237c2,0x237d5,0x237d7,0x2383a,0x2383a,0x239c2,0x239c2,0x23aa7,0x23aa7,0x23adb,0x23adb,0x23aee,0x23aee,0x23afa,0x23afa,0x23b1a,0x23b1a,0x23b5a,0x23b5a,0x23c63,0x23c63,0x23c99,0x23c9b,0x23cb5,0x23cb5,0x23cb7,0x23cb7,0x23cc7,0x23cc9,0x23cfc,0x23cff,0x23d40,0x23d40,0x23d5b,0x23d5b,0x23d7e,0x23d7e,0x23d8f,0x23d8f,0x23db6,0x23dbd,0x23de3,0x23de3,0x23df8,0x23df8,0x23e06,0x23e06,0x23e11,0x23e11,0x23e2c,0x23e31,0x23e39,0x23e39,0x23e88,0x23e8b,0x23eb9,0x23eb9,0x23ebf,0x23ebf,0x23ed7,0x23ed7,0x23ef7,0x23efc,0x23f35,0x23f35,0x23f41,0x23f41,0x23f4a,0x23f4a,0x23f61,0x23f61,0x23f7f,0x23f82,0x23f8f,0x23f8f,0x23fb4,0x23fb4,0x23fb7,0x23fb7,0x23fc0,0x23fc0,0x23fc5,0x23fc5,0x23feb,0x23ff0,0x24011,0x24011,0x24039,0x2403d,0x24057,0x24057,0x24085,0x24085,0x2408b,0x2408d,0x24091,0x24091,0x240c9,0x240c9,0x240e1,0x240e1,0x240ec,0x240ec,0x24104,0x24104,0x2410f,0x2410f,0x24119,0x24119,0x2413f,0x24140,0x24144,0x24144,0x2414e,0x2414e,0x24155,0x24157,0x2415c,0x2415c,0x2415f,0x2415f,0x24161,0x24161,0x24177,0x24177,0x2417a,0x2417a,0x241a3,0x241a5,0x241ac,0x241ac,0x241b5,0x241b5,0x241cd,0x241cd,0x241e2,0x241e2,0x241fc,0x241fc,0x2421b,0x2421b,0x2424b,0x2424b,0x24256,0x24256,0x24259,0x24259,0x24276,0x24278,0x24284,0x24284,0x24293,0x24293,0x24295,0x24295,0x242a5,0x242a5,0x242bf,0x242bf,0x242c1,0x242c1,0x242c9,0x242ca,0x242ee,0x242ee,0x242fa,0x242fa,0x2430d,0x2430d,0x2431a,0x2431a,0x24334,0x24334,0x24348,0x24348,0x24362,0x24365,0x2438c,0x2438c,0x24396,0x24396,0x2439c,0x2439c,0x243bd,0x243bd,0x243c1,0x243c1,0x243e9,0x243ea,0x243f2,0x243f2,0x243f8,0x243f8,0x24404,0x24404,0x24435,0x24436,0x2445a,0x2445b,0x24473,0x24473,0x24487,0x24488,0x244b9,0x244b9,0x244bc,0x244bc,0x244ce,0x244ce,0x244d3,0x244d3,0x244d6,0x244d6,0x24505,0x24505,0x24521,0x24521,0x24578,0x24578,0x245c8,0x245c8,0x24618,0x24618,0x2462a,0x2462a,0x24665,0x24665,0x24674,0x24674,0x24697,0x24697,0x246d4,0x246d4,0x24706,0x24706,0x24725,0x24725,0x2472f,0x2472f,0x2478f,0x2478f,0x247e0,0x247e0,0x24812,0x24812,0x24823,0x24823,0x24882,0x24882,0x248e9,0x248e9,0x248f0,0x248f3,0x248fb,0x248fb,0x248ff,0x24901,0x2490c,0x2490c,0x24916,0x24917,0x24919,0x24919,0x2492f,0x2492f,0x24933,0x24934,0x2493e,0x24943,0x24962,0x24963,0x24974,0x24976,0x2497b,0x2497b,0x2497f,0x2497f,0x24982,0x24982,0x24988,0x2498f,0x24994,0x24994,0x249a4,0x249a4,0x249a7,0x249a7,0x249a9,0x249a9,0x249ab,0x249ad,0x249b7,0x249bb,0x249c5,0x249c5,0x249d0,0x249d0,0x249da,0x249da,0x249de,0x249df,0x249e3,0x249e3,0x249e5,0x249e5,0x249ec,0x249ed,0x249f6,0x249f9,0x249fb,0x249fb,0x24a0e,0x24a0e,0x24a12,0x24a13,0x24a15,0x24a15,0x24a21,0x24a2a,0x24a3e,0x24a3e,0x24a42,0x24a42,0x24a45,0x24a45,0x24a4a,0x24a4a,0x24a4e,0x24a51,0x24a5d,0x24a5d,0x24a65,0x24a67,0x24a71,0x24a71,0x24a77,0x24a7a,0x24a8c,0x24a8c,0x24a93,0x24a96,0x24aa4,0x24aa7,0x24ab1,0x24ab3,0x24aba,0x24abc,0x24ac0,0x24ac0,0x24ac7,0x24ac7,0x24aca,0x24aca,0x24ad1,0x24ad1,0x24adf,0x24adf,0x24ae2,0x24ae2,0x24ae9,0x24ae9,0x24b0f,0x24b0f,0x24b6e,0x24b6e,0x24bf5,0x24bf5,0x24c09,0x24c09,0x24c9e,0x24c9f,0x24cc9,0x24cc9,0x24cd9,0x24cd9,0x24d06,0x24d06,0x24d13,0x24d13,0x24db8,0x24db8,0x24dea,0x24deb,0x24e3b,0x24e3b,0x24e50,0x24e50,0x24ea5,0x24ea5,0x24ea7,0x24ea7,0x24f0e,0x24f0e,0x24f5c,0x24f5c,0x24f82,0x24f82,0x24f86,0x24f86,0x24f97,0x24f97,0x24f9a,0x24f9a,0x24fa9,0x24fa9,0x24fb8,0x24fb8,0x24fc2,0x24fc2,0x2502c,0x2502c,0x25052,0x25052,0x2509d,0x2509d,0x2512b,0x2512b,0x25148,0x25148,0x2517d,0x2517e,0x251cd,0x251cd,0x251e3,0x251e3,0x251e6,0x251e7,0x25220,0x25221,0x25250,0x25250,0x25299,0x25299,0x252c7,0x252c7,0x252d8,0x252d8,0x2530e,0x2530e,0x25311,0x25311,0x25313,0x25313,0x25419,0x25419,0x25425,0x25425,0x2542f,0x25430,0x25446,0x25446,0x2546c,0x2546c,0x2546e,0x2546e,0x2549a,0x2549a,0x25531,0x25531,0x25535,0x25535,0x2553f,0x2553f,0x2555b,0x2555e,0x25562,0x25562,0x25565,0x25566,0x25581,0x25581,0x25584,0x25584,0x2558f,0x2558f,0x255b9,0x255b9,0x255d5,0x255d5,0x255db,0x255db,0x255e0,0x255e0,0x25605,0x25605,0x25635,0x25635,0x25651,0x25651,0x25683,0x25683,0x25695,0x25695,0x256e3,0x256e3,0x256f6,0x256f6,0x25706,0x25706,0x2571d,0x2571d,0x25725,0x25725,0x2573d,0x2573d,0x25772,0x25772,0x257c7,0x257c7,0x257df,0x257e1,0x25857,0x25857,0x2585d,0x2585d,0x25872,0x25872,0x258c8,0x258c8,0x258de,0x258de,0x258e1,0x258e1,0x25903,0x25903,0x25946,0x25946,0x25956,0x25956,0x259ac,0x259ac,0x259cc,0x259cc,0x25a54,0x25a54,0x25a95,0x25a95,0x25a9c,0x25a9c,0x25aae,0x25aaf,0x25ad7,0x25ad7,0x25ae9,0x25ae9,0x25b74,0x25b74,0x25b89,0x25b89,0x25bb3,0x25bb4,0x25bc6,0x25bc6,0x25be4,0x25be4,0x25be8,0x25be8,0x25c01,0x25c01,0x25c06,0x25c06,0x25c21,0x25c21,0x25c4a,0x25c4a,0x25c65,0x25c65,0x25c91,0x25c91,0x25ca4,0x25ca4,0x25cc0,0x25cc1,0x25cfe,0x25cfe,0x25d20,0x25d20,0x25d30,0x25d30,0x25d43,0x25d43,0x25d99,0x25d99,0x25db9,0x25db9,0x25e0e,0x25e0e,0x25e49,0x25e49,0x25e81,0x25e83,0x25ea6,0x25ea6,0x25ebc,0x25ebc,0x25ed7,0x25ed8,0x25f1a,0x25f1a,0x25f4b,0x25f4b,0x25fe1,0x25fe2,0x26021,0x26021,0x26029,0x26029,0x26048,0x26048,0x26064,0x26064,0x26083,0x26083,0x26097,0x26097,0x260a4,0x260a5,0x26102,0x26102,0x26121,0x26121,0x26159,0x2615c,0x261ad,0x261ae,0x261b2,0x261b2,0x261dd,0x261dd,0x26258,0x26258,0x26261,0x26261,0x2626a,0x2626b,0x262d0,0x262d0,0x26335,0x26335,0x2634b,0x2634c,0x26351,0x26351,0x263be,0x263be,0x263f5,0x263f5,0x263f8,0x263f8,0x26402,0x26402,0x26410,0x26412,0x2644a,0x2644a,0x26469,0x26469,0x26484,0x26484,0x26488,0x26489,0x2648d,0x2648d,0x26498,0x26498,0x26512,0x26512,0x26572,0x26572,0x265a0,0x265a0,0x265ad,0x265ad,0x265bf,0x265bf,0x26612,0x26612,0x26626,0x26626,0x266af,0x266af,0x266b1,0x266b1,0x266b5,0x266b5,0x266da,0x266da,0x266e8,0x266e8,0x266fc,0x266fc,0x26716,0x26716,0x26741,0x26741,0x26799,0x26799,0x267b3,0x267b4,0x267cc,0x267cc,0x2681c,0x2681c,0x26846,0x26846,0x2685e,0x2685e,0x2686e,0x2686e,0x26888,0x26888,0x2688a,0x2688a,0x26893,0x26893,0x268c7,0x268c7,0x2690e,0x2690e,0x26911,0x26911,0x26926,0x26926,0x26939,0x26939,0x26951,0x26951,0x269a8,0x269a8,0x269b5,0x269b5,0x269f2,0x269f2,0x269fa,0x269fa,0x26a2d,0x26a2e,0x26a34,0x26a34,0x26a42,0x26a42,0x26a51,0x26a52,0x26b05,0x26b05,0x26b0a,0x26b0a,0x26b13,0x26b13,0x26b15,0x26b15,0x26b23,0x26b23,0x26b28,0x26b28,0x26b50,0x26b53,0x26b5b,0x26b5b,0x26b75,0x26b75,0x26b82,0x26b82,0x26b96,0x26b97,0x26b9d,0x26b9d,0x26bb3,0x26bb3,0x26bc0,0x26bc0,0x26bf7,0x26bf7,0x26c21,0x26c21,0x26c40,0x26c41,0x26c46,0x26c46,0x26c7e,0x26c82,0x26ca4,0x26ca4,0x26cb7,0x26cb8,0x26cbd,0x26cbd,0x26cc0,0x26cc0,0x26cc3,0x26cc3,0x26cd1,0x26cd1,0x26d22,0x26d2a,0x26d51,0x26d51,0x26d74,0x26d74,0x26da0,0x26da7,0x26dae,0x26dae,0x26ddc,0x26ddc,0x26dea,0x26deb,0x26df0,0x26df0,0x26e00,0x26e00,0x26e05,0x26e05,0x26e07,0x26e07,0x26e12,0x26e12,0x26e42,0x26e45,0x26e6e,0x26e6e,0x26e72,0x26e72,0x26e77,0x26e77,0x26e84,0x26e84,0x26e88,0x26e88,0x26e8b,0x26e8b,0x26e99,0x26e99,0x26ed0,0x26ed7,0x26f26,0x26f26,0x26f73,0x26f74,0x26f9f,0x26f9f,0x26fa1,0x26fa1,0x26fbe,0x26fbe,0x26fde,0x26fdf,0x2700e,0x2700e,0x2704b,0x2704b,0x27052,0x27053,0x27088,0x27088,0x270ad,0x270af,0x270cd,0x270cd,0x270d2,0x270d2,0x270f0,0x270f0,0x270f8,0x270f8,0x27109,0x27109,0x2710c,0x2710d,0x27126,0x27127,0x27164,0x27165,0x27175,0x27175,0x271cd,0x271cd,0x2721b,0x2721b,0x27267,0x27267,0x27280,0x27280,0x27285,0x27285,0x2728b,0x2728b,0x272b2,0x272b2,0x272b6,0x272b6,0x272e6,0x272e6,0x27352,0x27352,0x2739a,0x2739a,0x273ff,0x273ff,0x27422,0x27422,0x27450,0x27450,0x27484,0x27484,0x27486,0x27486,0x27574,0x27574,0x275a3,0x275a3,0x275e0,0x275e0,0x275e4,0x275e4,0x275fd,0x275fe,0x27607,0x27607,0x2760c,0x2760c,0x27632,0x27632,0x27639,0x27639,0x27655,0x27657,0x27694,0x27694,0x2770f,0x2770f,0x27735,0x27736,0x27741,0x27741,0x2775e,0x2775e,0x27784,0x27785,0x277cc,0x277cc,0x27858,0x27858,0x27870,0x27870,0x2789d,0x2789d,0x278b2,0x278b2,0x278c8,0x278c8,0x27924,0x27924,0x27967,0x27967,0x2797a,0x2797a,0x279a0,0x279a0,0x279dd,0x279dd,0x279fd,0x279fd,0x27a0a,0x27a0a,0x27a0e,0x27a0e,0x27a3e,0x27a3e,0x27a53,0x27a53,0x27a59,0x27a59,0x27a79,0x27a79,0x27a84,0x27a84,0x27abd,0x27abe,0x27af4,0x27af4,0x27b06,0x27b06,0x27b0b,0x27b0b,0x27b18,0x27b18,0x27b38,0x27b3a,0x27b48,0x27b48,0x27b65,0x27b65,0x27bef,0x27bef,0x27bf4,0x27bf4,0x27c12,0x27c12,0x27c6c,0x27c6c,0x27cb1,0x27cb1,0x27cc5,0x27cc5,0x27d2f,0x27d2f,0x27d53,0x27d54,0x27d66,0x27d66,0x27d73,0x27d73,0x27d84,0x27d84,0x27d8f,0x27d8f,0x27d98,0x27d98,0x27dbd,0x27dbd,0x27ddc,0x27ddc,0x27e4d,0x27e4d,0x27e4f,0x27e4f,0x27f2e,0x27f2e,0x27fb7,0x27fb7,0x27ff9,0x27ff9,0x28002,0x28002,0x28009,0x28009,0x2801e,0x2801e,0x28023,0x28024,0x28048,0x28048,0x28083,0x28083,0x28090,0x28090,0x280bd,0x280be,0x280e8,0x280e9,0x280f4,0x280f4,0x2812e,0x2812e,0x2814f,0x2814f,0x2815d,0x2815d,0x2816f,0x2816f,0x28189,0x28189,0x281af,0x281af,0x281bc,0x281bc,0x28207,0x28207,0x28218,0x28218,0x2821a,0x2821a,0x28256,0x28256,0x2827c,0x2827c,0x2829b,0x2829b,0x282cd,0x282cd,0x282e2,0x282e2,0x28306,0x28306,0x28318,0x28318,0x2832f,0x2832f,0x2833a,0x2833a,0x28365,0x28365,0x2836d,0x2836d,0x2837d,0x2837d,0x2838a,0x2838a,0x28412,0x28412,0x28468,0x28468,0x2846c,0x2846c,0x28473,0x28473,0x28482,0x28482,0x28501,0x28501,0x2853c,0x2853d,0x2856c,0x2856c,0x285e8,0x285e8,0x285f4,0x285f4,0x28600,0x28600,0x2860b,0x2860b,0x28625,0x28625,0x2863b,0x2863b,0x286aa,0x286ab,0x286b2,0x286b2,0x286bc,0x286bc,0x286d8,0x286d8,0x286e6,0x286e6,0x2870f,0x2870f,0x28713,0x28713,0x28804,0x28804,0x2882b,0x2882b,0x2890d,0x2890d,0x28933,0x28933,0x28948,0x28949,0x28956,0x28956,0x28964,0x28964,0x28968,0x28968,0x2896c,0x2896d,0x2897e,0x2897e,0x28989,0x28989,0x289a8,0x289a8,0x289aa,0x289ab,0x289b8,0x289b8,0x289bc,0x289bc,0x289c0,0x289c0,0x289dc,0x289dc,0x289de,0x289de,0x289e1,0x289e1,0x289e3,0x289e4,0x289e7,0x289e8,0x289f9,0x289fc,0x28a0f,0x28a0f,0x28a16,0x28a16,0x28a25,0x28a25,0x28a29,0x28a29,0x28a32,0x28a32,0x28a36,0x28a36,0x28a44,0x28a4b,0x28a59,0x28a5a,0x28a81,0x28a83,0x28a9a,0x28a9c,0x28ac0,0x28ac0,0x28ac6,0x28ac6,0x28acb,0x28acc,0x28ace,0x28ace,0x28ade,0x28ae3,0x28ae5,0x28ae5,0x28aea,0x28aea,0x28afc,0x28afc,0x28b0c,0x28b0c,0x28b13,0x28b13,0x28b21,0x28b22,0x28b2b,0x28b2d,0x28b2f,0x28b2f,0x28b46,0x28b46,0x28b4c,0x28b4c,0x28b4e,0x28b4e,0x28b50,0x28b50,0x28b63,0x28b66,0x28b6c,0x28b6c,0x28b8f,0x28b8f,0x28b99,0x28b99,0x28b9c,0x28b9d,0x28bb9,0x28bb9,0x28bc2,0x28bc2,0x28bc5,0x28bc5,0x28bd4,0x28bd4,0x28bd7,0x28bd7,0x28bd9,0x28bda,0x28be7,0x28bec,0x28bf5,0x28bf5,0x28bff,0x28bff,0x28c03,0x28c03,0x28c09,0x28c09,0x28c1c,0x28c1d,0x28c23,0x28c23,0x28c26,0x28c26,0x28c2b,0x28c2b,0x28c30,0x28c30,0x28c39,0x28c39,0x28c3b,0x28c3b,0x28cca,0x28cca,0x28ccd,0x28ccd,0x28cd2,0x28cd2,0x28d34,0x28d34,0x28d99,0x28d99,0x28db9,0x28db9,0x28e0f,0x28e0f,0x28e36,0x28e36,0x28e39,0x28e39,0x28e65,0x28e66,0x28e97,0x28e97,0x28eac,0x28eac,0x28eb2,0x28eb3,0x28ed9,0x28ed9,0x28ee7,0x28ee7,0x28fc5,0x28fc5,0x29079,0x29079,0x29088,0x29088,0x2908b,0x2908b,0x29093,0x29093,0x290af,0x290b1,0x290c0,0x290c0,0x290e4,0x290e5,0x290ec,0x290ed,0x2910d,0x2910d,0x29110,0x29110,0x2913c,0x2913c,0x2914d,0x2914d,0x2915b,0x2915b,0x2915e,0x2915e,0x29170,0x29170,0x2919c,0x2919c,0x291a8,0x291a8,0x291d5,0x291d5,0x291eb,0x291eb,0x2941d,0x2941d,0x29420,0x29420,0x29433,0x29433,0x2943f,0x2943f,0x29448,0x29448,0x294d0,0x294d0,0x294d9,0x294da,0x294e5,0x294e5,0x294e7,0x294e7,0x2959e,0x2959e,0x295b0,0x295b0,0x295b8,0x295b8,0x295d7,0x295d7,0x295e9,0x295e9,0x295f4,0x295f4,0x2967f,0x2967f,0x29720,0x29720,0x29732,0x29732,0x297d4,0x297d4,0x29810,0x29810,0x29857,0x29857,0x298a4,0x298a4,0x298d1,0x298d1,0x298ea,0x298ea,0x298f1,0x298f1,0x298fa,0x298fa,0x29903,0x29903,0x29905,0x29905,0x2992f,0x2992f,0x29945,0x29945,0x29947,0x29949,0x2995d,0x2995d,0x2996a,0x2996a,0x2999d,0x2999d,0x299c3,0x299c3,0x299c9,0x299c9,0x29a28,0x29a28,0x29a4d,0x29a4d,0x29b05,0x29b05,0x29b0e,0x29b0e,0x29bd5,0x29bd5,0x29c73,0x29c73,0x29cad,0x29cad,0x29d3e,0x29d3e,0x29d5a,0x29d5a,0x29d7c,0x29d7c,0x29d98,0x29d98,0x29d9b,0x29d9b,0x29df6,0x29df6,0x29e06,0x29e06,0x29e2d,0x29e2d,0x29e68,0x29e68,0x29eac,0x29eac,0x29eb0,0x29eb0,0x29ec3,0x29ec3,0x29ef8,0x29ef8,0x29f23,0x29f23,0x29f30,0x29f30,0x29fb7,0x29fb7,0x29fde,0x29fde,0x2a014,0x2a014,0x2a087,0x2a087,0x2a0b9,0x2a0b9,0x2a0e1,0x2a0e1,0x2a0ed,0x2a0ed,0x2a0f3,0x2a0f3,0x2a0f8,0x2a0f8,0x2a0fe,0x2a0fe,0x2a107,0x2a107,0x2a123,0x2a123,0x2a133,0x2a134,0x2a150,0x2a150,0x2a192,0x2a193,0x2a1ab,0x2a1ab,0x2a1b4,0x2a1b5,0x2a1df,0x2a1df,0x2a1f5,0x2a1f5,0x2a220,0x2a220,0x2a233,0x2a233,0x2a293,0x2a293,0x2a29f,0x2a29f,0x2a2b2,0x2a2b2,0x2a2b4,0x2a2b4,0x2a2b6,0x2a2b6,0x2a2ba,0x2a2ba,0x2a2bd,0x2a2bd,0x2a2df,0x2a2df,0x2a2ff,0x2a2ff,0x2a351,0x2a351,0x2a3a9,0x2a3a9,0x2a3ed,0x2a3ed,0x2a434,0x2a434,0x2a45b,0x2a45b,0x2a5c6,0x2a5c6,0x2a5cb,0x2a5cb,0x2a601,0x2a601,0x2a632,0x2a632,0x2a64a,0x2a64a,0x2a65b,0x2a65b,0x2a6a9,0x2a6a9,0x2adff,0x2adff,0x2d544,0x2d544,0x2f825,0x2f825,0x2f83b,0x2f83b,0x2f840,0x2f840,0x2f878,0x2f878,0x2f894,0x2f894,0x2f8a6,0x2f8a6,0x2f8cd,0x2f8cd,0x2f8db,0x2f8db,0x2f994,0x2f994,0x2f9b2,0x2f9b2,0x2f9bc,0x2f9bc,0x2f9d4,0x2f9d4,0x30edd,0x30ede,0x3106c,0x3106c,]), + NotoFont.fromFlatRanges('Noto Sans Tagalog', 'http://fonts.gstatic.com/s/notosanstagalog/v15/J7aFnoNzCnFcV9ZI-sUYuvote1R0wwEAA8jHexnL.ttf', [0x20,0x20,0xa0,0xa0,0x1700,0x170c,0x170e,0x1714,0x1735,0x1736,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Tagbanwa', 'http://fonts.gstatic.com/s/notosanstagbanwa/v15/Y4GWYbB8VTEp4t3MKJSMmQdIKjRtt_nZRjQEaYpGoQ.ttf', [0x20,0x20,0xa0,0xa0,0x1735,0x1736,0x1760,0x176c,0x176e,0x1770,0x1772,0x1773,0x200b,0x200d,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Tai Le', 'http://fonts.gstatic.com/s/notosanstaile/v15/vEFK2-VODB8RrNDvZSUmVxEATwR58tK1W77HtMo.ttf', [0x20,0x20,0xa0,0xa0,0x300,0x301,0x307,0x308,0x30c,0x30c,0x1040,0x1049,0x1950,0x196d,0x1970,0x1974,0x200b,0x200d,0x25cc,0x25cc,0x3001,0x3002,0x3008,0x300b,]), + NotoFont.fromFlatRanges('Noto Sans Tai Tham', 'http://fonts.gstatic.com/s/notosanstaitham/v17/kJEbBv0U4hgtwxDUw2x9q7tbjLIfbPGHBoaVSAZ3MdLJBCUbPgquyaRGKMw.ttf', [0x20,0x20,0xa0,0xa0,0x1a20,0x1a5e,0x1a60,0x1a7c,0x1a7f,0x1a89,0x1a90,0x1a99,0x1aa0,0x1aad,0x200b,0x200d,0x2219,0x2219,]), + NotoFont.fromFlatRanges('Noto Sans Tai Viet', 'http://fonts.gstatic.com/s/notosanstaiviet/v15/8QIUdj3HhN_lv4jf9vsE-9GMOLsaSPZr644fWsRO9w.ttf', [0x20,0x20,0xa0,0xa0,0x200b,0x200d,0x25cc,0x25cc,0xa78b,0xa78c,0xaa80,0xaac2,0xaadb,0xaadf,]), + NotoFont.fromFlatRanges('Noto Sans Takri', 'http://fonts.gstatic.com/s/notosanstakri/v15/TuGJUVpzXI5FBtUq5a8bnKIOdTwQNO_W3khJXg.ttf', [0x20,0x20,0xa0,0xa0,0x964,0x965,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11680,0x116b8,0x116c0,0x116c9,]), + NotoFont.fromFlatRanges('Noto Sans Tamil', 'http://fonts.gstatic.com/s/notosanstamil/v21/ieVc2YdFI3GCY6SyQy1KfStzYKZgzN1z4LKDbeZce-0429tBManUktuex7vGo70RqKDt_EvT.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xb82,0xb83,0xb85,0xb8a,0xb8e,0xb90,0xb92,0xb95,0xb99,0xb9a,0xb9c,0xb9c,0xb9e,0xb9f,0xba3,0xba4,0xba8,0xbaa,0xbae,0xbb9,0xbbe,0xbc2,0xbc6,0xbc8,0xbca,0xbcd,0xbd0,0xbd0,0xbd7,0xbd7,0xbe6,0xbfa,0x1cda,0x1cda,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x2074,0x2074,0x2082,0x2084,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,0xa8f3,0xa8f3,0x11301,0x11301,0x11303,0x11303,0x1133b,0x1133c,]), + NotoFont.fromFlatRanges('Noto Sans Tamil Supplement', 'http://fonts.gstatic.com/s/notosanstamilsupplement/v19/DdTz78kEtnooLS5rXF1DaruiCd_bFp_Ph4sGcn7ax_vsAeMkeq1x.ttf', [0x11fc0,0x11ff1,0x11fff,0x11fff,]), + NotoFont.fromFlatRanges('Noto Sans Telugu', 'http://fonts.gstatic.com/s/notosanstelugu/v19/0FlxVOGZlE2Rrtr-HmgkMWJNjJ5_RyT8o8c7fHkeg-esVC5dzHkHIJQqrEntezbqQUbf-3v37w.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xad,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2c6,0x2c7,0x2c9,0x2c9,0x2d8,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x951,0x952,0x964,0x965,0xc00,0xc0c,0xc0e,0xc10,0xc12,0xc28,0xc2a,0xc39,0xc3d,0xc44,0xc46,0xc48,0xc4a,0xc4d,0xc55,0xc56,0xc58,0xc5a,0xc60,0xc63,0xc66,0xc6f,0xc77,0xc7f,0x1cda,0x1cda,0x1cf2,0x1cf2,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x20b9,0x20b9,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Thaana', 'http://fonts.gstatic.com/s/notosansthaana/v16/C8c14dM-vnz-s-3jaEsxlxHkBH-WZOETXfoQrfQ9Y4XrbhLhnu4-tbNu.ttf', [0x20,0x21,0x28,0x29,0x2c,0x2c,0x2e,0x2e,0x3a,0x3b,0xa0,0xa0,0x60c,0x60c,0x61b,0x61b,0x61f,0x61f,0x660,0x66c,0x780,0x7b1,0x200b,0x200f,0x2018,0x2019,0x201c,0x201d,0x25cc,0x25cc,0xfdf2,0xfdf2,0xfdfd,0xfdfd,]), + NotoFont.fromFlatRanges('Noto Sans Thai', 'http://fonts.gstatic.com/s/notosansthai/v20/iJWnBXeUZi_OHPqn4wq6hQ2_hbJ1xyN9wd43SofNWcd1MKVQt_So_9CdU5RtpzF-QRvzzXg.ttf', [0x20,0x7e,0xa0,0xa3,0xa5,0xa5,0xa7,0xab,0xae,0xb0,0xb4,0xb4,0xb6,0xb8,0xba,0xbb,0xbf,0x107,0x10a,0x113,0x116,0x11b,0x11e,0x123,0x126,0x127,0x12a,0x12b,0x12e,0x133,0x136,0x137,0x139,0x13e,0x141,0x148,0x14a,0x14d,0x150,0x15b,0x15e,0x161,0x164,0x165,0x16a,0x17e,0x1cd,0x1ce,0x218,0x21b,0x237,0x237,0x2bc,0x2bc,0x2c6,0x2c7,0x2c9,0x2c9,0x2d7,0x2dd,0x300,0x304,0x306,0x308,0x30a,0x30c,0x312,0x312,0x326,0x328,0x331,0x331,0xe01,0xe3a,0xe3f,0xe5b,0x1e80,0x1e85,0x1e9e,0x1e9e,0x1ef2,0x1ef3,0x200b,0x200d,0x2010,0x2010,0x2013,0x2014,0x2018,0x201a,0x201c,0x201e,0x2022,0x2022,0x2026,0x2026,0x2039,0x203a,0x20ac,0x20ac,0x2122,0x2122,0x2212,0x2212,0x25cc,0x25cc,]), + NotoFont.fromFlatRanges('Noto Sans Tifinagh', 'http://fonts.gstatic.com/s/notosanstifinagh/v15/I_uzMoCduATTei9eI8dawkHIwvmhCvbn6rnEcXfs4Q.ttf', [0x20,0x20,0xa0,0xa0,0x2c7,0x2c7,0x301,0x302,0x304,0x304,0x306,0x307,0x309,0x309,0x323,0x323,0x331,0x331,0x200c,0x200d,0x202e,0x202e,0x25cc,0x25cc,0x2d30,0x2d67,0x2d6f,0x2d70,0x2d7f,0x2d7f,]), + NotoFont.fromFlatRanges('Noto Sans Tirhuta', 'http://fonts.gstatic.com/s/notosanstirhuta/v15/t5t6IQYRNJ6TWjahPR6X-M-apUyby7uGUBsTrn5P.ttf', [0x20,0x20,0xa0,0xa0,0x951,0x952,0x964,0x965,0x9f4,0x9f7,0x1cf2,0x1cf2,0x200c,0x200d,0x25cc,0x25cc,0xa830,0xa839,0x11480,0x114c7,0x114d0,0x114d9,]), + NotoFont.fromFlatRanges('Noto Sans Ugaritic', 'http://fonts.gstatic.com/s/notosansugaritic/v15/3qTwoiqhnSyU8TNFIdhZVCwbjCpkAXXkMhoIkiazfg.ttf', [0x20,0x20,0xa0,0xa0,0x10380,0x1039d,0x1039f,0x1039f,]), + NotoFont.fromFlatRanges('Noto Sans Vai', 'http://fonts.gstatic.com/s/notosansvai/v15/NaPecZTSBuhTirw6IaFn_UrURMTsDIRSfr0.ttf', [0x20,0x20,0xa0,0xa0,0xa500,0xa62b,]), + NotoFont.fromFlatRanges('Noto Sans Wancho', 'http://fonts.gstatic.com/s/notosanswancho/v15/zrf-0GXXyfn6Fs0lH9P4cUubP0GBqAPopiRfKp8.ttf', [0x20,0x20,0x22,0x22,0x27,0x29,0x2c,0x2f,0x5b,0x5d,0x7b,0x7b,0x7d,0x7d,0xa0,0xa0,0x201c,0x201d,0x25cc,0x25cc,0x1e2c0,0x1e2f9,0x1e2ff,0x1e2ff,]), + NotoFont.fromFlatRanges('Noto Sans Warang Citi', 'http://fonts.gstatic.com/s/notosanswarangciti/v15/EYqtmb9SzL1YtsZSScyKDXIeOv3w-zgsNvKRpeVCCXzdgA.ttf', [0x20,0x20,0x27,0x27,0xa0,0xa0,0x200c,0x200d,0x118a0,0x118f2,0x118ff,0x118ff,]), + NotoFont.fromFlatRanges('Noto Sans Yi', 'http://fonts.gstatic.com/s/notosansyi/v15/sJoD3LFXjsSdcnzn071rO3apxVDJNVgSNg.ttf', [0x20,0x20,0xa0,0xa0,0x3001,0x3002,0x3008,0x3011,0x3014,0x301b,0x30fb,0x30fb,0xa000,0xa48c,0xa490,0xa4c6,0xff61,0xff65,]), + NotoFont.fromFlatRanges('Noto Sans Zanabazar Square', 'http://fonts.gstatic.com/s/notosanszanabazarsquare/v15/Cn-jJsuGWQxOjaGwMQ6fOicyxLBEMRfDtkzl4uagQtJxOCEgN0Gc.ttf', [0x20,0x20,0xa0,0xa0,0x25cc,0x25cc,0x11a00,0x11a47,]), +]; diff --git a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart index 2473dfdae5021..0cbc7ea3a790c 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/font_fallbacks.dart @@ -3,18 +3,20 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:convert'; import 'dart:typed_data'; import 'package:ui/src/engine/canvaskit/renderer.dart'; import '../dom.dart'; import '../font_change_util.dart'; +import '../initialization.dart'; import '../renderer.dart'; import '../util.dart'; import 'canvaskit_api.dart'; +import 'font_fallback_data.dart'; import 'fonts.dart'; import 'interval_tree.dart'; +import 'noto_font.dart'; /// Global static font fallback data. class FontFallbackData { @@ -28,13 +30,9 @@ class FontFallbackData { /// Used for tests. static void debugReset() { _instance = FontFallbackData(); + notoDownloadQueue = FallbackFontDownloadQueue(); } - /// Whether or not "Noto Sans Symbols" and "Noto Color Emoji" fonts have been - /// downloaded. We download these as fallbacks when no other font covers the - /// given code units. - bool registeredSymbolsAndEmoji = false; - /// Code units that no known font has a glyph for. final Set codeUnitsWithNoKnownFont = {}; @@ -48,15 +46,9 @@ class FontFallbackData { final Map> ranges = >{}; - for (final NotoFont font in _notoFonts) { - // TODO(yjbanov): instead of mutating the font tree during reset, it's - // better to construct an immutable tree of resolved fonts - // pointing back to the original NotoFont objects. Then - // resetting the tree would be a matter of reconstructing - // the new resolved tree. - font.reset(); + for (final NotoFont font in fallbackFonts) { // ignore: prefer_foreach - for (final CodeunitRange range in font.approximateUnicodeRanges) { + for (final CodeunitRange range in font.computeUnicodeRanges()) { ranges.putIfAbsent(font, () => []).add(range); } } @@ -69,8 +61,6 @@ class FontFallbackData { final List globalFontFallbacks = ['Roboto']; - final Map fontFallbackCounts = {}; - /// A list of code units to check against the global fallback fonts. final Set _codeUnitsToCheckAgainstFallbackFonts = {}; @@ -85,6 +75,9 @@ class FontFallbackData { void ensureFontsSupportText(String text, List fontFamilies) { // TODO(hterkelsen): Make this faster for the common case where the text // is supported by the given fonts. + if (debugDisableFontFallbacks) { + return; + } // If the text is ASCII, then skip this check. bool isAscii = true; @@ -164,6 +157,9 @@ class FontFallbackData { _scheduledCodeUnitCheck = false; // We don't know if the remaining code units are covered by our fallback // fonts. Check them and update the cache. + if (_codeUnitsToCheckAgainstFallbackFonts.isEmpty) { + return; + } final List codeUnits = _codeUnitsToCheckAgainstFallbackFonts.toList(); _codeUnitsToCheckAgainstFallbackFonts.clear(); final List codeUnitsSupported = @@ -224,23 +220,19 @@ class FontFallbackData { printWarning('Failed to parse fallback font $family as a font.'); return; } - fontFallbackCounts.putIfAbsent(family, () => 0); - final int fontFallbackTag = fontFallbackCounts[family]!; - fontFallbackCounts[family] = fontFallbackCounts[family]! + 1; - final String countedFamily = '$family $fontFallbackTag'; // Insert emoji font before all other fallback fonts so we use the emoji // whenever it's available. - registeredFallbackFonts.add(RegisteredFont(bytes, countedFamily, typeface)); + registeredFallbackFonts.add(RegisteredFont(bytes, family, typeface)); // Insert emoji font before all other fallback fonts so we use the emoji // whenever it's available. - if (family == 'Noto Color Emoji Compat') { + if (family == 'Noto Emoji') { if (globalFontFallbacks.first == 'Roboto') { - globalFontFallbacks.insert(1, countedFamily); + globalFontFallbacks.insert(1, family); } else { - globalFontFallbacks.insert(0, countedFamily); + globalFontFallbacks.insert(0, family); } } else { - globalFontFallbacks.add(countedFamily); + globalFontFallbacks.add(family); } } } @@ -261,212 +253,25 @@ Future findFontsForMissingCodeunits(List codeUnits) async { } } - for (final NotoFont font in fonts) { - await font.ensureResolved(); - } - // The call to `findMinimumFontsForCodeUnits` will remove all code units that // were matched by `fonts` from `unmatchedCodeUnits`. final Set unmatchedCodeUnits = Set.from(coveredCodeUnits); fonts = findMinimumFontsForCodeUnits(unmatchedCodeUnits, fonts); - final Set<_ResolvedNotoSubset> resolvedFonts = <_ResolvedNotoSubset>{}; - for (final int codeUnit in coveredCodeUnits) { - for (final NotoFont font in fonts) { - if (font.resolvedFont == null) { - // We failed to resolve the font earlier. - continue; - } - resolvedFonts.addAll(font.resolvedFont!.tree.intersections(codeUnit)); - } - } - resolvedFonts.forEach(notoDownloadQueue.add); + fonts.forEach(notoDownloadQueue.add); // We looked through the Noto font tree and didn't find any font families - // covering some code units, or we did find a font family, but when we - // downloaded the fonts we found that they actually didn't cover them. So - // we try looking them up in the symbols and emojis fonts. + // covering some code units. if (missingCodeUnits.isNotEmpty || unmatchedCodeUnits.isNotEmpty) { - if (!data.registeredSymbolsAndEmoji) { - await _registerSymbolsAndEmoji(); - } else { - if (!notoDownloadQueue.isPending) { - printWarning( - 'Could not find a set of Noto fonts to display all missing ' - 'characters. Please add a font asset for the missing characters.' - ' See: https://flutter.dev/docs/cookbook/design/fonts'); - data.codeUnitsWithNoKnownFont.addAll(missingCodeUnits); - } + if (!notoDownloadQueue.isPending) { + printWarning('Could not find a set of Noto fonts to display all missing ' + 'characters. Please add a font asset for the missing characters.' + ' See: https://flutter.dev/docs/cookbook/design/fonts'); + data.codeUnitsWithNoKnownFont.addAll(missingCodeUnits); } } } -/// Parse the CSS file for a font and make a list of resolved subsets. -/// -/// A CSS file from Google Fonts looks like this: -/// -/// /* [0] */ -/// @font-face { -/// font-family: 'Noto Sans KR'; -/// font-style: normal; -/// font-weight: 400; -/// src: url(https://fonts.gstatic.com/s/notosanskr/v13/PbykFmXiEBPT4ITbgNA5Cgm20xz64px_1hVWr0wuPNGmlQNMEfD4.0.woff2) format('woff2'); -/// unicode-range: U+f9ca-fa0b, U+ff03-ff05, U+ff07, U+ff0a-ff0b, U+ff0d-ff19, U+ff1b, U+ff1d, U+ff20-ff5b, U+ff5d, U+ffe0-ffe3, U+ffe5-ffe6; -/// } -/// /* [1] */ -/// @font-face { -/// font-family: 'Noto Sans KR'; -/// font-style: normal; -/// font-weight: 400; -/// src: url(https://fonts.gstatic.com/s/notosanskr/v13/PbykFmXiEBPT4ITbgNA5Cgm20xz64px_1hVWr0wuPNGmlQNMEfD4.1.woff2) format('woff2'); -/// unicode-range: U+f92f-f980, U+f982-f9c9; -/// } -/// /* [2] */ -/// @font-face { -/// font-family: 'Noto Sans KR'; -/// font-style: normal; -/// font-weight: 400; -/// src: url(https://fonts.gstatic.com/s/notosanskr/v13/PbykFmXiEBPT4ITbgNA5Cgm20xz64px_1hVWr0wuPNGmlQNMEfD4.2.woff2) format('woff2'); -/// unicode-range: U+d723-d728, U+d72a-d733, U+d735-d748, U+d74a-d74f, U+d752-d753, U+d755-d757, U+d75a-d75f, U+d762-d764, U+d766-d768, U+d76a-d76b, U+d76d-d76f, U+d771-d787, U+d789-d78b, U+d78d-d78f, U+d791-d797, U+d79a, U+d79c, U+d79e-d7a3, U+f900-f909, U+f90b-f92e; -/// } -_ResolvedNotoFont? _makeResolvedNotoFontFromCss(String css, String name) { - final List<_ResolvedNotoSubset> subsets = <_ResolvedNotoSubset>[]; - bool resolvingFontFace = false; - String? fontFaceUrl; - List? fontFaceUnicodeRanges; - for (final String line in LineSplitter.split(css)) { - // Search for the beginning of a @font-face. - if (!resolvingFontFace) { - if (line == '@font-face {') { - resolvingFontFace = true; - } else { - continue; - } - } else { - // We are resolving a @font-face, read out the url and ranges. - if (line.startsWith(' src:')) { - final int urlStart = line.indexOf('url('); - if (urlStart == -1) { - printWarning('Unable to resolve Noto font URL: $line'); - return null; - } - final int urlEnd = line.indexOf(')'); - fontFaceUrl = line.substring(urlStart + 4, urlEnd); - } else if (line.startsWith(' unicode-range:')) { - fontFaceUnicodeRanges = []; - final String rangeString = line.substring(17, line.length - 1); - final List rawRanges = rangeString.split(', '); - for (final String rawRange in rawRanges) { - final List startEnd = rawRange.split('-'); - if (startEnd.length == 1) { - final String singleRange = startEnd.single; - assert(singleRange.startsWith('U+')); - final int rangeValue = - int.parse(singleRange.substring(2), radix: 16); - fontFaceUnicodeRanges.add(CodeunitRange(rangeValue, rangeValue)); - } else { - assert(startEnd.length == 2); - final String startRange = startEnd[0]; - final String endRange = startEnd[1]; - assert(startRange.startsWith('U+')); - final int startValue = - int.parse(startRange.substring(2), radix: 16); - final int endValue = int.parse(endRange, radix: 16); - fontFaceUnicodeRanges.add(CodeunitRange(startValue, endValue)); - } - } - } else if (line == '}') { - if (fontFaceUrl == null || fontFaceUnicodeRanges == null) { - printWarning('Unable to parse Google Fonts CSS: $css'); - return null; - } - subsets - .add(_ResolvedNotoSubset(fontFaceUrl, name, fontFaceUnicodeRanges)); - resolvingFontFace = false; - } else { - continue; - } - } - } - - if (resolvingFontFace) { - printWarning('Unable to parse Google Fonts CSS: $css'); - return null; - } - - final Map<_ResolvedNotoSubset, List> rangesMap = - <_ResolvedNotoSubset, List>{}; - for (final _ResolvedNotoSubset subset in subsets) { - // ignore: prefer_foreach - for (final CodeunitRange range in subset.ranges) { - rangesMap.putIfAbsent(subset, () => []).add(range); - } - } - - if (rangesMap.isEmpty) { - printWarning('Parsed Google Fonts CSS was empty: $css'); - return null; - } - - final IntervalTree<_ResolvedNotoSubset> tree = - IntervalTree<_ResolvedNotoSubset>.createFromRanges(rangesMap); - - return _ResolvedNotoFont(name, subsets, tree); -} - -/// In the case where none of the known Noto Fonts cover a set of code units, -/// try the Symbols and Emoji fonts. We don't know the exact range of code units -/// that are covered by these fonts, so we download them and hope for the best. -Future _registerSymbolsAndEmoji() async { - final FontFallbackData data = FontFallbackData.instance; - if (data.registeredSymbolsAndEmoji) { - return; - } - data.registeredSymbolsAndEmoji = true; - const String emojiUrl = - 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'; - const String symbolsUrl = - 'https://fonts.googleapis.com/css2?family=Noto+Sans+Symbols'; - - final String emojiCss = - await notoDownloadQueue.downloader.downloadAsString(emojiUrl); - final String symbolsCss = - await notoDownloadQueue.downloader.downloadAsString(symbolsUrl); - - String? extractUrlFromCss(String css) { - for (final String line in LineSplitter.split(css)) { - if (line.startsWith(' src:')) { - final int urlStart = line.indexOf('url('); - if (urlStart == -1) { - printWarning('Unable to resolve Noto font URL: $line'); - return null; - } - final int urlEnd = line.indexOf(')'); - return line.substring(urlStart + 4, urlEnd); - } - } - printWarning('Unable to determine URL for Noto font'); - return null; - } - - final String? emojiFontUrl = extractUrlFromCss(emojiCss); - final String? symbolsFontUrl = extractUrlFromCss(symbolsCss); - - if (emojiFontUrl != null) { - notoDownloadQueue.add(_ResolvedNotoSubset( - emojiFontUrl, 'Noto Color Emoji Compat', const [])); - } else { - printWarning('Error parsing CSS for Noto Emoji font.'); - } - - if (symbolsFontUrl != null) { - notoDownloadQueue.add(_ResolvedNotoSubset( - symbolsFontUrl, 'Noto Sans Symbols', const [])); - } else { - printWarning('Error parsing CSS for Noto Symbols font.'); - } -} - /// Finds the minimum set of fonts which covers all of the [codeUnits]. /// /// Removes all code units covered by [fonts] from [codeUnits]. The code @@ -492,7 +297,7 @@ Set findMinimumFontsForCodeUnits( for (final NotoFont font in fonts) { int codeUnitsCovered = 0; for (final int codeUnit in codeUnits) { - if (font.resolvedFont?.tree.containsDeep(codeUnit) ?? false) { + if (font.contains(codeUnit)) { codeUnitsCovered++; } } @@ -534,321 +339,47 @@ Set findMinimumFontsForCodeUnits( if (bestFonts.contains(_notoSansJP)) { bestFont = _notoSansJP; } + } else if (language == 'ko') { + if (bestFonts.contains(_notoSansKR)) { + bestFont = _notoSansKR; + } + } else if (bestFonts.contains(_notoSansSC)) { + bestFont = _notoSansSC; + } + } else { + // To be predictable, if there is a tie for best font, choose a font + // from this list first, then just choose the first font. + if (bestFonts.contains(_notoSymbols)) { + bestFont = _notoSymbols; + } else if (bestFonts.contains(_notoSansSC)) { + bestFont = _notoSansSC; } } } codeUnits.removeWhere((int codeUnit) { - return bestFont.resolvedFont!.tree.containsDeep(codeUnit); + return bestFont.contains(codeUnit); }); - minimumFonts.addAll(bestFonts); + minimumFonts.add(bestFont); } return minimumFonts; } -class NotoFont { - NotoFont(this.name, this.approximateUnicodeRanges); - - final String name; - final List approximateUnicodeRanges; - - Completer? _decodingCompleter; - _ResolvedNotoFont? resolvedFont; - - String get googleFontsCssUrl => - 'https://fonts.googleapis.com/css2?family=${name.replaceAll(' ', '+')}'; - - Future ensureResolved() async { - if (resolvedFont == null) { - if (_decodingCompleter == null) { - _decodingCompleter = Completer(); - final String googleFontCss = await notoDownloadQueue.downloader - .downloadAsString(googleFontsCssUrl); - final _ResolvedNotoFont? googleFont = - _makeResolvedNotoFontFromCss(googleFontCss, name); - resolvedFont = googleFont; - _decodingCompleter!.complete(); - } else { - await _decodingCompleter!.future; - } - } - } - - void reset() { - resolvedFont = null; - _decodingCompleter = null; - } -} - -class CodeunitRange { - const CodeunitRange(this.start, this.end); - - final int start; - final int end; - - bool contains(int codeUnit) { - return start <= codeUnit && codeUnit <= end; - } - - @override - bool operator ==(dynamic other) { - if (other is! CodeunitRange) { - return false; - } - final CodeunitRange range = other; - return range.start == start && range.end == end; - } - - @override - int get hashCode => Object.hash(start, end); - - @override - String toString() => '[$start, $end]'; -} - -class _ResolvedNotoFont { - const _ResolvedNotoFont(this.name, this.subsets, this.tree); - - final String name; - final List<_ResolvedNotoSubset> subsets; - final IntervalTree<_ResolvedNotoSubset> tree; -} - -class _ResolvedNotoSubset { - _ResolvedNotoSubset(this.url, this.family, this.ranges); - - final String url; - final String family; - final List ranges; - - @override - String toString() => '_ResolvedNotoSubset($family, $url)'; -} +NotoFont _notoSansSC = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans SC'); +NotoFont _notoSansTC = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans TC'); +NotoFont _notoSansHK = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans HK'); +NotoFont _notoSansJP = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans JP'); +NotoFont _notoSansKR = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans KR'); +List _cjkFonts = [_notoSansSC, _notoSansTC, _notoSansHK, _notoSansJP, _notoSansKR]; -NotoFont _notoSansSC = NotoFont('Noto Sans SC', [ - const CodeunitRange(12288, 12591), - const CodeunitRange(12800, 13311), - const CodeunitRange(19968, 40959), - const CodeunitRange(65072, 65135), - const CodeunitRange(65280, 65519), -]); - -NotoFont _notoSansTC = NotoFont('Noto Sans TC', [ - const CodeunitRange(12288, 12351), - const CodeunitRange(12549, 12585), - const CodeunitRange(19968, 40959), -]); - -NotoFont _notoSansHK = NotoFont('Noto Sans HK', [ - const CodeunitRange(12288, 12351), - const CodeunitRange(12549, 12585), - const CodeunitRange(19968, 40959), -]); - -NotoFont _notoSansJP = NotoFont('Noto Sans JP', [ - const CodeunitRange(12288, 12543), - const CodeunitRange(19968, 40959), - const CodeunitRange(65280, 65519), -]); - -List _cjkFonts = [ - _notoSansSC, - _notoSansTC, - _notoSansHK, - _notoSansJP, -]; - -List _notoFonts = [ - _notoSansSC, - _notoSansTC, - _notoSansHK, - _notoSansJP, - NotoFont('Noto Naskh Arabic UI', [ - const CodeunitRange(1536, 1791), - const CodeunitRange(8204, 8206), - const CodeunitRange(8208, 8209), - const CodeunitRange(8271, 8271), - const CodeunitRange(11841, 11841), - const CodeunitRange(64336, 65023), - const CodeunitRange(65132, 65276), - ]), - NotoFont('Noto Sans Armenian', [ - const CodeunitRange(1328, 1424), - const CodeunitRange(64275, 64279), - ]), - NotoFont('Noto Sans Bengali UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(2433, 2555), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Myanmar UI', [ - const CodeunitRange(4096, 4255), - const CodeunitRange(8204, 8205), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Egyptian Hieroglyphs', [ - const CodeunitRange(77824, 78894), - ]), - NotoFont('Noto Sans Ethiopic', [ - const CodeunitRange(4608, 5017), - const CodeunitRange(11648, 11742), - const CodeunitRange(43777, 43822), - ]), - NotoFont('Noto Sans Georgian', [ - const CodeunitRange(1417, 1417), - const CodeunitRange(4256, 4351), - const CodeunitRange(11520, 11567), - ]), - NotoFont('Noto Sans Gujarati UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(2688, 2815), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - const CodeunitRange(43056, 43065), - ]), - NotoFont('Noto Sans Gurmukhi UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(2561, 2677), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - const CodeunitRange(9772, 9772), - const CodeunitRange(43056, 43065), - ]), - NotoFont('Noto Sans Hebrew', [ - const CodeunitRange(1424, 1535), - const CodeunitRange(8362, 8362), - const CodeunitRange(9676, 9676), - const CodeunitRange(64285, 64335), - ]), - NotoFont('Noto Sans Devanagari UI', [ - const CodeunitRange(2304, 2431), - const CodeunitRange(7376, 7414), - const CodeunitRange(7416, 7417), - const CodeunitRange(8204, 8205), - const CodeunitRange(8360, 8360), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - const CodeunitRange(43056, 43065), - const CodeunitRange(43232, 43259), - ]), - NotoFont('Noto Sans Kannada UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(3202, 3314), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Khmer UI', [ - const CodeunitRange(6016, 6143), - const CodeunitRange(8204, 8204), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans KR', [ - const CodeunitRange(12593, 12686), - const CodeunitRange(12800, 12828), - const CodeunitRange(12896, 12923), - const CodeunitRange(44032, 55215), - ]), - NotoFont('Noto Sans Lao UI', [ - const CodeunitRange(3713, 3807), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Malayalam UI', [ - const CodeunitRange(775, 775), - const CodeunitRange(803, 803), - const CodeunitRange(2404, 2405), - const CodeunitRange(3330, 3455), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Sinhala', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(3458, 3572), - const CodeunitRange(8204, 8205), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Tamil UI', [ - const CodeunitRange(2404, 2405), - const CodeunitRange(2946, 3066), - const CodeunitRange(8204, 8205), - const CodeunitRange(8377, 8377), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Telugu UI', [ - const CodeunitRange(2385, 2386), - const CodeunitRange(2404, 2405), - const CodeunitRange(3072, 3199), - const CodeunitRange(7386, 7386), - const CodeunitRange(8204, 8205), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans Thai UI', [ - const CodeunitRange(3585, 3675), - const CodeunitRange(8204, 8205), - const CodeunitRange(9676, 9676), - ]), - NotoFont('Noto Sans', [ - const CodeunitRange(0, 255), - const CodeunitRange(305, 305), - const CodeunitRange(338, 339), - const CodeunitRange(699, 700), - const CodeunitRange(710, 710), - const CodeunitRange(730, 730), - const CodeunitRange(732, 732), - const CodeunitRange(8192, 8303), - const CodeunitRange(8308, 8308), - const CodeunitRange(8364, 8364), - const CodeunitRange(8482, 8482), - const CodeunitRange(8593, 8593), - const CodeunitRange(8595, 8595), - const CodeunitRange(8722, 8722), - const CodeunitRange(8725, 8725), - const CodeunitRange(65279, 65279), - const CodeunitRange(65533, 65533), - const CodeunitRange(1024, 1119), - const CodeunitRange(1168, 1169), - const CodeunitRange(1200, 1201), - const CodeunitRange(8470, 8470), - const CodeunitRange(1120, 1327), - const CodeunitRange(7296, 7304), - const CodeunitRange(8372, 8372), - const CodeunitRange(11744, 11775), - const CodeunitRange(42560, 42655), - const CodeunitRange(65070, 65071), - const CodeunitRange(880, 1023), - const CodeunitRange(7936, 8191), - const CodeunitRange(256, 591), - const CodeunitRange(601, 601), - const CodeunitRange(7680, 7935), - const CodeunitRange(8224, 8224), - const CodeunitRange(8352, 8363), - const CodeunitRange(8365, 8399), - const CodeunitRange(8467, 8467), - const CodeunitRange(11360, 11391), - const CodeunitRange(42784, 43007), - const CodeunitRange(258, 259), - const CodeunitRange(272, 273), - const CodeunitRange(296, 297), - const CodeunitRange(360, 361), - const CodeunitRange(416, 417), - const CodeunitRange(431, 432), - const CodeunitRange(7840, 7929), - const CodeunitRange(8363, 8363), - ]), -]; +NotoFont _notoSymbols = fallbackFonts.singleWhere((NotoFont font) => font.name == 'Noto Sans Symbols'); class FallbackFontDownloadQueue { NotoDownloader downloader = NotoDownloader(); - final Set<_ResolvedNotoSubset> downloadedSubsets = <_ResolvedNotoSubset>{}; - final Map pendingSubsets = - {}; + final Set downloadedFonts = {}; + final Map pendingFonts = {}; - bool get isPending => pendingSubsets.isNotEmpty || _fontsLoading != null; + bool get isPending => pendingFonts.isNotEmpty || _fontsLoading != null; Future? _fontsLoading; bool get debugIsLoadingFonts => _fontsLoading != null; @@ -860,9 +391,9 @@ class FallbackFontDownloadQueue { if (_fontsLoading != null) { await _fontsLoading; } - if (pendingSubsets.isNotEmpty) { + if (pendingFonts.isNotEmpty) { await Future.delayed(const Duration(milliseconds: 100)); - if (pendingSubsets.isEmpty) { + if (pendingFonts.isEmpty) { await Future.delayed(const Duration(milliseconds: 100)); } } @@ -872,13 +403,13 @@ class FallbackFontDownloadQueue { } } - void add(_ResolvedNotoSubset subset) { - if (downloadedSubsets.contains(subset) || - pendingSubsets.containsKey(subset.url)) { + void add(NotoFont font) { + if (downloadedFonts.contains(font) || + pendingFonts.containsKey(font.url)) { return; } - final bool firstInBatch = pendingSubsets.isEmpty; - pendingSubsets[subset.url] = subset; + final bool firstInBatch = pendingFonts.isEmpty; + pendingFonts[font.url] = font; if (firstInBatch) { Timer.run(startDownloads); } @@ -887,20 +418,20 @@ class FallbackFontDownloadQueue { Future startDownloads() async { final Map> downloads = >{}; final Map downloadedData = {}; - for (final _ResolvedNotoSubset subset in pendingSubsets.values) { - downloads[subset.url] = Future(() async { + for (final NotoFont font in pendingFonts.values) { + downloads[font.url] = Future(() async { ByteBuffer buffer; try { - buffer = await downloader.downloadAsBytes(subset.url, - debugDescription: subset.family); + buffer = await downloader.downloadAsBytes(font.url, + debugDescription: font.name); } catch (e) { - pendingSubsets.remove(subset.url); - printWarning('Failed to load font ${subset.family} at ${subset.url}'); + pendingFonts.remove(font.url); + printWarning('Failed to load font ${font.name} at ${font.url}'); printWarning(e.toString()); return; } - downloadedSubsets.add(subset); - downloadedData[subset.url] = buffer.asUint8List(); + downloadedFonts.add(font); + downloadedData[font.url] = buffer.asUint8List(); }); } @@ -912,10 +443,10 @@ class FallbackFontDownloadQueue { final List downloadOrder = (downloadedData.keys.toList()..sort()).reversed.toList(); for (final String url in downloadOrder) { - final _ResolvedNotoSubset subset = pendingSubsets.remove(url)!; + final NotoFont font = pendingFonts.remove(url)!; final Uint8List bytes = downloadedData[url]!; - FontFallbackData.instance.registerFallbackFont(subset.family, bytes); - if (pendingSubsets.isEmpty) { + FontFallbackData.instance.registerFallbackFont(font.name, bytes); + if (pendingFonts.isEmpty) { _fontsLoading = renderer.fontCollection.ensureFontsLoaded(); try { await _fontsLoading; @@ -926,7 +457,7 @@ class FallbackFontDownloadQueue { } } - if (pendingSubsets.isNotEmpty) { + if (pendingFonts.isNotEmpty) { await startDownloads(); } } diff --git a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart index 29d16421bbb5b..7f10373c51527 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/interval_tree.dart @@ -4,7 +4,7 @@ import 'dart:math' as math; -import 'font_fallbacks.dart' show CodeunitRange; +import 'noto_font.dart' show CodeunitRange; /// A tree which stores a set of intervals that can be queried for intersection. class IntervalTree { diff --git a/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart b/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart new file mode 100644 index 0000000000000..83964c6f4222c --- /dev/null +++ b/lib/web_ui/lib/src/engine/canvaskit/noto_font.dart @@ -0,0 +1,98 @@ +// 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. + +class NotoFont { + const NotoFont(this.name, this.url, this._rangeStarts, this._rangeEnds); + + factory NotoFont.fromFlatRanges(String name, String url, List flatRanges) { + final List starts = []; + final List ends = []; + for (int i = 0; i < flatRanges.length; i += 2) { + starts.add(flatRanges[i]); + ends.add(flatRanges[i+1]); + } + return NotoFont(name, url, starts, ends); + } + + final String name; + final String url; + // A sorted list of Unicode range start points. + final List _rangeStarts; + + // A sorted list of Unicode range end points. + final List _rangeEnds; + + List computeUnicodeRanges() { + final List result = []; + for (int i = 0; i < _rangeStarts.length; i++) { + result.add(CodeunitRange(_rangeStarts[i], _rangeEnds[i])); + } + return result; + } + + // Returns `true` if this font has a glyph for the given [codeunit]. + bool contains(int codeUnit) { + // Binary search through the starts and ends to see if there + // is a range that contains the codeunit. + int min = 0; + int max = _rangeStarts.length - 1; + // Search for the first rangeStart that is greater than codeunit. + while (min < max) { + final int mid = (min + max) ~/ 2; + if (_rangeStarts[mid] > codeUnit) { + if (mid == 0) { + final int rangeStart = _rangeStarts[mid]; + final int rangeEnd = _rangeEnds[mid]; + return rangeStart <= codeUnit && codeUnit <= rangeEnd; + } + final int rangeStart = _rangeStarts[mid - 1]; + if (rangeStart <= codeUnit) { + final int rangeEnd = _rangeEnds[mid - 1]; + return rangeStart <= codeUnit && codeUnit <= rangeEnd; + } else { + max = mid - 1; + } + } else if (_rangeStarts[mid] < codeUnit) { + // If this is the last index, check if the codeunit is contained within it. + if (mid == _rangeStarts.length) { + final int rangeStart = _rangeStarts[mid]; + final int rangeEnd = _rangeEnds[mid]; + return rangeStart <= codeUnit && codeUnit <= rangeEnd; + } + min = mid + 1; + } else { + // _rangeStarts[mid] == codeUnit + return true; + } + } + return false; + } +} + +class CodeunitRange { + const CodeunitRange(this.start, this.end); + + final int start; + final int end; + + + bool contains(int codeUnit) { + return start <= codeUnit && codeUnit <= end; + } + + @override + bool operator ==(dynamic other) { + if (other is! CodeunitRange) { + return false; + } + final CodeunitRange range = other; + return range.start == start && range.end == end; + } + + @override + int get hashCode => Object.hash(start, end); + + @override + String toString() => '[$start, $end]'; +} diff --git a/lib/web_ui/lib/src/engine/initialization.dart b/lib/web_ui/lib/src/engine/initialization.dart index 682f1e13c9b75..025b1399f78b1 100644 --- a/lib/web_ui/lib/src/engine/initialization.dart +++ b/lib/web_ui/lib/src/engine/initialization.dart @@ -272,6 +272,19 @@ void _addUrlStrategyListener() { }); } +/// Whether to disable the font fallback system. +/// +/// We need to disable font fallbacks for some framework tests because +/// Flutter error messages may contain an arrow symbol which is not +/// covered by ASCII fonts. This causes us to try to download the +/// Noto Sans Symbols font, which kicks off a `Timer` which doesn't +/// complete before the Widget tree is disposed (this is by design). +bool get debugDisableFontFallbacks => _debugDisableFontFallbacks; +set debugDisableFontFallbacks(bool value) { + _debugDisableFontFallbacks = value; +} +bool _debugDisableFontFallbacks = false; + /// The shared instance of PlatformViewManager shared across the engine to handle /// rendering of PlatformViews into the web app. // TODO(dit): How to make this overridable from tests? diff --git a/lib/web_ui/test/canvaskit/canvas_golden_test.dart b/lib/web_ui/test/canvaskit/canvas_golden_test.dart index 3c093f7d6a5f9..a27a2e37b2d20 100644 --- a/lib/web_ui/test/canvaskit/canvas_golden_test.dart +++ b/lib/web_ui/test/canvaskit/canvas_golden_test.dart @@ -33,6 +33,7 @@ void testMain() { setUp(() { expect(notoDownloadQueue.downloader.debugActiveDownloadCount, 0); expect(notoDownloadQueue.isPending, isFalse); + FontFallbackData.debugReset(); }); tearDown(() { @@ -563,7 +564,6 @@ void testMain() { // some of these symbols. To make sure the test produces predictable // results we reset the fallback data forcing the engine to reload // fallbacks, which for this test will only load Noto Symbols. - FontFallbackData.debugReset(); await testTextStyle( 'symbols', outerText: '← ↑ → ↓ ', @@ -819,7 +819,6 @@ void testMain() { Future testSampleText(String language, String text, {ui.TextDirection textDirection = ui.TextDirection.ltr, bool write = false}) async { - FontFallbackData.debugReset(); const double testWidth = 300; double paragraphHeight = 0; final CkPicture picture = await generatePictureWhenFontsStable(() { @@ -1328,7 +1327,7 @@ Future testTextStyle( write: write, ); expect(notoDownloadQueue.debugIsLoadingFonts, isFalse); - expect(notoDownloadQueue.pendingSubsets, isEmpty); + expect(notoDownloadQueue.pendingFonts, isEmpty); expect(notoDownloadQueue.downloader.debugActiveDownloadCount, 0); } diff --git a/lib/web_ui/test/canvaskit/common.dart b/lib/web_ui/test/canvaskit/common.dart index bbf0db785858b..149a8bc9df6ee 100644 --- a/lib/web_ui/test/canvaskit/common.dart +++ b/lib/web_ui/test/canvaskit/common.dart @@ -23,6 +23,7 @@ void setUpCanvasKitTest() { setUpAll(() async { expect(renderer, isA(), reason: 'This test must run in CanvasKit mode.'); debugResetBrowserSupportsFinalizationRegistry(); + debugDisableFontFallbacks = false; await initializeEngine(assetManager: WebOnlyMockAssetManager()); }); diff --git a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart index b8ff69a560516..66ba97d7eb9fa 100644 --- a/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart +++ b/lib/web_ui/test/canvaskit/fallback_fonts_golden_test.dart @@ -28,10 +28,20 @@ void testMain() { ui.PlatformMessageCallback? savedCallback; setUp(() { + FontFallbackData.debugReset(); notoDownloadQueue.downloader = TestDownloader(); TestDownloader.mockDownloads.clear(); + final String notoSansArabicUrl = fallbackFonts + .singleWhere((NotoFont font) => font.name == 'Noto Sans Arabic') + .url; + final String notoEmojiUrl = fallbackFonts + .singleWhere((NotoFont font) => font.name == 'Noto Emoji') + .url; + TestDownloader.mockDownloads[notoSansArabicUrl] = + '/assets/fonts/NotoNaskhArabic-Regular.ttf'; + TestDownloader.mockDownloads[notoEmojiUrl] = + '/assets/fonts/NotoColorEmoji.ttf'; savedCallback = ui.window.onPlatformMessage; - FontFallbackData.debugReset(); }); tearDown(() { @@ -42,21 +52,8 @@ void testMain() { expect(FontFallbackData.instance.globalFontFallbacks, contains('Roboto')); }); - test('will download Noto Naskh Arabic if Arabic text is added', () async { + test('will download Noto Sans Arabic if Arabic text is added', () async { final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = - ''' -/* arabic */ -@font-face { - font-family: 'Noto Naskh Arabic UI'; - font-style: normal; - font-weight: 400; - src: url(/assets/fonts/NotoNaskhArabic-Regular.ttf) format('ttf'); - unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC; -} -'''; - expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); // Creating this paragraph should cause us to start to download the @@ -70,7 +67,7 @@ void testMain() { await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, - contains('Noto Naskh Arabic UI 0')); + contains('Noto Sans Arabic')); final CkPictureRecorder recorder = CkPictureRecorder(); final CkCanvas canvas = recorder.beginRecording(kDefaultRegion); @@ -97,28 +94,6 @@ void testMain() { test('will put the Noto Emoji font before other fallback fonts in the list', () async { final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'] = - ''' -@font-face { - font-family: 'Noto Color Emoji'; - src: url(/assets/fonts/NotoColorEmoji.ttf) format('ttf'); -} -'''; - - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = - ''' -/* arabic */ -@font-face { - font-family: 'Noto Naskh Arabic UI'; - font-style: normal; - font-weight: 400; - src: url(/assets/fonts/NotoNaskhArabic-Regular.ttf) format('ttf'); - unicode-range: U+0600-06FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE80-FEFC; -} -'''; - expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); // Creating this paragraph should cause us to start to download the @@ -132,7 +107,7 @@ void testMain() { await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, - ['Roboto', 'Noto Naskh Arabic UI 0']); + ['Roboto', 'Noto Sans Arabic']); pb = CkParagraphBuilder( CkParagraphStyle(), @@ -148,23 +123,14 @@ void testMain() { expect(FontFallbackData.instance.globalFontFallbacks, [ 'Roboto', - 'Noto Color Emoji Compat 0', - 'Noto Naskh Arabic UI 0', + 'Noto Emoji', + 'Noto Sans Arabic', ]); }); test('will download Noto Emojis and Noto Symbols if no matching Noto Font', () async { final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat'] = - ''' -@font-face { - font-family: 'Noto Color Emoji'; - src: url(/assets/fonts/NotoColorEmoji.ttf) format('ttf'); -} -'''; - expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); // Creating this paragraph should cause us to start to download the @@ -178,7 +144,7 @@ void testMain() { await notoDownloadQueue.debugWhenIdle(); expect(FontFallbackData.instance.globalFontFallbacks, - contains('Noto Color Emoji Compat 0')); + contains('Noto Emoji')); final CkPictureRecorder recorder = CkPictureRecorder(); final CkCanvas canvas = recorder.beginRecording(kDefaultRegion); @@ -202,30 +168,6 @@ void testMain() { // TODO(hterkelsen): https://github.com/flutter/flutter/issues/71520 }, skip: isSafari || isFirefox); - test('will gracefully fail if we cannot parse the Google Fonts CSS', - () async { - final Rasterizer rasterizer = CanvasKitRenderer.instance.rasterizer; - TestDownloader.mockDownloads[ - 'https://fonts.googleapis.com/css2?family=Noto+Naskh+Arabic+UI'] = - 'invalid CSS... this should cause our parser to fail'; - - expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); - - // Creating this paragraph should cause us to start to download the - // fallback font. - final CkParagraphBuilder pb = CkParagraphBuilder( - CkParagraphStyle(), - ); - pb.addText('مرحبا'); - - // Flush microtasks and test that we didn't start any downloads. - rasterizer.debugRunPostFrameCallbacks(); - await Future.delayed(Duration.zero); - - expect(notoDownloadQueue.isPending, isFalse); - expect(FontFallbackData.instance.globalFontFallbacks, ['Roboto']); - }); - // Regression test for https://github.com/flutter/flutter/issues/75836 // When we had this bug our font fallback resolution logic would end up in an // infinite loop and this test would freeze and time out. @@ -240,16 +182,12 @@ void testMain() { CkParagraphBuilder(CkParagraphStyle()).addText('ヽಠ'); rasterizer.debugRunPostFrameCallbacks(); - await notoDownloadQueue.downloader.debugWhenIdle(); + await notoDownloadQueue.debugWhenIdle(); expect( loggingDownloader.log, [ - 'https://fonts.googleapis.com/css2?family=Noto+Sans+SC', - 'https://fonts.googleapis.com/css2?family=Noto+Sans+JP', - 'https://fonts.googleapis.com/css2?family=Noto+Sans+Kannada+UI', 'Noto Sans SC', - 'Noto Sans JP', - 'Noto Sans Kannada UI', + 'Noto Sans Kannada', ], ); @@ -257,7 +195,7 @@ void testMain() { loggingDownloader.log.clear(); CkParagraphBuilder(CkParagraphStyle()).addText('ヽಠ'); rasterizer.debugRunPostFrameCallbacks(); - await notoDownloadQueue.downloader.debugWhenIdle(); + await notoDownloadQueue.debugWhenIdle(); expect(loggingDownloader.log, isEmpty); }); @@ -274,7 +212,7 @@ void testMain() { FontFallbackData.instance.notoTree; for (final NotoFont font in notoTree.root.enumerateAllElements()) { testedFonts.add(font.name); - for (final CodeunitRange range in font.approximateUnicodeRanges) { + for (final CodeunitRange range in font.computeUnicodeRanges()) { for (int codeUnit = range.start; codeUnit < range.end; codeUnit += 1) { @@ -289,30 +227,146 @@ void testMain() { testedFonts, unorderedEquals({ 'Noto Sans', - 'Noto Sans Malayalam UI', + 'Noto Emoji', + 'Noto Sans Symbols', + 'Noto Sans Symbols 2', + 'Noto Sans Adlam', + 'Noto Sans Anatolian Hieroglyphs', + 'Noto Sans Arabic', 'Noto Sans Armenian', + 'Noto Sans Avestan', + 'Noto Sans Balinese', + 'Noto Sans Bamum', + 'Noto Sans Bassa Vah', + 'Noto Sans Batak', + 'Noto Sans Bengali', + 'Noto Sans Bhaiksuki', + 'Noto Sans Brahmi', + 'Noto Sans Buginese', + 'Noto Sans Buhid', + 'Noto Sans Canadian Aboriginal', + 'Noto Sans Carian', + 'Noto Sans Caucasian Albanian', + 'Noto Sans Chakma', + 'Noto Sans Cham', + 'Noto Sans Cherokee', + 'Noto Sans Coptic', + 'Noto Sans Cuneiform', + 'Noto Sans Cypriot', + 'Noto Sans Deseret', + 'Noto Sans Devanagari', + 'Noto Sans Duployan', + 'Noto Sans Egyptian Hieroglyphs', + 'Noto Sans Elbasan', + 'Noto Sans Elymaic', 'Noto Sans Georgian', + 'Noto Sans Glagolitic', + 'Noto Sans Gothic', + 'Noto Sans Grantha', + 'Noto Sans Gujarati', + 'Noto Sans Gunjala Gondi', + 'Noto Sans Gurmukhi', + 'Noto Sans HK', + 'Noto Sans Hanunoo', + 'Noto Sans Hatran', 'Noto Sans Hebrew', - 'Noto Naskh Arabic UI', - 'Noto Sans Devanagari UI', - 'Noto Sans Telugu UI', - 'Noto Sans Tamil UI', - 'Noto Sans Kannada UI', - 'Noto Sans Sinhala', - 'Noto Sans Gurmukhi UI', - 'Noto Sans Gujarati UI', - 'Noto Sans Bengali UI', - 'Noto Sans Thai UI', - 'Noto Sans Lao UI', - 'Noto Sans Myanmar UI', - 'Noto Sans Ethiopic', - 'Noto Sans Khmer UI', - 'Noto Sans SC', + 'Noto Sans Imperial Aramaic', + 'Noto Sans Indic Siyaq Numbers', + 'Noto Sans Inscriptional Pahlavi', + 'Noto Sans Inscriptional Parthian', 'Noto Sans JP', - 'Noto Sans TC', - 'Noto Sans HK', + 'Noto Sans Javanese', 'Noto Sans KR', - 'Noto Sans Egyptian Hieroglyphs', + 'Noto Sans Kaithi', + 'Noto Sans Kannada', + 'Noto Sans Kayah Li', + 'Noto Sans Kharoshthi', + 'Noto Sans Khmer', + 'Noto Sans Khojki', + 'Noto Sans Khudawadi', + 'Noto Sans Lao', + 'Noto Sans Lepcha', + 'Noto Sans Limbu', + 'Noto Sans Linear A', + 'Noto Sans Linear B', + 'Noto Sans Lisu', + 'Noto Sans Lycian', + 'Noto Sans Lydian', + 'Noto Sans Mahajani', + 'Noto Sans Malayalam', + 'Noto Sans Mandaic', + 'Noto Sans Manichaean', + 'Noto Sans Marchen', + 'Noto Sans Masaram Gondi', + 'Noto Sans Math', + 'Noto Sans Mayan Numerals', + 'Noto Sans Medefaidrin', + 'Noto Sans Meetei Mayek', + 'Noto Sans Meroitic', + 'Noto Sans Miao', + 'Noto Sans Modi', + 'Noto Sans Mongolian', + 'Noto Sans Mro', + 'Noto Sans Multani', + 'Noto Sans Myanmar', + 'Noto Sans N Ko', + 'Noto Sans Nabataean', + 'Noto Sans New Tai Lue', + 'Noto Sans Newa', + 'Noto Sans Nushu', + 'Noto Sans Ogham', + 'Noto Sans Ol Chiki', + 'Noto Sans Old Hungarian', + 'Noto Sans Old Italic', + 'Noto Sans Old North Arabian', + 'Noto Sans Old Permic', + 'Noto Sans Old Persian', + 'Noto Sans Old Sogdian', + 'Noto Sans Old South Arabian', + 'Noto Sans Old Turkic', + 'Noto Sans Oriya', + 'Noto Sans Osage', + 'Noto Sans Osmanya', + 'Noto Sans Pahawh Hmong', + 'Noto Sans Palmyrene', + 'Noto Sans Pau Cin Hau', + 'Noto Sans Phags Pa', + 'Noto Sans Phoenician', + 'Noto Sans Psalter Pahlavi', + 'Noto Sans Rejang', + 'Noto Sans Runic', + 'Noto Sans SC', + 'Noto Sans Saurashtra', + 'Noto Sans Sharada', + 'Noto Sans Shavian', + 'Noto Sans Siddham', + 'Noto Sans Sinhala', + 'Noto Sans Sogdian', + 'Noto Sans Sora Sompeng', + 'Noto Sans Soyombo', + 'Noto Sans Sundanese', + 'Noto Sans Syloti Nagri', + 'Noto Sans Syriac', + 'Noto Sans TC', + 'Noto Sans Tagalog', + 'Noto Sans Tagbanwa', + 'Noto Sans Tai Le', + 'Noto Sans Tai Tham', + 'Noto Sans Tai Viet', + 'Noto Sans Takri', + 'Noto Sans Tamil', + 'Noto Sans Tamil Supplement', + 'Noto Sans Telugu', + 'Noto Sans Thaana', + 'Noto Sans Thai', + 'Noto Sans Tifinagh', + 'Noto Sans Tirhuta', + 'Noto Sans Ugaritic', + 'Noto Sans Vai', + 'Noto Sans Wancho', + 'Noto Sans Warang Citi', + 'Noto Sans Yi', + 'Noto Sans Zanabazar Square', })); // Construct random paragraphs out of supported code units. @@ -356,16 +410,34 @@ void testMain() { } class TestDownloader extends NotoDownloader { + // Where to redirect downloads to. static final Map mockDownloads = {}; @override Future downloadAsString(String url, {String? debugDescription}) async { if (mockDownloads.containsKey(url)) { - return mockDownloads[url]!; + url = mockDownloads[url]!; + final Uri uri = Uri.parse(url); + expect(uri.isScheme('http'), isFalse); + expect(uri.isScheme('https'), isFalse); + return super.downloadAsString(url); } else { return ''; } } + + @override + Future downloadAsBytes(String url, {String? debugDescription}) { + if (mockDownloads.containsKey(url)) { + url = mockDownloads[url]!; + final Uri uri = Uri.parse(url); + expect(uri.isScheme('http'), isFalse); + expect(uri.isScheme('https'), isFalse); + return super.downloadAsBytes(url); + } else { + return Future.value(Uint8List(0).buffer); + } + } } class LoggingDownloader implements NotoDownloader { From 82c2a5dcfa8c9cac6cc39898b808797f0bc43f47 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 19:40:15 -0400 Subject: [PATCH 544/558] Roll Skia from 502e75091b90 to b2b3396fa792 (4 revisions) (#35684) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index d158b0b1f268c..b5db9db0d6b1a 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': '502e75091b9086aa57cd62d6f31b38945b421153', + 'skia_revision': 'b2b3396fa79230454a903cad4fb3f76031eef737', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index e9e12d243ea52..5929809de1121 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 82861add9083a3ea845d3eedf9236ef0 +Signature: cb6699b2ca0250b81ebc2230d7cfabb7 UNUSED LICENSES: From 4e89793ac38f1180c87011364bf874ad39a69036 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 21:11:22 -0400 Subject: [PATCH 545/558] Roll Skia from b2b3396fa792 to 9e99d458a20c (1 revision) (#35686) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b5db9db0d6b1a..1c78a7e2ae83d 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': 'b2b3396fa79230454a903cad4fb3f76031eef737', + 'skia_revision': '9e99d458a20c546cc6cfd1c13b8916ad2f5f6b25', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 5929809de1121..f82e4707391b8 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: cb6699b2ca0250b81ebc2230d7cfabb7 +Signature: 4e6f81d0e4f9219bd100cd2004f29f30 UNUSED LICENSES: From 2ad79bea5b4665d876daf841b5948464588f1787 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 24 Aug 2022 22:45:02 -0400 Subject: [PATCH 546/558] Roll Skia from 9e99d458a20c to f0e6ef75e7f2 (1 revision) (#35688) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 1c78a7e2ae83d..2f182fef5cedc 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': '9e99d458a20c546cc6cfd1c13b8916ad2f5f6b25', + 'skia_revision': 'f0e6ef75e7f2f5d73ea409f5802b2d165abbe587', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f82e4707391b8..ee240708af2fa 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 4e6f81d0e4f9219bd100cd2004f29f30 +Signature: 7cc96753ad10de67b3667e77cbbd120f UNUSED LICENSES: From 9600c6c39b72d37a1cca397935753f23a110d337 Mon Sep 17 00:00:00 2001 From: Alexander Aprelev Date: Wed, 24 Aug 2022 22:35:36 -0700 Subject: [PATCH 547/558] Roll dart to 4738c1a1a514a1b4ed9f4df17f71e2c5d9011d7a (#35691) * Roll dart to 4738c1a1a514a1b4ed9f4df17f71e2c5d9011d7a Changes since last dart roll ``` 4738c1a1a51 Version 2.19.0-137.0.dev 84a39b064ff [infra] Disable Goma on dartk-linux-release-riscv64-qemu. 69fcdc8d470 Version 2.19.0-136.0.dev c0e74c44330 [dart fix] report undefined diagnostics 7dfe6825574 Migration: _task is non-null 310d6d06609 First draft of some process docs for the analyzer 39a671782b7 [vm] Don't run DFE with a low optimization threshold in profiler tests. ece330a7008 [analysis_server] Include annotation completions at end of class 2f3c69c361b Rename a subdirectory under doc to match what analysis_server has 00f032a6416 [ VM / Service ] Add isolateGroupId to IsolateRef and Isolate 992672b549f [gardening] Fix gcc bot - add suggested parenthesis around '&&' within '||' 33846f3678b [io/file] Add `exclusive` optional parameter to File.create, createSync. f73f25edab7 Revert to clang toolchain that was rolled in March 2b27d3257be Report duplicated field names in record literals 65b4621a09a Fix an exception when a record type appears in an extends clause 8a883fa54d1 Change `:` to `=` for default values in `pkg`. 177147bac30 [analysis_server] Improve handling of document modifications while computing completions dbac2a4df3d [cfe] Add InternalRecordLiteral ``` * Update license hash --- DEPS | 8 ++++---- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DEPS b/DEPS index 2f182fef5cedc..9c12ccbae2865 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': 'b535e8d0bfbedd5a7580a020befd1c46452ac633', + 'dart_revision': '4738c1a1a514a1b4ed9f4df17f71e2c5d9011d7a', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -164,7 +164,7 @@ 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/devtools': - {'packages': [{'version': 'git_revision:d131d19091f6b89ac89486bd92440a25a523e8b0', 'package': 'dart/third_party/flutter/devtools'}], 'dep_type': 'cipd'}, + {'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:d131d19091f6b89ac89486bd92440a25a523e8b0'}], 'dep_type': 'cipd'}, 'src/third_party/dart/third_party/pkg/args': Var('dart_git') + '/args.git@80d4abbd6b38b79bcdbc411b4b517628c7611232', @@ -329,7 +329,7 @@ deps = { Var('dart_git') + '/yaml_edit.git' + '@' + Var('dart_yaml_edit_rev'), 'src/third_party/dart/tools/sdks': - {'packages': [{'version': 'version:2.18.0-271.7.beta', 'package': 'dart/dart-sdk/${{platform}}'}], 'dep_type': 'cipd'}, + {'packages': [{'package': 'dart/dart-sdk/${{platform}}', 'version': 'version:2.18.0-271.7.beta'}], 'dep_type': 'cipd'}, # WARNING: end of dart dependencies list that is cleaned up automatically - see create_updated_flutter_deps.py. @@ -474,7 +474,7 @@ deps = { Var('github_git') + '/felangel/equatable.git' + '@' + '0ba67c72db8bed75877fc1caafa74112ee0bd921', # 2.0.2 'src/third_party/pkg/file': - Var('github_git') + '/google/file.dart.git' + '@' + '427bb20ccc852425d67f2880da2a9b4707c266b4', # 6.1.0 + Var('github_git') + '/google/file.dart.git' + '@' + 'b2e31cb6ef40b223701dbfa0b907fe58468484d7', # 6.1.4 'src/third_party/pkg/flutter_packages': Var('github_git') + '/flutter/packages.git' + '@' + '26990a2f75ab2028c3c77ffc869db11d6d866d18', # various diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 639f5f3e6d43e..39a0060e667bb 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: 96a953f119145ece42ec4269764ead98 +Signature: a1657391084c65e081040f2a5a58b06e UNUSED LICENSES: From 0f4009db719db77187306a17d80ddd0b9f832597 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 02:16:33 -0400 Subject: [PATCH 548/558] Roll Skia from f0e6ef75e7f2 to 848fe76219b0 (1 revision) (#35694) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 9c12ccbae2865..82a64ad723e98 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': 'f0e6ef75e7f2f5d73ea409f5802b2d165abbe587', + 'skia_revision': '848fe76219b0a1f65815b90f1c6a648658328fc3', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index ee240708af2fa..bdaea7a08dd9a 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 7cc96753ad10de67b3667e77cbbd120f +Signature: 85bbbb3ede68ed5b62a8d78799d583d7 UNUSED LICENSES: From 8f3402e0018dc5f8cc98332b861ce219918a8db6 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 03:45:14 -0400 Subject: [PATCH 549/558] Roll Skia from 848fe76219b0 to 1c68c37b1108 (2 revisions) (#35695) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 82a64ad723e98..25aea70b425c6 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': '848fe76219b0a1f65815b90f1c6a648658328fc3', + 'skia_revision': '1c68c37b1108719771304ef71f9963fb263d4a5b', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index bdaea7a08dd9a..e551b3ee55cd4 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 85bbbb3ede68ed5b62a8d78799d583d7 +Signature: d24ce0f611ad4b017d4aaef12f921749 UNUSED LICENSES: From 87ea227e3e16956c8896f3fde22e5b65e02997a0 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 05:36:24 -0400 Subject: [PATCH 550/558] Roll Fuchsia Mac SDK from uiiEV3lEQoosICL43... to Dze6-JhF8LT-exmW_... (#35696) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 25aea70b425c6..e9659121987e3 100644 --- a/DEPS +++ b/DEPS @@ -664,7 +664,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/mac-amd64', - 'version': 'uiiEV3lEQoosICL439Dnn0Ws0-K3akCMnRmkl8kbBdEC' + 'version': 'Dze6-JhF8LT-exmW_FbhtaUl_QFTlUnQHvtopxkj2H8C' } ], 'condition': 'host_os == "mac" and not download_fuchsia_sdk', From 8ccce665908bd9c4cd8bc393e244ab6f4b0d0530 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 06:36:10 -0400 Subject: [PATCH 551/558] Roll Skia from 1c68c37b1108 to bd506e3454b1 (1 revision) (#35697) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index e9659121987e3..498fa0871c0a5 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': '1c68c37b1108719771304ef71f9963fb263d4a5b', + 'skia_revision': 'bd506e3454b1aaee9b4b87fd971824e11f8527fe', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index e551b3ee55cd4..ec4295fdb742d 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d24ce0f611ad4b017d4aaef12f921749 +Signature: e9e270da0d2f3523a13e8a009efc5450 UNUSED LICENSES: From 77a77fd60a15d1f55f2f90768daf134fd8cff320 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 07:19:10 -0400 Subject: [PATCH 552/558] Roll Dart SDK from 4738c1a1a514 to 99ce4a80c6cb (1 revision) (#35699) --- DEPS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 498fa0871c0a5..982b680f2a507 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '4738c1a1a514a1b4ed9f4df17f71e2c5d9011d7a', + 'dart_revision': '99ce4a80c6cb174808fa1c08100dbcb9e50cbf78', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -164,7 +164,7 @@ 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/devtools': - {'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:d131d19091f6b89ac89486bd92440a25a523e8b0'}], 'dep_type': 'cipd'}, + {'packages': [{'version': 'git_revision:d131d19091f6b89ac89486bd92440a25a523e8b0', 'package': 'dart/third_party/flutter/devtools'}], 'dep_type': 'cipd'}, 'src/third_party/dart/third_party/pkg/args': Var('dart_git') + '/args.git@80d4abbd6b38b79bcdbc411b4b517628c7611232', @@ -329,7 +329,7 @@ deps = { Var('dart_git') + '/yaml_edit.git' + '@' + Var('dart_yaml_edit_rev'), 'src/third_party/dart/tools/sdks': - {'packages': [{'package': 'dart/dart-sdk/${{platform}}', 'version': 'version:2.18.0-271.7.beta'}], 'dep_type': 'cipd'}, + {'packages': [{'version': 'version:2.18.0-271.7.beta', 'package': 'dart/dart-sdk/${{platform}}'}], 'dep_type': 'cipd'}, # WARNING: end of dart dependencies list that is cleaned up automatically - see create_updated_flutter_deps.py. From aa40dbed02c2bc948977385e2da21d32f4c6658f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 08:26:12 -0400 Subject: [PATCH 553/558] Roll Skia from bd506e3454b1 to 142f4156948c (1 revision) (#35700) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 982b680f2a507..6eb303a6a4bc0 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': 'bd506e3454b1aaee9b4b87fd971824e11f8527fe', + 'skia_revision': '142f4156948c7c086beeb86553ecb095f1ad74e0', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index ec4295fdb742d..c0d559c35a888 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e9e270da0d2f3523a13e8a009efc5450 +Signature: 2cfc950165706a7126f7c370809d94af UNUSED LICENSES: From 72d264f78643ab58ffe1e4b9a81daf3127d28b54 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 10:17:18 -0400 Subject: [PATCH 554/558] Roll Skia from 142f4156948c to c93660cfeb33 (1 revision) (#35701) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6eb303a6a4bc0..82287c27f8dcd 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': '142f4156948c7c086beeb86553ecb095f1ad74e0', + 'skia_revision': 'c93660cfeb33538a1a73ff6b0dac9843e31bc299', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index c0d559c35a888..f32c7289230b6 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 2cfc950165706a7126f7c370809d94af +Signature: 481c0a75b0e1588dc084bfcef84fa8e2 UNUSED LICENSES: From bd7a1e0b2be084933c2be99249db332ab8ff08d6 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 25 Aug 2022 07:21:23 -0700 Subject: [PATCH 555/558] [Impeller] Render on Simulator (#35692) --- flow/surface_frame.cc | 5 ++- flow/surface_frame_unittests.cc | 12 +++++++ .../renderer/backend/metal/render_pass_mtl.mm | 31 +++++++++++++------ impeller/renderer/platform.h | 2 +- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/flow/surface_frame.cc b/flow/surface_frame.cc index c8a6bbf6bc3c1..d3133daa07385 100644 --- a/flow/surface_frame.cc +++ b/flow/surface_frame.cc @@ -6,6 +6,7 @@ #include +#include "flutter/flow/layers/layer.h" #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" #include "third_party/skia/include/utils/SkNWayCanvas.h" @@ -25,9 +26,7 @@ SurfaceFrame::SurfaceFrame(sk_sp surface, if (surface_) { canvas_ = surface_->getCanvas(); } else if (display_list_fallback) { - dl_recorder_ = sk_make_sp( - SkRect::MakeWH(std::numeric_limits::max(), - std::numeric_limits::max())); + dl_recorder_ = sk_make_sp(kGiantRect); canvas_ = dl_recorder_.get(); } } diff --git a/flow/surface_frame_unittests.cc b/flow/surface_frame_unittests.cc index c7a0bc5132af9..7bc4d07ef564f 100644 --- a/flow/surface_frame_unittests.cc +++ b/flow/surface_frame_unittests.cc @@ -20,4 +20,16 @@ TEST(FlowTest, SurfaceFrameDoesNotSubmitInDtor) { surface_frame.reset(); } +TEST(FlowTest, SurfaceFrameDoesNotHaveEmptyCanvas) { + SurfaceFrame::FramebufferInfo framebuffer_info; + SurfaceFrame frame( + /*surface=*/nullptr, framebuffer_info, + /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }, + /*context_result=*/nullptr, /*display_list_fallback=*/true); + + EXPECT_FALSE(frame.SkiaCanvas()->getLocalClipBounds().isEmpty()); + EXPECT_FALSE( + frame.SkiaCanvas()->quickReject(SkRect::MakeLTRB(10, 10, 50, 50))); +} + } // namespace flutter diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index c277bbb50569b..e8c825af36b2b 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -493,18 +493,31 @@ static bool Bind(PassBindingsCache& pass, if (!mtl_index_buffer) { return false; } + FML_DCHECK(command.index_count * (command.index_type == IndexType::k16bit ? 2 : 4) == command.index_buffer.range.length); - // Returns void. All error checking must be done by this point. - [encoder drawIndexedPrimitives:ToMTLPrimitiveType(command.primitive_type) - indexCount:command.index_count - indexType:ToMTLIndexType(command.index_type) - indexBuffer:mtl_index_buffer - indexBufferOffset:command.index_buffer.range.offset - instanceCount:command.instance_count - baseVertex:command.base_vertex - baseInstance:0u]; + + if (command.instance_count != 1u) { +#if TARGET_OS_SIMULATOR + VALIDATION_LOG << "iOS Simulator does not support instanced rendering."; + return false; +#endif + [encoder drawIndexedPrimitives:ToMTLPrimitiveType(command.primitive_type) + indexCount:command.index_count + indexType:ToMTLIndexType(command.index_type) + indexBuffer:mtl_index_buffer + indexBufferOffset:command.index_buffer.range.offset + instanceCount:command.instance_count + baseVertex:command.base_vertex + baseInstance:0u]; + } else { + [encoder drawIndexedPrimitives:ToMTLPrimitiveType(command.primitive_type) + indexCount:command.index_count + indexType:ToMTLIndexType(command.index_type) + indexBuffer:mtl_index_buffer + indexBufferOffset:command.index_buffer.range.offset]; + } } return true; } diff --git a/impeller/renderer/platform.h b/impeller/renderer/platform.h index c2783d7581e08..6076e810b3d17 100644 --- a/impeller/renderer/platform.h +++ b/impeller/renderer/platform.h @@ -12,7 +12,7 @@ namespace impeller { constexpr size_t DefaultUniformAlignment() { -#if FML_OS_IOS +#if FML_OS_IOS && !TARGET_OS_SIMULATOR return 16u; #elif FML_OS_MACOSX return 256u; From 198e87cd7ebfae7538bb7ac28b5dd2ef59aca6d5 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 12:17:09 -0400 Subject: [PATCH 556/558] Roll Skia from c93660cfeb33 to 05135dc0eb78 (6 revisions) (#35704) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index 82287c27f8dcd..c77c812b1d195 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': 'c93660cfeb33538a1a73ff6b0dac9843e31bc299', + 'skia_revision': '05135dc0eb78a968d38da8c45c246033a906a8e6', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index f32c7289230b6..fa51ba75f2c02 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 481c0a75b0e1588dc084bfcef84fa8e2 +Signature: d62d493621dabf3ba608807e4ff137df UNUSED LICENSES: @@ -2651,8 +2651,6 @@ FILE: ../../../third_party/skia/src/sksl/SkSLContext.cpp FILE: ../../../third_party/skia/src/sksl/SkSLIntrinsicList.h FILE: ../../../third_party/skia/src/sksl/SkSLMangler.h FILE: ../../../third_party/skia/src/sksl/SkSLOperator.cpp -FILE: ../../../third_party/skia/src/sksl/SkSLSharedCompiler.cpp -FILE: ../../../third_party/skia/src/sksl/SkSLSharedCompiler.h FILE: ../../../third_party/skia/src/sksl/SkSLThreadContext.h FILE: ../../../third_party/skia/src/sksl/analysis/SkSLCanExitWithoutReturningValue.cpp FILE: ../../../third_party/skia/src/sksl/analysis/SkSLCheckProgramStructure.cpp From ebf65036d1bf0d7fefc55f6d1e21f61f85455752 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 12:51:18 -0400 Subject: [PATCH 557/558] Roll Dart SDK from 99ce4a80c6cb to 268aa39b1999 (1 revision) (#35705) --- DEPS | 2 +- ci/licenses_golden/licenses_third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index c77c812b1d195..b078a0ecbbb05 100644 --- a/DEPS +++ b/DEPS @@ -36,7 +36,7 @@ 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': '99ce4a80c6cb174808fa1c08100dbcb9e50cbf78', + 'dart_revision': '268aa39b1999072555e094059295c5a212152c27', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py diff --git a/ci/licenses_golden/licenses_third_party b/ci/licenses_golden/licenses_third_party index 39a0060e667bb..97593374fb2bb 100644 --- a/ci/licenses_golden/licenses_third_party +++ b/ci/licenses_golden/licenses_third_party @@ -1,4 +1,4 @@ -Signature: a1657391084c65e081040f2a5a58b06e +Signature: 17f3f2238676062b964586ee0a786b06 UNUSED LICENSES: From b9ba6792001806b9a6a27f89edd7d5f312f67ae6 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Thu, 25 Aug 2022 13:48:53 -0400 Subject: [PATCH 558/558] Roll Skia from 05135dc0eb78 to dee2a6ebfcdf (6 revisions) (#35706) --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b078a0ecbbb05..bb5dbe816c051 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': '05135dc0eb78a968d38da8c45c246033a906a8e6', + 'skia_revision': 'dee2a6ebfcdfff981b8b0a520c23220ab5673089', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index fa51ba75f2c02..7fbb2b093d167 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d62d493621dabf3ba608807e4ff137df +Signature: 1a0bb0241ba71bb09e074a4cb1724a73 UNUSED LICENSES: