diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index d0182f4580ab0..b68946dde0cd8 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -298,8 +298,6 @@ FILE: ../../../flutter/lib/ui/painting/color_filter.cc FILE: ../../../flutter/lib/ui/painting/color_filter.h FILE: ../../../flutter/lib/ui/painting/engine_layer.cc FILE: ../../../flutter/lib/ui/painting/engine_layer.h -FILE: ../../../flutter/lib/ui/painting/frame_info.cc -FILE: ../../../flutter/lib/ui/painting/frame_info.h FILE: ../../../flutter/lib/ui/painting/gradient.cc FILE: ../../../flutter/lib/ui/painting/gradient.h FILE: ../../../flutter/lib/ui/painting/image.cc diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index c904141b338e8..a38298f460975 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -30,8 +30,6 @@ source_set("ui") { "painting/color_filter.h", "painting/engine_layer.cc", "painting/engine_layer.h", - "painting/frame_info.cc", - "painting/frame_info.h", "painting/gradient.cc", "painting/gradient.h", "painting/image.cc", diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart index 715ba20023278..e86347d9b5389 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -22,14 +22,16 @@ class Scene extends NativeFieldWrapperClass2 { /// Creates a raster image representation of the current state of the scene. /// This is a slow operation that is performed on a background thread. - Future toImage(int width, int height) { + Future toImage(int width, int height) async { if (width <= 0 || height <= 0) { throw Exception('Invalid image dimensions.'); } - return _futurize((_Callback callback) => _toImage(width, height, callback)); + final Image image = Image._(); + await _futurize((_Callback callback) => _toImage(image, width, height, callback)); + return image; } - String _toImage(int width, int height, _Callback callback) native 'Scene_toImage'; + String _toImage(Image outImage, int width, int height, _Callback callback) native 'Scene_toImage'; /// Releases the resources used by this scene. /// diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index f5403ecae9a61..4c2aa16fa0253 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -61,7 +61,8 @@ void Scene::dispose() { ClearDartWrapper(); } -Dart_Handle Scene::toImage(uint32_t width, +Dart_Handle Scene::toImage(Dart_Handle image_handle, + uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { TRACE_EVENT0("flutter", "Scene::toImage"); @@ -75,7 +76,8 @@ Dart_Handle Scene::toImage(uint32_t width, return tonic::ToDart("Could not flatten scene into a layer tree."); } - return Picture::RasterizeToImage(picture, width, height, raw_image_callback); + return Picture::RasterizeToImage(image_handle, picture, width, height, + raw_image_callback); } std::unique_ptr Scene::takeLayerTree() { diff --git a/lib/ui/compositing/scene.h b/lib/ui/compositing/scene.h index d46ca5d3d4281..7039dc410874e 100644 --- a/lib/ui/compositing/scene.h +++ b/lib/ui/compositing/scene.h @@ -32,7 +32,8 @@ class Scene : public RefCountedDartWrappable { std::unique_ptr takeLayerTree(); - Dart_Handle toImage(uint32_t width, + Dart_Handle toImage(Dart_Handle image_handle, + uint32_t width, uint32_t height, Dart_Handle image_callback); diff --git a/lib/ui/dart_ui.cc b/lib/ui/dart_ui.cc index 5b3189dfa80f8..c3b758564a5d0 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -13,7 +13,6 @@ #include "flutter/lib/ui/painting/codec.h" #include "flutter/lib/ui/painting/color_filter.h" #include "flutter/lib/ui/painting/engine_layer.h" -#include "flutter/lib/ui/painting/frame_info.h" #include "flutter/lib/ui/painting/gradient.h" #include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/image_filter.h" @@ -80,7 +79,6 @@ void DartUI::InitForGlobal() { DartRuntimeHooks::RegisterNatives(g_natives); EngineLayer::RegisterNatives(g_natives); FontCollection::RegisterNatives(g_natives); - FrameInfo::RegisterNatives(g_natives); ImageFilter::RegisterNatives(g_natives); ImageShader::RegisterNatives(g_natives); IsolateNameServerNatives::RegisterNatives(g_natives); diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index dbcbc7d01db60..24d179365da60 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1639,22 +1639,19 @@ typedef ImageDecoderCallback = void Function(Image result); /// /// To obtain an instance of the [FrameInfo] interface, see /// [Codec.getNextFrame]. -@pragma('vm:entry-point') -class FrameInfo extends NativeFieldWrapperClass2 { +class FrameInfo { /// This class is created by the engine, and should not be instantiated /// or extended directly. /// /// To obtain an instance of the [FrameInfo] interface, see /// [Codec.getNextFrame]. - @pragma('vm:entry-point') - FrameInfo._(); + FrameInfo._(int durationMilliseconds, this.image) : duration = Duration(milliseconds: durationMilliseconds); /// The duration this frame should be shown. - Duration get duration => Duration(milliseconds: _durationMillis); - int get _durationMillis native 'FrameInfo_durationMillis'; + final Duration duration; /// The [Image] object for this frame. - Image get image native 'FrameInfo_image'; + final Image image; } /// A handle to an image codec. @@ -1684,21 +1681,32 @@ class Codec extends NativeFieldWrapperClass2 { /// * -1 for infinity repetitions. int get repetitionCount native 'Codec_repetitionCount'; + FrameInfo _cachedFrame; + /// Fetches the next animation frame. /// /// Wraps back to the first frame after returning the last frame. /// /// The returned future can complete with an error if the decoding has failed. - Future getNextFrame() { - return _futurize(_getNextFrame); + Future getNextFrame() async { + if (_cachedFrame == null || frameCount != 1) { + final Image image = Image._(); + final int durationMilliseconds = await _futurize((_Callback callback) => _getNextFrame(image, callback)); + _cachedFrame = FrameInfo._(durationMilliseconds, image); + } + return _cachedFrame; } /// Returns an error message on failure, null on success. - String _getNextFrame(_Callback callback) native 'Codec_getNextFrame'; + String _getNextFrame(Image outImage, _Callback callback) native 'Codec_getNextFrame'; /// Release the resources used by this object. The object is no longer usable /// after this method is called. - void dispose() native 'Codec_dispose'; + void dispose() { + _cachedFrame = null; + _dispose(); + } + void _dispose() native 'Codec_dispose'; } /// Instantiates an image codec [Codec] object. @@ -1718,10 +1726,12 @@ class Codec extends NativeFieldWrapperClass2 { Future instantiateImageCodec(Uint8List list, { int targetWidth, int targetHeight, -}) { - return _futurize( - (_Callback callback) => _instantiateImageCodec(list, callback, null, targetWidth ?? _kDoNotResizeDimension, targetHeight ?? _kDoNotResizeDimension) - ); +}) async { + final Codec codec = Codec._(); + await _futurize((_Callback callback) { + return _instantiateImageCodec(codec, list, callback, null, targetWidth ?? _kDoNotResizeDimension, targetHeight ?? _kDoNotResizeDimension); + }); + return codec; } /// Instantiates a [Codec] object for an image binary data. @@ -1735,7 +1745,7 @@ Future instantiateImageCodec(Uint8List list, { /// If both are equal to [_kDoNotResizeDimension], then the image maintains its real size. /// /// Returns an error message if the instantiation has failed, null otherwise. -String _instantiateImageCodec(Uint8List list, _Callback callback, _ImageInfo imageInfo, int targetWidth, int targetHeight) +String _instantiateImageCodec(Codec outCodec, Uint8List list, _Callback callback, _ImageInfo imageInfo, int targetWidth, int targetHeight) native 'instantiateImageCodec'; /// Loads a single image frame from a byte array into an [Image] object. @@ -1776,11 +1786,12 @@ void decodeImageFromPixels( {int rowBytes, int targetWidth, int targetHeight} ) { final _ImageInfo imageInfo = _ImageInfo(width, height, format.index, rowBytes); - final Future codecFuture = _futurize( - (_Callback callback) => _instantiateImageCodec(pixels, callback, imageInfo, targetWidth ?? _kDoNotResizeDimension, targetHeight ?? _kDoNotResizeDimension) - ); - codecFuture.then((Codec codec) => codec.getNextFrame()) - .then((FrameInfo frameInfo) => callback(frameInfo.image)); + final Codec codec = Codec._(); + _futurize( + (_Callback callback) => _instantiateImageCodec(codec, pixels, callback, imageInfo, targetWidth ?? _kDoNotResizeDimension, targetHeight ?? _kDoNotResizeDimension) + ).then((bool _) { + codec.getNextFrame().then((FrameInfo frameInfo) => callback(frameInfo.image)); + }); } /// Determines the winding rule that decides how the interior of a [Path] is @@ -4125,15 +4136,17 @@ class Picture extends NativeFieldWrapperClass2 { /// /// Although the image is returned synchronously, the picture is actually /// rasterized the first time the image is drawn and then cached. - Future toImage(int width, int height) { + Future toImage(int width, int height) async { if (width <= 0 || height <= 0) throw Exception('Invalid image dimensions.'); - return _futurize( - (_Callback callback) => _toImage(width, height, callback) + final Image image = Image._(); + await _futurize( + (_Callback callback) => _toImage(image, width, height, callback) ); + return image; } - String _toImage(int width, int height, _Callback callback) native 'Picture_toImage'; + String _toImage(Image outImage, int width, int height, _Callback callback) native 'Picture_toImage'; /// Release the resources used by this object. The object is no longer usable /// after this method is called. diff --git a/lib/ui/painting/codec.cc b/lib/ui/painting/codec.cc index 829b9db65ed9d..76ee2b9fe71e1 100644 --- a/lib/ui/painting/codec.cc +++ b/lib/ui/painting/codec.cc @@ -10,7 +10,6 @@ #include "flutter/fml/logging.h" #include "flutter/fml/make_copyable.h" #include "flutter/fml/trace_event.h" -#include "flutter/lib/ui/painting/frame_info.h" #include "flutter/lib/ui/painting/multi_frame_codec.h" #include "flutter/lib/ui/painting/single_frame_codec.h" #include "third_party/skia/include/codec/SkCodec.h" @@ -145,13 +144,14 @@ static std::variant ConvertImageInfo( } static void InstantiateImageCodec(Dart_NativeArguments args) { - Dart_Handle callback_handle = Dart_GetNativeArgument(args, 1); + Dart_Handle codec_handle = Dart_GetNativeArgument(args, 0); + Dart_Handle callback_handle = Dart_GetNativeArgument(args, 2); if (!Dart_IsClosure(callback_handle)) { Dart_SetReturnValue(args, tonic::ToDart("Callback must be a function")); return; } - Dart_Handle image_info_handle = Dart_GetNativeArgument(args, 2); + Dart_Handle image_info_handle = Dart_GetNativeArgument(args, 3); std::optional image_info; @@ -171,7 +171,7 @@ static void InstantiateImageCodec(Dart_NativeArguments args) { { Dart_Handle exception = nullptr; tonic::Uint8List list = - tonic::DartConverter::FromArguments(args, 0, + tonic::DartConverter::FromArguments(args, 1, exception); if (exception) { Dart_SetReturnValue(args, exception); @@ -191,9 +191,9 @@ static void InstantiateImageCodec(Dart_NativeArguments args) { } const int targetWidth = - tonic::DartConverter::FromDart(Dart_GetNativeArgument(args, 3)); - const int targetHeight = tonic::DartConverter::FromDart(Dart_GetNativeArgument(args, 4)); + const int targetHeight = + tonic::DartConverter::FromDart(Dart_GetNativeArgument(args, 5)); std::unique_ptr codec; bool single_frame; @@ -208,8 +208,6 @@ static void InstantiateImageCodec(Dart_NativeArguments args) { single_frame = codec->getFrameCount() == 1; } - fml::RefPtr ui_codec; - if (single_frame) { ImageDecoder::ImageDescriptor descriptor; descriptor.decompressed_image_info = image_info; @@ -222,12 +220,13 @@ static void InstantiateImageCodec(Dart_NativeArguments args) { } descriptor.data = std::move(buffer); - ui_codec = fml::MakeRefCounted(std::move(descriptor)); + SingleFrameCodec::Create(codec_handle, std::move(descriptor)); } else { - ui_codec = fml::MakeRefCounted(std::move(codec)); + MultiFrameCodec::Create(codec_handle, std::move(codec)); } - tonic::DartInvoke(callback_handle, {ToDart(ui_codec)}); + tonic::DartInvoke(callback_handle, {Dart_True()}); + Dart_SetReturnValue(args, Dart_Null()); } IMPLEMENT_WRAPPERTYPEINFO(ui, Codec); @@ -246,7 +245,7 @@ void Codec::dispose() { void Codec::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({ - {"instantiateImageCodec", InstantiateImageCodec, 5, true}, + {"instantiateImageCodec", InstantiateImageCodec, 6, true}, }); natives->Register({FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); } diff --git a/lib/ui/painting/codec.h b/lib/ui/painting/codec.h index 2e0c746eac2d6..53ac9e426448d 100644 --- a/lib/ui/painting/codec.h +++ b/lib/ui/painting/codec.h @@ -6,7 +6,6 @@ #define FLUTTER_LIB_UI_PAINTING_CODEC_H_ #include "flutter/lib/ui/dart_wrapper.h" -#include "flutter/lib/ui/painting/frame_info.h" #include "third_party/skia/include/codec/SkCodec.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkImage.h" @@ -30,7 +29,8 @@ class Codec : public RefCountedDartWrappable { virtual int repetitionCount() const = 0; - virtual Dart_Handle getNextFrame(Dart_Handle callback_handle) = 0; + virtual Dart_Handle getNextFrame(Dart_Handle image_handle, + Dart_Handle callback_handle) = 0; void dispose(); diff --git a/lib/ui/painting/frame_info.cc b/lib/ui/painting/frame_info.cc deleted file mode 100644 index ad77f7b50d8a4..0000000000000 --- a/lib/ui/painting/frame_info.cc +++ /dev/null @@ -1,30 +0,0 @@ - -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/lib/ui/painting/frame_info.h" - -#include "third_party/tonic/dart_binding_macros.h" -#include "third_party/tonic/dart_library_natives.h" - -namespace flutter { - -IMPLEMENT_WRAPPERTYPEINFO(ui, FrameInfo); - -#define FOR_EACH_BINDING(V) \ - V(FrameInfo, durationMillis) \ - V(FrameInfo, image) - -FOR_EACH_BINDING(DART_NATIVE_CALLBACK) - -FrameInfo::FrameInfo(fml::RefPtr image, int durationMillis) - : image_(std::move(image)), durationMillis_(durationMillis) {} - -FrameInfo::~FrameInfo(){}; - -void FrameInfo::RegisterNatives(tonic::DartLibraryNatives* natives) { - natives->Register({FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); -} - -} // namespace flutter diff --git a/lib/ui/painting/frame_info.h b/lib/ui/painting/frame_info.h deleted file mode 100644 index 184b132d17791..0000000000000 --- a/lib/ui/painting/frame_info.h +++ /dev/null @@ -1,37 +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_LIB_UI_PAINTING_FRAME_INFO_H_ -#define FLUTTER_LIB_UI_PAINTING_FRAME_INFO_H_ - -#include "flutter/lib/ui/dart_wrapper.h" -#include "flutter/lib/ui/painting/image.h" - -namespace flutter { - -// A single animation frame. -class FrameInfo final : public RefCountedDartWrappable { - DEFINE_WRAPPERTYPEINFO(); - - public: - int durationMillis() { return durationMillis_; } - fml::RefPtr image() { return image_; } - - static void RegisterNatives(tonic::DartLibraryNatives* natives); - - private: - FrameInfo(fml::RefPtr image, int durationMillis); - - ~FrameInfo() override; - - const fml::RefPtr image_; - const int durationMillis_; - - FML_FRIEND_MAKE_REF_COUNTED(FrameInfo); - FML_FRIEND_REF_COUNTED_THREAD_SAFE(FrameInfo); -}; - -} // namespace flutter - -#endif // FLUTTER_LIB_UI_PAINTING_FRAME_INFO_H_ diff --git a/lib/ui/painting/image.h b/lib/ui/painting/image.h index 516a2e5d59c49..43a00517421b8 100644 --- a/lib/ui/painting/image.h +++ b/lib/ui/painting/image.h @@ -22,8 +22,10 @@ class CanvasImage final : public RefCountedDartWrappable { public: ~CanvasImage() override; - static fml::RefPtr Create() { - return fml::MakeRefCounted(); + static fml::RefPtr Create(Dart_Handle dart_handle) { + auto image = fml::MakeRefCounted(); + image->AssociateWithDartWrapper(dart_handle); + return image; } int width() { return image_.get()->width(); } diff --git a/lib/ui/painting/multi_frame_codec.cc b/lib/ui/painting/multi_frame_codec.cc index f650e25a97e61..c38ecb48930e3 100644 --- a/lib/ui/painting/multi_frame_codec.cc +++ b/lib/ui/painting/multi_frame_codec.cc @@ -20,8 +20,11 @@ MultiFrameCodec::MultiFrameCodec(std::unique_ptr codec) MultiFrameCodec::~MultiFrameCodec() = default; static void InvokeNextFrameCallback( - fml::RefPtr frameInfo, + sk_sp skImage, + fml::RefPtr canvas_image, std::unique_ptr callback, + fml::RefPtr unref_queue, + SkCodec::FrameInfo skFrameInfo, size_t trace_id) { std::shared_ptr dart_state = callback->dart_state().lock(); if (!dart_state) { @@ -30,10 +33,13 @@ static void InvokeNextFrameCallback( return; } tonic::DartState::Scope scope(dart_state); - if (!frameInfo) { - tonic::DartInvoke(callback->value(), {Dart_Null()}); + + if (skImage) { + canvas_image->set_image({skImage, std::move(unref_queue)}); + tonic::DartInvoke(callback->value(), + {tonic::ToDart(skFrameInfo.fDuration)}); } else { - tonic::DartInvoke(callback->value(), {ToDart(frameInfo)}); + tonic::DartInvoke(callback->value(), {Dart_Null()}); } } @@ -129,30 +135,32 @@ sk_sp MultiFrameCodec::GetNextFrameImage( } void MultiFrameCodec::GetNextFrameAndInvokeCallback( + fml::RefPtr canvas_image, std::unique_ptr callback, fml::RefPtr ui_task_runner, fml::WeakPtr resourceContext, fml::RefPtr unref_queue, size_t trace_id) { - fml::RefPtr frameInfo = NULL; sk_sp skImage = GetNextFrameImage(resourceContext); + SkCodec::FrameInfo skFrameInfo; if (skImage) { - fml::RefPtr image = CanvasImage::Create(); - image->set_image({skImage, std::move(unref_queue)}); - SkCodec::FrameInfo skFrameInfo; codec_->getFrameInfo(nextFrameIndex_, &skFrameInfo); - frameInfo = - fml::MakeRefCounted(std::move(image), skFrameInfo.fDuration); } nextFrameIndex_ = (nextFrameIndex_ + 1) % frameCount_; ui_task_runner->PostTask(fml::MakeCopyable( - [callback = std::move(callback), frameInfo, trace_id]() mutable { - InvokeNextFrameCallback(frameInfo, std::move(callback), trace_id); + [skImage = std::move(skImage), callback = std::move(callback), + canvas_image = std::move(canvas_image), + unref_queue = std::move(unref_queue), + skFrameInfo = std::move(skFrameInfo), trace_id]() mutable { + InvokeNextFrameCallback(std::move(skImage), std::move(canvas_image), + std::move(callback), std::move(unref_queue), + std::move(skFrameInfo), trace_id); })); } -Dart_Handle MultiFrameCodec::getNextFrame(Dart_Handle callback_handle) { +Dart_Handle MultiFrameCodec::getNextFrame(Dart_Handle image_handle, + Dart_Handle callback_handle) { static size_t trace_counter = 1; const size_t trace_id = trace_counter++; @@ -160,17 +168,19 @@ Dart_Handle MultiFrameCodec::getNextFrame(Dart_Handle callback_handle) { return tonic::ToDart("Callback must be a function"); } + auto canvas_image = CanvasImage::Create(image_handle); auto* dart_state = UIDartState::Current(); const auto& task_runners = dart_state->GetTaskRunners(); task_runners.GetIOTaskRunner()->PostTask(fml::MakeCopyable( - [callback = std::make_unique( + [canvas_image = std::move(canvas_image), + callback = std::make_unique( tonic::DartState::Current(), callback_handle), this, trace_id, ui_task_runner = task_runners.GetUITaskRunner(), io_manager = dart_state->GetIOManager()]() mutable { GetNextFrameAndInvokeCallback( - std::move(callback), std::move(ui_task_runner), + canvas_image, std::move(callback), std::move(ui_task_runner), io_manager->GetResourceContext(), io_manager->GetSkiaUnrefQueue(), trace_id); })); diff --git a/lib/ui/painting/multi_frame_codec.h b/lib/ui/painting/multi_frame_codec.h index 0be63c2a57582..1abcded241469 100644 --- a/lib/ui/painting/multi_frame_codec.h +++ b/lib/ui/painting/multi_frame_codec.h @@ -5,15 +5,23 @@ #ifndef FLUTTER_LIB_UI_PAINTING_MUTLI_FRAME_CODEC_H_ #define FLUTTER_LIB_UI_PAINTING_MUTLI_FRAME_CODEC_H_ +#include "flutter/flow/skia_gpu_object.h" #include "flutter/fml/macros.h" +#include "flutter/fml/memory/weak_ptr.h" #include "flutter/lib/ui/painting/codec.h" +#include "flutter/lib/ui/painting/image.h" namespace flutter { class MultiFrameCodec : public Codec { public: - MultiFrameCodec(std::unique_ptr codec); - + static fml::RefPtr Create(Dart_Handle codec_handle, + std::unique_ptr codec) { + auto multi_frame_codec = + fml::MakeRefCounted(std::move(codec)); + multi_frame_codec->AssociateWithDartWrapper(codec_handle); + return multi_frame_codec; + } ~MultiFrameCodec() override; // |Codec| @@ -23,9 +31,10 @@ class MultiFrameCodec : public Codec { int repetitionCount() const override; // |Codec| - Dart_Handle getNextFrame(Dart_Handle args) override; + Dart_Handle getNextFrame(Dart_Handle image_handle, Dart_Handle args) override; private: + MultiFrameCodec(std::unique_ptr codec); const std::unique_ptr codec_; const int frameCount_; const int repetitionCount_; @@ -39,6 +48,7 @@ class MultiFrameCodec : public Codec { sk_sp GetNextFrameImage(fml::WeakPtr resourceContext); void GetNextFrameAndInvokeCallback( + fml::RefPtr canvas_image, std::unique_ptr callback, fml::RefPtr ui_task_runner, fml::WeakPtr resourceContext, diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 8527b83ec139b..34d765221e0a7 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -40,14 +40,16 @@ Picture::Picture(flutter::SkiaGPUObject picture) Picture::~Picture() = default; -Dart_Handle Picture::toImage(uint32_t width, +Dart_Handle Picture::toImage(Dart_Handle image_handle, + uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { if (!picture_.get()) { return tonic::ToDart("Picture is null"); } - return RasterizeToImage(picture_.get(), width, height, raw_image_callback); + return RasterizeToImage(image_handle, picture_.get(), width, height, + raw_image_callback); } void Picture::dispose() { @@ -62,7 +64,8 @@ size_t Picture::GetAllocationSize() { } } -Dart_Handle Picture::RasterizeToImage(sk_sp picture, +Dart_Handle Picture::RasterizeToImage(Dart_Handle image_handle, + sk_sp picture, uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { @@ -74,6 +77,8 @@ Dart_Handle Picture::RasterizeToImage(sk_sp picture, return tonic::ToDart("Image dimensions for scene were invalid."); } + auto canvas_image = CanvasImage::Create(image_handle); + auto* dart_state = UIDartState::Current(); tonic::DartPersistentValue* image_callback = new tonic::DartPersistentValue(dart_state, raw_image_callback); @@ -89,7 +94,7 @@ Dart_Handle Picture::RasterizeToImage(sk_sp picture, auto picture_bounds = SkISize::Make(width, height); - auto ui_task = fml::MakeCopyable([image_callback, unref_queue]( + auto ui_task = fml::MakeCopyable([canvas_image, image_callback, unref_queue]( sk_sp raster_image) mutable { auto dart_state = image_callback->dart_state().lock(); if (!dart_state) { @@ -100,15 +105,14 @@ Dart_Handle Picture::RasterizeToImage(sk_sp picture, if (!raster_image) { tonic::DartInvoke(image_callback->Get(), {Dart_Null()}); + delete image_callback; return; } - auto dart_image = CanvasImage::Create(); - dart_image->set_image({std::move(raster_image), std::move(unref_queue)}); - auto* raw_dart_image = tonic::ToDart(std::move(dart_image)); + canvas_image->set_image({std::move(raster_image), std::move(unref_queue)}); // All done! - tonic::DartInvoke(image_callback->Get(), {raw_dart_image}); + tonic::DartInvoke(image_callback->Get(), {Dart_True()}); // image_callback is associated with the Dart isolate and must be deleted // on the UI thread diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index f6dd98887d264..7ed628550c4f7 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -28,7 +28,8 @@ class Picture : public RefCountedDartWrappable { sk_sp picture() const { return picture_.get(); } - Dart_Handle toImage(uint32_t width, + Dart_Handle toImage(Dart_Handle image_handle, + uint32_t width, uint32_t height, Dart_Handle raw_image_callback); @@ -38,7 +39,8 @@ class Picture : public RefCountedDartWrappable { static void RegisterNatives(tonic::DartLibraryNatives* natives); - static Dart_Handle RasterizeToImage(sk_sp picture, + static Dart_Handle RasterizeToImage(Dart_Handle image_handle, + sk_sp picture, uint32_t width, uint32_t height, Dart_Handle raw_image_callback); diff --git a/lib/ui/painting/single_frame_codec.cc b/lib/ui/painting/single_frame_codec.cc index 44361f583a583..51eb870001a3e 100644 --- a/lib/ui/painting/single_frame_codec.cc +++ b/lib/ui/painting/single_frame_codec.cc @@ -4,7 +4,6 @@ #include "flutter/lib/ui/painting/single_frame_codec.h" -#include "flutter/lib/ui/painting/frame_info.h" #include "flutter/lib/ui/ui_dart_state.h" #include "third_party/tonic/logging/dart_invoke.h" @@ -23,16 +22,20 @@ int SingleFrameCodec::repetitionCount() const { return 0; } -Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle callback_handle) { +Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle image_handle, + Dart_Handle callback_handle) { if (!Dart_IsClosure(callback_handle)) { return tonic::ToDart("Callback must be a function"); } if (status_ == Status::kComplete) { - tonic::DartInvoke(callback_handle, {tonic::ToDart(cached_frame_)}); - return Dart_Null(); + return tonic::ToDart( + "Dart callers are responsible for caching the frame callback " + "information"); } + auto canvas_image = CanvasImage::Create(image_handle); + // This has to be valid because this method is called from Dart. auto dart_state = UIDartState::Current(); @@ -57,7 +60,7 @@ Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle callback_handle) { fml::RefPtr* raw_codec_ref = new fml::RefPtr(this); - decoder->Decode(descriptor_, [raw_codec_ref](auto image) { + decoder->Decode(descriptor_, [canvas_image, raw_codec_ref](auto image) { std::unique_ptr> codec_ref(raw_codec_ref); fml::RefPtr codec(std::move(*codec_ref)); @@ -66,18 +69,14 @@ Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle callback_handle) { if (!state) { // This is probably because the isolate has been terminated before the // image could be decoded. - return; } tonic::DartState::Scope scope(state.get()); if (image.get()) { - auto canvas_image = fml::MakeRefCounted(); canvas_image->set_image(std::move(image)); - - codec->cached_frame_ = fml::MakeRefCounted( - std::move(canvas_image), 0 /* duration */); + codec->cached_frame_image_size_ = canvas_image->GetAllocationSize(); } // The cached frame is now available and should be returned to any future @@ -85,9 +84,8 @@ Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle callback_handle) { codec->status_ = Status::kComplete; // Invoke any callbacks that were provided before the frame was decoded. - Dart_Handle frame = tonic::ToDart(codec->cached_frame_); for (const DartPersistentValue& callback : codec->pending_callbacks_) { - tonic::DartInvoke(callback.value(), {frame}); + tonic::DartInvoke(callback.value(), {tonic::ToDart(0)}); } codec->pending_callbacks_.clear(); }); @@ -97,17 +95,13 @@ Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle callback_handle) { descriptor_.data.reset(); status_ = Status::kInProgress; - return Dart_Null(); } size_t SingleFrameCodec::GetAllocationSize() { const auto& data = descriptor_.data; const auto data_byte_size = data ? data->size() : 0; - const auto frame_byte_size = (cached_frame_ && cached_frame_->image()) - ? cached_frame_->image()->GetAllocationSize() - : 0; - return data_byte_size + frame_byte_size + sizeof(this); + return data_byte_size + cached_frame_image_size_ + sizeof(this); } } // namespace flutter diff --git a/lib/ui/painting/single_frame_codec.h b/lib/ui/painting/single_frame_codec.h index b01638c71ce63..48639deb10a90 100644 --- a/lib/ui/painting/single_frame_codec.h +++ b/lib/ui/painting/single_frame_codec.h @@ -7,15 +7,20 @@ #include "flutter/fml/macros.h" #include "flutter/lib/ui/painting/codec.h" -#include "flutter/lib/ui/painting/frame_info.h" +#include "flutter/lib/ui/painting/image.h" #include "flutter/lib/ui/painting/image_decoder.h" namespace flutter { class SingleFrameCodec : public Codec { public: - SingleFrameCodec(ImageDecoder::ImageDescriptor descriptor); - + static fml::RefPtr Create( + Dart_Handle codec_handle, + ImageDecoder::ImageDescriptor descriptor) { + auto codec = fml::MakeRefCounted(std::move(descriptor)); + codec->AssociateWithDartWrapper(codec_handle); + return codec; + } ~SingleFrameCodec() override; // |Codec| @@ -25,16 +30,18 @@ class SingleFrameCodec : public Codec { int repetitionCount() const override; // |Codec| - Dart_Handle getNextFrame(Dart_Handle args) override; + Dart_Handle getNextFrame(Dart_Handle image_handle, + Dart_Handle callback_handle) override; // |DartWrappable| size_t GetAllocationSize() override; private: + SingleFrameCodec(ImageDecoder::ImageDescriptor descriptor); enum class Status { kNew, kInProgress, kComplete }; Status status_; ImageDecoder::ImageDescriptor descriptor_; - fml::RefPtr cached_frame_; + size_t cached_frame_image_size_; std::vector pending_callbacks_; FML_FRIEND_MAKE_REF_COUNTED(SingleFrameCodec); diff --git a/third_party/tonic/dart_state.cc b/third_party/tonic/dart_state.cc index b711a22977788..870f058b9f2fc 100644 --- a/third_party/tonic/dart_state.cc +++ b/third_party/tonic/dart_state.cc @@ -22,7 +22,6 @@ DartState::Scope::~Scope() {} DartState::DartState(int dirfd, std::function message_epilogue) : isolate_(nullptr), - private_constructor_name_(), class_library_(new DartClassLibrary), message_handler_(new DartMessageHandler()), file_loader_(new FileLoader(dirfd)), @@ -37,12 +36,6 @@ void DartState::SetIsolate(Dart_Isolate isolate) { if (!isolate_) return; - private_constructor_name_.Clear(); - Dart_EnterScope(); - private_constructor_name_.Set( - this, Dart_NewPersistentHandle(Dart_NewStringFromCString("_"))); - Dart_ExitScope(); - DidSetIsolate(); } diff --git a/third_party/tonic/dart_state.h b/third_party/tonic/dart_state.h index 845914937dcd0..d2c6e03cb7cc9 100644 --- a/third_party/tonic/dart_state.h +++ b/third_party/tonic/dart_state.h @@ -49,12 +49,6 @@ class DartState : public std::enable_shared_from_this { Dart_Isolate isolate() { return isolate_; } void SetIsolate(Dart_Isolate isolate); - // TODO(https://github.com/flutter/flutter/issues/50997): Work around until we - // drop the need for Dart_New in tonic. - Dart_PersistentHandle private_constructor_name() { - return private_constructor_name_.Get(); - } - DartClassLibrary& class_library() { return *class_library_; } DartMessageHandler& message_handler() { return *message_handler_; } FileLoader& file_loader() { return *file_loader_; } @@ -76,7 +70,6 @@ class DartState : public std::enable_shared_from_this { private: Dart_Isolate isolate_; - DartPersistentValue private_constructor_name_; std::unique_ptr class_library_; std::unique_ptr message_handler_; std::unique_ptr file_loader_; diff --git a/third_party/tonic/dart_wrappable.cc b/third_party/tonic/dart_wrappable.cc index 4ebfda7e1a362..42c8fff2805b2 100644 --- a/third_party/tonic/dart_wrappable.cc +++ b/third_party/tonic/dart_wrappable.cc @@ -15,33 +15,6 @@ DartWrappable::~DartWrappable() { TONIC_CHECK(!dart_wrapper_); } -// TODO(dnfield): Delete this. https://github.com/flutter/flutter/issues/50997 -Dart_Handle DartWrappable::CreateDartWrapper(DartState* dart_state) { - TONIC_DCHECK(!dart_wrapper_); - const DartWrapperInfo& info = GetDartWrapperInfo(); - - Dart_PersistentHandle type = dart_state->class_library().GetClass(info); - TONIC_DCHECK(!LogIfError(type)); - - Dart_Handle wrapper = - Dart_New(type, dart_state->private_constructor_name(), 0, nullptr); - - TONIC_DCHECK(!LogIfError(wrapper)); - - Dart_Handle res = Dart_SetNativeInstanceField( - wrapper, kPeerIndex, reinterpret_cast(this)); - TONIC_DCHECK(!LogIfError(res)); - res = Dart_SetNativeInstanceField(wrapper, kWrapperInfoIndex, - reinterpret_cast(&info)); - TONIC_DCHECK(!LogIfError(res)); - - this->RetainDartWrappableReference(); // Balanced in FinalizeDartWrapper. - dart_wrapper_ = Dart_NewWeakPersistentHandle( - wrapper, this, GetAllocationSize(), &FinalizeDartWrapper); - - return wrapper; -} - void DartWrappable::AssociateWithDartWrapper(Dart_Handle wrapper) { TONIC_DCHECK(!dart_wrapper_); TONIC_CHECK(!LogIfError(wrapper)); @@ -74,7 +47,8 @@ void DartWrappable::FinalizeDartWrapper(void* isolate_callback_data, void* peer) { DartWrappable* wrappable = reinterpret_cast(peer); wrappable->dart_wrapper_ = nullptr; - wrappable->ReleaseDartWrappableReference(); // Balanced in CreateDartWrapper. + wrappable->ReleaseDartWrappableReference(); // Balanced in + // AssociateWithDartWrapper. } size_t DartWrappable::GetAllocationSize() { diff --git a/third_party/tonic/dart_wrappable.h b/third_party/tonic/dart_wrappable.h index 1d2e5e75bacb2..d4a6e1711aa15 100644 --- a/third_party/tonic/dart_wrappable.h +++ b/third_party/tonic/dart_wrappable.h @@ -43,10 +43,6 @@ class DartWrappable { virtual void ReleaseDartWrappableReference() const = 0; - // Use this method sparingly. It follows a slower path using Dart_New. - // Prefer constructing the object in Dart code and using - // AssociateWithDartWrapper. - Dart_Handle CreateDartWrapper(DartState* dart_state); void AssociateWithDartWrapper(Dart_Handle wrappable); void ClearDartWrapper(); // Warning: Might delete this. Dart_WeakPersistentHandle dart_wrapper() const { return dart_wrapper_; } @@ -107,18 +103,23 @@ struct DartConverter< return Dart_Null(); if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) return Dart_HandleFromWeakPersistent(wrapper); - return val->CreateDartWrapper(DartState::Current()); + + Log("Do not create non-primitive Dart objects from C++ code."); + TONIC_DCHECK(false); + return Dart_NewApiError("Invalid object conversion"); } static void SetReturnValue(Dart_NativeArguments args, DartWrappable* val, bool auto_scope = true) { - if (!val) + if (!val) { Dart_SetReturnValue(args, Dart_Null()); - else if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) + } else if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) { Dart_SetWeakHandleReturnValue(args, wrapper); - else - Dart_SetReturnValue(args, val->CreateDartWrapper(DartState::Current())); + } else { + Log("Do not create non-primitive Dart objects from C++ code."); + TONIC_DCHECK(false); + } } static T* FromDart(Dart_Handle handle) {