LazyLoadingElement.h 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /*
  2. * Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <LibWeb/Forward.h>
  9. #include <LibWeb/HTML/AttributeNames.h>
  10. namespace Web::HTML {
  11. // Lazy-loaded elements should invoke this macro to inject overridden LazyLoadingElement methods.
  12. #define LAZY_LOADING_ELEMENT(ElementClass) \
  13. private: \
  14. virtual JS::GCPtr<JS::HeapFunction<void()>> take_lazy_load_resumption_steps(Badge<DOM::Document>) override \
  15. { \
  16. return take_lazy_load_resumption_steps_internal(); \
  17. } \
  18. \
  19. virtual bool is_lazy_loading() const override { return true; }
  20. enum class LazyLoading {
  21. Lazy,
  22. Eager,
  23. };
  24. template<typename T>
  25. class LazyLoadingElement {
  26. public:
  27. // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#lazy-loading-attributes
  28. [[nodiscard]] LazyLoading lazy_loading_attribute() const
  29. {
  30. auto& element = static_cast<T const&>(*this);
  31. auto value = element.attribute(HTML::AttributeNames::loading);
  32. if (value.has_value() && value->equals_ignoring_ascii_case("lazy"sv))
  33. return LazyLoading::Lazy;
  34. return LazyLoading::Eager;
  35. }
  36. // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#will-lazy-load-element-steps
  37. [[nodiscard]] bool will_lazy_load_element() const
  38. {
  39. auto& element = static_cast<T const&>(*this);
  40. // 1. If scripting is disabled for element, then return false.
  41. // Spec Note: This is an anti-tracking measure, because if a user agent supported lazy loading when scripting is
  42. // disabled, it would still be possible for a site to track a user's approximate scroll position throughout
  43. // a session, by strategically placing images in a page's markup such that a server can track how many
  44. // images are requested and when.
  45. if (element.is_scripting_disabled())
  46. return false;
  47. // 2. If element's lazy loading attribute is in the Lazy state, then return true.
  48. // 3. Return false.
  49. return lazy_loading_attribute() == LazyLoading::Lazy;
  50. }
  51. void set_lazy_load_resumption_steps(Function<void()> steps)
  52. {
  53. auto& element = static_cast<T&>(*this);
  54. m_lazy_load_resumption_steps = JS::create_heap_function(element.vm().heap(), move(steps));
  55. }
  56. void visit_lazy_loading_element(JS::Cell::Visitor& visitor)
  57. {
  58. visitor.visit(m_lazy_load_resumption_steps);
  59. }
  60. protected:
  61. LazyLoadingElement() = default;
  62. virtual ~LazyLoadingElement() = default;
  63. JS::GCPtr<JS::HeapFunction<void()>> take_lazy_load_resumption_steps_internal()
  64. {
  65. auto lazy_load_resumption_steps = m_lazy_load_resumption_steps;
  66. m_lazy_load_resumption_steps = nullptr;
  67. return lazy_load_resumption_steps;
  68. }
  69. private:
  70. // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#lazy-load-resumption-steps
  71. // Each img and iframe element has associated lazy load resumption steps, initially null.
  72. JS::GCPtr<JS::HeapFunction<void()>> m_lazy_load_resumption_steps;
  73. };
  74. }