diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index a8ebd7a632004..0a20df33b8a76 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -4960,6 +4960,22 @@ class ImmutableBuffer extends NativeFieldWrapperClass2 { } void _init(Uint8List list, _Callback callback) native 'ImmutableBuffer_init'; + /// Create a buffer from the asset with key [assetKey]. + /// + /// Returns `null` if the asset does not exist. + static ImmutableBuffer? fromAsset(String assetKey) { + final ImmutableBuffer buffer = ImmutableBuffer._(0); + bool success = false; + _fromAsset(assetKey, buffer, (void result) { + success = true; + }); + if (!success) { + return null; + } + return buffer; + } + static void _fromAsset(String assetKey, ImmutableBuffer buffer, _Callback callback) native 'ImmutableBuffer_fromAsset'; + /// The length, in bytes, of the underlying data. final int length; diff --git a/lib/ui/painting/immutable_buffer.cc b/lib/ui/painting/immutable_buffer.cc index 6491785f6eae0..60ac5404af6ce 100644 --- a/lib/ui/painting/immutable_buffer.cc +++ b/lib/ui/painting/immutable_buffer.cc @@ -10,6 +10,8 @@ #include "third_party/tonic/converter/dart_converter.h" #include "third_party/tonic/dart_args.h" #include "third_party/tonic/dart_binding_macros.h" +#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/window/platform_configuration.h" #if OS_ANDROID #include @@ -30,6 +32,9 @@ ImmutableBuffer::~ImmutableBuffer() {} void ImmutableBuffer::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({{"ImmutableBuffer_init", ImmutableBuffer::init, 3, true}, FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); + natives->Register({{"ImmutableBuffer_fromAsset", ImmutableBuffer::fromAsset, 3, true}, + FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); + } void ImmutableBuffer::init(Dart_NativeArguments args) { @@ -53,6 +58,49 @@ size_t ImmutableBuffer::GetAllocationSize() const { return sizeof(ImmutableBuffer) + data_->size(); } +void ImmutableBuffer::fromAsset(Dart_NativeArguments args) { + UIDartState::ThrowIfUIOperationsProhibited(); + 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 asset_name_handle = Dart_GetNativeArgument(args, 0); + uint8_t* chars = nullptr; + intptr_t asset_length = 0; + Dart_Handle result = + Dart_StringToUTF8(asset_name_handle, &chars, &asset_length); + if (Dart_IsError(result)) { + Dart_PropagateError(result); + return; + } + Dart_Handle immutable_buffer = Dart_GetNativeArgument(args, 1); + + std::string asset_name = std::string{reinterpret_cast(chars), + static_cast(asset_length)}; + + std::shared_ptr asset_manager = UIDartState::Current() + ->platform_configuration() + ->client() + ->GetAssetManager(); + std::unique_ptr data = asset_manager->GetAsMapping(asset_name); + + if (data == nullptr) { + return; + } + const void* bytes = static_cast(data->GetMapping()); + void* peer = reinterpret_cast(data.release()); + auto size = data->GetSize(); + SkData::ReleaseProc proc = [](const void* ptr, void* context) { + // TODO: what do + }; + + auto sk_data = SkData::MakeWithProc(bytes, size, proc, peer); + auto buffer = fml::MakeRefCounted(sk_data); + buffer->AssociateWithDartWrapper(immutable_buffer); + tonic::DartInvoke(callback_handle, {Dart_TypeVoid()}); +} + #if OS_ANDROID // Compressed image buffers are allocated on the UI thread but are deleted on a diff --git a/lib/ui/painting/immutable_buffer.h b/lib/ui/painting/immutable_buffer.h index ff7299881d643..a5ae9144067c9 100644 --- a/lib/ui/painting/immutable_buffer.h +++ b/lib/ui/painting/immutable_buffer.h @@ -39,6 +39,15 @@ class ImmutableBuffer : public RefCountedDartWrappable { /// when the copy has completed. static void init(Dart_NativeArguments args); + /// Create a new ImmutableData from a Dart asset key. + /// + /// The zero indexed argument is the UTF8 encoded string which corresponds to + /// the asset manager key. + /// + /// The first indexed argument is a callback that can optionally be invoked + /// with the resulting ImmutableData. + static void fromAsset(Dart_NativeArguments args); + /// The length of the data in bytes. size_t length() const { FML_DCHECK(data_); diff --git a/lib/ui/window/platform_configuration.h b/lib/ui/window/platform_configuration.h index 4652c7c5dcdbb..72b5c01ece41c 100644 --- a/lib/ui/window/platform_configuration.h +++ b/lib/ui/window/platform_configuration.h @@ -11,6 +11,7 @@ #include #include +#include "flutter/assets/asset_manager.h" #include "flutter/fml/time/time_point.h" #include "flutter/lib/ui/semantics/semantics_update.h" #include "flutter/lib/ui/window/platform_message.h" @@ -111,6 +112,8 @@ class PlatformConfigurationClient { /// creation. virtual FontCollection& GetFontCollection() = 0; + virtual std::shared_ptr GetAssetManager() = 0; + //-------------------------------------------------------------------------- /// @brief Notifies this client of the name of the root isolate and its /// port when that isolate is launched, restarted (in the diff --git a/lib/web_ui/lib/src/ui/assets.dart b/lib/web_ui/lib/src/ui/assets.dart new file mode 100644 index 0000000000000..efc138a4639ef --- /dev/null +++ b/lib/web_ui/lib/src/ui/assets.dart @@ -0,0 +1,17 @@ +// 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. + +// @dart = 2.10 +part of ui; + +/// Load the asset bytes specified by [assetKey]. +/// +/// The [assetKey] is generally the filepath of the asset which is bundled +/// into the flutter application. This API is not supported on the +/// Web. +/// +/// If the [assetKey] does not correspond to a real asset, returns `null`. +ByteData? loadAsset(String assetKey) { + return null; +} diff --git a/lib/web_ui/lib/ui.dart b/lib/web_ui/lib/ui.dart index 13d5ee2813b20..e1af78fff2d77 100644 --- a/lib/web_ui/lib/ui.dart +++ b/lib/web_ui/lib/ui.dart @@ -35,6 +35,7 @@ part 'src/ui/test_embedding.dart'; part 'src/ui/text.dart'; part 'src/ui/tile_mode.dart'; part 'src/ui/window.dart'; +part 'src/ui/assets.dart'; /// Provides a compile time constant to customize flutter framework and other /// users of ui engine for web runtime. diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 7761bee4ea7ea..0bd0f0073dc1f 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/runtime/runtime_controller.h" +#include "flutter/assets/asset_manager.h" #include "flutter/fml/message_loop.h" #include "flutter/fml/trace_event.h" @@ -335,6 +336,11 @@ FontCollection& RuntimeController::GetFontCollection() { return client_.GetFontCollection(); } +// |PlatfromConfigurationClient| +std::shared_ptr RuntimeController::GetAssetManager() { + return client_.GetAssetManager(); +} + // |PlatformConfigurationClient| void RuntimeController::UpdateIsolateDescription(const std::string isolate_name, int64_t isolate_port) { diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 4767d01fbcb13..6a8e24bcccd74 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -8,6 +8,7 @@ #include #include +#include "flutter/assets/asset_manager.h" #include "flutter/common/task_runners.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/fml/macros.h" @@ -508,6 +509,9 @@ class RuntimeController : public PlatformConfigurationClient { // |PlatformConfigurationClient| FontCollection& GetFontCollection() override; + // |PlatformConfigurationClient| + std::shared_ptr GetAssetManager() override; + // |PlatformConfigurationClient| void UpdateIsolateDescription(const std::string isolate_name, int64_t isolate_port) override; diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index 20059827b8150..38d174fd0a961 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -8,6 +8,7 @@ #include #include +#include "flutter/assets/asset_manager.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/lib/ui/semantics/custom_accessibility_action.h" #include "flutter/lib/ui/semantics/semantics_node.h" @@ -32,6 +33,8 @@ class RuntimeDelegate { virtual FontCollection& GetFontCollection() = 0; + virtual std::shared_ptr GetAssetManager() = 0; + virtual void UpdateIsolateDescription(const std::string isolate_name, int64_t isolate_port) = 0; diff --git a/shell/common/engine.cc b/shell/common/engine.cc index d2384c03579cf..1962b48543a30 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -515,6 +515,10 @@ FontCollection& Engine::GetFontCollection() { return font_collection_; } +std::shared_ptr Engine::GetAssetManager() { + return asset_manager_; +} + void Engine::DoDispatchPacket(std::unique_ptr packet, uint64_t trace_flow_id) { animator_->EnqueueTraceFlowId(trace_flow_id); diff --git a/shell/common/engine.h b/shell/common/engine.h index b8d98aa766291..873c6455e7a92 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -734,6 +734,9 @@ class Engine final : public RuntimeDelegate, // |RuntimeDelegate| FontCollection& GetFontCollection() override; + // |RuntimeDelegate| + std::shared_ptr GetAssetManager() override; + // |PointerDataDispatcher::Delegate| void DoDispatchPacket(std::unique_ptr packet, uint64_t trace_flow_id) override; diff --git a/shell/common/engine_unittests.cc b/shell/common/engine_unittests.cc index 3390507f68d9b..976be23019d56 100644 --- a/shell/common/engine_unittests.cc +++ b/shell/common/engine_unittests.cc @@ -49,6 +49,7 @@ class MockRuntimeDelegate : public RuntimeDelegate { void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates)); MOCK_METHOD1(HandlePlatformMessage, void(fml::RefPtr)); MOCK_METHOD0(GetFontCollection, FontCollection&()); + MOCK_METHOD0(GetAssetManager, std::shared_ptr()); MOCK_METHOD2(UpdateIsolateDescription, void(const std::string, int64_t)); MOCK_METHOD1(SetNeedsReportTimings, void(bool)); MOCK_METHOD1(ComputePlatformResolvedLocale, diff --git a/testing/dart/assets_test.dart b/testing/dart/assets_test.dart new file mode 100644 index 0000000000000..99d3661038d02 --- /dev/null +++ b/testing/dart/assets_test.dart @@ -0,0 +1,18 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// @dart = 2.6 +import 'dart:ui' as ui; + +import 'package:test/test.dart'; + +void main() { + test('Loading an asset that does not exist returns null', () { + expect(ui.loadAsset('ThisDoesNotExist'), null); + }); + + test('returns the bytes of a bundled asset', () { + expect(ui.loadAsset('FontManifest.json'), isNotNull); + }); +}