From ce0794bfb8087641b872c68202cc1d93fcf53022 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 20 May 2024 14:57:22 -0700 Subject: [PATCH 01/18] [Impeller] Fix use-after-move in SwapchainVK. (#52933) Fix lint encountered in https://github.com/flutter/engine/pull/52932. --- .../renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc | 2 +- .../renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h | 2 +- impeller/renderer/backend/vulkan/swapchain/swapchain_vk.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc index ad805a0a8cd72..ddfdece798929 100644 --- a/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.cc @@ -19,7 +19,7 @@ bool AHBSwapchainVK::IsAvailableOnPlatform() { AHBSwapchainVK::AHBSwapchainVK(const std::shared_ptr& context, ANativeWindow* window, - vk::UniqueSurfaceKHR surface, + const vk::UniqueSurfaceKHR& surface, const ISize& size, bool enable_msaa) : context_(context), diff --git a/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h index a3b330f71cfc5..ddbcd13a52c95 100644 --- a/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h +++ b/impeller/renderer/backend/vulkan/swapchain/ahb/ahb_swapchain_vk.h @@ -57,7 +57,7 @@ class AHBSwapchainVK final : public SwapchainVK { explicit AHBSwapchainVK(const std::shared_ptr& context, ANativeWindow* window, - vk::UniqueSurfaceKHR surface, + const vk::UniqueSurfaceKHR& surface, const ISize& size, bool enable_msaa); }; diff --git a/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.cc b/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.cc index a2cb44509bb61..ce1951de8516a 100644 --- a/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.cc +++ b/impeller/renderer/backend/vulkan/swapchain/swapchain_vk.cc @@ -67,7 +67,7 @@ std::shared_ptr SwapchainVK::Create( auto ahb_swapchain = std::shared_ptr(new AHBSwapchainVK( context, // window.GetHandle(), // - std::move(surface), // + surface, // window.GetSize(), // enable_msaa // )); From dd2b6f4a2b089fb9ece8b09a7d1ce0f722dbf194 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 20 May 2024 17:59:33 -0400 Subject: [PATCH 02/18] Roll Dart SDK from 08f4324c988b to 01a77883e9e9 (1 revision) (#52936) https://dart.googlesource.com/sdk.git/+log/08f4324c988b..01a77883e9e9 2024-05-20 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-173.0.dev If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/dart-sdk-flutter-engine Please CC bdero@google.com,dart-vm-team@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter Engine: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 10 +++++----- sky/packages/sky_engine/LICENSE | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DEPS b/DEPS index 56542d945aa6f..a463b70e89bdd 100644 --- a/DEPS +++ b/DEPS @@ -56,7 +56,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': '08f4324c988b0a2278259d5d1c0d1ee0d68c1714', + 'dart_revision': '01a77883e9e983dbee08c1609faf6059e41dfb45', # WARNING: DO NOT EDIT MANUALLY # The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py @@ -350,7 +350,7 @@ deps = { {'dep_type': 'cipd', 'packages': [{'package': 'dart/third_party/flutter/devtools', 'version': 'git_revision:e2a7208bb8eed852b1f9dedabf423f187e947a7d'}]}, 'src/flutter/third_party/dart/third_party/pkg/args': - Var('dart_git') + '/args.git@5c83bc9785d6c32ffe6824ba79fadcc51fbcd1c1', + Var('dart_git') + '/args.git@cf905519d67054a5e8d8835ffd4b247d8bbb602d', 'src/flutter/third_party/dart/third_party/pkg/async': Var('dart_git') + '/async.git@77a25d77392b131df4ecac85bcfe9a30f82a9f40', @@ -401,7 +401,7 @@ deps = { Var('dart_git') + '/html.git@00d34611eee5eff976bd12a631357a4d591ef5fb', 'src/flutter/third_party/dart/third_party/pkg/http': - Var('dart_git') + '/http.git@76deb751b41a675ac214d0ce2b9919f406175137', + Var('dart_git') + '/http.git@5c01453ab467408194143d4106092201f03ed98e', 'src/flutter/third_party/dart/third_party/pkg/http_multi_server': Var('dart_git') + '/http_multi_server.git@4a791af861da1cf53b57d9928fbc605f57139e4f', @@ -431,7 +431,7 @@ deps = { Var('dart_git') + '/mime.git@b01c9a24e0991da479bd405138be3b3e403ff456', 'src/flutter/third_party/dart/third_party/pkg/mockito': - Var('dart_git') + '/mockito.git@4be52e16d06c8c5384d1cf5a511f0c9a7d829cf7', + Var('dart_git') + '/mockito.git@2302814df66e651b6710311366501523dbee2e11', 'src/flutter/third_party/dart/third_party/pkg/native': Var('dart_git') + '/native.git@fef40aebc3cf34654919e8a5785b6c50b3ea445c', @@ -503,7 +503,7 @@ deps = { Var('dart_git') + '/web.git' + '@' + Var('dart_web_rev'), 'src/flutter/third_party/dart/third_party/pkg/web_socket_channel': - Var('dart_git') + '/web_socket_channel.git@8c77d6fb8597fde3a0d1058ed7b7b9d6e4df6cc4', + Var('dart_git') + '/web_socket_channel.git@45b8ce9ce9fb5194a24d3dff8913c573fbe7896a', 'src/flutter/third_party/dart/third_party/pkg/webdev': Var('dart_git') + '/webdev.git' + '@' + Var('dart_webdev_rev'), diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index e7c4f429a186c..a13d8b0c6f586 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -32293,7 +32293,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/08f4324c988b0a2278259d5d1c0d1ee0d68c1714 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/01a77883e9e983dbee08c1609faf6059e41dfb45 /third_party/fallback_root_certificates/ -------------------------------------------------------------------------------- From 6264763a8282799f812b90c5b34bea352f49726c Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 20 May 2024 15:15:05 -0700 Subject: [PATCH 03/18] [Impeller] write glyphs to malloc buffer. (#52937) Writing to a malloc buffer and then copying is faster on a variety of Pixel devices. Since this change was supposed to be a performance optimization, just back it out. --- .../backends/skia/typographer_context_skia.cc | 65 ++++--------------- 1 file changed, 11 insertions(+), 54 deletions(-) diff --git a/impeller/typographer/backends/skia/typographer_context_skia.cc b/impeller/typographer/backends/skia/typographer_context_skia.cc index 52616ed85d454..96027ea9906d4 100644 --- a/impeller/typographer/backends/skia/typographer_context_skia.cc +++ b/impeller/typographer/backends/skia/typographer_context_skia.cc @@ -46,56 +46,6 @@ namespace impeller { // https://github.com/flutter/flutter/issues/114563 constexpr auto kPadding = 2; -namespace { - -class HostBufferAllocator : public SkBitmap::Allocator { - public: - explicit HostBufferAllocator(HostBuffer& host_buffer) - : host_buffer_(host_buffer) {} - - [[nodiscard]] BufferView TakeBufferView() { - buffer_view_.buffer->Flush(); - return std::move(buffer_view_); - } - - // |SkBitmap::Allocator| - bool allocPixelRef(SkBitmap* bitmap) override { - if (!bitmap) { - return false; - } - const SkImageInfo& info = bitmap->info(); - if (kUnknown_SkColorType == info.colorType() || info.width() < 0 || - info.height() < 0 || !info.validRowBytes(bitmap->rowBytes())) { - return false; - } - - size_t required_bytes = bitmap->rowBytes() * bitmap->height(); - BufferView buffer_view = host_buffer_.Emplace(nullptr, required_bytes, - DefaultUniformAlignment()); - - // The impeller host buffer is not cleared between frames and may contain - // stale data. The Skia software canvas does not write to pixels without - // any contents, which causes this data to leak through. - ::memset(buffer_view.buffer->OnGetContents() + buffer_view.range.offset, 0, - required_bytes); - - auto pixel_ref = sk_sp(new SkPixelRef( - info.width(), info.height(), - buffer_view.buffer->OnGetContents() + buffer_view.range.offset, - bitmap->rowBytes())); - - bitmap->setPixelRef(std::move(pixel_ref), 0, 0); - buffer_view_ = std::move(buffer_view); - return true; - } - - private: - BufferView buffer_view_; - HostBuffer& host_buffer_; -}; - -} // namespace - std::shared_ptr TypographerContextSkia::Make() { return std::make_shared(); } @@ -282,9 +232,8 @@ static bool UpdateAtlasBitmap(const GlyphAtlas& atlas, } SkBitmap bitmap; - HostBufferAllocator allocator(host_buffer); bitmap.setInfo(GetImageInfo(atlas, size)); - if (!bitmap.tryAllocPixels(&allocator)) { + if (!bitmap.tryAllocPixels()) { return false; } auto surface = SkSurfaces::WrapPixels(bitmap.pixmap()); @@ -298,11 +247,19 @@ static bool UpdateAtlasBitmap(const GlyphAtlas& atlas, DrawGlyph(canvas, pair.scaled_font, pair.glyph, has_color); + // Writing to a malloc'd buffer and then copying to the staging buffers + // benchmarks as substantially faster on a number of Android devices. + BufferView buffer_view = host_buffer.Emplace( + bitmap.getAddr(0, 0), + size.Area() * BytesPerPixelForPixelFormat( + atlas.GetTexture()->GetTextureDescriptor().format), + DefaultUniformAlignment()); + // convert_to_read is set to false so that the texture remains in a transfer // dst layout until we finish writing to it below. This only has an impact // on Vulkan where we are responsible for managing image layouts. - if (!blit_pass->AddCopy(allocator.TakeBufferView(), // - texture, // + if (!blit_pass->AddCopy(std::move(buffer_view), // + texture, // IRect::MakeXYWH(pos->GetLeft(), pos->GetTop(), size.width, size.height), // /*label=*/"", // From ceec2504bfabfdf972355d9ab2b8892bc208d658 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 20 May 2024 18:30:09 -0400 Subject: [PATCH 04/18] Roll Skia from 0b8d8ce44d1f to 977a43773f7c (1 revision) (#52938) https://skia.googlesource.com/skia.git/+log/0b8d8ce44d1f..977a43773f7c 2024-05-20 ccameron@chromium.org Decode and encode ISO 21496-1 JPEG images 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 bdero@google.com,brianosman@google.com,jlavrova@google.com,rmistry@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://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index a463b70e89bdd..b44ec4531eb90 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '0b8d8ce44d1f79cd39443a2247482495d2f84c45', + 'skia_revision': '977a43773f7ce1c6e69cf966deb534311b3a18b4', # 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 2a866d848a4fd..99041bbf6d580 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 8285c3928d926c49ed70d7aebd0fcdd1 +Signature: 90deea79130a38a0bf37741e7b65f8d7 ==================================================================================================== LIBRARY: etc1 From 4117490208f1b1301e9bfa53fc32b5fb01acef43 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 20 May 2024 19:28:22 -0400 Subject: [PATCH 05/18] Roll Skia from 977a43773f7c to 62f369c75994 (1 revision) (#52941) https://skia.googlesource.com/skia.git/+log/977a43773f7c..62f369c75994 2024-05-20 ccameron@google.com Revert "Decode and encode ISO 21496-1 JPEG images" 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 bdero@google.com,brianosman@google.com,jlavrova@google.com,rmistry@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://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b44ec4531eb90..ec808d51d044f 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '977a43773f7ce1c6e69cf966deb534311b3a18b4', + 'skia_revision': '62f369c759947272dfdd2d8f060afadbcc361e79', # 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 99041bbf6d580..2a866d848a4fd 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 90deea79130a38a0bf37741e7b65f8d7 +Signature: 8285c3928d926c49ed70d7aebd0fcdd1 ==================================================================================================== LIBRARY: etc1 From fd24d4079168aa224ea04e46991ce4aa956be713 Mon Sep 17 00:00:00 2001 From: Harry Terkelsen <1961493+harryterkelsen@users.noreply.github.com> Date: Mon, 20 May 2024 16:59:06 -0700 Subject: [PATCH 06/18] [canvaskit] Refactor HtmlImageCodec to generalize to different renderers (#52905) Refactor `HtmlImageCodec` to decouple it from the html renderer so other renderers can create a `ui.Image` via `Image.decode()`. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- ci/licenses_golden/licenses_flutter | 8 +- lib/web_ui/lib/src/engine.dart | 4 +- .../lib/src/engine/html/bitmap_canvas.dart | 130 +++--- lib/web_ui/lib/src/engine/html/canvas.dart | 2 +- lib/web_ui/lib/src/engine/html/image.dart | 126 ++++++ lib/web_ui/lib/src/engine/html/picture.dart | 123 +++++- .../lib/src/engine/html/recording_canvas.dart | 19 +- lib/web_ui/lib/src/engine/html/renderer.dart | 414 +++++++++--------- .../lib/src/engine/html/scene_builder.dart | 1 - .../src/engine/html/shaders/image_shader.dart | 34 +- ...dec.dart => html_image_element_codec.dart} | 126 +----- lib/web_ui/lib/src/engine/image_decoder.dart | 90 ++-- lib/web_ui/lib/src/engine/picture.dart | 127 ------ ...art => html_image_element_codec_test.dart} | 26 +- 14 files changed, 644 insertions(+), 586 deletions(-) create mode 100644 lib/web_ui/lib/src/engine/html/image.dart rename lib/web_ui/lib/src/engine/{html_image_codec.dart => html_image_element_codec.dart} (58%) delete mode 100644 lib/web_ui/lib/src/engine/picture.dart rename lib/web_ui/test/engine/image/{html_image_codec_test.dart => html_image_element_codec_test.dart} (83%) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index acae397d1e4ca..fea7dbcef2234 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -43279,6 +43279,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/clip.dart + ../../../flu ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/color_filter.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/debug_canvas_reuse_overlay.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/dom_canvas.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/image.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/image_filter.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/offset.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/opacity.dart + ../../../flutter/LICENSE @@ -43311,7 +43312,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/shaders/vertex_shaders.d ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/surface.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/surface_stats.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html/transform.dart + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html_image_codec.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/html_image_element_codec.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/image_decoder.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/initialization.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_app.dart + ../../../flutter/LICENSE @@ -43328,7 +43329,6 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/navigation/history.dart + ../ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/noto_font.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/noto_font_encoding.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/onscreen_logging.dart + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/picture.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/platform_dispatcher.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/platform_dispatcher/app_lifecycle_state.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/platform_dispatcher/view_focus_binding.dart + ../../../flutter/LICENSE @@ -46156,6 +46156,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/clip.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/color_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/debug_canvas_reuse_overlay.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/dom_canvas.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/image.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/image_filter.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/offset.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/opacity.dart @@ -46188,7 +46189,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/shaders/vertex_shaders.dar FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/surface.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/surface_stats.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/html/transform.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/html_image_codec.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/html_image_element_codec.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/image_decoder.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/initialization.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/js_interop/js_app.dart @@ -46205,7 +46206,6 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/navigation/history.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/noto_font.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/noto_font_encoding.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/onscreen_logging.dart -FILE: ../../../flutter/lib/web_ui/lib/src/engine/picture.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/platform_dispatcher.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/platform_dispatcher/app_lifecycle_state.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/platform_dispatcher/view_focus_binding.dart diff --git a/lib/web_ui/lib/src/engine.dart b/lib/web_ui/lib/src/engine.dart index 48932ef12a533..1890fa1a1648f 100644 --- a/lib/web_ui/lib/src/engine.dart +++ b/lib/web_ui/lib/src/engine.dart @@ -73,6 +73,7 @@ export 'engine/html/clip.dart'; export 'engine/html/color_filter.dart'; export 'engine/html/debug_canvas_reuse_overlay.dart'; export 'engine/html/dom_canvas.dart'; +export 'engine/html/image.dart'; export 'engine/html/image_filter.dart'; export 'engine/html/offset.dart'; export 'engine/html/opacity.dart'; @@ -105,7 +106,7 @@ export 'engine/html/shaders/vertex_shaders.dart'; export 'engine/html/surface.dart'; export 'engine/html/surface_stats.dart'; export 'engine/html/transform.dart'; -export 'engine/html_image_codec.dart'; +export 'engine/html_image_element_codec.dart'; export 'engine/image_decoder.dart'; export 'engine/initialization.dart'; export 'engine/js_interop/js_app.dart'; @@ -122,7 +123,6 @@ export 'engine/navigation/history.dart'; export 'engine/noto_font.dart'; export 'engine/noto_font_encoding.dart'; export 'engine/onscreen_logging.dart'; -export 'engine/picture.dart'; export 'engine/platform_dispatcher.dart'; export 'engine/platform_dispatcher/app_lifecycle_state.dart'; export 'engine/platform_dispatcher/view_focus_binding.dart'; 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 c201407c669a9..9695f4dbb291d 100644 --- a/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/bitmap_canvas.dart @@ -13,13 +13,13 @@ import '../display.dart'; import '../dom.dart'; import '../engine_canvas.dart'; import '../frame_reference.dart'; -import '../html_image_codec.dart'; import '../text/canvas_paragraph.dart'; import '../util.dart'; import '../vector_math.dart'; import 'clip.dart'; import 'color_filter.dart'; import 'dom_canvas.dart'; +import 'image.dart'; import 'painting.dart'; import 'path/path.dart'; import 'recording_canvas.dart'; @@ -207,7 +207,8 @@ class BitmapCanvas extends EngineCanvas { static int heightToPhysical(double height) { final double boundsHeight = height + 1; - return (boundsHeight * EngineFlutterDisplay.instance.browserDevicePixelRatio) + return (boundsHeight * + EngineFlutterDisplay.instance.browserDevicePixelRatio) .ceil() + 2 * kPaddingPixels; } @@ -252,7 +253,8 @@ class BitmapCanvas extends EngineCanvas { /// * [PersistedPicture._recycleCanvas] which also uses this method /// for the same reason. bool isReusable() { - return _devicePixelRatio == EngineFlutterDisplay.instance.browserDevicePixelRatio; + return _devicePixelRatio == + EngineFlutterDisplay.instance.browserDevicePixelRatio; } /// Returns a "data://" URI containing a representation of the image in this @@ -365,12 +367,12 @@ class BitmapCanvas extends EngineCanvas { return false; } return _renderStrategy.isInsideSvgFilterTree || - _contains3dTransform || - (_childOverdraw && - !_canvasPool.hasCanvas && - paint.maskFilter == null && - paint.shader == null && - paint.style != ui.PaintingStyle.stroke); + _contains3dTransform || + (_childOverdraw && + !_canvasPool.hasCanvas && + paint.maskFilter == null && + paint.shader == null && + paint.style != ui.PaintingStyle.stroke); } /// Same as [_useDomForRenderingFill] but allows stroke as well. @@ -381,13 +383,13 @@ class BitmapCanvas extends EngineCanvas { return false; } return _renderStrategy.isInsideSvgFilterTree || - _contains3dTransform || - ((_childOverdraw || - _renderStrategy.hasImageElements || - _renderStrategy.hasParagraphs) && - !_canvasPool.hasCanvas && - paint.maskFilter == null && - paint.shader == null); + _contains3dTransform || + ((_childOverdraw || + _renderStrategy.hasImageElements || + _renderStrategy.hasParagraphs) && + !_canvasPool.hasCanvas && + paint.maskFilter == null && + paint.shader == null); } @override @@ -512,7 +514,8 @@ class BitmapCanvas extends EngineCanvas { @override void drawCircle(ui.Offset c, double radius, SurfacePaintData paint) { if (_useDomForRenderingFillAndStroke(paint)) { - final ui.Rect rect = adjustRectForDom(ui.Rect.fromCircle(center: c, radius: radius), paint); + final ui.Rect rect = adjustRectForDom( + ui.Rect.fromCircle(center: c, radius: radius), paint); final DomHTMLElement element = buildDrawRectElement( rect, paint, 'draw-circle', _canvasPool.currentTransform); _drawElement(element, rect.topLeft, paint); @@ -572,7 +575,8 @@ class BitmapCanvas extends EngineCanvas { final bool isStroke = paint.style == ui.PaintingStyle.stroke; final String cssColor = colorValueToCssString(paint.color); final double sigma = paint.maskFilter!.webOnlySigma; - if (ui_web.browser.browserEngine == ui_web.BrowserEngine.webkit && !isStroke) { + if (ui_web.browser.browserEngine == ui_web.BrowserEngine.webkit && + !isStroke) { // A bug in webkit leaves artifacts when this element is animated // with filter: blur, we use boxShadow instead. element.style.boxShadow = '0px 0px ${sigma * 2.0}px $cssColor'; @@ -625,7 +629,8 @@ class BitmapCanvas extends EngineCanvas { ui.Image image, ui.Offset p, SurfacePaintData paint) { final HtmlImage htmlImage = image as HtmlImage; final ui.BlendMode? blendMode = paint.blendMode; - final EngineHtmlColorFilter? colorFilter = createHtmlColorFilter(paint.colorFilter); + final EngineHtmlColorFilter? colorFilter = + createHtmlColorFilter(paint.colorFilter); DomHTMLElement imgElement; if (colorFilter is ModeHtmlColorFilter) { imgElement = _createImageElementWithBlend( @@ -748,8 +753,7 @@ class BitmapCanvas extends EngineCanvas { targetWidth *= image.width / src.width; targetHeight *= image.height / src.height; } - _applyTargetSize( - imgElement as DomHTMLElement, targetWidth, targetHeight); + _applyTargetSize(imgElement as DomHTMLElement, targetWidth, targetHeight); if (requiresClipping) { restore(); } @@ -831,7 +835,8 @@ class BitmapCanvas extends EngineCanvas { ui.BlendMode colorFilterBlendMode, SurfacePaintData paint) { // For srcIn blendMode, we use an svg filter to apply to image element. - final SvgFilter svgFilter = svgFilterFromBlendMode(filterColor, colorFilterBlendMode); + final SvgFilter svgFilter = + svgFilterFromBlendMode(filterColor, colorFilterBlendMode); rootElement.append(svgFilter.element); _children.add(svgFilter.element); final DomHTMLElement imgElement = _reuseOrCreateImage(image); @@ -893,7 +898,8 @@ class BitmapCanvas extends EngineCanvas { /// /// The text is drawn starting at coordinates ([x], [y]). It uses the current /// font set by the most recent call to [setCssFont]. - void drawText(String text, double x, double y, {ui.PaintingStyle? style, List? shadows}) { + void drawText(String text, double x, double y, + {ui.PaintingStyle? style, List? shadows}) { final DomCanvasRenderingContext2D ctx = _canvasPool.context; if (shadows != null) { ctx.save(); @@ -932,27 +938,23 @@ class BitmapCanvas extends EngineCanvas { // Cannot composite if the paragraph cannot be drawn into bitmap canvas // in the first place. paragraph.canDrawOnCanvas && - // Cannot composite if there's no bitmap canvas to composite into. - // Creating a new bitmap canvas just to draw text doesn't make sense. - _canvasPool.hasCanvas && - !_childOverdraw && - // Bitmap canvas introduces correctness issues in the presence of SVG - // filters, so prefer plain HTML in this case. - !_renderStrategy.isInsideSvgFilterTree; + // Cannot composite if there's no bitmap canvas to composite into. + // Creating a new bitmap canvas just to draw text doesn't make sense. + _canvasPool.hasCanvas && + !_childOverdraw && + // Bitmap canvas introduces correctness issues in the presence of SVG + // filters, so prefer plain HTML in this case. + !_renderStrategy.isInsideSvgFilterTree; if (canCompositeIntoBitmapCanvas) { paragraph.paint(this, offset); return; } - final DomElement paragraphElement = - drawParagraphElement(paragraph, offset); + final DomElement paragraphElement = drawParagraphElement(paragraph, offset); if (_canvasPool.isClipped) { - final List clipElements = _clipContent( - _canvasPool.clipStack!, - paragraphElement, - offset, - _canvasPool.currentTransform); + final List clipElements = _clipContent(_canvasPool.clipStack!, + paragraphElement, offset, _canvasPool.currentTransform); for (final DomElement clipElement in clipElements) { rootElement.append(clipElement); _children.add(clipElement); @@ -1050,7 +1052,8 @@ class BitmapCanvas extends EngineCanvas { void endOfPaint() { _canvasPool.endOfPaint(); _elementCache?.commitFrame(); - if (_contains3dTransform && ui_web.browser.browserEngine == ui_web.BrowserEngine.webkit) { + if (_contains3dTransform && + ui_web.browser.browserEngine == ui_web.BrowserEngine.webkit) { // Copy the children list to avoid concurrent modification. final List children = rootElement.children.toList(); for (final DomElement element in children) { @@ -1080,10 +1083,12 @@ class BitmapCanvas extends EngineCanvas { final double width = ui.window.physicalSize.width * dpr; final double height = ui.window.physicalSize.height * dpr; final Vector3 topLeft = inverted.perspectiveTransform(x: 0, y: 0, z: 0); - final Vector3 topRight = inverted.perspectiveTransform(x: width, y: 0, z: 0); + final Vector3 topRight = + inverted.perspectiveTransform(x: width, y: 0, z: 0); final Vector3 bottomRight = inverted.perspectiveTransform(x: width, y: height, z: 0); - final Vector3 bottomLeft = inverted.perspectiveTransform(x: 0, y: height, z: 0); + final Vector3 bottomLeft = + inverted.perspectiveTransform(x: 0, y: height, z: 0); return ui.Rect.fromLTRB( math.min(topLeft.x, math.min(topRight.x, math.min(bottomRight.x, bottomLeft.x))), @@ -1254,13 +1259,17 @@ SvgBlendMode? blendModeToSvgEnum(ui.BlendMode? blendMode) { case ui.BlendMode.srcATop: return const SvgBlendMode(kCompositeSourceAtop, SVG_FEBLEND_MODE_UNKNOWN); case ui.BlendMode.dstOver: - return const SvgBlendMode(kCompositeDestinationOver, SVG_FEBLEND_MODE_UNKNOWN); + return const SvgBlendMode( + kCompositeDestinationOver, SVG_FEBLEND_MODE_UNKNOWN); case ui.BlendMode.dstIn: - return const SvgBlendMode(kCompositeDestinationIn, SVG_FEBLEND_MODE_UNKNOWN); + return const SvgBlendMode( + kCompositeDestinationIn, SVG_FEBLEND_MODE_UNKNOWN); case ui.BlendMode.dstOut: - return const SvgBlendMode(kCompositeDestinationOut, SVG_FEBLEND_MODE_UNKNOWN); + return const SvgBlendMode( + kCompositeDestinationOut, SVG_FEBLEND_MODE_UNKNOWN); case ui.BlendMode.dstATop: - return const SvgBlendMode(kCompositeDestinationAtop, SVG_FEBLEND_MODE_UNKNOWN); + return const SvgBlendMode( + kCompositeDestinationAtop, SVG_FEBLEND_MODE_UNKNOWN); case ui.BlendMode.plus: return const SvgBlendMode(kCompositeLighter, SVG_FEBLEND_MODE_UNKNOWN); case ui.BlendMode.src: @@ -1271,7 +1280,8 @@ SvgBlendMode? blendModeToSvgEnum(ui.BlendMode? blendMode) { // Falling back to multiply, ignoring alpha channel. // TODO(ferhat): only used for debug, find better fallback for web. case ui.BlendMode.modulate: - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_MULTIPLY); + return const SvgBlendMode( + kCompositeSourceOver, SVG_FEBLEND_MODE_MULTIPLY); case ui.BlendMode.screen: return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_SCREEN); case ui.BlendMode.overlay: @@ -1281,32 +1291,40 @@ SvgBlendMode? blendModeToSvgEnum(ui.BlendMode? blendMode) { case ui.BlendMode.lighten: return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_LIGHTEN); case ui.BlendMode.colorDodge: - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_COLOR_DODGE); + return const SvgBlendMode( + kCompositeSourceOver, SVG_FEBLEND_MODE_COLOR_DODGE); case ui.BlendMode.colorBurn: - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_COLOR_BURN); + return const SvgBlendMode( + kCompositeSourceOver, SVG_FEBLEND_MODE_COLOR_BURN); case ui.BlendMode.hardLight: - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_HARD_LIGHT); + return const SvgBlendMode( + kCompositeSourceOver, SVG_FEBLEND_MODE_HARD_LIGHT); case ui.BlendMode.softLight: - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_SOFT_LIGHT); + return const SvgBlendMode( + kCompositeSourceOver, SVG_FEBLEND_MODE_SOFT_LIGHT); case ui.BlendMode.difference: - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_DIFFERENCE); + return const SvgBlendMode( + kCompositeSourceOver, SVG_FEBLEND_MODE_DIFFERENCE); case ui.BlendMode.exclusion: - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_EXCLUSION); + return const SvgBlendMode( + kCompositeSourceOver, SVG_FEBLEND_MODE_EXCLUSION); case ui.BlendMode.hue: return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_HUE); case ui.BlendMode.saturation: - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_SATURATION); + return const SvgBlendMode( + kCompositeSourceOver, SVG_FEBLEND_MODE_SATURATION); case ui.BlendMode.color: return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_COLOR); case ui.BlendMode.luminosity: - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_LUMINOSITY); + return const SvgBlendMode( + kCompositeSourceOver, SVG_FEBLEND_MODE_LUMINOSITY); default: assert( false, 'Flutter Web does not support the blend mode: $blendMode', ); - return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_NORMAL); + return const SvgBlendMode(kCompositeSourceOver, SVG_FEBLEND_MODE_NORMAL); } } @@ -1344,8 +1362,8 @@ String stringForStrokeJoin(ui.StrokeJoin strokeJoin) { /// overflow:hidden with bounds to clip child or sets a clip-path to clip /// it's contents. The clipping rectangles are nested and returned together /// with a list of svg elements that provide clip-paths. -List _clipContent(List clipStack, - DomElement content, ui.Offset offset, Matrix4 currentTransform) { +List _clipContent(List clipStack, DomElement content, + ui.Offset offset, Matrix4 currentTransform) { DomElement? root, curElement; final List clipDefs = []; final int len = clipStack.length; diff --git a/lib/web_ui/lib/src/engine/html/canvas.dart b/lib/web_ui/lib/src/engine/html/canvas.dart index c086a832e4f66..220756f482bdf 100644 --- a/lib/web_ui/lib/src/engine/html/canvas.dart +++ b/lib/web_ui/lib/src/engine/html/canvas.dart @@ -7,11 +7,11 @@ import 'dart:typed_data'; import 'package:ui/ui.dart' as ui; -import '../picture.dart'; import '../util.dart'; import '../validators.dart'; import '../vector_math.dart'; import 'painting.dart'; +import 'picture.dart'; import 'recording_canvas.dart'; import 'render_vertices.dart'; diff --git a/lib/web_ui/lib/src/engine/html/image.dart b/lib/web_ui/lib/src/engine/html/image.dart new file mode 100644 index 0000000000000..72c9f9ddbbda9 --- /dev/null +++ b/lib/web_ui/lib/src/engine/html/image.dart @@ -0,0 +1,126 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; + +import 'package:ui/src/engine.dart'; +import 'package:ui/ui.dart' as ui; + +class HtmlRendererImageCodec extends HtmlImageElementCodec { + HtmlRendererImageCodec(super.src, {super.chunkCallback}); + + @override + ui.Image createImageFromHTMLImageElement( + DomHTMLImageElement image, + int naturalWidth, + int naturalHeight, + ) { + return HtmlImage(image, naturalWidth, naturalHeight); + } +} + +class HtmlRendererBlobCodec extends HtmlBlobCodec { + HtmlRendererBlobCodec(super.blob); + + @override + ui.Image createImageFromHTMLImageElement( + DomHTMLImageElement image, + int naturalWidth, + int naturalHeight, + ) { + return HtmlImage(image, naturalWidth, naturalHeight); + } +} + +class HtmlImage implements ui.Image { + HtmlImage(this.imgElement, this.width, this.height) { + ui.Image.onCreate?.call(this); + } + + final DomHTMLImageElement imgElement; + bool _didClone = false; + + bool _disposed = false; + @override + void dispose() { + ui.Image.onDispose?.call(this); + // Do nothing. The codec that owns this image should take care of + // releasing the object url. + assert(() { + _disposed = true; + return true; + }()); + } + + @override + bool get debugDisposed { + bool? result; + assert(() { + result = _disposed; + return true; + }()); + + if (result != null) { + return result!; + } + + throw StateError( + 'Image.debugDisposed is only available when asserts are enabled.'); + } + + @override + ui.Image clone() => this; + + @override + bool isCloneOf(ui.Image other) => other == this; + + @override + List? debugGetOpenHandleStackTraces() => null; + + @override + final int width; + + @override + final int height; + + @override + Future toByteData( + {ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba}) { + switch (format) { + // TODO(ColdPaleLight): https://github.com/flutter/flutter/issues/89128 + // The format rawRgba always returns straight rather than premul currently. + case ui.ImageByteFormat.rawRgba: + case ui.ImageByteFormat.rawStraightRgba: + final DomCanvasElement canvas = createDomCanvasElement() + ..width = width.toDouble() + ..height = height.toDouble(); + final DomCanvasRenderingContext2D ctx = canvas.context2D; + ctx.drawImage(imgElement, 0, 0); + final DomImageData imageData = ctx.getImageData(0, 0, width, height); + return Future.value(imageData.data.buffer.asByteData()); + default: + if (imgElement.src?.startsWith('data:') ?? false) { + final UriData data = UriData.fromUri(Uri.parse(imgElement.src!)); + return Future.value( + data.contentAsBytes().buffer.asByteData()); + } else { + return Future.value(); + } + } + } + + @override + ui.ColorSpace get colorSpace => ui.ColorSpace.sRGB; + + DomHTMLImageElement cloneImageElement() { + if (!_didClone) { + _didClone = true; + imgElement.style.position = 'absolute'; + } + return imgElement.cloneNode(true) as DomHTMLImageElement; + } + + @override + String toString() => '[$width\u00D7$height]'; +} diff --git a/lib/web_ui/lib/src/engine/html/picture.dart b/lib/web_ui/lib/src/engine/html/picture.dart index eb47c407f91a4..312b2642b9716 100644 --- a/lib/web_ui/lib/src/engine/html/picture.dart +++ b/lib/web_ui/lib/src/engine/html/picture.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:async'; import 'dart:math' as math; import 'dart:typed_data'; @@ -10,16 +11,133 @@ import 'package:ui/ui.dart' as ui; import '../dom.dart'; import '../engine_canvas.dart'; import '../frame_reference.dart'; -import '../picture.dart'; import '../util.dart'; import '../vector_math.dart'; import 'bitmap_canvas.dart'; import 'debug_canvas_reuse_overlay.dart'; import 'dom_canvas.dart'; +import 'image.dart'; import 'path/path_metrics.dart'; +import 'recording_canvas.dart'; import 'surface.dart'; import 'surface_stats.dart'; +class EnginePictureRecorder implements ui.PictureRecorder { + EnginePictureRecorder(); + + RecordingCanvas? _canvas; + late ui.Rect cullRect; + bool _isRecording = false; + + RecordingCanvas beginRecording(ui.Rect bounds) { + assert(!_isRecording); + cullRect = bounds; + _isRecording = true; + return _canvas = RecordingCanvas(cullRect); + } + + @override + bool get isRecording => _isRecording; + + @override + EnginePicture endRecording() { + if (!_isRecording) { + // The mobile version returns an empty picture in this case. To match the + // behavior we produce a blank picture too. + beginRecording(ui.Rect.largest); + } + _isRecording = false; + _canvas!.endRecording(); + final EnginePicture result = EnginePicture(_canvas, cullRect); + // We invoke the handler here, not in the Picture constructor, because we want + // [result.approximateBytesUsed] to be available for the handler. + ui.Picture.onCreate?.call(result); + return result; + } +} + +/// An implementation of [ui.Picture] which is backed by a [RecordingCanvas]. +class EnginePicture implements ui.Picture { + /// This class is created by the engine, and should not be instantiated + /// or extended directly. + /// + /// To create a [Picture], use a [PictureRecorder]. + EnginePicture(this.recordingCanvas, this.cullRect); + + @override + Future toImage(int width, int height) async { + final ui.Rect imageRect = + ui.Rect.fromLTRB(0, 0, width.toDouble(), height.toDouble()); + final BitmapCanvas canvas = BitmapCanvas.imageData(imageRect); + recordingCanvas!.apply(canvas, imageRect); + final String imageDataUrl = canvas.toDataUrl(); + final DomHTMLImageElement imageElement = createDomHTMLImageElement() + ..src = imageDataUrl + ..width = width.toDouble() + ..height = height.toDouble(); + + // The image loads asynchronously. We need to wait before returning, + // otherwise the returned HtmlImage will be temporarily unusable. + final Completer onImageLoaded = Completer.sync(); + + // Ignoring the returned futures from onError and onLoad because we're + // communicating through the `onImageLoaded` completer. + late final DomEventListener errorListener; + errorListener = createDomEventListener((DomEvent event) { + onImageLoaded.completeError(event); + imageElement.removeEventListener('error', errorListener); + }); + imageElement.addEventListener('error', errorListener); + late final DomEventListener loadListener; + loadListener = createDomEventListener((DomEvent event) { + onImageLoaded.complete(HtmlImage( + imageElement, + width, + height, + )); + imageElement.removeEventListener('load', loadListener); + }); + imageElement.addEventListener('load', loadListener); + return onImageLoaded.future; + } + + @override + ui.Image toImageSync(int width, int height) { + throw UnsupportedError( + 'toImageSync is not supported on the HTML backend. Use drawPicture instead, or toImage.'); + } + + bool _disposed = false; + + @override + void dispose() { + ui.Picture.onDispose?.call(this); + _disposed = true; + } + + @override + bool get debugDisposed { + bool? result; + assert(() { + result = _disposed; + return true; + }()); + + if (result != null) { + return result!; + } + + throw StateError( + 'Picture.debugDisposed is only available when asserts are enabled.'); + } + + @override + int get approximateBytesUsed => 0; + + final RecordingCanvas? recordingCanvas; + final ui.Rect? cullRect; +} + // TODO(yjbanov): this is currently very naive. We probably want to cache // fewer large canvases than small canvases. We could also // improve cache hit count if we did not require exact canvas @@ -228,8 +346,7 @@ class PersistedPicture extends PersistedLeafSurface { if (parent!.projectedClip == null) { _exactLocalCullRect = localPaintBounds; } else { - _exactLocalCullRect = - localPaintBounds!.intersect(parent!.projectedClip!); + _exactLocalCullRect = localPaintBounds!.intersect(parent!.projectedClip!); } if (_exactLocalCullRect!.width <= 0 || _exactLocalCullRect!.height <= 0) { _exactLocalCullRect = ui.Rect.zero; 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 1494cf333d085..1f353fae20802 100644 --- a/lib/web_ui/lib/src/engine/html/recording_canvas.dart +++ b/lib/web_ui/lib/src/engine/html/recording_canvas.dart @@ -8,7 +8,6 @@ import 'dart:typed_data'; import 'package:ui/ui.dart' as ui; import '../engine_canvas.dart'; -import '../picture.dart'; import '../rrect_renderer.dart'; import '../shadow.dart'; import '../text/canvas_paragraph.dart'; @@ -17,6 +16,7 @@ import '../vector_math.dart'; import 'painting.dart'; import 'path/path.dart'; import 'path/path_utils.dart'; +import 'picture.dart'; import 'render_vertices.dart'; import 'shaders/image_shader.dart'; @@ -24,7 +24,7 @@ import 'shaders/image_shader.dart'; const bool _debugDumpPaintCommands = false; // Returns the squared length of the x, y (of a border radius). -double _measureBorderRadius(double x, double y) => x*x + y*y; +double _measureBorderRadius(double x, double y) => x * x + y * y; /// Records canvas commands to be applied to a [EngineCanvas]. /// @@ -314,7 +314,8 @@ class RecordingCanvas { _commands.add(command); } - ui.Rect? getDestinationClipBounds() => _paintBounds.getDestinationClipBounds(); + ui.Rect? getDestinationClipBounds() => + _paintBounds.getDestinationClipBounds(); void drawColor(ui.Color color, ui.BlendMode blendMode) { assert(!_recordingEnded); @@ -539,7 +540,8 @@ class RecordingCanvas { _didDraw = true; final double left = offset.dx; final double top = offset.dy; - final PaintDrawImage command = PaintDrawImage(image, offset, paint.paintData); + final PaintDrawImage command = + PaintDrawImage(image, offset, paint.paintData); _paintBounds.growLTRB( left, top, left + image.width, top + image.height, command); _commands.add(command); @@ -845,7 +847,8 @@ class PaintTransform extends PaintCommand { String toString() { String result = super.toString(); assert(() { - result = 'transform(Matrix4.fromFloat32List(Float32List.fromList([${matrix4.join(', ')}])))'; + result = + 'transform(Matrix4.fromFloat32List(Float32List.fromList([${matrix4.join(', ')}])))'; return true; }()); return result; @@ -1421,7 +1424,8 @@ class Ellipse extends PathCommand { anticlockwise ? startAngle - endAngle : endAngle - startAngle, matrix4, bezierPath); - targetPath.addPathWithMode(bezierPath, 0, 0, matrix4, SPathAddPathMode.kAppend); + targetPath.addPathWithMode( + bezierPath, 0, 0, matrix4, SPathAddPathMode.kAppend); } void _drawArcWithBezier( @@ -1680,7 +1684,8 @@ class RRectCommand extends PathCommand { void transform(Float32List matrix4, SurfacePath targetPath) { final ui.Path roundRectPath = ui.Path(); RRectToPathRenderer(roundRectPath).render(rrect); - targetPath.addPathWithMode(roundRectPath, 0, 0, matrix4, SPathAddPathMode.kAppend); + targetPath.addPathWithMode( + roundRectPath, 0, 0, matrix4, SPathAddPathMode.kAppend); } @override diff --git a/lib/web_ui/lib/src/engine/html/renderer.dart b/lib/web_ui/lib/src/engine/html/renderer.dart index b41fac3739234..96720c592c768 100644 --- a/lib/web_ui/lib/src/engine/html/renderer.dart +++ b/lib/web_ui/lib/src/engine/html/renderer.dart @@ -45,11 +45,8 @@ class HtmlRenderer implements Renderer { List? textureCoordinates, List? colors, List? indices, - }) => SurfaceVertices( - mode, - positions, - colors: colors, - indices: indices); + }) => + SurfaceVertices(mode, positions, colors: colors, indices: indices); @override ui.Vertices createVerticesRaw( @@ -58,25 +55,20 @@ class HtmlRenderer implements Renderer { Float32List? textureCoordinates, Int32List? colors, Uint16List? indices, - }) => SurfaceVertices.raw( - mode, - positions, - colors: colors, - indices: indices); + }) => + SurfaceVertices.raw(mode, positions, colors: colors, indices: indices); @override ui.Canvas createCanvas(ui.PictureRecorder recorder, [ui.Rect? cullRect]) => - SurfaceCanvas(recorder as EnginePictureRecorder, 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); + 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( @@ -86,38 +78,27 @@ class HtmlRenderer implements Renderer { List? colorStops, ui.TileMode tileMode = ui.TileMode.clamp, Float32List? matrix4, - ]) => GradientRadial(center, radius, colors, colorStops, tileMode, matrix4); + ]) => + 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); + 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(); @@ -127,45 +108,48 @@ class HtmlRenderer implements Renderer { // 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); + 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}) { + 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.'); + throw UnimplementedError( + 'ImageFilter.dilate not implemented for HTML renderer.'); } @override - ui.ImageFilter createErodeImageFilter({double radiusX = 0.0, double radiusY = 0.0}) { + 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.'); + 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); + 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}) { + 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.'); + throw UnimplementedError( + 'ImageFilter.erode not implemented for HTML renderer.'); } @override - Future instantiateImageCodec( - Uint8List list, { - int? targetWidth, - int? targetHeight, - bool allowUpscaling = true}) async { + Future instantiateImageCodec(Uint8List list, + {int? targetWidth, int? targetHeight, bool allowUpscaling = true}) async { final DomBlob blob = createDomBlob([list.buffer]); - return HtmlBlobCodec(blob); + return HtmlRendererBlobCodec(blob); } @override @@ -173,38 +157,35 @@ class HtmlRenderer implements Renderer { Uri uri, { ui_web.ImageCodecChunkCallback? chunkCallback, }) async { - return HtmlCodec(uri.toString(), chunkCallback: chunkCallback); + return HtmlRendererImageCodec(uri.toString(), chunkCallback: 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 - }) { + 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); + + 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); + 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(); @@ -218,111 +199,112 @@ class HtmlRenderer implements 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, - leadingDistribution: leadingDistribution, - 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, - ); + 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, + leadingDistribution: leadingDistribution, + 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); + CanvasParagraphBuilder(style as EngineParagraphStyle); @override Future renderScene(ui.Scene scene, ui.FlutterView view) async { - final EngineFlutterView implicitView = EnginePlatformDispatcher.instance.implicitView!; + final EngineFlutterView implicitView = + EnginePlatformDispatcher.instance.implicitView!; scene as SurfaceScene; implicitView.dom.setScene(scene.webOnlyRootElement!); final FrameTimingRecorder? recorder = scene.timingRecorder; @@ -331,7 +313,7 @@ class HtmlRenderer implements Renderer { } @override - void clearFragmentProgramCache() { } + void clearFragmentProgramCache() {} @override Future createFragmentProgram(String assetKey) { @@ -339,34 +321,35 @@ class HtmlRenderer implements Renderer { } @override - ui.LineMetrics createLineMetrics({ - required bool hardBreak, - required double ascent, - required double descent, - required double unscaledAscent, - required double height, - required double width, - required double left, - required double baseline, - required int lineNumber - }) => EngineLineMetrics( - hardBreak: hardBreak, - ascent: ascent, - descent: descent, - unscaledAscent: unscaledAscent, - height: height, - width: width, - left: left, - baseline: baseline, - lineNumber: lineNumber - ); - - @override - Future createImageFromImageBitmap(DomImageBitmap imageSource) async { + ui.LineMetrics createLineMetrics( + {required bool hardBreak, + required double ascent, + required double descent, + required double unscaledAscent, + required double height, + required double width, + required double left, + required double baseline, + required int lineNumber}) => + EngineLineMetrics( + hardBreak: hardBreak, + ascent: ascent, + descent: descent, + unscaledAscent: unscaledAscent, + height: height, + width: width, + left: left, + baseline: baseline, + lineNumber: lineNumber); + + @override + Future createImageFromImageBitmap( + DomImageBitmap imageSource) async { final int width = imageSource.width.toDartInt; final int height = imageSource.height.toDartInt; final OffScreenCanvas canvas = OffScreenCanvas(width, height); - final DomCanvasRenderingContextBitmapRenderer context = canvas.getBitmapRendererContext()!; + final DomCanvasRenderingContextBitmapRenderer context = + canvas.getBitmapRendererContext()!; context.transferFromImageBitmap(imageSource); final DomHTMLImageElement imageElement = createDomHTMLImageElement(); late final DomEventListener loadListener; @@ -378,7 +361,8 @@ class HtmlRenderer implements Renderer { imageElement.removeEventListener('error', errorListener); }); errorListener = createDomEventListener((DomEvent event) { - completer.completeError(Exception('Failed to create image from image bitmap.')); + completer.completeError( + Exception('Failed to create image from image bitmap.')); imageElement.removeEventListener('load', loadListener); imageElement.removeEventListener('error', errorListener); }); 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 68d0457bc797d..ff63108231e6e 100644 --- a/lib/web_ui/lib/src/engine/html/scene_builder.dart +++ b/lib/web_ui/lib/src/engine/html/scene_builder.dart @@ -10,7 +10,6 @@ import 'package:ui/ui_web/src/ui_web.dart' as ui_web; import '../../engine.dart' show FrameTimingRecorder, kProfileApplyFrame, kProfilePrerollFrame; import '../display.dart'; import '../dom.dart'; -import '../picture.dart'; import '../profiler.dart'; import '../util.dart'; import '../vector_math.dart'; 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 59801155ad9a5..2b6be0d435976 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 @@ -8,9 +8,9 @@ import 'package:ui/ui.dart' as ui; import '../../browser_detection.dart'; import '../../dom.dart'; -import '../../html_image_codec.dart'; import '../../safe_browser_api.dart'; import '../../vector_math.dart'; +import '../image.dart'; import '../render_vertices.dart'; import 'vertex_shaders.dart'; @@ -83,7 +83,8 @@ class EngineImageShader implements ui.ImageShader { final int imageHeight = image.height; final int newWidth = imageWidth * mirrorX; final int newHeight = imageHeight * mirrorY; - final OffScreenCanvas offscreenCanvas = OffScreenCanvas(newWidth, newHeight); + final OffScreenCanvas offscreenCanvas = + OffScreenCanvas(newWidth, newHeight); final Object renderContext = offscreenCanvas.getContext2d()!; for (int y = 0; y < mirrorY; y++) { for (int x = 0; x < mirrorX; x++) { @@ -151,7 +152,8 @@ class EngineImageShader implements ui.ImageShader { const int vertexCount = 6; final Float32List vertices = Float32List(vertexCount * 2); - final ui.Rect vRect = shaderBounds.translate(-shaderBounds.left, -shaderBounds.top); + final ui.Rect vRect = + shaderBounds.translate(-shaderBounds.left, -shaderBounds.top); vertices[0] = vRect.left; vertices[1] = vRect.top; vertices[2] = vRect.right; @@ -168,20 +170,15 @@ class EngineImageShader implements ui.ImageShader { final Object positionAttributeLocation = gl.getAttributeLocation(glProgram.program, 'position'); - setupVertexTransforms(gl, glProgram, 0, 0, - widthInPixels.toDouble(), heightInPixels.toDouble(), transform); + setupVertexTransforms(gl, glProgram, 0, 0, widthInPixels.toDouble(), + heightInPixels.toDouble(), transform); - requiresTileOffset = shaderBounds.left !=0 || shaderBounds.top != 0; + requiresTileOffset = shaderBounds.left != 0 || shaderBounds.top != 0; /// To map from vertex position to texture coordinate in 0..1 range, /// we setup scalar to be used in vertex shader. - setupTextureTransform( - gl, - glProgram, - shaderBounds.left, - shaderBounds.top, - 1.0 / image.width.toDouble(), - 1.0 / image.height.toDouble()); + setupTextureTransform(gl, glProgram, shaderBounds.left, shaderBounds.top, + 1.0 / image.width.toDouble(), 1.0 / image.height.toDouble()); /// Setup geometry. /// @@ -192,12 +189,14 @@ class EngineImageShader implements ui.ImageShader { if (isWebGl2) { /// Create a vertex array object. vao = gl.createVertexArray(); + /// Set vertex array object as active one. gl.bindVertexArray(vao!); } /// Turn on position attribute. gl.enableVertexAttribArray(positionAttributeLocation); + /// Bind buffer as position buffer and transfer data. gl.bindArrayBuffer(positionsBuffer); bufferVertexData(gl, vertices, ui.window.devicePixelRatio); @@ -215,6 +214,7 @@ class EngineImageShader implements ui.ImageShader { /// Copy image to the texture. final Object? texture = gl.createTexture(); + /// Texture units are a global array of references to the textures. /// By setting activeTexture, we associate the bound texture to a unit. /// Every time we call a texture function such as texImage2D with a target @@ -230,11 +230,11 @@ class EngineImageShader implements ui.ImageShader { if (isWebGl2) { /// Texture REPEAT and MIRROR is only supported in WebGL 2, for /// WebGL 1.0 we let shader compute correct uv coordinates. - gl.texParameteri(gl.kTexture2D, gl.kTextureWrapS, - tileModeToGlWrapping(gl, tileModeX)); + gl.texParameteri( + gl.kTexture2D, gl.kTextureWrapS, tileModeToGlWrapping(gl, tileModeX)); - gl.texParameteri(gl.kTexture2D, gl.kTextureWrapT, - tileModeToGlWrapping(gl, tileModeY)); + gl.texParameteri( + gl.kTexture2D, gl.kTextureWrapT, tileModeToGlWrapping(gl, tileModeY)); /// Mipmapping saves your texture in different resolutions /// so the graphics card can choose which resolution is optimal diff --git a/lib/web_ui/lib/src/engine/html_image_codec.dart b/lib/web_ui/lib/src/engine/html_image_element_codec.dart similarity index 58% rename from lib/web_ui/lib/src/engine/html_image_codec.dart rename to lib/web_ui/lib/src/engine/html_image_element_codec.dart index facba38c0951f..b40fec7dabcf0 100644 --- a/lib/web_ui/lib/src/engine/html_image_codec.dart +++ b/lib/web_ui/lib/src/engine/html_image_element_codec.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:typed_data'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; @@ -12,20 +11,20 @@ import 'dom.dart'; import 'safe_browser_api.dart'; Object? get _jsImageDecodeFunction => getJsProperty( - getJsProperty( - getJsProperty(domWindow, 'Image'), - 'prototype', - ), - 'decode', -); + getJsProperty( + getJsProperty(domWindow, 'Image'), + 'prototype', + ), + 'decode', + ); final bool _supportsDecode = _jsImageDecodeFunction != null; // TODO(mdebbar): Deprecate this and remove it. // https://github.com/flutter/flutter/issues/127395 typedef WebOnlyImageCodecChunkCallback = ui_web.ImageCodecChunkCallback; -class HtmlCodec implements ui.Codec { - HtmlCodec(this.src, {this.chunkCallback}); +abstract class HtmlImageElementCodec implements ui.Codec { + HtmlImageElementCodec(this.src, {this.chunkCallback}); final String src; final ui_web.ImageCodecChunkCallback? chunkCallback; @@ -42,7 +41,7 @@ class HtmlCodec implements ui.Codec { // Currently there is no way to watch decode progress, so // we add 0/100 , 100/100 progress callbacks to enable loading progress // builders to create UI. - chunkCallback?.call(0, 100); + chunkCallback?.call(0, 100); if (_supportsDecode) { final DomHTMLImageElement imgElement = createDomHTMLImageElement(); imgElement.src = src; @@ -56,12 +55,14 @@ class HtmlCodec implements ui.Codec { int naturalWidth = imgElement.naturalWidth.toInt(); int naturalHeight = imgElement.naturalHeight.toInt(); // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=700533. - if (naturalWidth == 0 && naturalHeight == 0 && ui_web.browser.browserEngine == ui_web.BrowserEngine.firefox) { + if (naturalWidth == 0 && + naturalHeight == 0 && + ui_web.browser.browserEngine == ui_web.BrowserEngine.firefox) { const int kDefaultImageSizeFallback = 300; naturalWidth = kDefaultImageSizeFallback; naturalHeight = kDefaultImageSizeFallback; } - final HtmlImage image = HtmlImage( + final ui.Image image = createImageFromHTMLImageElement( imgElement, naturalWidth, naturalHeight, @@ -101,7 +102,7 @@ class HtmlCodec implements ui.Codec { } imgElement.removeEventListener('load', loadListener); imgElement.removeEventListener('error', errorListener); - final HtmlImage image = HtmlImage( + final ui.Image image = createImageFromHTMLImageElement( imgElement, imgElement.naturalWidth.toInt(), imgElement.naturalHeight.toInt(), @@ -112,11 +113,18 @@ class HtmlCodec implements ui.Codec { imgElement.src = src; } + /// Creates a [ui.Image] from an [HTMLImageElement] that has been loaded. + ui.Image createImageFromHTMLImageElement( + DomHTMLImageElement image, + int naturalWidth, + int naturalHeight, + ); + @override void dispose() {} } -class HtmlBlobCodec extends HtmlCodec { +abstract class HtmlBlobCodec extends HtmlImageElementCodec { HtmlBlobCodec(this.blob) : super(domWindow.URL.createObjectURL(blob)); final DomBlob blob; @@ -136,93 +144,3 @@ class SingleFrameInfo implements ui.FrameInfo { @override final ui.Image image; } - -class HtmlImage implements ui.Image { - HtmlImage(this.imgElement, this.width, this.height) { - ui.Image.onCreate?.call(this); - } - - final DomHTMLImageElement imgElement; - bool _didClone = false; - - bool _disposed = false; - @override - void dispose() { - ui.Image.onDispose?.call(this); - // Do nothing. The codec that owns this image should take care of - // releasing the object url. - assert(() { - _disposed = true; - return true; - }()); - } - - @override - bool get debugDisposed { - bool? result; - assert(() { - result = _disposed; - return true; - }()); - - if (result != null) { - return result!; - } - - throw StateError('Image.debugDisposed is only available when asserts are enabled.'); - } - - - @override - ui.Image clone() => this; - - @override - bool isCloneOf(ui.Image other) => other == this; - - @override - List? debugGetOpenHandleStackTraces() => null; - - @override - final int width; - - @override - final int height; - - @override - Future toByteData({ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba}) { - switch (format) { - // TODO(ColdPaleLight): https://github.com/flutter/flutter/issues/89128 - // The format rawRgba always returns straight rather than premul currently. - case ui.ImageByteFormat.rawRgba: - case ui.ImageByteFormat.rawStraightRgba: - final DomCanvasElement canvas = createDomCanvasElement() - ..width = width.toDouble() - ..height = height.toDouble(); - final DomCanvasRenderingContext2D ctx = canvas.context2D; - ctx.drawImage(imgElement, 0, 0); - final DomImageData imageData = ctx.getImageData(0, 0, width, height); - return Future.value(imageData.data.buffer.asByteData()); - default: - if (imgElement.src?.startsWith('data:') ?? false) { - final UriData data = UriData.fromUri(Uri.parse(imgElement.src!)); - return Future.value(data.contentAsBytes().buffer.asByteData()); - } else { - return Future.value(); - } - } - } - - @override - ui.ColorSpace get colorSpace => ui.ColorSpace.sRGB; - - DomHTMLImageElement cloneImageElement() { - if (!_didClone) { - _didClone = true; - imgElement.style.position = 'absolute'; - } - return imgElement.cloneNode(true) as DomHTMLImageElement; - } - - @override - String toString() => '[$width\u00D7$height]'; -} diff --git a/lib/web_ui/lib/src/engine/image_decoder.dart b/lib/web_ui/lib/src/engine/image_decoder.dart index a6e3bbd524681..94d564952dd1a 100644 --- a/lib/web_ui/lib/src/engine/image_decoder.dart +++ b/lib/web_ui/lib/src/engine/image_decoder.dart @@ -60,10 +60,8 @@ abstract class BrowserImageDecoder implements ui.Codec { } void _debugCheckNotDisposed() { - assert( - !_isDisposed, - 'Cannot use this image decoder. It has been disposed of.' - ); + assert(!_isDisposed, + 'Cannot use this image decoder. It has been disposed of.'); } /// The index of the frame that will be decoded on the next call of [getNextFrame]; @@ -95,7 +93,8 @@ abstract class BrowserImageDecoder implements ui.Codec { if (_cachedWebDecoder != null) { // Give the cached value some time for reuse, e.g. if the image is // currently animating. - _cacheExpirationClock.datetime = DateTime.now().add(_kWebDecoderExpireDuration); + _cacheExpirationClock.datetime = + DateTime.now().add(_kWebDecoderExpireDuration); return _cachedWebDecoder!; } @@ -131,9 +130,11 @@ abstract class BrowserImageDecoder implements ui.Codec { // We coerce the DOM's `repetitionCount` into an int by explicitly // handling `infinity`. Note: This will still throw if the DOM returns a // `NaN`. - final double rawRepetitionCount = webDecoder.tracks.selectedTrack!.repetitionCount; - repetitionCount = rawRepetitionCount == double.infinity ? -1 : - rawRepetitionCount.toInt(); + final double rawRepetitionCount = + webDecoder.tracks.selectedTrack!.repetitionCount; + repetitionCount = rawRepetitionCount == double.infinity + ? -1 + : rawRepetitionCount.toInt(); _cachedWebDecoder = webDecoder; // Expire the decoder if it's not used for several seconds. If the image is @@ -150,7 +151,8 @@ abstract class BrowserImageDecoder implements ui.Codec { _cachedWebDecoder = null; _cacheExpirationClock.callback = null; }; - _cacheExpirationClock.datetime = DateTime.now().add(_kWebDecoderExpireDuration); + _cacheExpirationClock.datetime = + DateTime.now().add(_kWebDecoderExpireDuration); return webDecoder; } catch (error) { @@ -163,10 +165,9 @@ abstract class BrowserImageDecoder implements ui.Codec { } } throw ImageCodecException( - "Failed to decode image using the browser's ImageDecoder API.\n" - 'Image source: $debugSource\n' - 'Original browser error: $error' - ); + "Failed to decode image using the browser's ImageDecoder API.\n" + 'Image source: $debugSource\n' + 'Original browser error: $error'); } } @@ -183,11 +184,15 @@ abstract class BrowserImageDecoder implements ui.Codec { // Duration can be null if the image is not animated. However, Flutter // requires a non-null value. 0 indicates that the frame is meant to be // displayed indefinitely, which is fine for a static image. - final Duration duration = Duration(microseconds: frame.duration?.toInt() ?? 0); + final Duration duration = + Duration(microseconds: frame.duration?.toInt() ?? 0); final ui.Image image = generateImageFromVideoFrame(frame); return AnimatedImageFrameInfo(duration, image); } + /// Creates a [ui.Image] from a [VideoFrame]. Implementers of this class + /// should override this method to create a [ui.Image] that is appropriate + /// for their associated renderer. ui.Image generateImageFromVideoFrame(VideoFrame frame); } @@ -213,7 +218,8 @@ String? detectContentType(Uint8List data) { return debugContentTypeDetector!.call(data); } - formatLoop: for (final ImageFileFormat format in ImageFileFormat.values) { + formatLoop: + for (final ImageFileFormat format in ImageFileFormat.values) { if (data.length < format.header.length) { continue; } @@ -274,7 +280,8 @@ class ImageFileFormat { // https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/webcodecs/image_decoder_external.cc;l=38;drc=fd8802b593110ea18a97ef044f8a40dd24a622ec // PNG - ImageFileFormat([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A], 'image/png'), + ImageFileFormat( + [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A], 'image/png'), // GIF87a ImageFileFormat([0x47, 0x49, 0x46, 0x38, 0x37, 0x61], 'image/gif'), @@ -286,7 +293,20 @@ class ImageFileFormat { ImageFileFormat([0xFF, 0xD8, 0xFF], 'image/jpeg'), // WebP - ImageFileFormat([0x52, 0x49, 0x46, 0x46, null, null, null, null, 0x57, 0x45, 0x42, 0x50], 'image/webp'), + ImageFileFormat([ + 0x52, + 0x49, + 0x46, + 0x46, + null, + null, + null, + null, + 0x57, + 0x45, + 0x42, + 0x50 + ], 'image/webp'), // BMP ImageFileFormat([0x42, 0x4D], 'image/bmp'), @@ -302,7 +322,7 @@ typedef DebugContentTypeDetector = String? Function(Uint8List); /// This is useful in tests, for example, to test unsupported content types. DebugContentTypeDetector? debugContentTypeDetector; -/// A string of bytes that every AVIF image contains somehwere in its first 16 +/// A string of bytes that every AVIF image contains somewhere in its first 16 /// bytes. /// /// This signature is necessary but not sufficient, which may lead to false @@ -320,7 +340,8 @@ final List _avifSignature = 'ftyp'.codeUnits; /// Optimistically detects whether [data] is an AVIF image file. bool isAvif(Uint8List data) { - firstByteLoop: for (int i = 0; i < 16; i += 1) { + firstByteLoop: + for (int i = 0; i < 16; i += 1) { for (int j = 0; j < _avifSignature.length; j += 1) { if (i + j >= data.length) { // Reached EOF without finding the signature. @@ -360,12 +381,10 @@ class ResizingCodec implements ui.Codec { final ui.FrameInfo frameInfo = await delegate.getNextFrame(); return AnimatedImageFrameInfo( frameInfo.duration, - scaleImageIfNeeded( - frameInfo.image, - targetWidth: targetWidth, - targetHeight: targetHeight, - allowUpscaling: allowUpscaling - ), + scaleImageIfNeeded(frameInfo.image, + targetWidth: targetWidth, + targetHeight: targetHeight, + allowUpscaling: allowUpscaling), ); } @@ -407,21 +426,18 @@ ui.Image scaleImageIfNeeded( }) { final int width = image.width; final int height = image.height; - final ui.Size? scaledSize = _scaledSize( - width, - height, - targetWidth, - targetHeight - ); + final ui.Size? scaledSize = + _scaledSize(width, height, targetWidth, targetHeight); if (scaledSize == null) { return image; } if (!allowUpscaling && - (scaledSize.width > width || scaledSize.height > height)) { - return image; + (scaledSize.width > width || scaledSize.height > height)) { + return image; } - final ui.Rect outputRect = ui.Rect.fromLTWH(0, 0, scaledSize.width, scaledSize.height); + final ui.Rect outputRect = + ui.Rect.fromLTWH(0, 0, scaledSize.width, scaledSize.height); final ui.PictureRecorder recorder = ui.PictureRecorder(); final ui.Canvas canvas = ui.Canvas(recorder, outputRect); @@ -432,10 +448,8 @@ ui.Image scaleImageIfNeeded( ui.Paint(), ); final ui.Picture picture = recorder.endRecording(); - final ui.Image finalImage = picture.toImageSync( - scaledSize.width.round(), - scaledSize.height.round() - ); + final ui.Image finalImage = + picture.toImageSync(scaledSize.width.round(), scaledSize.height.round()); picture.dispose(); image.dispose(); return finalImage; diff --git a/lib/web_ui/lib/src/engine/picture.dart b/lib/web_ui/lib/src/engine/picture.dart deleted file mode 100644 index db469b7ccc65e..0000000000000 --- a/lib/web_ui/lib/src/engine/picture.dart +++ /dev/null @@ -1,127 +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:ui/ui.dart' as ui; - -import 'dom.dart'; -import 'html/bitmap_canvas.dart'; -import 'html/recording_canvas.dart'; -import 'html_image_codec.dart'; - -/// An implementation of [ui.PictureRecorder] backed by a [RecordingCanvas]. -class EnginePictureRecorder implements ui.PictureRecorder { - EnginePictureRecorder(); - - RecordingCanvas? _canvas; - late ui.Rect cullRect; - bool _isRecording = false; - - RecordingCanvas beginRecording(ui.Rect bounds) { - assert(!_isRecording); - cullRect = bounds; - _isRecording = true; - return _canvas = RecordingCanvas(cullRect); - } - - @override - bool get isRecording => _isRecording; - - @override - EnginePicture endRecording() { - if (!_isRecording) { - // The mobile version returns an empty picture in this case. To match the - // behavior we produce a blank picture too. - beginRecording(ui.Rect.largest); - } - _isRecording = false; - _canvas!.endRecording(); - final EnginePicture result = EnginePicture(_canvas, cullRect); - // We invoke the handler here, not in the Picture constructor, because we want - // [result.approximateBytesUsed] to be available for the handler. - ui.Picture.onCreate?.call(result); - return result; - } -} - -/// An implementation of [ui.Picture] which is backed by a [RecordingCanvas]. -class EnginePicture implements ui.Picture { - /// This class is created by the engine, and should not be instantiated - /// or extended directly. - /// - /// To create a [Picture], use a [PictureRecorder]. - EnginePicture(this.recordingCanvas, this.cullRect); - - @override - Future toImage(int width, int height) async { - final ui.Rect imageRect = ui.Rect.fromLTRB(0, 0, width.toDouble(), height.toDouble()); - final BitmapCanvas canvas = BitmapCanvas.imageData(imageRect); - recordingCanvas!.apply(canvas, imageRect); - final String imageDataUrl = canvas.toDataUrl(); - final DomHTMLImageElement imageElement = createDomHTMLImageElement() - ..src = imageDataUrl - ..width = width.toDouble() - ..height = height.toDouble(); - - // The image loads asynchronously. We need to wait before returning, - // otherwise the returned HtmlImage will be temporarily unusable. - final Completer onImageLoaded = Completer.sync(); - - // Ignoring the returned futures from onError and onLoad because we're - // communicating through the `onImageLoaded` completer. - late final DomEventListener errorListener; - errorListener = createDomEventListener((DomEvent event) { - onImageLoaded.completeError(event); - imageElement.removeEventListener('error', errorListener); - }); - imageElement.addEventListener('error', errorListener); - late final DomEventListener loadListener; - loadListener = createDomEventListener((DomEvent event) { - onImageLoaded.complete(HtmlImage( - imageElement, - width, - height, - )); - imageElement.removeEventListener('load', loadListener); - }); - imageElement.addEventListener('load', loadListener); - return onImageLoaded.future; - } - - @override - ui.Image toImageSync(int width, int height) { - throw UnsupportedError('toImageSync is not supported on the HTML backend. Use drawPicture instead, or toImage.'); - } - - bool _disposed = false; - - @override - void dispose() { - ui.Picture.onDispose?.call(this); - _disposed = true; - } - - @override - bool get debugDisposed { - bool? result; - assert(() { - result = _disposed; - return true; - }()); - - if (result != null) { - return result!; - } - - throw StateError('Picture.debugDisposed is only available when asserts are enabled.'); - } - - - @override - int get approximateBytesUsed => 0; - - final RecordingCanvas? recordingCanvas; - final ui.Rect? cullRect; -} diff --git a/lib/web_ui/test/engine/image/html_image_codec_test.dart b/lib/web_ui/test/engine/image/html_image_element_codec_test.dart similarity index 83% rename from lib/web_ui/test/engine/image/html_image_codec_test.dart rename to lib/web_ui/test/engine/image/html_image_element_codec_test.dart index e161cea5fb25e..bbbf9ed2a58aa 100644 --- a/lib/web_ui/test/engine/image/html_image_codec_test.dart +++ b/lib/web_ui/test/engine/image/html_image_element_codec_test.dart @@ -7,7 +7,8 @@ import 'dart:typed_data'; import 'package:test/bootstrap/browser.dart'; import 'package:test/test.dart'; -import 'package:ui/src/engine/html_image_codec.dart'; +import 'package:ui/src/engine/html/image.dart'; +import 'package:ui/src/engine/html_image_element_codec.dart'; import 'package:ui/ui.dart' as ui; import 'package:ui/ui_web/src/ui_web.dart' as ui_web; @@ -19,7 +20,7 @@ void main() { Future testMain() async { setUpUnitTests(); - group('HtmCodec', () { + group('$HtmlImageElementCodec', () { test('supports raw images - RGBA8888', () async { final Completer completer = Completer(); const int width = 200; @@ -59,14 +60,16 @@ Future testMain() async { expect(image.height, height); }); test('loads sample image', () async { - final HtmlCodec codec = HtmlCodec('sample_image1.png'); + final HtmlImageElementCodec codec = + HtmlRendererImageCodec('sample_image1.png'); final ui.FrameInfo frameInfo = await codec.getNextFrame(); expect(frameInfo.image, isNotNull); expect(frameInfo.image.width, 100); expect(frameInfo.image.toString(), '[100×100]'); }); test('dispose image image', () async { - final HtmlCodec codec = HtmlCodec('sample_image1.png'); + final HtmlImageElementCodec codec = + HtmlRendererImageCodec('sample_image1.png'); final ui.FrameInfo frameInfo = await codec.getNextFrame(); expect(frameInfo.image, isNotNull); expect(frameInfo.image.debugDisposed, isFalse); @@ -75,8 +78,8 @@ Future testMain() async { }); test('provides image loading progress', () async { final StringBuffer buffer = StringBuffer(); - final HtmlCodec codec = HtmlCodec('sample_image1.png', - chunkCallback: (int loaded, int total) { + final HtmlImageElementCodec codec = HtmlRendererImageCodec( + 'sample_image1.png', chunkCallback: (int loaded, int total) { buffer.write('$loaded/$total,'); }); await codec.getNextFrame(); @@ -86,7 +89,7 @@ Future testMain() async { /// Regression test for Firefox /// https://github.com/flutter/flutter/issues/66412 test('Returns nonzero natural width/height', () async { - final HtmlCodec codec = HtmlCodec( + final HtmlImageElementCodec codec = HtmlRendererImageCodec( 'data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9I' 'jAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dG' 'l0bGU+QWJzdHJhY3QgaWNvbjwvdGl0bGU+PHBhdGggZD0iTTEyIDBjOS42MDEgMCAx' @@ -105,7 +108,8 @@ Future testMain() async { group('ImageCodecUrl', () { test('loads sample image from web', () async { final Uri uri = Uri.base.resolve('sample_image1.png'); - final HtmlCodec codec = await ui_web.createImageCodecFromUrl(uri) as HtmlCodec; + final HtmlImageElementCodec codec = + await ui_web.createImageCodecFromUrl(uri) as HtmlImageElementCodec; final ui.FrameInfo frameInfo = await codec.getNextFrame(); expect(frameInfo.image, isNotNull); expect(frameInfo.image.width, 100); @@ -113,10 +117,10 @@ Future testMain() async { test('provides image loading progress from web', () async { final Uri uri = Uri.base.resolve('sample_image1.png'); final StringBuffer buffer = StringBuffer(); - final HtmlCodec codec = await ui_web.createImageCodecFromUrl(uri, - chunkCallback: (int loaded, int total) { + final HtmlImageElementCodec codec = await ui_web + .createImageCodecFromUrl(uri, chunkCallback: (int loaded, int total) { buffer.write('$loaded/$total,'); - }) as HtmlCodec; + }) as HtmlImageElementCodec; await codec.getNextFrame(); expect(buffer.toString(), '0/100,100/100,'); }); From ba84e44784cde7089506176612c8be0d55340516 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Mon, 20 May 2024 17:59:14 -0700 Subject: [PATCH 07/18] [Impeller] Reland: Remove Entity capture/AiksInspector. (#52932) Resolves https://github.com/flutter/flutter/issues/134748. This was a really fun experiment. I learned a lot from it, and it genuinely helped me solve some coverage-related problems, but the reality is it was too little too late -- by the time we had this capture system, we had already solved most of the problems that would have benefitted from this. It's been a few months since I've used or extended the capabilities of this capture system for something, and I don't have the spare time/energy to give it the love it needs to realize the vision I had for it. I still almost exclusively use a combination of native frame captures and print debugging to solve problems. RIP in peace. This reverts commit https://github.com/flutter/engine/commit/351390905b81930cad5d8af947f69126786b46f0. (https://github.com/flutter/engine/pull/52680) --- ci/licenses_golden/licenses_flutter | 8 - impeller/BUILD.gn | 4 - impeller/aiks/BUILD.gn | 2 - impeller/aiks/aiks_playground.cc | 25 +- impeller/aiks/aiks_playground.h | 2 - impeller/aiks/aiks_playground_inspector.cc | 277 ---------------- impeller/aiks/aiks_playground_inspector.h | 55 ---- impeller/aiks/aiks_unittests.cc | 33 -- impeller/core/BUILD.gn | 2 - impeller/core/capture.cc | 220 ------------- impeller/core/capture.h | 300 ------------------ impeller/entity/contents/content_context.h | 5 +- impeller/entity/contents/contents.cc | 3 +- .../entity/contents/solid_color_contents.cc | 3 +- impeller/entity/contents/texture_contents.cc | 21 +- impeller/entity/entity.cc | 8 - impeller/entity/entity.h | 6 - impeller/entity/entity_pass.cc | 36 +-- impeller/entity/entity_pass.h | 4 - impeller/entity/entity_pass_clip_stack.cc | 12 - impeller/renderer/context.cc | 4 +- impeller/renderer/context.h | 3 - impeller/tools/impeller.gni | 3 - shell/gpu/gpu_surface_gl_impeller.h | 1 + shell/gpu/gpu_surface_vulkan_impeller.h | 1 + testing/impeller_golden_tests_output.txt | 3 - 26 files changed, 33 insertions(+), 1008 deletions(-) delete mode 100644 impeller/aiks/aiks_playground_inspector.cc delete mode 100644 impeller/aiks/aiks_playground_inspector.h delete mode 100644 impeller/core/capture.cc delete mode 100644 impeller/core/capture.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index fea7dbcef2234..e0733e40eee9d 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -42255,8 +42255,6 @@ ORIGIN: ../../../flutter/impeller/aiks/aiks_context.cc + ../../../flutter/LICENS ORIGIN: ../../../flutter/impeller/aiks/aiks_context.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/aiks/aiks_playground.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/aiks/aiks_playground.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/aiks/aiks_playground_inspector.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/aiks/aiks_playground_inspector.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/aiks/canvas.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/aiks/canvas.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/aiks/canvas_benchmarks.cc + ../../../flutter/LICENSE @@ -42354,8 +42352,6 @@ ORIGIN: ../../../flutter/impeller/core/allocator.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/allocator.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/buffer_view.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/buffer_view.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/core/capture.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/impeller/core/capture.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/device_buffer.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/device_buffer.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/impeller/core/device_buffer_descriptor.cc + ../../../flutter/LICENSE @@ -45126,8 +45122,6 @@ FILE: ../../../flutter/impeller/aiks/aiks_context.cc FILE: ../../../flutter/impeller/aiks/aiks_context.h FILE: ../../../flutter/impeller/aiks/aiks_playground.cc FILE: ../../../flutter/impeller/aiks/aiks_playground.h -FILE: ../../../flutter/impeller/aiks/aiks_playground_inspector.cc -FILE: ../../../flutter/impeller/aiks/aiks_playground_inspector.h FILE: ../../../flutter/impeller/aiks/canvas.cc FILE: ../../../flutter/impeller/aiks/canvas.h FILE: ../../../flutter/impeller/aiks/canvas_benchmarks.cc @@ -45225,8 +45219,6 @@ FILE: ../../../flutter/impeller/core/allocator.cc FILE: ../../../flutter/impeller/core/allocator.h FILE: ../../../flutter/impeller/core/buffer_view.cc FILE: ../../../flutter/impeller/core/buffer_view.h -FILE: ../../../flutter/impeller/core/capture.cc -FILE: ../../../flutter/impeller/core/capture.h FILE: ../../../flutter/impeller/core/device_buffer.cc FILE: ../../../flutter/impeller/core/device_buffer.h FILE: ../../../flutter/impeller/core/device_buffer_descriptor.cc diff --git a/impeller/BUILD.gn b/impeller/BUILD.gn index 86a638abea5f8..8e7aee9978027 100644 --- a/impeller/BUILD.gn +++ b/impeller/BUILD.gn @@ -14,10 +14,6 @@ config("impeller_public_config") { defines += [ "IMPELLER_DEBUG=1" ] } - if (impeller_capture) { - defines += [ "IMPELLER_ENABLE_CAPTURE=1" ] - } - if (impeller_supports_rendering) { defines += [ "IMPELLER_SUPPORTS_RENDERING=1" ] } diff --git a/impeller/aiks/BUILD.gn b/impeller/aiks/BUILD.gn index b98a96ecd1211..35a97ac681868 100644 --- a/impeller/aiks/BUILD.gn +++ b/impeller/aiks/BUILD.gn @@ -45,8 +45,6 @@ impeller_component("aiks_playground") { sources = [ "aiks_playground.cc", "aiks_playground.h", - "aiks_playground_inspector.cc", - "aiks_playground_inspector.h", ] deps = [ ":aiks", diff --git a/impeller/aiks/aiks_playground.cc b/impeller/aiks/aiks_playground.cc index d423698f5a483..df533a434aab2 100644 --- a/impeller/aiks/aiks_playground.cc +++ b/impeller/aiks/aiks_playground.cc @@ -5,6 +5,7 @@ #include "impeller/aiks/aiks_playground.h" #include +#include #include "impeller/aiks/aiks_context.h" #include "impeller/display_list/dl_dispatcher.h" @@ -24,14 +25,24 @@ void AiksPlayground::SetTypographerContext( } void AiksPlayground::TearDown() { - inspector_.HackResetDueToTextureLeaks(); PlaygroundTest::TearDown(); } bool AiksPlayground::OpenPlaygroundHere(Picture picture) { - return OpenPlaygroundHere([&picture](AiksContext& renderer) -> Picture { - return std::move(picture); - }); + if (!switches_.enable_playground) { + return true; + } + + AiksContext renderer(GetContext(), typographer_context_); + + if (!renderer.IsValid()) { + return false; + } + + return Playground::OpenPlaygroundHere( + [&renderer, &picture](RenderTarget& render_target) -> bool { + return renderer.Render(picture, render_target, true); + }); } bool AiksPlayground::OpenPlaygroundHere(AiksPlaygroundCallback callback) { @@ -46,10 +57,8 @@ bool AiksPlayground::OpenPlaygroundHere(AiksPlaygroundCallback callback) { } return Playground::OpenPlaygroundHere( - [this, &renderer, &callback](RenderTarget& render_target) -> bool { - const std::optional& picture = inspector_.RenderInspector( - renderer, [&]() { return callback(renderer); }); - + [&renderer, &callback](RenderTarget& render_target) -> bool { + std::optional picture = callback(renderer); if (!picture.has_value()) { return false; } diff --git a/impeller/aiks/aiks_playground.h b/impeller/aiks/aiks_playground.h index ee219f94d94a3..c2e9532520232 100644 --- a/impeller/aiks/aiks_playground.h +++ b/impeller/aiks/aiks_playground.h @@ -7,7 +7,6 @@ #include "flutter/display_list/display_list.h" #include "impeller/aiks/aiks_context.h" -#include "impeller/aiks/aiks_playground_inspector.h" #include "impeller/aiks/picture.h" #include "impeller/playground/playground_test.h" #include "impeller/typographer/typographer_context.h" @@ -41,7 +40,6 @@ class AiksPlayground : public PlaygroundTest { private: std::shared_ptr typographer_context_; - AiksInspector inspector_; AiksPlayground(const AiksPlayground&) = delete; diff --git a/impeller/aiks/aiks_playground_inspector.cc b/impeller/aiks/aiks_playground_inspector.cc deleted file mode 100644 index 89ace8c5d1283..0000000000000 --- a/impeller/aiks/aiks_playground_inspector.cc +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "impeller/aiks/aiks_playground_inspector.h" - -#include - -#include "impeller/core/capture.h" -#include "impeller/entity/entity_pass.h" -#include "impeller/renderer/context.h" -#include "third_party/imgui/imgui.h" -#include "third_party/imgui/imgui_internal.h" - -namespace impeller { - -static const char* kElementsWindowName = "Elements"; -static const char* kPropertiesWindowName = "Properties"; - -static const std::initializer_list kSupportedDocuments = { - EntityPass::kCaptureDocumentName}; - -AiksInspector::AiksInspector() = default; - -const std::optional& AiksInspector::RenderInspector( - AiksContext& aiks_context, - const std::function()>& picture_callback) { - //---------------------------------------------------------------------------- - /// Configure the next frame. - /// - - RenderCapture(aiks_context.GetContext()->capture); - - //---------------------------------------------------------------------------- - /// Configure the next frame. - /// - - if (ImGui::IsKeyPressed(ImGuiKey_Z)) { - wireframe_ = !wireframe_; - aiks_context.GetContentContext().SetWireframe(wireframe_); - } - - if (ImGui::IsKeyPressed(ImGuiKey_C)) { - capturing_ = !capturing_; - if (capturing_) { - aiks_context.GetContext()->capture = - CaptureContext::MakeAllowlist({kSupportedDocuments}); - } - } - if (!capturing_) { - hovered_element_ = nullptr; - selected_element_ = nullptr; - aiks_context.GetContext()->capture = CaptureContext::MakeInactive(); - std::optional new_picture = picture_callback(); - - // If the new picture doesn't have a pass, that means it was already moved - // into the inspector. Simply re-emit the last received valid picture. - if (!new_picture.has_value() || new_picture->pass) { - last_picture_ = std::move(new_picture); - } - } - - return last_picture_; -} - -void AiksInspector::HackResetDueToTextureLeaks() { - last_picture_.reset(); -} - -static const auto kPropertiesProcTable = CaptureProcTable{ - .boolean = - [](CaptureBooleanProperty& p) { - ImGui::Checkbox(p.label.c_str(), &p.value); - }, - .integer = - [](CaptureIntegerProperty& p) { - if (p.options.range.has_value()) { - ImGui::SliderInt(p.label.c_str(), &p.value, - static_cast(p.options.range->min), - static_cast(p.options.range->max)); - return; - } - ImGui::InputInt(p.label.c_str(), &p.value); - }, - .scalar = - [](CaptureScalarProperty& p) { - if (p.options.range.has_value()) { - ImGui::SliderFloat(p.label.c_str(), &p.value, p.options.range->min, - p.options.range->max); - return; - } - ImGui::DragFloat(p.label.c_str(), &p.value, 0.01); - }, - .point = - [](CapturePointProperty& p) { - if (p.options.range.has_value()) { - ImGui::SliderFloat2(p.label.c_str(), - reinterpret_cast(&p.value), - p.options.range->min, p.options.range->max); - return; - } - ImGui::DragFloat2(p.label.c_str(), reinterpret_cast(&p.value), - 0.01); - }, - .vector3 = - [](CaptureVector3Property& p) { - if (p.options.range.has_value()) { - ImGui::SliderFloat3(p.label.c_str(), - reinterpret_cast(&p.value), - p.options.range->min, p.options.range->max); - return; - } - ImGui::DragFloat3(p.label.c_str(), reinterpret_cast(&p.value), - 0.01); - }, - .rect = - [](CaptureRectProperty& p) { - ImGui::DragFloat4(p.label.c_str(), reinterpret_cast(&p.value), - 0.01); - }, - .color = - [](CaptureColorProperty& p) { - ImGui::ColorEdit4(p.label.c_str(), - reinterpret_cast(&p.value)); - }, - .matrix = - [](CaptureMatrixProperty& p) { - float* pointer = reinterpret_cast(&p.value); - ImGui::DragFloat4((p.label + " X basis").c_str(), pointer, 0.001); - ImGui::DragFloat4((p.label + " Y basis").c_str(), pointer + 4, 0.001); - ImGui::DragFloat4((p.label + " Z basis").c_str(), pointer + 8, 0.001); - ImGui::DragFloat4((p.label + " Translation").c_str(), pointer + 12, - 0.001); - }, - .string = - [](CaptureStringProperty& p) { - ImGui::InputTextEx(p.label.c_str(), "", - // Fine as long as it's read-only. - const_cast(p.value.c_str()), p.value.size(), - ImVec2(0, 0), ImGuiInputTextFlags_ReadOnly); - }, -}; - -void AiksInspector::RenderCapture(CaptureContext& capture_context) { - if (!capturing_) { - return; - } - - auto document = capture_context.GetDocument(EntityPass::kCaptureDocumentName); - - //---------------------------------------------------------------------------- - /// Setup a shared dockspace to collect the capture windows. - /// - - ImGui::SetNextWindowBgAlpha(0.5); - ImGui::Begin("Capture"); - auto dockspace_id = ImGui::GetID("CaptureDockspace"); - if (!ImGui::DockBuilderGetNode(dockspace_id)) { - ImGui::SetWindowSize(ImVec2(370, 680)); - ImGui::SetWindowPos(ImVec2(640, 55)); - - ImGui::DockBuilderRemoveNode(dockspace_id); - ImGui::DockBuilderAddNode(dockspace_id); - - ImGuiID opposite_id; - ImGuiID up_id = ImGui::DockBuilderSplitNode(dockspace_id, ImGuiDir_Up, 0.6, - nullptr, &opposite_id); - ImGuiID down_id = ImGui::DockBuilderSplitNode(opposite_id, ImGuiDir_Down, - 0.0, nullptr, nullptr); - ImGui::DockBuilderDockWindow(kElementsWindowName, up_id); - ImGui::DockBuilderDockWindow(kPropertiesWindowName, down_id); - - ImGui::DockBuilderFinish(dockspace_id); - } - ImGui::DockSpace(dockspace_id); - ImGui::End(); // Capture window. - - //---------------------------------------------------------------------------- - /// Element hierarchy window. - /// - - ImGui::Begin(kElementsWindowName); - auto root_element = document.GetElement(); - hovered_element_ = nullptr; - if (root_element) { - RenderCaptureElement(*root_element); - } - ImGui::End(); // Hierarchy window. - - if (selected_element_) { - //---------------------------------------------------------------------------- - /// Properties window. - /// - - ImGui::Begin(kPropertiesWindowName); - { - selected_element_->properties.Iterate([&](CaptureProperty& property) { - property.Invoke(kPropertiesProcTable); - }); - } - ImGui::End(); // Inspector window. - - //---------------------------------------------------------------------------- - /// Selected coverage highlighting. - /// - - auto coverage_property = - selected_element_->properties.FindFirstByLabel("Coverage"); - if (coverage_property) { - auto coverage = coverage_property->AsRect(); - if (coverage.has_value()) { - Scalar scale = ImGui::GetWindowDpiScale(); - ImGui::GetBackgroundDrawList()->AddRect( - ImVec2(coverage->GetLeft() / scale, - coverage->GetTop() / scale), // p_min - ImVec2(coverage->GetRight() / scale, - coverage->GetBottom() / scale), // p_max - 0x992222FF, // col - 0.0, // rounding - ImDrawFlags_None, // flags - 8.0); // thickness - } - } - } - - //---------------------------------------------------------------------------- - /// Hover coverage highlight. - /// - - if (hovered_element_) { - auto coverage_property = - hovered_element_->properties.FindFirstByLabel("Coverage"); - if (coverage_property) { - auto coverage = coverage_property->AsRect(); - if (coverage.has_value()) { - Scalar scale = ImGui::GetWindowDpiScale(); - ImGui::GetBackgroundDrawList()->AddRect( - ImVec2(coverage->GetLeft() / scale, - coverage->GetTop() / scale), // p_min - ImVec2(coverage->GetRight() / scale, - coverage->GetBottom() / scale), // p_max - 0x66FF2222, // col - 0.0, // rounding - ImDrawFlags_None, // flags - 8.0); // thickness - } - } - } -} - -void AiksInspector::RenderCaptureElement(CaptureElement& element) { - ImGui::PushID(&element); - - bool is_selected = selected_element_ == &element; - bool has_children = element.children.Count() > 0; - - bool opened = ImGui::TreeNodeEx( - element.label.c_str(), (is_selected ? ImGuiTreeNodeFlags_Selected : 0) | - (has_children ? 0 : ImGuiTreeNodeFlags_Leaf) | - ImGuiTreeNodeFlags_SpanFullWidth | - ImGuiTreeNodeFlags_OpenOnArrow | - ImGuiTreeNodeFlags_DefaultOpen); - if (ImGui::IsItemClicked()) { - selected_element_ = &element; - } - if (ImGui::IsItemHovered()) { - hovered_element_ = &element; - } - if (opened) { - element.children.Iterate( - [&](CaptureElement& child) { RenderCaptureElement(child); }); - ImGui::TreePop(); - } - ImGui::PopID(); -} - -} // namespace impeller diff --git a/impeller/aiks/aiks_playground_inspector.h b/impeller/aiks/aiks_playground_inspector.h deleted file mode 100644 index 297fb16b64e69..0000000000000 --- a/impeller/aiks/aiks_playground_inspector.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_IMPELLER_AIKS_AIKS_PLAYGROUND_INSPECTOR_H_ -#define FLUTTER_IMPELLER_AIKS_AIKS_PLAYGROUND_INSPECTOR_H_ - -#include -#include - -#include "flutter/fml/macros.h" -#include "impeller/aiks/aiks_context.h" -#include "impeller/aiks/picture.h" -#include "impeller/core/capture.h" -#include "impeller/renderer/context.h" - -namespace impeller { - -class AiksInspector { - public: - AiksInspector(); - - const std::optional& RenderInspector( - AiksContext& aiks_context, - const std::function()>& picture_callback); - - // Resets (releases) the underlying |Picture| object. - // - // Underlying issue: . - // - // The tear-down code is not running in the right order; we still have a - // reference to the |Picture| object when the |Context| is being destroyed, - // which causes the |Texture| objects to leak. - // - // TODO(matanlurey): https://github.com/flutter/flutter/issues/134748. - void HackResetDueToTextureLeaks(); - - private: - void RenderCapture(CaptureContext& capture_context); - void RenderCaptureElement(CaptureElement& element); - - bool capturing_ = false; - bool wireframe_ = false; - CaptureElement* hovered_element_ = nullptr; - CaptureElement* selected_element_ = nullptr; - std::optional last_picture_; - - AiksInspector(const AiksInspector&) = delete; - - AiksInspector& operator=(const AiksInspector&) = delete; -}; - -}; // namespace impeller - -#endif // FLUTTER_IMPELLER_AIKS_AIKS_PLAYGROUND_INSPECTOR_H_ diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 12c5414ae1b70..b214c91d027a8 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -20,7 +20,6 @@ #include "impeller/aiks/image_filter.h" #include "impeller/aiks/paint_pass_delegate.h" #include "impeller/aiks/testing/context_spy.h" -#include "impeller/core/capture.h" #include "impeller/core/device_buffer.h" #include "impeller/entity/contents/solid_color_contents.h" #include "impeller/geometry/color.h" @@ -2596,38 +2595,6 @@ TEST_P(AiksTest, PipelineBlendSingleParameter) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } -TEST_P(AiksTest, CaptureContext) { - auto capture_context = CaptureContext::MakeAllowlist({"TestDocument"}); - - auto callback = [&](AiksContext& renderer) -> std::optional { - Canvas canvas; - - capture_context.Rewind(); - auto document = capture_context.GetDocument("TestDocument"); - - auto color = document.AddColor("Background color", Color::CornflowerBlue()); - canvas.DrawPaint({.color = color}); - - if (AiksTest::ImGuiBegin("TestDocument", nullptr, - ImGuiWindowFlags_AlwaysAutoResize)) { - document.GetElement()->properties.Iterate([](CaptureProperty& property) { - property.Invoke({.color = [](CaptureColorProperty& p) { - ImGui::ColorEdit4(p.label.c_str(), - reinterpret_cast(&p.value)); - }}); - }); - ImGui::End(); - } - - return canvas.EndRecordingAsPicture(); - }; - OpenPlaygroundHere(callback); -} - -TEST_P(AiksTest, CaptureInactivatedByDefault) { - ASSERT_FALSE(GetContext()->capture.IsActive()); -} - // Regression test for https://github.com/flutter/flutter/issues/134678. TEST_P(AiksTest, ReleasesTextureOnTeardown) { auto context = MakeContext(); diff --git a/impeller/core/BUILD.gn b/impeller/core/BUILD.gn index e4587bda12a83..e526c46115313 100644 --- a/impeller/core/BUILD.gn +++ b/impeller/core/BUILD.gn @@ -10,8 +10,6 @@ impeller_component("core") { "allocator.h", "buffer_view.cc", "buffer_view.h", - "capture.cc", - "capture.h", "device_buffer.cc", "device_buffer.h", "device_buffer_descriptor.cc", diff --git a/impeller/core/capture.cc b/impeller/core/capture.cc deleted file mode 100644 index a4b4c462b829b..0000000000000 --- a/impeller/core/capture.cc +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "impeller/core/capture.h" - -#include -#include - -namespace impeller { - -//----------------------------------------------------------------------------- -/// CaptureProperty -/// - -CaptureProperty::CaptureProperty(const std::string& label, Options options) - : CaptureCursorListElement(label), options(options) {} - -CaptureProperty::~CaptureProperty() = default; - -bool CaptureProperty::MatchesCloselyEnough(const CaptureProperty& other) const { - if (label != other.label) { - return false; - } - if (GetType() != other.GetType()) { - return false; - } - return true; -} - -#define _CAPTURE_PROPERTY_CAST_DEFINITION(type_name, pascal_name, lower_name) \ - std::optional CaptureProperty::As##pascal_name() const { \ - if (GetType() != Type::k##pascal_name) { \ - return std::nullopt; \ - } \ - return reinterpret_cast(this) \ - ->value; \ - } - -_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_CAST_DEFINITION); - -#define _CAPTURE_PROPERTY_DEFINITION(type_name, pascal_name, lower_name) \ - Capture##pascal_name##Property::Capture##pascal_name##Property( \ - const std::string& label, type_name value, Options options) \ - : CaptureProperty(label, options), value(std::move(value)) {} \ - \ - std::shared_ptr \ - Capture##pascal_name##Property::Make(const std::string& label, \ - type_name value, Options options) { \ - auto result = std::shared_ptr( \ - new Capture##pascal_name##Property(label, std::move(value), options)); \ - return result; \ - } \ - \ - CaptureProperty::Type Capture##pascal_name##Property::GetType() const { \ - return Type::k##pascal_name; \ - } \ - \ - void Capture##pascal_name##Property::Invoke( \ - const CaptureProcTable& proc_table) { \ - proc_table.lower_name(*this); \ - } - -_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_DEFINITION); - -//----------------------------------------------------------------------------- -/// CaptureElement -/// - -CaptureElement::CaptureElement(const std::string& label) - : CaptureCursorListElement(label) {} - -std::shared_ptr CaptureElement::Make(const std::string& label) { - return std::shared_ptr(new CaptureElement(label)); -} - -void CaptureElement::Rewind() { - properties.Rewind(); - children.Rewind(); -} - -bool CaptureElement::MatchesCloselyEnough(const CaptureElement& other) const { - return label == other.label; -} - -//----------------------------------------------------------------------------- -/// Capture -/// - -Capture::Capture() = default; - -#ifdef IMPELLER_ENABLE_CAPTURE -Capture::Capture(const std::string& label) - : element_(CaptureElement::Make(label)), active_(true) { - element_->label = label; -} -#else -Capture::Capture(const std::string& label) {} -#endif - -Capture Capture::MakeInactive() { - return Capture(); -} - -std::shared_ptr Capture::GetElement() const { -#ifdef IMPELLER_ENABLE_CAPTURE - return element_; -#else - return nullptr; -#endif -} - -void Capture::Rewind() { - return GetElement()->Rewind(); -} - -#ifdef IMPELLER_ENABLE_CAPTURE -#define _CAPTURE_PROPERTY_RECORDER_DEFINITION(type_name, pascal_name, \ - lower_name) \ - type_name Capture::Add##pascal_name(std::string_view label, type_name value, \ - CaptureProperty::Options options) { \ - if (!active_) { \ - return value; \ - } \ - FML_DCHECK(element_ != nullptr); \ - \ - std::string label_clone = std::string(label); \ - auto new_value = Capture##pascal_name##Property::Make( \ - label_clone, std::move(value), options); \ - \ - auto next = std::reinterpret_pointer_cast( \ - element_->properties.GetNext(std::move(new_value), options.readonly)); \ - \ - return next->value; \ - } - -_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_RECORDER_DEFINITION); -#endif - -//----------------------------------------------------------------------------- -/// CaptureContext -/// - -#ifdef IMPELLER_ENABLE_CAPTURE -CaptureContext::CaptureContext() : active_(true) {} -CaptureContext::CaptureContext(std::initializer_list allowlist) - : active_(true), allowlist_(allowlist) {} -#else -CaptureContext::CaptureContext() {} -CaptureContext::CaptureContext(std::initializer_list allowlist) {} -#endif - -CaptureContext::CaptureContext(CaptureContext::InactiveFlag) {} - -CaptureContext CaptureContext::MakeInactive() { - return CaptureContext(InactiveFlag{}); -} - -CaptureContext CaptureContext::MakeAllowlist( - std::initializer_list allowlist) { - return CaptureContext(allowlist); -} - -bool CaptureContext::IsActive() const { -#ifdef IMPELLER_ENABLE_CAPTURE - return active_; -#else - return false; -#endif -} - -void CaptureContext::Rewind() { -#ifdef IMPELLER_ENABLE_CAPTURE - for (auto& [name, capture] : documents_) { - capture.GetElement()->Rewind(); - } -#else - return; -#endif -} - -Capture CaptureContext::GetDocument(const std::string& label) { -#ifdef IMPELLER_ENABLE_CAPTURE - if (!active_) { - return Capture::MakeInactive(); - } - - if (allowlist_.has_value()) { - if (allowlist_->find(label) == allowlist_->end()) { - return Capture::MakeInactive(); - } - } - - auto found = documents_.find(label); - if (found != documents_.end()) { - // Always rewind when fetching an existing document. - found->second.Rewind(); - return found->second; - } - - auto new_document = Capture(label); - documents_.emplace(label, new_document); - return new_document; -#else - return Capture::MakeInactive(); -#endif -} - -bool CaptureContext::DoesDocumentExist(const std::string& label) const { -#ifdef IMPELLER_ENABLE_CAPTURE - if (!active_) { - return false; - } - return documents_.find(label) != documents_.end(); -#else - return false; -#endif -} - -} // namespace impeller diff --git a/impeller/core/capture.h b/impeller/core/capture.h deleted file mode 100644 index 9e5c0d9318417..0000000000000 --- a/impeller/core/capture.h +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_IMPELLER_CORE_CAPTURE_H_ -#define FLUTTER_IMPELLER_CORE_CAPTURE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "flutter/fml/logging.h" -#include "flutter/fml/macros.h" -#include "impeller/geometry/color.h" -#include "impeller/geometry/matrix.h" -#include "impeller/geometry/point.h" -#include "impeller/geometry/rect.h" -#include "impeller/geometry/scalar.h" -#include "impeller/geometry/vector.h" - -namespace impeller { - -struct CaptureProcTable; - -#define _FOR_EACH_CAPTURE_PROPERTY(PROPERTY_V) \ - PROPERTY_V(bool, Boolean, boolean) \ - PROPERTY_V(int, Integer, integer) \ - PROPERTY_V(Scalar, Scalar, scalar) \ - PROPERTY_V(Point, Point, point) \ - PROPERTY_V(Vector3, Vector3, vector3) \ - PROPERTY_V(Rect, Rect, rect) \ - PROPERTY_V(Color, Color, color) \ - PROPERTY_V(Matrix, Matrix, matrix) \ - PROPERTY_V(std::string, String, string) - -template -struct CaptureCursorListElement { - std::string label; - - explicit CaptureCursorListElement(const std::string& label) : label(label){}; - - virtual ~CaptureCursorListElement() = default; - - //---------------------------------------------------------------------------- - /// @brief Determines if previously captured data matches closely enough with - /// newly recorded data to safely emitted in its place. If this - /// returns `false`, then the remaining elements in the capture list - /// are discarded and re-recorded. - /// - /// This mechanism ensures that the UI of an interactive inspector can - /// never deviate from reality, even if the schema of the captured - /// data were to significantly deviate. - /// - virtual bool MatchesCloselyEnough(const Type& other) const = 0; -}; - -#define _CAPTURE_TYPE(type_name, pascal_name, lower_name) k##pascal_name, - -#define _CAPTURE_PROPERTY_CAST_DECLARATION(type_name, pascal_name, lower_name) \ - std::optional As##pascal_name() const; - -/// A capturable property type -struct CaptureProperty : public CaptureCursorListElement { - enum class Type { _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_TYPE) }; - - struct Options { - struct Range { - Scalar min; - Scalar max; - }; - - /// Readonly properties are always re-recorded during capture. Any edits - /// made to readonly values in-between captures are overwritten during the - /// next capture. - bool readonly = false; - - /// An inspector hint that can be used for displaying sliders. Only used for - /// numeric types. Rounded down for integer types. - std::optional range; - }; - - Options options; - - CaptureProperty(const std::string& label, Options options); - - virtual ~CaptureProperty(); - - virtual Type GetType() const = 0; - - virtual void Invoke(const CaptureProcTable& proc_table) = 0; - - bool MatchesCloselyEnough(const CaptureProperty& other) const override; - - _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_CAST_DECLARATION) -}; - -#define _CAPTURE_PROPERTY_DECLARATION(type_name, pascal_name, lower_name) \ - struct Capture##pascal_name##Property final : public CaptureProperty { \ - type_name value; \ - \ - static std::shared_ptr \ - Make(const std::string& label, type_name value, Options options); \ - \ - /* |CaptureProperty| */ \ - Type GetType() const override; \ - \ - /* |CaptureProperty| */ \ - void Invoke(const CaptureProcTable& proc_table) override; \ - \ - private: \ - Capture##pascal_name##Property(const std::string& label, \ - type_name value, \ - Options options); \ - \ - FML_DISALLOW_COPY_AND_ASSIGN(Capture##pascal_name##Property); \ - }; - -_FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_DECLARATION); - -#define _CAPTURE_PROC(type_name, pascal_name, lower_name) \ - std::function lower_name = \ - [](Capture##pascal_name##Property& value) {}; - -struct CaptureProcTable { - _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROC) -}; - -template -class CapturePlaybackList { - public: - CapturePlaybackList() = default; - - ~CapturePlaybackList() { - // Force the list element type to inherit the CRTP type. We can't enforce - // this as a template requirement directly because `CaptureElement` has a - // recursive `CaptureCursorList` property, and so the - // compiler fails the check due to the type being incomplete. - static_assert(std::is_base_of_v, Type>); - } - - void Rewind() { cursor_ = 0; } - - size_t Count() { return values_.size(); } - - std::shared_ptr GetNext(std::shared_ptr captured, - bool force_overwrite) { - if (cursor_ < values_.size()) { - std::shared_ptr& result = values_[cursor_]; - - if (result->MatchesCloselyEnough(*captured)) { - if (force_overwrite) { - values_[cursor_] = captured; - } - // Safe playback is possible. - ++cursor_; - return result; - } - // The data has changed too much from the last capture to safely continue - // playback. Discard this and all subsequent elements to re-record. - values_.resize(cursor_); - } - - ++cursor_; - values_.push_back(captured); - return captured; - } - - std::shared_ptr FindFirstByLabel(const std::string& label) { - for (std::shared_ptr& value : values_) { - if (value->label == label) { - return value; - } - } - return nullptr; - } - - void Iterate(std::function iterator) const { - for (auto& value : values_) { - iterator(*value); - } - } - - private: - size_t cursor_ = 0; - std::vector> values_; - - CapturePlaybackList(const CapturePlaybackList&) = delete; - - CapturePlaybackList& operator=(const CapturePlaybackList&) = delete; -}; - -/// A document of capture data, containing a list of properties and a list -/// of subdocuments. -struct CaptureElement final : public CaptureCursorListElement { - CapturePlaybackList properties; - CapturePlaybackList children; - - static std::shared_ptr Make(const std::string& label); - - void Rewind(); - - bool MatchesCloselyEnough(const CaptureElement& other) const override; - - private: - explicit CaptureElement(const std::string& label); - - CaptureElement(const CaptureElement&) = delete; - - CaptureElement& operator=(const CaptureElement&) = delete; -}; - -#ifdef IMPELLER_ENABLE_CAPTURE -#define _CAPTURE_PROPERTY_RECORDER_DECLARATION(type_name, pascal_name, \ - lower_name) \ - type_name Add##pascal_name(std::string_view label, type_name value, \ - CaptureProperty::Options options = {}); -#else -#define _CAPTURE_PROPERTY_RECORDER_DECLARATION(type_name, pascal_name, \ - lower_name) \ - inline type_name Add##pascal_name(std::string_view label, type_name value, \ - CaptureProperty::Options options = {}) { \ - return value; \ - } -#endif - -class Capture { - public: - explicit Capture(const std::string& label); - - Capture(); - - static Capture MakeInactive(); - - inline Capture CreateChild(std::string_view label) { -#ifdef IMPELLER_ENABLE_CAPTURE - if (!active_) { - return Capture(); - } - - std::string label_copy = std::string(label); - auto new_capture = Capture(label_copy); - new_capture.element_ = - element_->children.GetNext(new_capture.element_, false); - new_capture.element_->Rewind(); - return new_capture; -#else - return Capture(); -#endif - } - - std::shared_ptr GetElement() const; - - void Rewind(); - - _FOR_EACH_CAPTURE_PROPERTY(_CAPTURE_PROPERTY_RECORDER_DECLARATION) - - private: -#ifdef IMPELLER_ENABLE_CAPTURE - std::shared_ptr element_; - bool active_ = false; -#endif -}; - -class CaptureContext { - public: - CaptureContext(); - - static CaptureContext MakeInactive(); - - static CaptureContext MakeAllowlist( - std::initializer_list allowlist); - - bool IsActive() const; - - void Rewind(); - - Capture GetDocument(const std::string& label); - - bool DoesDocumentExist(const std::string& label) const; - - private: - struct InactiveFlag {}; - explicit CaptureContext(InactiveFlag); - CaptureContext(std::initializer_list allowlist); - -#ifdef IMPELLER_ENABLE_CAPTURE - bool active_ = false; - std::optional> allowlist_; - std::unordered_map documents_; -#endif -}; - -} // namespace impeller - -#endif // FLUTTER_IMPELLER_CORE_CAPTURE_H_ diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index 1888845a222f8..aa173c3b04fc1 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -10,18 +10,17 @@ #include #include -#include "flutter/fml/build_config.h" #include "flutter/fml/logging.h" #include "flutter/fml/status_or.h" #include "impeller/base/validation.h" #include "impeller/core/formats.h" #include "impeller/core/host_buffer.h" -#include "impeller/entity/entity.h" #include "impeller/renderer/capabilities.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/pipeline.h" #include "impeller/renderer/pipeline_descriptor.h" #include "impeller/renderer/render_target.h" +#include "impeller/typographer/lazy_glyph_atlas.h" #include "impeller/typographer/typographer_context.h" #include "impeller/entity/border_mask_blur.frag.h" @@ -54,8 +53,6 @@ #include "impeller/entity/tiled_texture_fill.frag.h" #include "impeller/entity/yuv_to_rgb_filter.frag.h" -#include "impeller/typographer/glyph_atlas.h" - #include "impeller/entity/conical_gradient_ssbo_fill.frag.h" #include "impeller/entity/linear_gradient_ssbo_fill.frag.h" #include "impeller/entity/radial_gradient_ssbo_fill.frag.h" diff --git a/impeller/entity/contents/contents.cc b/impeller/entity/contents/contents.cc index 2c24482a544eb..421713761175e 100644 --- a/impeller/entity/contents/contents.cc +++ b/impeller/entity/contents/contents.cc @@ -6,12 +6,11 @@ #include #include "fml/logging.h" -#include "impeller/base/strings.h" #include "impeller/base/validation.h" #include "impeller/core/formats.h" #include "impeller/entity/contents/anonymous_contents.h" #include "impeller/entity/contents/content_context.h" -#include "impeller/entity/contents/texture_contents.h" +#include "impeller/entity/entity.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/render_pass.h" diff --git a/impeller/entity/contents/solid_color_contents.cc b/impeller/entity/contents/solid_color_contents.cc index 083ac7d61ec38..0c99d47990b7b 100644 --- a/impeller/entity/contents/solid_color_contents.cc +++ b/impeller/entity/contents/solid_color_contents.cc @@ -48,11 +48,10 @@ std::optional SolidColorContents::GetCoverage( bool SolidColorContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - auto capture = entity.GetCapture().CreateChild("SolidColorContents"); using VS = SolidFillPipeline::VertexShader; VS::FrameInfo frame_info; - frame_info.color = capture.AddColor("Color", GetColor()).Premultiply(); + frame_info.color = GetColor().Premultiply(); PipelineBuilderCallback pipeline_callback = [&renderer](ContentContextOptions options) { diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc index 72fce8d0ff211..a2af33e96c486 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc @@ -109,8 +109,6 @@ std::optional TextureContents::RenderToSnapshot( bool TextureContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { - auto capture = entity.GetCapture().CreateChild("TextureContents"); - using VS = TextureFillVertexShader; using FS = TextureFillFragmentShader; using FSStrict = TextureFillStrictSrcFragmentShader; @@ -124,18 +122,15 @@ bool TextureContents::Render(const ContentContext& renderer, texture_->GetTextureDescriptor().type == TextureType::kTextureExternalOES; FML_DCHECK(!is_external_texture); - auto source_rect = capture.AddRect("Source rect", source_rect_); auto texture_coords = - Rect::MakeSize(texture_->GetSize()).Project(source_rect); + Rect::MakeSize(texture_->GetSize()).Project(source_rect_); VertexBufferBuilder vertex_builder; - auto destination_rect = - capture.AddRect("Destination rect", destination_rect_); vertex_builder.AddVertices({ - {destination_rect.GetLeftTop(), texture_coords.GetLeftTop()}, - {destination_rect.GetRightTop(), texture_coords.GetRightTop()}, - {destination_rect.GetLeftBottom(), texture_coords.GetLeftBottom()}, - {destination_rect.GetRightBottom(), texture_coords.GetRightBottom()}, + {destination_rect_.GetLeftTop(), texture_coords.GetLeftTop()}, + {destination_rect_.GetRightTop(), texture_coords.GetRightTop()}, + {destination_rect_.GetLeftBottom(), texture_coords.GetLeftBottom()}, + {destination_rect_.GetRightBottom(), texture_coords.GetRightBottom()}, }); auto& host_buffer = renderer.GetTransientsBuffer(); @@ -170,11 +165,11 @@ bool TextureContents::Render(const ContentContext& renderer, // texel to ensure that linear filtering does not sample anything outside // the source rect bounds. auto strict_texture_coords = - Rect::MakeSize(texture_->GetSize()).Project(source_rect.Expand(-0.5)); + Rect::MakeSize(texture_->GetSize()).Project(source_rect_.Expand(-0.5)); FSStrict::FragInfo frag_info; frag_info.source_rect = Vector4(strict_texture_coords.GetLTRB()); - frag_info.alpha = capture.AddScalar("Alpha", GetOpacity()); + frag_info.alpha = GetOpacity(); FSStrict::BindFragInfo(pass, host_buffer.EmplaceUniform((frag_info))); FSStrict::BindTextureSampler( pass, texture_, @@ -182,7 +177,7 @@ bool TextureContents::Render(const ContentContext& renderer, sampler_descriptor_)); } else { FS::FragInfo frag_info; - frag_info.alpha = capture.AddScalar("Alpha", GetOpacity()); + frag_info.alpha = GetOpacity(); FS::BindFragInfo(pass, host_buffer.EmplaceUniform((frag_info))); FS::BindTextureSampler( pass, texture_, diff --git a/impeller/entity/entity.cc b/impeller/entity/entity.cc index 9111a61d29318..cb336892d3a61 100644 --- a/impeller/entity/entity.cc +++ b/impeller/entity/entity.cc @@ -188,16 +188,8 @@ Scalar Entity::DeriveTextScale() const { return GetTransform().GetMaxBasisLengthXY(); } -Capture& Entity::GetCapture() const { - return capture_; -} - Entity Entity::Clone() const { return Entity(*this); } -void Entity::SetCapture(Capture capture) const { - capture_ = std::move(capture); -} - } // namespace impeller diff --git a/impeller/entity/entity.h b/impeller/entity/entity.h index d2d4eb9596a64..0161d7153eaac 100644 --- a/impeller/entity/entity.h +++ b/impeller/entity/entity.h @@ -7,7 +7,6 @@ #include -#include "impeller/core/capture.h" #include "impeller/entity/contents/contents.h" #include "impeller/geometry/color.h" #include "impeller/geometry/matrix.h" @@ -123,10 +122,6 @@ class Entity { Scalar DeriveTextScale() const; - Capture& GetCapture() const; - - void SetCapture(Capture capture) const; - Entity Clone() const; private: @@ -136,7 +131,6 @@ class Entity { std::shared_ptr contents_; BlendMode blend_mode_ = BlendMode::kSourceOver; uint32_t clip_depth_ = 1u; - mutable Capture capture_; }; } // namespace impeller diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 596f4412daf84..4ed42ceeb0cd8 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -44,8 +44,6 @@ std::tuple, BlendMode> ElementAsBackgroundColor( } } // namespace -const std::string EntityPass::kCaptureDocumentName = "EntityPass"; - EntityPass::EntityPass() = default; EntityPass::~EntityPass() = default; @@ -354,9 +352,6 @@ bool EntityPass::DoesBackdropGetRead(ContentContext& renderer) const { bool EntityPass::Render(ContentContext& renderer, const RenderTarget& render_target) const { - auto capture = - renderer.GetContext()->capture.GetDocument(kCaptureDocumentName); - renderer.GetRenderTargetCache()->Start(); fml::ScopedCleanupClosure reset_state([&renderer]() { renderer.GetLazyGlyphAtlas()->ResetTextFrames(); @@ -377,10 +372,6 @@ bool EntityPass::Render(ContentContext& renderer, return false; } - capture.AddRect("Coverage", - Rect::MakeSize(root_render_target.GetRenderTargetSize()), - {.readonly = true}); - const auto& lazy_glyph_atlas = renderer.GetLazyGlyphAtlas(); IterateAllEntities([&lazy_glyph_atlas](const Entity& entity) { if (const auto& contents = entity.GetContents()) { @@ -402,7 +393,6 @@ bool EntityPass::Render(ContentContext& renderer, GetClearColorOrDefault(render_target.GetRenderTargetSize())); if (!OnRender(renderer, // renderer - capture, // capture offscreen_target.GetRenderTarget() .GetRenderTargetSize(), // root_pass_size offscreen_target, // pass_target @@ -509,7 +499,6 @@ bool EntityPass::Render(ContentContext& renderer, return OnRender( // renderer, // renderer - capture, // capture root_render_target.GetRenderTargetSize(), // root_pass_size pass_target, // pass_target Point(), // global_pass_position @@ -521,7 +510,6 @@ bool EntityPass::Render(ContentContext& renderer, EntityPass::EntityResult EntityPass::GetEntityForElement( const EntityPass::Element& element, ContentContext& renderer, - Capture& capture, InlinePassContext& pass_context, ISize root_pass_size, Point global_pass_position, @@ -533,7 +521,6 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( /// if (const auto& entity = std::get_if(&element)) { Entity element_entity = entity->Clone(); - element_entity.SetCapture(capture.CreateChild("Entity")); if (!global_pass_position.IsZero()) { // If the pass image is going to be rendered with a non-zero position, @@ -558,11 +545,9 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( if (!subpass->backdrop_filter_proc_ && subpass->delegate_->CanCollapseIntoParentPass(subpass)) { - auto subpass_capture = capture.CreateChild("EntityPass (Collapsed)"); // Directly render into the parent target and move on. if (!subpass->OnRender( renderer, // renderer - subpass_capture, // capture root_pass_size, // root_pass_size pass_context.GetPassTarget(), // pass_target global_pass_position, // global_pass_position @@ -606,12 +591,10 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( if (!clip_coverage_stack.HasCoverage()) { // The current clip is empty. This means the pass texture won't be // visible, so skip it. - capture.CreateChild("Subpass Entity (Skipped: Empty clip A)"); return EntityPass::EntityResult::Skip(); } auto clip_coverage_back = clip_coverage_stack.CurrentClipCoverage(); if (!clip_coverage_back.has_value()) { - capture.CreateChild("Subpass Entity (Skipped: Empty clip B)"); return EntityPass::EntityResult::Skip(); } @@ -623,14 +606,12 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( .GetRenderTargetSize())) .Intersection(clip_coverage_back.value()); if (!coverage_limit.has_value()) { - capture.CreateChild("Subpass Entity (Skipped: Empty coverage limit A)"); return EntityPass::EntityResult::Skip(); } coverage_limit = coverage_limit->Intersection(Rect::MakeSize(root_pass_size)); if (!coverage_limit.has_value()) { - capture.CreateChild("Subpass Entity (Skipped: Empty coverage limit B)"); return EntityPass::EntityResult::Skip(); } @@ -639,13 +620,11 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( ? coverage_limit : GetSubpassCoverage(*subpass, coverage_limit); if (!subpass_coverage.has_value()) { - capture.CreateChild("Subpass Entity (Skipped: Empty subpass coverage A)"); return EntityPass::EntityResult::Skip(); } auto subpass_size = ISize(subpass_coverage->GetSize()); if (subpass_size.IsEmpty()) { - capture.CreateChild("Subpass Entity (Skipped: Empty subpass coverage B)"); return EntityPass::EntityResult::Skip(); } @@ -660,9 +639,6 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( return EntityPass::EntityResult::Failure(); } - auto subpass_capture = capture.CreateChild("EntityPass"); - subpass_capture.AddRect("Coverage", *subpass_coverage, {.readonly = true}); - // Start non-collapsed subpasses with a fresh clip coverage stack limited by // the subpass coverage. This is important because image filters applied to // save layers may transform the subpass texture after it's rendered, @@ -674,7 +650,6 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( // time they are transient). if (!subpass->OnRender( renderer, // renderer - subpass_capture, // capture root_pass_size, // root_pass_size subpass_target, // pass_target subpass_coverage->GetOrigin(), // global_pass_position @@ -714,16 +689,11 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( return EntityPass::EntityResult::Failure(); } Entity element_entity; - Capture subpass_texture_capture = - capture.CreateChild("Entity (Subpass texture)"); element_entity.SetClipDepth(subpass->clip_depth_); - element_entity.SetCapture(subpass_texture_capture); element_entity.SetContents(std::move(offscreen_texture_contents)); element_entity.SetBlendMode(subpass->blend_mode_); - element_entity.SetTransform(subpass_texture_capture.AddMatrix( - "Transform", - Matrix::MakeTranslation( - Vector3(subpass_coverage->GetOrigin() - global_pass_position)))); + element_entity.SetTransform(Matrix::MakeTranslation( + Vector3(subpass_coverage->GetOrigin() - global_pass_position))); return EntityPass::EntityResult::Success(std::move(element_entity)); } @@ -846,7 +816,6 @@ bool EntityPass::RenderElement(Entity& element_entity, bool EntityPass::OnRender( ContentContext& renderer, - Capture& capture, ISize root_pass_size, EntityPassTarget& pass_target, Point global_pass_position, @@ -919,7 +888,6 @@ bool EntityPass::OnRender( EntityResult result = GetEntityForElement(element, // element renderer, // renderer - capture, // capture pass_context, // pass_context root_pass_size, // root_pass_size global_pass_position, // global_pass_position diff --git a/impeller/entity/entity_pass.h b/impeller/entity/entity_pass.h index 4fcf7f6cf3b05..87731602d6925 100644 --- a/impeller/entity/entity_pass.h +++ b/impeller/entity/entity_pass.h @@ -53,8 +53,6 @@ class EntityPass { /// `GetEntityForElement()`. using Element = std::variant>; - static const std::string kCaptureDocumentName; - using BackdropFilterProc = std::function( FilterInput::Ref, const Matrix& effect_transform, @@ -238,7 +236,6 @@ class EntityPass { EntityResult GetEntityForElement(const EntityPass::Element& element, ContentContext& renderer, - Capture& capture, InlinePassContext& pass_context, ISize root_pass_size, Point global_pass_position, @@ -304,7 +301,6 @@ class EntityPass { /// parent pass. /// bool OnRender(ContentContext& renderer, - Capture& capture, ISize root_pass_size, EntityPassTarget& pass_target, Point global_pass_position, diff --git a/impeller/entity/entity_pass_clip_stack.cc b/impeller/entity/entity_pass_clip_stack.cc index 68dcf2271eca5..54a30aceef209 100644 --- a/impeller/entity/entity_pass_clip_stack.cc +++ b/impeller/entity/entity_pass_clip_stack.cc @@ -124,18 +124,6 @@ EntityPassClipStack::ClipStateResult EntityPassClipStack::ApplyClipState( } break; } -#ifdef IMPELLER_ENABLE_CAPTURE - { - auto element_entity_coverage = entity.GetCoverage(); - if (element_entity_coverage.has_value()) { - element_entity_coverage = - element_entity_coverage->Shift(global_pass_position); - entity.GetCapture().AddRect("Coverage", *element_entity_coverage, - {.readonly = true}); - } - } -#endif - RecordEntity(entity, global_clip_coverage.type, subpass_state.clip_coverage.back().coverage); diff --git a/impeller/renderer/context.cc b/impeller/renderer/context.cc index fb42d5744a10b..b6d5a624cb97a 100644 --- a/impeller/renderer/context.cc +++ b/impeller/renderer/context.cc @@ -4,13 +4,11 @@ #include "impeller/renderer/context.h" -#include "impeller/core/capture.h" - namespace impeller { Context::~Context() = default; -Context::Context() : capture(CaptureContext::MakeInactive()) {} +Context::Context() = default; bool Context::UpdateOffscreenLayerPixelFormat(PixelFormat format) { return false; diff --git a/impeller/renderer/context.h b/impeller/renderer/context.h index 59ac871aad483..4a51560978bb2 100644 --- a/impeller/renderer/context.h +++ b/impeller/renderer/context.h @@ -9,7 +9,6 @@ #include #include "impeller/core/allocator.h" -#include "impeller/core/capture.h" #include "impeller/core/formats.h" #include "impeller/renderer/capabilities.h" #include "impeller/renderer/command_queue.h" @@ -171,8 +170,6 @@ class Context { /// virtual void Shutdown() = 0; - CaptureContext capture; - /// Stores a task on the `ContextMTL` that is awaiting access for the GPU. /// /// The task will be executed in the event that the GPU access has changed to diff --git a/impeller/tools/impeller.gni b/impeller/tools/impeller.gni index e07fa42286797..3db9152849533 100644 --- a/impeller/tools/impeller.gni +++ b/impeller/tools/impeller.gni @@ -11,9 +11,6 @@ declare_args() { impeller_debug = flutter_runtime_mode == "debug" || flutter_runtime_mode == "profile" - # Whether the runtime capture/playback system is enabled. - impeller_capture = flutter_runtime_mode == "debug" - # Whether the Metal backend is enabled. impeller_enable_metal = (is_mac || is_ios) && target_os != "fuchsia" diff --git a/shell/gpu/gpu_surface_gl_impeller.h b/shell/gpu/gpu_surface_gl_impeller.h index 5b6fbd9c1f3b5..d35dd14e962f5 100644 --- a/shell/gpu/gpu_surface_gl_impeller.h +++ b/shell/gpu/gpu_surface_gl_impeller.h @@ -12,6 +12,7 @@ #include "flutter/impeller/aiks/aiks_context.h" #include "flutter/impeller/renderer/context.h" #include "flutter/shell/gpu/gpu_surface_gl_delegate.h" +#include "impeller/renderer/renderer.h" namespace flutter { diff --git a/shell/gpu/gpu_surface_vulkan_impeller.h b/shell/gpu/gpu_surface_vulkan_impeller.h index 3ddb106fa7c49..fb761329ee95a 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.h +++ b/shell/gpu/gpu_surface_vulkan_impeller.h @@ -12,6 +12,7 @@ #include "flutter/impeller/aiks/aiks_context.h" #include "flutter/impeller/renderer/context.h" #include "flutter/shell/gpu/gpu_surface_vulkan_delegate.h" +#include "impeller/renderer/renderer.h" namespace flutter { diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index 1ec4f8151e373..2c01885f63a97 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -478,9 +478,6 @@ impeller_Play_AiksTest_CanRenderWithContiguousClipRestores_Vulkan.png impeller_Play_AiksTest_CanSaveLayerStandalone_Metal.png impeller_Play_AiksTest_CanSaveLayerStandalone_OpenGLES.png impeller_Play_AiksTest_CanSaveLayerStandalone_Vulkan.png -impeller_Play_AiksTest_CaptureContext_Metal.png -impeller_Play_AiksTest_CaptureContext_OpenGLES.png -impeller_Play_AiksTest_CaptureContext_Vulkan.png impeller_Play_AiksTest_ClearBlendWithBlur_Metal.png impeller_Play_AiksTest_ClearBlendWithBlur_OpenGLES.png impeller_Play_AiksTest_ClearBlendWithBlur_Vulkan.png From 61b5fbf3827ee72edfa31a5795cb25918272215f Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 20 May 2024 21:07:22 -0400 Subject: [PATCH 08/18] Roll Fuchsia Linux SDK from jXE7fqJI6VWFMaIdV... to HHwlAJN5imwf3yX4i... (#52944) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/fuchsia-linux-sdk-flutter-engine Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. 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://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_fuchsia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ec808d51d044f..7d07299ea2dfa 100644 --- a/DEPS +++ b/DEPS @@ -979,7 +979,7 @@ deps = { 'packages': [ { 'package': 'fuchsia/sdk/core/linux-amd64', - 'version': 'jXE7fqJI6VWFMaIdVFOYsP39O5i8wsvIrBGYhR35Y_EC' + 'version': 'HHwlAJN5imwf3yX4i6DhvMFhgYzp7YIXIsEYuvsx9JEC' } ], 'condition': 'download_fuchsia_deps and not download_fuchsia_sdk', diff --git a/ci/licenses_golden/licenses_fuchsia b/ci/licenses_golden/licenses_fuchsia index 2a651137e3cf9..0c64ee9e5bb44 100644 --- a/ci/licenses_golden/licenses_fuchsia +++ b/ci/licenses_golden/licenses_fuchsia @@ -1,4 +1,4 @@ -Signature: f3985d91db3c365458b0b427636437d7 +Signature: bc800599d1df16f0de082b6186b26587 ==================================================================================================== LIBRARY: fuchsia_sdk From 64398fa8c638777ddc664b2db66b953a823fb661 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 20 May 2024 22:02:23 -0400 Subject: [PATCH 09/18] Roll Dart SDK from 01a77883e9e9 to d1a786ef6888 (1 revision) (#52945) https://dart.googlesource.com/sdk.git/+log/01a77883e9e9..d1a786ef6888 2024-05-21 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-174.0.dev If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/dart-sdk-flutter-engine Please CC bdero@google.com,dart-vm-team@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter Engine: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_dart | 4 ++-- sky/packages/sky_engine/LICENSE | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index 7d07299ea2dfa..4f1562623d1bb 100644 --- a/DEPS +++ b/DEPS @@ -56,7 +56,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': '01a77883e9e983dbee08c1609faf6059e41dfb45', + 'dart_revision': 'd1a786ef6888b3552e6086972b871a3392c6d3c9', # 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_dart b/ci/licenses_golden/licenses_dart index 74ac40cf6a6e6..f6bba3d3b2ca4 100644 --- a/ci/licenses_golden/licenses_dart +++ b/ci/licenses_golden/licenses_dart @@ -1,4 +1,4 @@ -Signature: 8337f558670a6918da72fea198de06ad +Signature: 8ad659ac1d6d8a8bfb23da91ac0eefc7 ==================================================================================================== LIBRARY: dart @@ -4741,7 +4741,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/54c384453207ec07e8b6d84e001a2b4154189ef0 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/d1a786ef6888b3552e6086972b871a3392c6d3c9 /third_party/fallback_root_certificates/ ==================================================================================================== diff --git a/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index a13d8b0c6f586..76a1fd38e42d7 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -32293,7 +32293,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/01a77883e9e983dbee08c1609faf6059e41dfb45 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/d1a786ef6888b3552e6086972b871a3392c6d3c9 /third_party/fallback_root_certificates/ -------------------------------------------------------------------------------- From 3df7bae721cb65b6aa687b95608baf5324cf12b3 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Mon, 20 May 2024 23:43:03 -0400 Subject: [PATCH 10/18] Roll Skia from 62f369c75994 to 97d3b45d6b00 (1 revision) (#52946) https://skia.googlesource.com/skia.git/+log/62f369c75994..97d3b45d6b00 2024-05-21 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from de5559d9b295 to ba47ac8ffa90 (6 revisions) 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 bdero@google.com,brianosman@google.com,jlavrova@google.com,rmistry@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://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 4f1562623d1bb..a126044ec36fc 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '62f369c759947272dfdd2d8f060afadbcc361e79', + 'skia_revision': '97d3b45d6b00b9f749a4c1b82fcff700a7915a16', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From 7b1363ef9e1f0a89a0b1e148c56c46142ab071f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 May 2024 05:57:05 +0000 Subject: [PATCH 11/18] Bump actions/checkout from 4.1.5 to 4.1.6 (#52948) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.5 to 4.1.6.
Release notes

Sourced from actions/checkout's releases.

v4.1.6

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v4.1.5...v4.1.6

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.6

v4.1.5

v4.1.4

v4.1.3

v4.1.2

v4.1.1

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.1.5&new-version=4.1.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/engine-cp.yml | 2 +- .github/workflows/scorecards-analysis.yml | 2 +- .github/workflows/third_party_scan.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/engine-cp.yml b/.github/workflows/engine-cp.yml index 2f4528bb6f97a..20f33a7b12f8f 100644 --- a/.github/workflows/engine-cp.yml +++ b/.github/workflows/engine-cp.yml @@ -30,7 +30,7 @@ jobs: run: | echo "COMMIT_SHA=$(echo ${{ github.event.pull_request.merge_commit_sha }})" >> $GITHUB_ENV - name: Checkout Flutter Engine Repo - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 with: repository: flutteractionsbot/engine path: engine diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index f0b99c685151d..a901aea2f0257 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -22,7 +22,7 @@ jobs: id-token: write steps: - name: "Checkout code" - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 with: persist-credentials: false - name: "Run analysis" diff --git a/.github/workflows/third_party_scan.yml b/.github/workflows/third_party_scan.yml index 62cfc11957f47..0fd8268286f43 100644 --- a/.github/workflows/third_party_scan.yml +++ b/.github/workflows/third_party_scan.yml @@ -21,7 +21,7 @@ jobs: contents: read steps: - name: "Checkout code" - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 with: persist-credentials: false - name: "setup python" From b25c32d5c6e4795c204a1a90bf97cffb0dfb5ca1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 May 2024 05:57:08 +0000 Subject: [PATCH 12/18] Bump github/codeql-action from 2.13.4 to 3.25.6 (#52949) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.13.4 to 3.25.6.
Release notes

Sourced from github/codeql-action's releases.

CodeQL Bundle v2.17.3

Bundles CodeQL CLI v2.17.3

Includes the following CodeQL language packs from github/codeql@codeql-cli/v2.17.3:

CodeQL Bundle v2.17.2

Bundles CodeQL CLI v2.17.2

Includes the following CodeQL language packs from github/codeql@codeql-cli/v2.17.2:

CodeQL Bundle v2.17.1

Bundles CodeQL CLI v2.17.1

Includes the following CodeQL language packs from github/codeql@codeql-cli/v2.17.1:

... (truncated)

Changelog

Sourced from github/codeql-action's changelog.

CodeQL Action Changelog

See the releases page for the relevant changes to the CodeQL CLI and language packs.

Note that the only difference between v2 and v3 of the CodeQL Action is the node version they support, with v3 running on node 20 while we continue to release v2 to support running on node 16. For example 3.22.11 was the first v3 release and is functionally identical to 2.22.11. This approach ensures an easy way to track exactly which features are included in different versions, indicated by the minor and patch version numbers.

[UNRELEASED]

No user facing changes.

3.25.6 - 20 May 2024

  • Update default CodeQL bundle version to 2.17.3. #2295

3.25.5 - 13 May 2024

  • Add a compatibility matrix of supported CodeQL Action, CodeQL CLI, and GitHub Enterprise Server versions to the https://github.com/github/codeql-action/blob/main/README.md. #2273
  • Avoid printing out a warning for a missing on.push trigger when the CodeQL Action is triggered via a workflow_call event. #2274
  • The tools: latest input to the init Action has been renamed to tools: linked. This option specifies that the Action should use the tools shipped at the same time as the Action. The old name will continue to work for backwards compatibility, but we recommend that new workflows use the new name. #2281

3.25.4 - 08 May 2024

  • Update default CodeQL bundle version to 2.17.2. #2270

3.25.3 - 25 Apr 2024

  • Update default CodeQL bundle version to 2.17.1. #2247
  • Workflows running on macos-latest using CodeQL CLI versions before v2.15.1 will need to either upgrade their CLI version to v2.15.1 or newer, or change the platform to an Intel MacOS runner, such as macos-12. ARM machines with SIP disabled, including the newest macos-latest image, are unsupported for CLI versions before 2.15.1. #2261

3.25.2 - 22 Apr 2024

No user facing changes.

3.25.1 - 17 Apr 2024

  • We are rolling out a feature in April/May 2024 that improves the reliability and performance of analyzing code when analyzing a compiled language with the autobuild build mode. #2235
  • Fix a bug where the init Action would fail if --overwrite was specified in CODEQL_ACTION_EXTRA_OPTIONS. #2245

3.25.0 - 15 Apr 2024

  • The deprecated feature for extracting dependencies for a Python analysis has been removed. #2224

    As a result, the following inputs and environment variables are now ignored:

    • The setup-python-dependencies input to the init Action
    • The CODEQL_ACTION_DISABLE_PYTHON_DEPENDENCY_INSTALLATION environment variable

    We recommend removing any references to these from your workflows. For more information, see the release notes for CodeQL Action v3.23.0 and v2.23.0.

  • Automatically overwrite an existing database if found on the filesystem. #2229

  • Bump the minimum CodeQL bundle version to 2.12.6. #2232

... (truncated)

Commits
  • 9fdb3e4 Merge pull request #2300 from github/update-v3.25.6-63d519c0a
  • 00792ab Update changelog for v3.25.6
  • 63d519c Merge pull request #2295 from github/update-bundle/codeql-bundle-v2.17.3
  • 0d9161c Merge pull request #2293 from github/henrymercer/update-build-mode-autobuild-...
  • e9e2729 Add changelog note
  • de1ac31 Update default bundle to codeql-bundle-v2.17.3
  • a57c67b Merge pull request #2286 from github/koesie10/ghec-dr-db-upload
  • b7ef64e Merge pull request #2294 from github/dependabot/npm_and_yarn/npm-d3285d5234
  • e54dea2 Update checked-in dependencies
  • 3b42294 Bump the npm group across 1 directory with 4 updates
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=2.13.4&new-version=3.25.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .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 a901aea2f0257..3dd3211631bf8 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -49,6 +49,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@cdcdbb579706841c47f7063dda365e292e5cad7a + uses: github/codeql-action/upload-sarif@9fdb3e49720b44c48891d036bb502feb25684276 with: sarif_file: results.sarif From d6d26047a7dbf193f1031450ce071067f52d2730 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 21 May 2024 01:59:10 -0400 Subject: [PATCH 13/18] Roll Dart SDK from d1a786ef6888 to cb763e4dad50 (1 revision) (#52950) https://dart.googlesource.com/sdk.git/+log/d1a786ef6888..cb763e4dad50 2024-05-21 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-175.0.dev If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/dart-sdk-flutter-engine Please CC bdero@google.com,dart-vm-team@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter Engine: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- sky/packages/sky_engine/LICENSE | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index a126044ec36fc..ea5146677023f 100644 --- a/DEPS +++ b/DEPS @@ -56,7 +56,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': 'd1a786ef6888b3552e6086972b871a3392c6d3c9', + 'dart_revision': 'cb763e4dad50ed78f0cfa3d3966eceaa1447913e', # 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/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index 76a1fd38e42d7..dc41cf66e0adc 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -32293,7 +32293,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/d1a786ef6888b3552e6086972b871a3392c6d3c9 +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/cb763e4dad50ed78f0cfa3d3966eceaa1447913e /third_party/fallback_root_certificates/ -------------------------------------------------------------------------------- From d5ef1aeed4e295ea7bc06d8e4854b5edb74a1c59 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 21 May 2024 02:03:02 -0400 Subject: [PATCH 14/18] Roll Skia from 97d3b45d6b00 to 1a52d4d5f45e (1 revision) (#52947) https://skia.googlesource.com/skia.git/+log/97d3b45d6b00..1a52d4d5f45e 2024-05-21 skia-autoroll@skia-public.iam.gserviceaccount.com Roll Skia Infra from 1e93252a646d to 5bc1c10e55d1 (4 revisions) 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 bdero@google.com,brianosman@google.com,jlavrova@google.com,rmistry@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://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index ea5146677023f..4827ff6b00962 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '97d3b45d6b00b9f749a4c1b82fcff700a7915a16', + 'skia_revision': '1a52d4d5f45e7cb3221949dfa436077087d297b2', # 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 2a866d848a4fd..9579c8c3968e9 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: 8285c3928d926c49ed70d7aebd0fcdd1 +Signature: c3bcbeeca732dd3dda923ff34615e6c8 ==================================================================================================== LIBRARY: etc1 From 2f9a6908ed35fbceb389d3bc2963b905167d7fbc Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 21 May 2024 02:58:31 -0400 Subject: [PATCH 15/18] Roll Skia from 1a52d4d5f45e to 2102f791405c (1 revision) (#52951) https://skia.googlesource.com/skia.git/+log/1a52d4d5f45e..2102f791405c 2024-05-21 skia-autoroll@skia-public.iam.gserviceaccount.com Roll SK Tool from 5bc1c10e55d1 to 2ff22cdc8aef 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 bdero@google.com,brianosman@google.com,jlavrova@google.com,rmistry@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://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 4827ff6b00962..1c739d5f20f9d 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '1a52d4d5f45e7cb3221949dfa436077087d297b2', + 'skia_revision': '2102f791405c180fc3c98d6c7d55742924b8bec4', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. From b339ecbe1b9fcc9fab1e2925ee13e90fcdda5b61 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 21 May 2024 08:26:16 -0400 Subject: [PATCH 16/18] Roll Skia from 2102f791405c to c6bb2106c13b (1 revision) (#52952) https://skia.googlesource.com/skia.git/+log/2102f791405c..c6bb2106c13b 2024-05-21 ccameron@chromium.org Reland: Decode and encode ISO 21496-1 JPEG images 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 brianosman@google.com,jlavrova@google.com,jonahwilliams@google.com,rmistry@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://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 1c739d5f20f9d..349bbf5848f88 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': '2102f791405c180fc3c98d6c7d55742924b8bec4', + 'skia_revision': 'c6bb2106c13b23d67f95562c99ade38d4b0e2eb1', # 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 9579c8c3968e9..084ad6cad2302 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: c3bcbeeca732dd3dda923ff34615e6c8 +Signature: d25e2a7fd614cab49001be4b68406f38 ==================================================================================================== LIBRARY: etc1 From 0b5d5a70dab92163c7af9b24eb582ba26bb66f96 Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 21 May 2024 09:57:05 -0400 Subject: [PATCH 17/18] Roll Dart SDK from cb763e4dad50 to dd768e0d1890 (1 revision) (#52953) https://dart.googlesource.com/sdk.git/+log/cb763e4dad50..dd768e0d1890 2024-05-21 dart-internal-merge@dart-ci-internal.iam.gserviceaccount.com Version 3.5.0-176.0.dev If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/dart-sdk-flutter-engine Please CC dart-vm-team@google.com,jonahwilliams@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter Engine: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- sky/packages/sky_engine/LICENSE | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 349bbf5848f88..88adc2c1dcb27 100644 --- a/DEPS +++ b/DEPS @@ -56,7 +56,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': 'cb763e4dad50ed78f0cfa3d3966eceaa1447913e', + 'dart_revision': 'dd768e0d1890fc34fc3f413c899668416aa2bb66', # 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/sky/packages/sky_engine/LICENSE b/sky/packages/sky_engine/LICENSE index dc41cf66e0adc..ebf74b01f3329 100644 --- a/sky/packages/sky_engine/LICENSE +++ b/sky/packages/sky_engine/LICENSE @@ -32293,7 +32293,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. -You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/cb763e4dad50ed78f0cfa3d3966eceaa1447913e +You may obtain a copy of this library's Source Code Form from: https://dart.googlesource.com/sdk/+/dd768e0d1890fc34fc3f413c899668416aa2bb66 /third_party/fallback_root_certificates/ -------------------------------------------------------------------------------- From 8a352f01e503f3299bce3c8053460073d5bb2f0b Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Tue, 21 May 2024 10:36:35 -0400 Subject: [PATCH 18/18] Roll Skia from c6bb2106c13b to e0881f06f94a (1 revision) (#52954) https://skia.googlesource.com/skia.git/+log/c6bb2106c13b..e0881f06f94a 2024-05-21 egdaniel@google.com [Graphite] Add support for user provided labels on Images. 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 brianosman@google.com,jlavrova@google.com,jonahwilliams@google.com,rmistry@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://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 88adc2c1dcb27..c3f5722e65167 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'c6bb2106c13b23d67f95562c99ade38d4b0e2eb1', + 'skia_revision': 'e0881f06f94a1bc31e0a5ecd4618090002f61c28', # 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 084ad6cad2302..335783d2ff5de 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: d25e2a7fd614cab49001be4b68406f38 +Signature: 98ac0abadbcf8306913f51e1d907b550 ==================================================================================================== LIBRARY: etc1