ImageResource.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Function.h>
  7. #include <LibGfx/Bitmap.h>
  8. #include <LibImageDecoderClient/Client.h>
  9. #include <LibWeb/Loader/ImageResource.h>
  10. namespace Web {
  11. ImageResource::ImageResource(const LoadRequest& request)
  12. : Resource(Type::Image, request)
  13. {
  14. }
  15. ImageResource::~ImageResource()
  16. {
  17. }
  18. int ImageResource::frame_duration(size_t frame_index) const
  19. {
  20. decode_if_needed();
  21. if (frame_index >= m_decoded_frames.size())
  22. return 0;
  23. return m_decoded_frames[frame_index].duration;
  24. }
  25. static ImageDecoderClient::Client& image_decoder_client()
  26. {
  27. static RefPtr<ImageDecoderClient::Client> image_decoder_client;
  28. if (!image_decoder_client) {
  29. image_decoder_client = ImageDecoderClient::Client::construct();
  30. image_decoder_client->on_death = [&] {
  31. image_decoder_client = nullptr;
  32. };
  33. }
  34. return *image_decoder_client;
  35. }
  36. void ImageResource::decode_if_needed() const
  37. {
  38. if (!has_encoded_data())
  39. return;
  40. if (m_has_attempted_decode)
  41. return;
  42. if (!m_decoded_frames.is_empty())
  43. return;
  44. NonnullRefPtr decoder = image_decoder_client();
  45. auto image = decoder->decode_image(encoded_data());
  46. if (image.has_value()) {
  47. m_loop_count = image.value().loop_count;
  48. m_animated = image.value().is_animated;
  49. m_decoded_frames.resize(image.value().frames.size());
  50. for (size_t i = 0; i < m_decoded_frames.size(); ++i) {
  51. auto& frame = m_decoded_frames[i];
  52. frame.bitmap = image.value().frames[i].bitmap;
  53. frame.duration = image.value().frames[i].duration;
  54. }
  55. }
  56. m_has_attempted_decode = true;
  57. }
  58. const Gfx::Bitmap* ImageResource::bitmap(size_t frame_index) const
  59. {
  60. decode_if_needed();
  61. if (frame_index >= m_decoded_frames.size())
  62. return nullptr;
  63. return m_decoded_frames[frame_index].bitmap;
  64. }
  65. void ImageResource::update_volatility()
  66. {
  67. bool visible_in_viewport = false;
  68. for_each_client([&](auto& client) {
  69. if (static_cast<const ImageResourceClient&>(client).is_visible_in_viewport())
  70. visible_in_viewport = true;
  71. });
  72. if (!visible_in_viewport) {
  73. for (auto& frame : m_decoded_frames) {
  74. if (frame.bitmap)
  75. frame.bitmap->set_volatile();
  76. }
  77. return;
  78. }
  79. bool still_has_decoded_image = true;
  80. for (auto& frame : m_decoded_frames) {
  81. if (!frame.bitmap) {
  82. still_has_decoded_image = false;
  83. } else {
  84. bool still_has_frame = frame.bitmap->set_nonvolatile();
  85. if (!still_has_frame)
  86. still_has_decoded_image = false;
  87. }
  88. }
  89. if (still_has_decoded_image)
  90. return;
  91. m_decoded_frames.clear();
  92. m_has_attempted_decode = false;
  93. }
  94. ImageResourceClient::~ImageResourceClient()
  95. {
  96. }
  97. }