diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index b68946dde0cd8..d0182f4580ab0 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -298,6 +298,8 @@ 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 a38298f460975..c904141b338e8 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -30,6 +30,8 @@ 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 e86347d9b5389..715ba20023278 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -22,16 +22,14 @@ 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) async { + Future toImage(int width, int height) { if (width <= 0 || height <= 0) { throw Exception('Invalid image dimensions.'); } - final Image image = Image._(); - await _futurize((_Callback callback) => _toImage(image, width, height, callback)); - return image; + return _futurize((_Callback callback) => _toImage(width, height, callback)); } - String _toImage(Image outImage, int width, int height, _Callback callback) native 'Scene_toImage'; + String _toImage(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 4c2aa16fa0253..f5403ecae9a61 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -61,8 +61,7 @@ void Scene::dispose() { ClearDartWrapper(); } -Dart_Handle Scene::toImage(Dart_Handle image_handle, - uint32_t width, +Dart_Handle Scene::toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { TRACE_EVENT0("flutter", "Scene::toImage"); @@ -76,8 +75,7 @@ Dart_Handle Scene::toImage(Dart_Handle image_handle, return tonic::ToDart("Could not flatten scene into a layer tree."); } - return Picture::RasterizeToImage(image_handle, picture, width, height, - raw_image_callback); + return Picture::RasterizeToImage(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 7039dc410874e..d46ca5d3d4281 100644 --- a/lib/ui/compositing/scene.h +++ b/lib/ui/compositing/scene.h @@ -32,8 +32,7 @@ class Scene : public RefCountedDartWrappable { std::unique_ptr takeLayerTree(); - Dart_Handle toImage(Dart_Handle image_handle, - uint32_t width, + Dart_Handle toImage(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 c3b758564a5d0..5b3189dfa80f8 100644 --- a/lib/ui/dart_ui.cc +++ b/lib/ui/dart_ui.cc @@ -13,6 +13,7 @@ #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" @@ -79,6 +80,7 @@ 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 24d179365da60..dbcbc7d01db60 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -1639,19 +1639,22 @@ typedef ImageDecoderCallback = void Function(Image result); /// /// To obtain an instance of the [FrameInfo] interface, see /// [Codec.getNextFrame]. -class FrameInfo { +@pragma('vm:entry-point') +class FrameInfo extends NativeFieldWrapperClass2 { /// 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]. - FrameInfo._(int durationMilliseconds, this.image) : duration = Duration(milliseconds: durationMilliseconds); + @pragma('vm:entry-point') + FrameInfo._(); /// The duration this frame should be shown. - final Duration duration; + Duration get duration => Duration(milliseconds: _durationMillis); + int get _durationMillis native 'FrameInfo_durationMillis'; /// The [Image] object for this frame. - final Image image; + Image get image native 'FrameInfo_image'; } /// A handle to an image codec. @@ -1681,32 +1684,21 @@ 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() 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; + Future getNextFrame() { + return _futurize(_getNextFrame); } /// Returns an error message on failure, null on success. - String _getNextFrame(Image outImage, _Callback callback) native 'Codec_getNextFrame'; + String _getNextFrame(_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() { - _cachedFrame = null; - _dispose(); - } - void _dispose() native 'Codec_dispose'; + void dispose() native 'Codec_dispose'; } /// Instantiates an image codec [Codec] object. @@ -1726,12 +1718,10 @@ class Codec extends NativeFieldWrapperClass2 { Future instantiateImageCodec(Uint8List list, { int targetWidth, int targetHeight, -}) async { - final Codec codec = Codec._(); - await _futurize((_Callback callback) { - return _instantiateImageCodec(codec, list, callback, null, targetWidth ?? _kDoNotResizeDimension, targetHeight ?? _kDoNotResizeDimension); - }); - return codec; +}) { + return _futurize( + (_Callback callback) => _instantiateImageCodec(list, callback, null, targetWidth ?? _kDoNotResizeDimension, targetHeight ?? _kDoNotResizeDimension) + ); } /// Instantiates a [Codec] object for an image binary data. @@ -1745,7 +1735,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(Codec outCodec, Uint8List list, _Callback callback, _ImageInfo imageInfo, int targetWidth, int targetHeight) +String _instantiateImageCodec(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. @@ -1786,12 +1776,11 @@ void decodeImageFromPixels( {int rowBytes, int targetWidth, int targetHeight} ) { final _ImageInfo imageInfo = _ImageInfo(width, height, format.index, rowBytes); - 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)); - }); + 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)); } /// Determines the winding rule that decides how the interior of a [Path] is @@ -4136,17 +4125,15 @@ 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) async { + Future toImage(int width, int height) { if (width <= 0 || height <= 0) throw Exception('Invalid image dimensions.'); - final Image image = Image._(); - await _futurize( - (_Callback callback) => _toImage(image, width, height, callback) + return _futurize( + (_Callback callback) => _toImage(width, height, callback) ); - return image; } - String _toImage(Image outImage, int width, int height, _Callback callback) native 'Picture_toImage'; + String _toImage(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 76ee2b9fe71e1..829b9db65ed9d 100644 --- a/lib/ui/painting/codec.cc +++ b/lib/ui/painting/codec.cc @@ -10,6 +10,7 @@ #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" @@ -144,14 +145,13 @@ static std::variant ConvertImageInfo( } static void InstantiateImageCodec(Dart_NativeArguments args) { - Dart_Handle codec_handle = Dart_GetNativeArgument(args, 0); - Dart_Handle callback_handle = Dart_GetNativeArgument(args, 2); + Dart_Handle callback_handle = Dart_GetNativeArgument(args, 1); if (!Dart_IsClosure(callback_handle)) { Dart_SetReturnValue(args, tonic::ToDart("Callback must be a function")); return; } - Dart_Handle image_info_handle = Dart_GetNativeArgument(args, 3); + Dart_Handle image_info_handle = Dart_GetNativeArgument(args, 2); 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, 1, + tonic::DartConverter::FromArguments(args, 0, 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, 4)); + tonic::DartConverter::FromDart(Dart_GetNativeArgument(args, 3)); const int targetHeight = - tonic::DartConverter::FromDart(Dart_GetNativeArgument(args, 5)); + tonic::DartConverter::FromDart(Dart_GetNativeArgument(args, 4)); std::unique_ptr codec; bool single_frame; @@ -208,6 +208,8 @@ 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; @@ -220,13 +222,12 @@ static void InstantiateImageCodec(Dart_NativeArguments args) { } descriptor.data = std::move(buffer); - SingleFrameCodec::Create(codec_handle, std::move(descriptor)); + ui_codec = fml::MakeRefCounted(std::move(descriptor)); } else { - MultiFrameCodec::Create(codec_handle, std::move(codec)); + ui_codec = fml::MakeRefCounted(std::move(codec)); } - tonic::DartInvoke(callback_handle, {Dart_True()}); - Dart_SetReturnValue(args, Dart_Null()); + tonic::DartInvoke(callback_handle, {ToDart(ui_codec)}); } IMPLEMENT_WRAPPERTYPEINFO(ui, Codec); @@ -245,7 +246,7 @@ void Codec::dispose() { void Codec::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({ - {"instantiateImageCodec", InstantiateImageCodec, 6, true}, + {"instantiateImageCodec", InstantiateImageCodec, 5, true}, }); natives->Register({FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); } diff --git a/lib/ui/painting/codec.h b/lib/ui/painting/codec.h index 53ac9e426448d..2e0c746eac2d6 100644 --- a/lib/ui/painting/codec.h +++ b/lib/ui/painting/codec.h @@ -6,6 +6,7 @@ #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" @@ -29,8 +30,7 @@ class Codec : public RefCountedDartWrappable { virtual int repetitionCount() const = 0; - virtual Dart_Handle getNextFrame(Dart_Handle image_handle, - Dart_Handle callback_handle) = 0; + virtual Dart_Handle getNextFrame(Dart_Handle callback_handle) = 0; void dispose(); diff --git a/lib/ui/painting/frame_info.cc b/lib/ui/painting/frame_info.cc new file mode 100644 index 0000000000000..ad77f7b50d8a4 --- /dev/null +++ b/lib/ui/painting/frame_info.cc @@ -0,0 +1,30 @@ + +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#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 new file mode 100644 index 0000000000000..184b132d17791 --- /dev/null +++ b/lib/ui/painting/frame_info.h @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#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 43a00517421b8..516a2e5d59c49 100644 --- a/lib/ui/painting/image.h +++ b/lib/ui/painting/image.h @@ -22,10 +22,8 @@ class CanvasImage final : public RefCountedDartWrappable { public: ~CanvasImage() override; - static fml::RefPtr Create(Dart_Handle dart_handle) { - auto image = fml::MakeRefCounted(); - image->AssociateWithDartWrapper(dart_handle); - return image; + static fml::RefPtr Create() { + return fml::MakeRefCounted(); } 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 c38ecb48930e3..f650e25a97e61 100644 --- a/lib/ui/painting/multi_frame_codec.cc +++ b/lib/ui/painting/multi_frame_codec.cc @@ -20,11 +20,8 @@ MultiFrameCodec::MultiFrameCodec(std::unique_ptr codec) MultiFrameCodec::~MultiFrameCodec() = default; static void InvokeNextFrameCallback( - sk_sp skImage, - fml::RefPtr canvas_image, + fml::RefPtr frameInfo, 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) { @@ -33,13 +30,10 @@ static void InvokeNextFrameCallback( return; } tonic::DartState::Scope scope(dart_state); - - if (skImage) { - canvas_image->set_image({skImage, std::move(unref_queue)}); - tonic::DartInvoke(callback->value(), - {tonic::ToDart(skFrameInfo.fDuration)}); - } else { + if (!frameInfo) { tonic::DartInvoke(callback->value(), {Dart_Null()}); + } else { + tonic::DartInvoke(callback->value(), {ToDart(frameInfo)}); } } @@ -135,32 +129,30 @@ 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( - [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); + [callback = std::move(callback), frameInfo, trace_id]() mutable { + InvokeNextFrameCallback(frameInfo, std::move(callback), trace_id); })); } -Dart_Handle MultiFrameCodec::getNextFrame(Dart_Handle image_handle, - Dart_Handle callback_handle) { +Dart_Handle MultiFrameCodec::getNextFrame(Dart_Handle callback_handle) { static size_t trace_counter = 1; const size_t trace_id = trace_counter++; @@ -168,19 +160,17 @@ Dart_Handle MultiFrameCodec::getNextFrame(Dart_Handle image_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( - [canvas_image = std::move(canvas_image), - callback = std::make_unique( + [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( - canvas_image, std::move(callback), std::move(ui_task_runner), + 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 1abcded241469..0be63c2a57582 100644 --- a/lib/ui/painting/multi_frame_codec.h +++ b/lib/ui/painting/multi_frame_codec.h @@ -5,23 +5,15 @@ #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: - 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(std::unique_ptr codec); + ~MultiFrameCodec() override; // |Codec| @@ -31,10 +23,9 @@ class MultiFrameCodec : public Codec { int repetitionCount() const override; // |Codec| - Dart_Handle getNextFrame(Dart_Handle image_handle, Dart_Handle args) override; + Dart_Handle getNextFrame(Dart_Handle args) override; private: - MultiFrameCodec(std::unique_ptr codec); const std::unique_ptr codec_; const int frameCount_; const int repetitionCount_; @@ -48,7 +39,6 @@ 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 34d765221e0a7..8527b83ec139b 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -40,16 +40,14 @@ Picture::Picture(flutter::SkiaGPUObject picture) Picture::~Picture() = default; -Dart_Handle Picture::toImage(Dart_Handle image_handle, - uint32_t width, +Dart_Handle Picture::toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { if (!picture_.get()) { return tonic::ToDart("Picture is null"); } - return RasterizeToImage(image_handle, picture_.get(), width, height, - raw_image_callback); + return RasterizeToImage(picture_.get(), width, height, raw_image_callback); } void Picture::dispose() { @@ -64,8 +62,7 @@ size_t Picture::GetAllocationSize() { } } -Dart_Handle Picture::RasterizeToImage(Dart_Handle image_handle, - sk_sp picture, +Dart_Handle Picture::RasterizeToImage(sk_sp picture, uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { @@ -77,8 +74,6 @@ Dart_Handle Picture::RasterizeToImage(Dart_Handle image_handle, 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); @@ -94,7 +89,7 @@ Dart_Handle Picture::RasterizeToImage(Dart_Handle image_handle, auto picture_bounds = SkISize::Make(width, height); - auto ui_task = fml::MakeCopyable([canvas_image, image_callback, unref_queue]( + auto ui_task = fml::MakeCopyable([image_callback, unref_queue]( sk_sp raster_image) mutable { auto dart_state = image_callback->dart_state().lock(); if (!dart_state) { @@ -105,14 +100,15 @@ Dart_Handle Picture::RasterizeToImage(Dart_Handle image_handle, if (!raster_image) { tonic::DartInvoke(image_callback->Get(), {Dart_Null()}); - delete image_callback; return; } - canvas_image->set_image({std::move(raster_image), std::move(unref_queue)}); + 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)); // All done! - tonic::DartInvoke(image_callback->Get(), {Dart_True()}); + tonic::DartInvoke(image_callback->Get(), {raw_dart_image}); // 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 7ed628550c4f7..f6dd98887d264 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -28,8 +28,7 @@ class Picture : public RefCountedDartWrappable { sk_sp picture() const { return picture_.get(); } - Dart_Handle toImage(Dart_Handle image_handle, - uint32_t width, + Dart_Handle toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback); @@ -39,8 +38,7 @@ class Picture : public RefCountedDartWrappable { static void RegisterNatives(tonic::DartLibraryNatives* natives); - static Dart_Handle RasterizeToImage(Dart_Handle image_handle, - sk_sp picture, + static Dart_Handle RasterizeToImage(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 51eb870001a3e..44361f583a583 100644 --- a/lib/ui/painting/single_frame_codec.cc +++ b/lib/ui/painting/single_frame_codec.cc @@ -4,6 +4,7 @@ #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" @@ -22,20 +23,16 @@ int SingleFrameCodec::repetitionCount() const { return 0; } -Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle image_handle, - Dart_Handle callback_handle) { +Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle callback_handle) { if (!Dart_IsClosure(callback_handle)) { return tonic::ToDart("Callback must be a function"); } if (status_ == Status::kComplete) { - return tonic::ToDart( - "Dart callers are responsible for caching the frame callback " - "information"); + tonic::DartInvoke(callback_handle, {tonic::ToDart(cached_frame_)}); + return Dart_Null(); } - auto canvas_image = CanvasImage::Create(image_handle); - // This has to be valid because this method is called from Dart. auto dart_state = UIDartState::Current(); @@ -60,7 +57,7 @@ Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle image_handle, fml::RefPtr* raw_codec_ref = new fml::RefPtr(this); - decoder->Decode(descriptor_, [canvas_image, raw_codec_ref](auto image) { + decoder->Decode(descriptor_, [raw_codec_ref](auto image) { std::unique_ptr> codec_ref(raw_codec_ref); fml::RefPtr codec(std::move(*codec_ref)); @@ -69,14 +66,18 @@ Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle image_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_image_size_ = canvas_image->GetAllocationSize(); + + codec->cached_frame_ = fml::MakeRefCounted( + std::move(canvas_image), 0 /* duration */); } // The cached frame is now available and should be returned to any future @@ -84,8 +85,9 @@ Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle image_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(), {tonic::ToDart(0)}); + tonic::DartInvoke(callback.value(), {frame}); } codec->pending_callbacks_.clear(); }); @@ -95,13 +97,17 @@ Dart_Handle SingleFrameCodec::getNextFrame(Dart_Handle image_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; - return data_byte_size + cached_frame_image_size_ + sizeof(this); + const auto frame_byte_size = (cached_frame_ && cached_frame_->image()) + ? cached_frame_->image()->GetAllocationSize() + : 0; + return data_byte_size + frame_byte_size + sizeof(this); } } // namespace flutter diff --git a/lib/ui/painting/single_frame_codec.h b/lib/ui/painting/single_frame_codec.h index 48639deb10a90..b01638c71ce63 100644 --- a/lib/ui/painting/single_frame_codec.h +++ b/lib/ui/painting/single_frame_codec.h @@ -7,20 +7,15 @@ #include "flutter/fml/macros.h" #include "flutter/lib/ui/painting/codec.h" -#include "flutter/lib/ui/painting/image.h" +#include "flutter/lib/ui/painting/frame_info.h" #include "flutter/lib/ui/painting/image_decoder.h" namespace flutter { class SingleFrameCodec : public Codec { public: - 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(ImageDecoder::ImageDescriptor descriptor); + ~SingleFrameCodec() override; // |Codec| @@ -30,18 +25,16 @@ class SingleFrameCodec : public Codec { int repetitionCount() const override; // |Codec| - Dart_Handle getNextFrame(Dart_Handle image_handle, - Dart_Handle callback_handle) override; + Dart_Handle getNextFrame(Dart_Handle args) override; // |DartWrappable| size_t GetAllocationSize() override; private: - SingleFrameCodec(ImageDecoder::ImageDescriptor descriptor); enum class Status { kNew, kInProgress, kComplete }; Status status_; ImageDecoder::ImageDescriptor descriptor_; - size_t cached_frame_image_size_; + fml::RefPtr cached_frame_; 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 870f058b9f2fc..b711a22977788 100644 --- a/third_party/tonic/dart_state.cc +++ b/third_party/tonic/dart_state.cc @@ -22,6 +22,7 @@ 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)), @@ -36,6 +37,12 @@ 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 d2c6e03cb7cc9..845914937dcd0 100644 --- a/third_party/tonic/dart_state.h +++ b/third_party/tonic/dart_state.h @@ -49,6 +49,12 @@ 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_; } @@ -70,6 +76,7 @@ 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 42c8fff2805b2..4ebfda7e1a362 100644 --- a/third_party/tonic/dart_wrappable.cc +++ b/third_party/tonic/dart_wrappable.cc @@ -15,6 +15,33 @@ 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)); @@ -47,8 +74,7 @@ void DartWrappable::FinalizeDartWrapper(void* isolate_callback_data, void* peer) { DartWrappable* wrappable = reinterpret_cast(peer); wrappable->dart_wrapper_ = nullptr; - wrappable->ReleaseDartWrappableReference(); // Balanced in - // AssociateWithDartWrapper. + wrappable->ReleaseDartWrappableReference(); // Balanced in CreateDartWrapper. } size_t DartWrappable::GetAllocationSize() { diff --git a/third_party/tonic/dart_wrappable.h b/third_party/tonic/dart_wrappable.h index d4a6e1711aa15..1d2e5e75bacb2 100644 --- a/third_party/tonic/dart_wrappable.h +++ b/third_party/tonic/dart_wrappable.h @@ -43,6 +43,10 @@ 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_; } @@ -103,23 +107,18 @@ struct DartConverter< return Dart_Null(); if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) return Dart_HandleFromWeakPersistent(wrapper); - - Log("Do not create non-primitive Dart objects from C++ code."); - TONIC_DCHECK(false); - return Dart_NewApiError("Invalid object conversion"); + return val->CreateDartWrapper(DartState::Current()); } 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 { - Log("Do not create non-primitive Dart objects from C++ code."); - TONIC_DCHECK(false); - } + else + Dart_SetReturnValue(args, val->CreateDartWrapper(DartState::Current())); } static T* FromDart(Dart_Handle handle) {