Userland: Remove remaining callers of synchronous ImageDecoder API

Most of these now just await the image decoding, equivalent (ish) to
the old behavior. A more async-aware refactor should happen some time
in the future.
This commit is contained in:
Andrew Kaster 2024-04-19 16:10:57 -06:00 committed by Andrew Kaster
commit 1c3f11a5a6
Notes: sideshowbarker 2024-07-16 21:39:23 +09:00
7 changed files with 21 additions and 41 deletions

View file

@ -237,16 +237,15 @@ ErrorOr<void> ViewWidget::try_open_file(String const& path, Core::File& file)
// Use out-of-process decoding for raster formats.
auto client = TRY(ImageDecoderClient::Client::try_create());
auto mime_type = Core::guess_mime_type_based_on_filename(path);
auto decoded_image = client->decode_image(file_data, OptionalNone {}, mime_type);
if (!decoded_image.has_value()) {
return Error::from_string_literal("Failed to decode image");
}
is_animated = decoded_image->is_animated;
loop_count = decoded_image->loop_count;
frames.ensure_capacity(decoded_image->frames.size());
for (u32 i = 0; i < decoded_image->frames.size(); i++) {
auto& frame_data = decoded_image->frames[i];
frames.unchecked_append({ BitmapImage::create(frame_data.bitmap, decoded_image->scale), int(frame_data.duration) });
// FIXME: Refactor file opening to be more async-aware, and don't await this promise
auto decoded_image = TRY(client->decode_image(file_data, {}, {}, OptionalNone {}, mime_type)->await());
is_animated = decoded_image.is_animated;
loop_count = decoded_image.loop_count;
frames.ensure_capacity(decoded_image.frames.size());
for (u32 i = 0; i < decoded_image.frames.size(); i++) {
auto& frame_data = decoded_image.frames[i];
frames.unchecked_append({ BitmapImage::create(frame_data.bitmap, decoded_image.scale), int(frame_data.duration) });
}
}

View file

@ -57,14 +57,9 @@ ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Image::decode_bitmap(ReadonlyBytes bitmap_da
auto optional_mime_type = guessed_mime_type.map([](auto mime_type) { return mime_type.to_byte_string(); });
// FIXME: Find a way to avoid the memory copying here.
auto maybe_decoded_image = client->decode_image(bitmap_data, OptionalNone {}, optional_mime_type);
if (!maybe_decoded_image.has_value())
return Error::from_string_literal("Image decode failed");
// FIXME: Support multi-frame images?
auto decoded_image = maybe_decoded_image.release_value();
if (decoded_image.frames.is_empty())
return Error::from_string_literal("Image decode failed (no frames)");
// FIXME: Support multi-frame images
// FIXME: Refactor image decoding to be more async-aware, and don't await this promise
auto decoded_image = TRY(client->decode_image(bitmap_data, {}, {}, OptionalNone {}, optional_mime_type)->await());
return decoded_image.frames.first().bitmap;
}

View file

@ -195,8 +195,9 @@ RefPtr<Gfx::Bitmap> SoundPlayerWidget::get_image_from_music_file()
// FIXME: We randomly select the first picture available for the track,
// We might want to hardcode or let the user set a preference.
auto decoded_image_or_error = m_image_decoder_client.decode_image(pictures[0].data);
if (!decoded_image_or_error.has_value())
// FIXME: Refactor image decoding to be more async-aware, and don't await this promise
auto decoded_image_or_error = m_image_decoder_client.decode_image(pictures[0].data, {}, {})->await();
if (decoded_image_or_error.is_error())
return {};
auto const decoded_image = decoded_image_or_error.release_value();

View file

@ -717,9 +717,9 @@ static ErrorOr<NonnullRefPtr<Gfx::Bitmap>> render_thumbnail(StringView path)
}
auto mime_type = Core::guess_mime_type_based_on_filename(path);
auto decoded_image = maybe_client->decode_image(file->bytes(), thumbnail_size, mime_type);
if (!decoded_image.has_value())
return Error::from_string_literal("Unable to decode the image.");
// FIXME: Refactor thumbnail rendering to be more async-aware. Possibly return this promise to the caller.
auto decoded_image = TRY(maybe_client->decode_image(file->bytes(), {}, {}, thumbnail_size, mime_type)->await());
return decoded_image;
}));

View file

@ -60,16 +60,6 @@ NonnullRefPtr<Core::Promise<DecodedImage>> Client::decode_image(ReadonlyBytes en
return promise;
}
Optional<DecodedImage> Client::decode_image(ReadonlyBytes encoded_data, Optional<Gfx::IntSize> ideal_size, Optional<ByteString> mime_type)
{
auto promise = decode_image(
encoded_data, [](auto) -> ErrorOr<void> { return {}; }, [](Error&) -> void {}, ideal_size, mime_type);
auto result = promise->await();
if (result.is_error())
return {};
return result.release_value();
}
void Client::did_decode_image(i64 image_id, bool is_animated, u32 loop_count, Vector<Gfx::ShareableBitmap> const& bitmaps, Vector<u32> const& durations, Gfx::FloatPoint scale)
{
VERIFY(!bitmaps.is_empty());

View file

@ -36,9 +36,6 @@ public:
NonnullRefPtr<Core::Promise<DecodedImage>> decode_image(ReadonlyBytes, Function<ErrorOr<void>(DecodedImage&)> on_resolved, Function<void(Error&)> on_rejected, Optional<Gfx::IntSize> ideal_size = {}, Optional<ByteString> mime_type = {});
// FIXME: Move all clients to the promise-based API and get rid of this synchronous (i.e. EventLoop-spinning) one.
Optional<DecodedImage> decode_image(ReadonlyBytes, Optional<Gfx::IntSize> ideal_size = {}, Optional<ByteString> mime_type = {});
Function<void()> on_death;
private:

View file

@ -100,12 +100,10 @@ ErrorOr<NonnullRefPtr<Client>> Client::create(StringView image_path, StringView
ScopeGuard guard = [&] { image_decoder->shutdown(); };
auto byte_buffer = TRY(image_file->read_until_eof(16 * KiB));
auto maybe_image = image_decoder->decode_image(byte_buffer);
auto image_promise = image_decoder->decode_image(byte_buffer, {}, {});
auto image_result = TRY(image_promise->await());
if (!maybe_image.has_value())
return Error::from_string_view("Image could not be read"sv);
auto image = maybe_image->frames.take_first().bitmap;
auto image = image_result.frames.take_first().bitmap;
// Make sure to not draw out of bounds; some servers will disconnect us for that!
if (image->width() > canvas_size.width()) {