ImageResource.cpp 2.8 KB

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