Make IOManager own resource context (flutter/engine#7272)

* Make IOManager own resource context
This commit is contained in:
Dan Field 2019-01-14 13:46:38 -08:00 committed by GitHub
parent e088b1fccd
commit a9728ab07a
18 changed files with 116 additions and 84 deletions

View File

@ -230,6 +230,7 @@ FILE: ../../../flutter/lib/ui/dart_wrapper.h
FILE: ../../../flutter/lib/ui/geometry.dart
FILE: ../../../flutter/lib/ui/hash_codes.dart
FILE: ../../../flutter/lib/ui/hooks.dart
FILE: ../../../flutter/lib/ui/io_manager.h
FILE: ../../../flutter/lib/ui/isolate_name_server.dart
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.cc
FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.h

View File

@ -15,6 +15,7 @@ source_set("ui") {
"dart_ui.cc",
"dart_ui.h",
"dart_wrapper.h",
"io_manager.h",
"isolate_name_server/isolate_name_server.cc",
"isolate_name_server/isolate_name_server.h",
"isolate_name_server/isolate_name_server_natives.cc",

View File

@ -0,0 +1,25 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_LIB_UI_IO_MANAGER_H_
#define FLUTTER_LIB_UI_IO_MANAGER_H_
#include "flutter/flow/skia_gpu_object.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "third_party/skia/include/gpu/GrContext.h"
namespace blink {
// Interface for methods that manage access to the resource GrContext and Skia
// unref queue. Meant to be implemented by the owner of the resource GrContext,
// i.e. the shell's IOManager.
class IOManager {
public:
virtual fml::WeakPtr<GrContext> GetResourceContext() const = 0;
virtual fml::RefPtr<flow::SkiaUnrefQueue> GetSkiaUnrefQueue() const = 0;
};
} // namespace blink
#endif // FLUTTER_LIB_UI_IO_MANAGER_H_

View File

@ -17,8 +17,7 @@ UIDartState::UIDartState(TaskRunners task_runners,
TaskObserverAdd add_callback,
TaskObserverRemove remove_callback,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> skia_unref_queue,
fml::WeakPtr<IOManager> io_manager,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
std::string logger_prefix,
@ -27,11 +26,10 @@ UIDartState::UIDartState(TaskRunners task_runners,
add_callback_(std::move(add_callback)),
remove_callback_(std::move(remove_callback)),
snapshot_delegate_(std::move(snapshot_delegate)),
resource_context_(std::move(resource_context)),
io_manager_(std::move(io_manager)),
advisory_script_uri_(std::move(advisory_script_uri)),
advisory_script_entrypoint_(std::move(advisory_script_entrypoint)),
logger_prefix_(std::move(logger_prefix)),
skia_unref_queue_(std::move(skia_unref_queue)),
isolate_name_server_(isolate_name_server) {
AddOrRemoveTaskObserver(true /* add */);
}
@ -78,7 +76,10 @@ const TaskRunners& UIDartState::GetTaskRunners() const {
}
fml::RefPtr<flow::SkiaUnrefQueue> UIDartState::GetSkiaUnrefQueue() const {
return skia_unref_queue_;
if (!io_manager_) {
return nullptr;
}
return io_manager_->GetSkiaUnrefQueue();
}
void UIDartState::ScheduleMicrotask(Dart_Handle closure) {
@ -114,7 +115,10 @@ fml::WeakPtr<SnapshotDelegate> UIDartState::GetSnapshotDelegate() const {
}
fml::WeakPtr<GrContext> UIDartState::GetResourceContext() const {
return resource_context_;
if (!io_manager_) {
return {};
}
return io_manager_->GetResourceContext();
}
IsolateNameServer* UIDartState::GetIsolateNameServer() {

View File

@ -14,6 +14,7 @@
#include "flutter/flow/skia_gpu_object.h"
#include "flutter/fml/build_config.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/lib/ui/io_manager.h"
#include "flutter/lib/ui/isolate_name_server/isolate_name_server.h"
#include "flutter/lib/ui/snapshot_delegate.h"
#include "third_party/dart/runtime/include/dart_api.h"
@ -72,8 +73,7 @@ class UIDartState : public tonic::DartState {
TaskObserverAdd add_callback,
TaskObserverRemove remove_callback,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> skia_unref_queue,
fml::WeakPtr<IOManager> io_manager,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
std::string logger_prefix,
@ -94,14 +94,13 @@ class UIDartState : public tonic::DartState {
const TaskObserverAdd add_callback_;
const TaskObserverRemove remove_callback_;
fml::WeakPtr<SnapshotDelegate> snapshot_delegate_;
fml::WeakPtr<GrContext> resource_context_;
fml::WeakPtr<IOManager> io_manager_;
const std::string advisory_script_uri_;
const std::string advisory_script_entrypoint_;
const std::string logger_prefix_;
Dart_Port main_port_ = ILLEGAL_PORT;
std::string debug_name_;
std::unique_ptr<Window> window_;
fml::RefPtr<flow::SkiaUnrefQueue> skia_unref_queue_;
tonic::DartMicrotaskQueue microtask_queue_;
IsolateNameServer* isolate_name_server_;

View File

@ -35,8 +35,7 @@ std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
TaskRunners task_runners,
std::unique_ptr<Window> window,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
fml::WeakPtr<IOManager> io_manager,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
Dart_IsolateFlags* flags) {
@ -56,8 +55,7 @@ std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
std::move(shared_snapshot), // shared snapshot
task_runners, // task runners
std::move(snapshot_delegate), // snapshot delegate
std::move(resource_context), // resource context
std::move(unref_queue), // skia unref queue
std::move(io_manager), // IO manager
advisory_script_uri, // advisory URI
advisory_script_entrypoint, // advisory entrypoint
nullptr // child isolate preparer will be set when this isolate is
@ -100,8 +98,7 @@ DartIsolate::DartIsolate(DartVM* vm,
fml::RefPtr<DartSnapshot> shared_snapshot,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
fml::WeakPtr<IOManager> io_manager,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
ChildIsolatePreparer child_isolate_preparer)
@ -109,8 +106,7 @@ DartIsolate::DartIsolate(DartVM* vm,
vm->GetSettings().task_observer_add,
vm->GetSettings().task_observer_remove,
std::move(snapshot_delegate),
std::move(resource_context),
std::move(unref_queue),
std::move(io_manager),
advisory_script_uri,
advisory_script_entrypoint,
vm->GetSettings().log_tag,
@ -534,8 +530,7 @@ Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate(
null_task_runners, // task runners
nullptr, // window
{}, // snapshot delegate
{}, // resource context
{}, // unref queue
{}, // IO Manager
advisory_script_uri == nullptr ? ""
: advisory_script_uri, // script uri
advisory_script_entrypoint == nullptr
@ -645,8 +640,7 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair(
(*raw_embedder_isolate)->GetSharedSnapshot(), // shared_snapshot
null_task_runners, // task_runners
fml::WeakPtr<SnapshotDelegate>{}, // snapshot_delegate
fml::WeakPtr<GrContext>{}, // resource_context
nullptr, // unref_queue
fml::WeakPtr<IOManager>{}, // io_manager
advisory_script_uri, // advisory_script_uri
advisory_script_entrypoint, // advisory_script_entrypoint
(*raw_embedder_isolate)->child_isolate_preparer_));

View File

@ -12,6 +12,7 @@
#include "flutter/fml/compiler_specific.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/mapping.h"
#include "flutter/lib/ui/io_manager.h"
#include "flutter/lib/ui/snapshot_delegate.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "flutter/lib/ui/window/window.h"
@ -46,8 +47,7 @@ class DartIsolate : public UIDartState {
TaskRunners task_runners,
std::unique_ptr<Window> window,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
fml::WeakPtr<IOManager> io_manager,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
Dart_IsolateFlags* flags = nullptr);
@ -57,8 +57,7 @@ class DartIsolate : public UIDartState {
fml::RefPtr<DartSnapshot> shared_snapshot,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
fml::WeakPtr<IOManager> io_manager,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
ChildIsolatePreparer child_isolate_preparer);

View File

@ -36,8 +36,7 @@ TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) {
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // resource context
nullptr, // unref qeueue
{}, // io manager
"main.dart", // advisory uri
"main" // advisory entrypoint
);
@ -66,8 +65,7 @@ TEST_F(DartIsolateTest, IsolateShutdownCallbackIsInIsolateScope) {
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // resource context
nullptr, // unref qeueue
{}, // io manager
"main.dart", // advisory uri
"main" // advisory entrypoint
);

View File

@ -21,8 +21,7 @@ RuntimeController::RuntimeController(
fml::RefPtr<DartSnapshot> p_shared_snapshot,
TaskRunners p_task_runners,
fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
fml::WeakPtr<GrContext> p_resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> p_unref_queue,
fml::WeakPtr<IOManager> p_io_manager,
std::string p_advisory_script_uri,
std::string p_advisory_script_entrypoint,
std::function<void(int64_t)> p_idle_notification_callback)
@ -32,8 +31,7 @@ RuntimeController::RuntimeController(
std::move(p_shared_snapshot),
std::move(p_task_runners),
std::move(p_snapshot_delegate),
std::move(p_resource_context),
std::move(p_unref_queue),
std::move(p_io_manager),
std::move(p_advisory_script_uri),
std::move(p_advisory_script_entrypoint),
p_idle_notification_callback,
@ -46,8 +44,7 @@ RuntimeController::RuntimeController(
fml::RefPtr<DartSnapshot> p_shared_snapshot,
TaskRunners p_task_runners,
fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
fml::WeakPtr<GrContext> p_resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> p_unref_queue,
fml::WeakPtr<IOManager> p_io_manager,
std::string p_advisory_script_uri,
std::string p_advisory_script_entrypoint,
std::function<void(int64_t)> idle_notification_callback,
@ -58,8 +55,7 @@ RuntimeController::RuntimeController(
shared_snapshot_(std::move(p_shared_snapshot)),
task_runners_(p_task_runners),
snapshot_delegate_(p_snapshot_delegate),
resource_context_(p_resource_context),
unref_queue_(p_unref_queue),
io_manager_(p_io_manager),
advisory_script_uri_(p_advisory_script_uri),
advisory_script_entrypoint_(p_advisory_script_entrypoint),
idle_notification_callback_(idle_notification_callback),
@ -71,8 +67,7 @@ RuntimeController::RuntimeController(
task_runners_,
std::make_unique<Window>(this),
snapshot_delegate_,
resource_context_,
unref_queue_,
io_manager_,
p_advisory_script_uri,
p_advisory_script_entrypoint)) {
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
@ -120,8 +115,7 @@ std::unique_ptr<RuntimeController> RuntimeController::Clone() const {
shared_snapshot_, //
task_runners_, //
snapshot_delegate_, //
resource_context_, //
unref_queue_, //
io_manager_, //
advisory_script_uri_, //
advisory_script_entrypoint_, //
idle_notification_callback_, //

View File

@ -11,6 +11,7 @@
#include "flutter/common/task_runners.h"
#include "flutter/flow/layers/layer_tree.h"
#include "flutter/fml/macros.h"
#include "flutter/lib/ui/io_manager.h"
#include "flutter/lib/ui/text/font_collection.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "flutter/lib/ui/window/pointer_data_packet.h"
@ -33,8 +34,7 @@ class RuntimeController final : public WindowClient {
fml::RefPtr<DartSnapshot> shared_snapshot,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
fml::WeakPtr<IOManager> io_manager,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
std::function<void(int64_t)> idle_notification_callback);
@ -122,8 +122,7 @@ class RuntimeController final : public WindowClient {
fml::RefPtr<DartSnapshot> shared_snapshot_;
TaskRunners task_runners_;
fml::WeakPtr<SnapshotDelegate> snapshot_delegate_;
fml::WeakPtr<GrContext> resource_context_;
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue_;
fml::WeakPtr<IOManager> io_manager_;
std::string advisory_script_uri_;
std::string advisory_script_entrypoint_;
std::function<void(int64_t)> idle_notification_callback_;
@ -137,8 +136,7 @@ class RuntimeController final : public WindowClient {
fml::RefPtr<DartSnapshot> shared_snapshot,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
fml::WeakPtr<IOManager> io_manager,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
std::function<void(int64_t)> idle_notification_callback,

View File

@ -42,8 +42,7 @@ Engine::Engine(Delegate& delegate,
blink::Settings settings,
std::unique_ptr<Animator> animator,
fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue)
fml::WeakPtr<blink::IOManager> io_manager)
: delegate_(delegate),
settings_(std::move(settings)),
animator_(std::move(animator)),
@ -60,8 +59,7 @@ Engine::Engine(Delegate& delegate,
std::move(shared_snapshot), // shared snapshot
std::move(task_runners), // task runners
std::move(snapshot_delegate), // snapshot delegate
std::move(resource_context), // resource context
std::move(unref_queue), // skia unref queue
std::move(io_manager), // io manager
settings_.advisory_script_uri, // advisory script uri
settings_.advisory_script_entrypoint, // advisory script entrypoint
settings_.idle_notification_callback // idle notification callback

View File

@ -22,6 +22,7 @@
#include "flutter/runtime/runtime_controller.h"
#include "flutter/runtime/runtime_delegate.h"
#include "flutter/shell/common/animator.h"
#include "flutter/shell/common/io_manager.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/run_configuration.h"
#include "third_party/skia/include/core/SkPicture.h"
@ -61,8 +62,7 @@ class Engine final : public blink::RuntimeDelegate {
blink::Settings settings,
std::unique_ptr<Animator> animator,
fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<GrContext> resource_context,
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue);
fml::WeakPtr<blink::IOManager> io_manager);
~Engine() override;

View File

@ -71,8 +71,19 @@ fml::WeakPtr<GrContext> IOManager::GetResourceContext() const {
: fml::WeakPtr<GrContext>();
}
void IOManager::UpdateResourceContext(sk_sp<GrContext> resource_context) {
resource_context_ = std::move(resource_context);
resource_context_weak_factory_ =
resource_context_ ? std::make_unique<fml::WeakPtrFactory<GrContext>>(
resource_context_.get())
: nullptr;
}
fml::RefPtr<flow::SkiaUnrefQueue> IOManager::GetSkiaUnrefQueue() const {
return unref_queue_;
}
fml::WeakPtr<IOManager> IOManager::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
} // namespace shell

View File

@ -10,11 +10,12 @@
#include "flutter/flow/skia_gpu_object.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/lib/ui/io_manager.h"
#include "third_party/skia/include/gpu/GrContext.h"
namespace shell {
class IOManager {
class IOManager : public blink::IOManager {
public:
// Convenience methods for platforms to create a GrContext used to supply to
// the IOManager. The platforms may create the context themselves if they so
@ -25,11 +26,15 @@ class IOManager {
IOManager(sk_sp<GrContext> resource_context,
fml::RefPtr<fml::TaskRunner> unref_queue_task_runner);
~IOManager();
virtual ~IOManager();
fml::WeakPtr<GrContext> GetResourceContext() const;
fml::WeakPtr<GrContext> GetResourceContext() const override;
fml::RefPtr<flow::SkiaUnrefQueue> GetSkiaUnrefQueue() const;
void UpdateResourceContext(sk_sp<GrContext> resource_context);
fml::RefPtr<flow::SkiaUnrefQueue> GetSkiaUnrefQueue() const override;
fml::WeakPtr<IOManager> GetWeakPtr();
private:
// Resource context management.

View File

@ -67,22 +67,16 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
// other subsystems.
fml::AutoResetWaitableEvent io_latch;
std::unique_ptr<IOManager> io_manager;
fml::WeakPtr<GrContext> resource_context;
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue;
auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner();
fml::TaskRunner::RunNowOrPostTask(
io_task_runner,
[&io_latch, //
&io_manager, //
&resource_context, //
&unref_queue, //
&platform_view, //
io_task_runner //
[&io_latch, //
&io_manager, //
&platform_view, //
io_task_runner //
]() {
io_manager = std::make_unique<IOManager>(
platform_view->CreateResourceContext(), io_task_runner);
resource_context = io_manager->GetResourceContext();
unref_queue = io_manager->GetSkiaUnrefQueue();
io_latch.Signal();
});
io_latch.Wait();
@ -119,8 +113,7 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
shared_snapshot = std::move(shared_snapshot), //
vsync_waiter = std::move(vsync_waiter), //
snapshot_delegate = std::move(snapshot_delegate), //
resource_context = std::move(resource_context), //
unref_queue = std::move(unref_queue) //
io_manager = io_manager->GetWeakPtr() //
]() mutable {
const auto& task_runners = shell->GetTaskRunners();
@ -137,8 +130,7 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
shell->GetSettings(), //
std::move(animator), //
std::move(snapshot_delegate), //
std::move(resource_context), //
std::move(unref_queue) //
std::move(io_manager) //
);
ui_latch.Signal();
}));
@ -433,7 +425,7 @@ void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
if (rasterizer) {
rasterizer->Setup(std::move(surface));
}
// Step 2: All done. Signal the latch that the platform thread is waiting
// Step 3: All done. Signal the latch that the platform thread is waiting
// on.
latch.Signal();
});
@ -445,14 +437,26 @@ void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
if (engine) {
engine->OnOutputSurfaceCreated();
}
// Step 1: Next, tell the GPU thread that it should create a surface for its
// Step 2: Next, tell the GPU thread that it should create a surface for its
// rasterizer.
fml::TaskRunner::RunNowOrPostTask(gpu_task_runner, gpu_task);
};
// Step 0: Post a task onto the UI thread to tell the engine that it has an
// output surface.
fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task);
auto io_task = [io_manager = io_manager_->GetWeakPtr(),
platform_view = platform_view_->GetWeakPtr(),
ui_task_runner = task_runners_.GetUITaskRunner(), ui_task] {
if (io_manager) {
io_manager->UpdateResourceContext(
platform_view ? platform_view->CreateResourceContext() : nullptr);
}
// Step 1: Next, post a task on the UI thread to tell the engine that it has
// an output surface.
fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
};
// Step 0: Tell the IO thread that the PlatformView has a GLContext that can
// be used to create a resource context.
fml::TaskRunner::RunNowOrPostTask(task_runners_.GetIOTaskRunner(), io_task);
latch.Wait();
}

View File

@ -16,7 +16,7 @@ void testCanvas(CanvasCallback callback) {
}
void main() {
test('canvas APIs should not crash', () {
test('canvas APIs should not crash', () async {
final Paint paint = Paint();
final Rect rect = Rect.fromLTRB(double.nan, double.nan, double.nan, double.nan);
final RRect rrect = RRect.fromRectAndCorners(rect);
@ -29,7 +29,7 @@ void main() {
final Canvas recorderCanvas = Canvas(recorder);
recorderCanvas.scale(1.0, 1.0);
final Picture picture = recorder.endRecording();
final Image image = picture.toImage(1, 1);
final Image image = await picture.toImage(1, 1);
try { Canvas(null, null); } catch (error) { } // ignore: empty_catches
try { Canvas(null, rect); } catch (error) { } // ignore: empty_catches

View File

@ -20,7 +20,8 @@ void main() {
group('Image.toByteData', () {
group('RGBA format', () {
test('works with simple image', () async {
final ByteData data = await Square4x4Image.image.toByteData();
final Image image = await Square4x4Image.image;
final ByteData data = await image.toByteData();
expect(Uint8List.view(data.buffer), Square4x4Image.bytes);
});
@ -35,7 +36,7 @@ void main() {
group('Unmodified format', () {
test('works with simple image', () async {
final Image image = Square4x4Image.image;
final Image image = await Square4x4Image.image;
final ByteData data = await image.toByteData(format: ImageByteFormat.rawUnmodified);
expect(Uint8List.view(data.buffer), Square4x4Image.bytes);
});
@ -51,7 +52,7 @@ void main() {
group('PNG format', () {
test('works with simple image', () async {
final Image image = Square4x4Image.image;
final Image image = await Square4x4Image.image;
final ByteData data = await image.toByteData(format: ImageByteFormat.png);
final List<int> expected = await readFile('square.png');
expect(Uint8List.view(data.buffer), expected);
@ -63,7 +64,7 @@ void main() {
class Square4x4Image {
Square4x4Image._();
static Image get image {
static Future<Image> get image async {
final double width = _kWidth.toDouble();
final double radius = _kRadius.toDouble();
final double innerWidth = (_kWidth - 2 * _kRadius).toDouble();
@ -82,7 +83,7 @@ class Square4x4Image {
canvas.drawRect(Rect.fromLTWH(0.0, 0.0, width, width), black);
canvas.drawRect(
Rect.fromLTWH(radius, radius, innerWidth, innerWidth), green);
return recorder.endRecording().toImage(_kWidth, _kWidth);
return await recorder.endRecording().toImage(_kWidth, _kWidth);
}
static List<int> get bytes {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 B

After

Width:  |  Height:  |  Size: 112 B