ImageLoader.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Debug.h>
  7. #include <LibCore/Timer.h>
  8. #include <LibGfx/Bitmap.h>
  9. #include <LibWeb/DOM/Document.h>
  10. #include <LibWeb/DOM/Element.h>
  11. #include <LibWeb/Loader/ImageLoader.h>
  12. #include <LibWeb/Loader/ResourceLoader.h>
  13. namespace Web {
  14. ImageLoader::ImageLoader(DOM::Element& owner_element)
  15. : m_owner_element(owner_element)
  16. , m_timer(Core::Timer::construct())
  17. {
  18. }
  19. void ImageLoader::load(const AK::URL& url)
  20. {
  21. m_redirects_count = 0;
  22. load_without_resetting_redirect_counter(url);
  23. }
  24. void ImageLoader::load_without_resetting_redirect_counter(AK::URL const& url)
  25. {
  26. m_loading_state = LoadingState::Loading;
  27. auto request = LoadRequest::create_for_url_on_page(url, m_owner_element.document().page());
  28. set_resource(ResourceLoader::the().load_resource(Resource::Type::Image, request));
  29. }
  30. void ImageLoader::set_visible_in_viewport(bool visible_in_viewport) const
  31. {
  32. if (m_visible_in_viewport == visible_in_viewport)
  33. return;
  34. m_visible_in_viewport = visible_in_viewport;
  35. // FIXME: Don't update volatility every time. If we're here, we're probably scanning through
  36. // the whole document, updating "is visible in viewport" flags, and this could lead
  37. // to the same bitmap being marked volatile back and forth unnecessarily.
  38. if (resource())
  39. const_cast<ImageResource*>(resource())->update_volatility();
  40. }
  41. void ImageLoader::resource_did_load()
  42. {
  43. VERIFY(resource());
  44. // For 3xx (Redirection) responses, the Location value refers to the preferred target resource for automatically redirecting the request.
  45. auto status_code = resource()->status_code();
  46. if (status_code.has_value() && *status_code >= 300 && *status_code <= 399) {
  47. auto location = resource()->response_headers().get("Location");
  48. if (location.has_value()) {
  49. if (m_redirects_count > maximum_redirects_allowed) {
  50. m_redirects_count = 0;
  51. m_loading_state = LoadingState::Failed;
  52. if (on_fail)
  53. on_fail();
  54. return;
  55. }
  56. m_redirects_count++;
  57. load_without_resetting_redirect_counter(resource()->url().complete_url(location.value()));
  58. return;
  59. }
  60. }
  61. m_redirects_count = 0;
  62. if (!resource()->mime_type().starts_with("image/")) {
  63. m_loading_state = LoadingState::Failed;
  64. if (on_fail)
  65. on_fail();
  66. return;
  67. }
  68. m_loading_state = LoadingState::Loaded;
  69. if constexpr (IMAGE_LOADER_DEBUG) {
  70. if (!resource()->has_encoded_data()) {
  71. dbgln("ImageLoader: Resource did load, no encoded data. URL: {}", resource()->url());
  72. } else {
  73. dbgln("ImageLoader: Resource did load, has encoded data. URL: {}", resource()->url());
  74. }
  75. }
  76. if (resource()->is_animated() && resource()->frame_count() > 1) {
  77. m_timer->set_interval(resource()->frame_duration(0));
  78. m_timer->on_timeout = [this] { animate(); };
  79. m_timer->start();
  80. }
  81. if (on_load)
  82. on_load();
  83. }
  84. void ImageLoader::animate()
  85. {
  86. if (!m_visible_in_viewport)
  87. return;
  88. m_current_frame_index = (m_current_frame_index + 1) % resource()->frame_count();
  89. auto current_frame_duration = resource()->frame_duration(m_current_frame_index);
  90. if (current_frame_duration != m_timer->interval()) {
  91. m_timer->restart(current_frame_duration);
  92. }
  93. if (m_current_frame_index == resource()->frame_count() - 1) {
  94. ++m_loops_completed;
  95. if (m_loops_completed > 0 && m_loops_completed == resource()->loop_count()) {
  96. m_timer->stop();
  97. }
  98. }
  99. if (on_animate)
  100. on_animate();
  101. }
  102. void ImageLoader::resource_did_fail()
  103. {
  104. dbgln("ImageLoader: Resource did fail. URL: {}", resource()->url());
  105. m_loading_state = LoadingState::Failed;
  106. if (on_fail)
  107. on_fail();
  108. }
  109. bool ImageLoader::has_image() const
  110. {
  111. if (!resource())
  112. return false;
  113. return bitmap(0);
  114. }
  115. unsigned ImageLoader::width() const
  116. {
  117. if (!resource())
  118. return 0;
  119. return bitmap(0) ? bitmap(0)->width() : 0;
  120. }
  121. unsigned ImageLoader::height() const
  122. {
  123. if (!resource())
  124. return 0;
  125. return bitmap(0) ? bitmap(0)->height() : 0;
  126. }
  127. const Gfx::Bitmap* ImageLoader::bitmap(size_t frame_index) const
  128. {
  129. if (!resource())
  130. return nullptr;
  131. return resource()->bitmap(frame_index);
  132. }
  133. }