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