ImageResource.cpp 2.8 KB

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