ConnectionFromClient.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Debug.h>
  7. #include <AK/IDAllocator.h>
  8. #include <ImageDecoder/ConnectionFromClient.h>
  9. #include <ImageDecoder/ImageDecoderClientEndpoint.h>
  10. #include <LibGfx/Bitmap.h>
  11. #include <LibGfx/ImageFormats/ImageDecoder.h>
  12. #include <LibGfx/ImageFormats/TIFFMetadata.h>
  13. namespace ImageDecoder {
  14. static HashMap<int, RefPtr<ConnectionFromClient>> s_connections;
  15. static IDAllocator s_client_ids;
  16. ConnectionFromClient::ConnectionFromClient(IPC::Transport transport)
  17. : IPC::ConnectionFromClient<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>(*this, move(transport), s_client_ids.allocate())
  18. {
  19. s_connections.set(client_id(), *this);
  20. }
  21. void ConnectionFromClient::die()
  22. {
  23. for (auto& [_, job] : m_pending_jobs) {
  24. job->cancel();
  25. }
  26. m_pending_jobs.clear();
  27. auto client_id = this->client_id();
  28. s_connections.remove(client_id);
  29. s_client_ids.deallocate(client_id);
  30. if (s_connections.is_empty()) {
  31. Threading::quit_background_thread();
  32. Core::EventLoop::current().quit(0);
  33. }
  34. }
  35. ErrorOr<IPC::File> ConnectionFromClient::connect_new_client()
  36. {
  37. int socket_fds[2] {};
  38. if (auto err = Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds); err.is_error())
  39. return err.release_error();
  40. auto client_socket_or_error = Core::LocalSocket::adopt_fd(socket_fds[0]);
  41. if (client_socket_or_error.is_error()) {
  42. close(socket_fds[0]);
  43. close(socket_fds[1]);
  44. return client_socket_or_error.release_error();
  45. }
  46. auto client_socket = client_socket_or_error.release_value();
  47. // Note: A ref is stored in the static s_connections map
  48. auto client = adopt_ref(*new ConnectionFromClient(IPC::Transport(move(client_socket))));
  49. return IPC::File::adopt_fd(socket_fds[1]);
  50. }
  51. Messages::ImageDecoderServer::ConnectNewClientsResponse ConnectionFromClient::connect_new_clients(size_t count)
  52. {
  53. Vector<IPC::File> files;
  54. files.ensure_capacity(count);
  55. for (size_t i = 0; i < count; ++i) {
  56. auto file_or_error = connect_new_client();
  57. if (file_or_error.is_error()) {
  58. dbgln("Failed to connect new client: {}", file_or_error.error());
  59. return Vector<IPC::File> {};
  60. }
  61. files.unchecked_append(file_or_error.release_value());
  62. }
  63. return files;
  64. }
  65. static void decode_image_to_bitmaps_and_durations_with_decoder(Gfx::ImageDecoder const& decoder, Optional<Gfx::IntSize> ideal_size, Vector<Optional<NonnullRefPtr<Gfx::Bitmap>>>& bitmaps, Vector<u32>& durations)
  66. {
  67. for (size_t i = 0; i < decoder.frame_count(); ++i) {
  68. auto frame_or_error = decoder.frame(i, ideal_size);
  69. if (frame_or_error.is_error()) {
  70. bitmaps.append({});
  71. durations.append(0);
  72. } else {
  73. auto frame = frame_or_error.release_value();
  74. bitmaps.append(frame.image.release_nonnull());
  75. durations.append(frame.duration);
  76. }
  77. }
  78. }
  79. static ErrorOr<ConnectionFromClient::DecodeResult> decode_image_to_details(Core::AnonymousBuffer const& encoded_buffer, Optional<Gfx::IntSize> ideal_size, Optional<ByteString> const& known_mime_type)
  80. {
  81. auto decoder = TRY(Gfx::ImageDecoder::try_create_for_raw_bytes(ReadonlyBytes { encoded_buffer.data<u8>(), encoded_buffer.size() }, known_mime_type));
  82. if (!decoder)
  83. return Error::from_string_literal("Could not find suitable image decoder plugin for data");
  84. if (!decoder->frame_count())
  85. return Error::from_string_literal("Could not decode image from encoded data");
  86. ConnectionFromClient::DecodeResult result;
  87. result.is_animated = decoder->is_animated();
  88. result.loop_count = decoder->loop_count();
  89. Vector<Optional<NonnullRefPtr<Gfx::Bitmap>>> bitmaps;
  90. if (auto maybe_metadata = decoder->metadata(); maybe_metadata.has_value() && is<Gfx::ExifMetadata>(*maybe_metadata)) {
  91. auto const& exif = static_cast<Gfx::ExifMetadata const&>(maybe_metadata.value());
  92. if (exif.x_resolution().has_value() && exif.y_resolution().has_value()) {
  93. auto const x_resolution = exif.x_resolution()->as_double();
  94. auto const y_resolution = exif.y_resolution()->as_double();
  95. if (x_resolution < y_resolution)
  96. result.scale.set_y(x_resolution / y_resolution);
  97. else
  98. result.scale.set_x(y_resolution / x_resolution);
  99. }
  100. }
  101. decode_image_to_bitmaps_and_durations_with_decoder(*decoder, move(ideal_size), bitmaps, result.durations);
  102. if (bitmaps.is_empty())
  103. return Error::from_string_literal("Could not decode image");
  104. result.bitmaps = Gfx::BitmapSequence { bitmaps };
  105. return result;
  106. }
  107. NonnullRefPtr<ConnectionFromClient::Job> ConnectionFromClient::make_decode_image_job(i64 image_id, Core::AnonymousBuffer encoded_buffer, Optional<Gfx::IntSize> ideal_size, Optional<ByteString> mime_type)
  108. {
  109. return Job::construct(
  110. [encoded_buffer = move(encoded_buffer), ideal_size = move(ideal_size), mime_type = move(mime_type)](auto&) -> ErrorOr<DecodeResult> {
  111. return TRY(decode_image_to_details(encoded_buffer, ideal_size, mime_type));
  112. },
  113. [strong_this = NonnullRefPtr(*this), image_id](DecodeResult result) -> ErrorOr<void> {
  114. strong_this->async_did_decode_image(image_id, result.is_animated, result.loop_count, result.bitmaps, result.durations, result.scale);
  115. strong_this->m_pending_jobs.remove(image_id);
  116. return {};
  117. },
  118. [strong_this = NonnullRefPtr(*this), image_id](Error error) -> void {
  119. if (strong_this->is_open())
  120. strong_this->async_did_fail_to_decode_image(image_id, MUST(String::formatted("Decoding failed: {}", error)));
  121. strong_this->m_pending_jobs.remove(image_id);
  122. });
  123. }
  124. Messages::ImageDecoderServer::DecodeImageResponse ConnectionFromClient::decode_image(Core::AnonymousBuffer const& encoded_buffer, Optional<Gfx::IntSize> const& ideal_size, Optional<ByteString> const& mime_type)
  125. {
  126. auto image_id = m_next_image_id++;
  127. if (!encoded_buffer.is_valid()) {
  128. dbgln_if(IMAGE_DECODER_DEBUG, "Encoded data is invalid");
  129. async_did_fail_to_decode_image(image_id, "Encoded data is invalid"_string);
  130. return image_id;
  131. }
  132. m_pending_jobs.set(image_id, make_decode_image_job(image_id, encoded_buffer, ideal_size, mime_type));
  133. return image_id;
  134. }
  135. void ConnectionFromClient::cancel_decoding(i64 image_id)
  136. {
  137. if (auto job = m_pending_jobs.take(image_id); job.has_value()) {
  138. job.value()->cancel();
  139. }
  140. }
  141. }