blob: a87bf9f1919770418c0da13fb2522de10541e41d [file] [log] [blame]
// Copyright 2015 The Chromium 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/image_decoding.h"
#include "flutter/flow/texture_image.h"
#include "flutter/lib/ui/painting/image.h"
#include "flutter/lib/ui/painting/resource_context.h"
#include "flutter/glue/drain_data_pipe_job.h"
#include "flutter/glue/movable_wrapper.h"
#include "flutter/glue/trace_event.h"
#include "lib/ftl/tasks/task_runner.h"
#include "lib/tonic/dart_persistent_value.h"
#include "lib/tonic/logging/dart_invoke.h"
#include "lib/tonic/mojo_converter.h"
#include "lib/tonic/typed_data/uint8_list.h"
#include "flutter/sky/engine/public/platform/Platform.h"
#include "flutter/sky/engine/wtf/PassOwnPtr.h"
#include "third_party/skia/include/core/SkImageGenerator.h"
using tonic::DartInvoke;
using tonic::DartPersistentValue;
using tonic::DartState;
using tonic::ToDart;
namespace blink {
namespace {
sk_sp<SkImage> DecodeImage(std::vector<char> buffer) {
TRACE_EVENT0("blink", "DecodeImage");
if (buffer.empty()) {
return nullptr;
}
sk_sp<SkData> sk_data = SkData::MakeWithoutCopy(buffer.data(), buffer.size());
if (sk_data == nullptr) {
return nullptr;
}
std::unique_ptr<SkImageGenerator> generator(
SkImageGenerator::NewFromEncoded(sk_data.get()));
if (generator == nullptr) {
return nullptr;
}
GrContext* context = ResourceContext::Get();
// First, try to create a texture image from the generator.
if (sk_sp<SkImage> image = flow::TextureImageCreate(context, *generator)) {
return image;
}
// The, as a fallback, try to create a regular Skia managed image. These
// don't require a context ready.
return flow::BitmapImageCreate(*generator);
}
void InvokeImageCallback(sk_sp<SkImage> image,
PassOwnPtr<DartPersistentValue> callback) {
tonic::DartState* dart_state = callback->dart_state().get();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
if (!image) {
DartInvoke(callback->value(), {Dart_Null()});
} else {
ftl::RefPtr<CanvasImage> resultImage = CanvasImage::Create();
resultImage->set_image(std::move(image));
DartInvoke(callback->value(), {ToDart(resultImage)});
}
}
void DecodeImageAndInvokeImageCallback(PassOwnPtr<DartPersistentValue> callback,
std::vector<char> buffer) {
sk_sp<SkImage> image = DecodeImage(std::move(buffer));
Platform::current()->GetUITaskRunner()->PostTask(
[callback, image]() { InvokeImageCallback(image, callback); });
}
void DecodeImageFromDataPipe(Dart_NativeArguments args) {
Dart_Handle exception = nullptr;
auto consumer = glue::WrapMovable(
tonic::DartConverter<mojo::ScopedDataPipeConsumerHandle>::FromArguments(
args, 0, exception));
if (exception) {
Dart_ThrowException(exception);
return;
}
Dart_Handle callback_handle = Dart_GetNativeArgument(args, 1);
if (!Dart_IsClosure(callback_handle)) {
Dart_ThrowException(ToDart("Callback must be a function"));
return;
}
PassOwnPtr<DartPersistentValue> callback =
adoptPtr(new DartPersistentValue(DartState::Current(), callback_handle));
Platform::current()->GetIOTaskRunner()->PostTask(
[callback, consumer]() mutable {
glue::DrainDataPipeJob* job = nullptr;
job = new glue::DrainDataPipeJob(
consumer.Unwrap(), [callback, job](std::vector<char> buffer) {
delete job;
DecodeImageAndInvokeImageCallback(callback, std::move(buffer));
});
});
}
void DecodeImageFromList(Dart_NativeArguments args) {
Dart_Handle exception = nullptr;
tonic::Uint8List list =
tonic::DartConverter<tonic::Uint8List>::FromArguments(args, 0, exception);
if (exception) {
Dart_ThrowException(exception);
return;
}
Dart_Handle callback_handle = Dart_GetNativeArgument(args, 1);
if (!Dart_IsClosure(callback_handle)) {
Dart_ThrowException(ToDart("Callback must be a function"));
return;
}
PassOwnPtr<DartPersistentValue> callback =
adoptPtr(new DartPersistentValue(DartState::Current(), callback_handle));
const char* bytes = reinterpret_cast<const char*>(list.data());
PassOwnPtr<std::vector<char>> buffer =
adoptPtr(new std::vector<char>(bytes, bytes + list.num_elements()));
Platform::current()->GetIOTaskRunner()->PostTask([callback, buffer]() {
DecodeImageAndInvokeImageCallback(callback, std::move(*buffer));
});
}
} // namespace
void ImageDecoding::RegisterNatives(tonic::DartLibraryNatives* natives) {
natives->Register({
{"decodeImageFromDataPipe", DecodeImageFromDataPipe, 2, true},
{"decodeImageFromList", DecodeImageFromList, 2, true},
});
}
} // namespace blink