HTMLVideoElement.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibGfx/Bitmap.h>
  8. #include <LibWeb/Bindings/Intrinsics.h>
  9. #include <LibWeb/DOM/Document.h>
  10. #include <LibWeb/HTML/HTMLVideoElement.h>
  11. #include <LibWeb/HTML/VideoTrack.h>
  12. #include <LibWeb/Layout/VideoBox.h>
  13. #include <LibWeb/Platform/Timer.h>
  14. namespace Web::HTML {
  15. // FIXME: Determine a reasonable framerate somehow. For now, this is roughly 24fps.
  16. static constexpr int s_frame_delay_ms = 42;
  17. HTMLVideoElement::HTMLVideoElement(DOM::Document& document, DOM::QualifiedName qualified_name)
  18. : HTMLMediaElement(document, move(qualified_name))
  19. {
  20. }
  21. HTMLVideoElement::~HTMLVideoElement() = default;
  22. JS::ThrowCompletionOr<void> HTMLVideoElement::initialize(JS::Realm& realm)
  23. {
  24. MUST_OR_THROW_OOM(Base::initialize(realm));
  25. set_prototype(&Bindings::ensure_web_prototype<Bindings::HTMLVideoElementPrototype>(realm, "HTMLVideoElement"));
  26. return {};
  27. }
  28. void HTMLVideoElement::visit_edges(Cell::Visitor& visitor)
  29. {
  30. Base::visit_edges(visitor);
  31. visitor.visit(m_video_track);
  32. }
  33. JS::GCPtr<Layout::Node> HTMLVideoElement::create_layout_node(NonnullRefPtr<CSS::StyleProperties> style)
  34. {
  35. return heap().allocate_without_realm<Layout::VideoBox>(document(), *this, move(style));
  36. }
  37. Layout::VideoBox* HTMLVideoElement::layout_node()
  38. {
  39. return static_cast<Layout::VideoBox*>(Node::layout_node());
  40. }
  41. Layout::VideoBox const* HTMLVideoElement::layout_node() const
  42. {
  43. return static_cast<Layout::VideoBox const*>(Node::layout_node());
  44. }
  45. // https://html.spec.whatwg.org/multipage/media.html#dom-video-videowidth
  46. u32 HTMLVideoElement::video_width() const
  47. {
  48. // The videoWidth IDL attribute must return the intrinsic width of the video in CSS pixels. The videoHeight IDL
  49. // attribute must return the intrinsic height of the video in CSS pixels. If the element's readyState attribute
  50. // is HAVE_NOTHING, then the attributes must return 0.
  51. if (ready_state() == ReadyState::HaveNothing)
  52. return 0;
  53. return m_video_width;
  54. }
  55. // https://html.spec.whatwg.org/multipage/media.html#dom-video-videoheight
  56. u32 HTMLVideoElement::video_height() const
  57. {
  58. // The videoWidth IDL attribute must return the intrinsic width of the video in CSS pixels. The videoHeight IDL
  59. // attribute must return the intrinsic height of the video in CSS pixels. If the element's readyState attribute
  60. // is HAVE_NOTHING, then the attributes must return 0.
  61. if (ready_state() == ReadyState::HaveNothing)
  62. return 0;
  63. return m_video_height;
  64. }
  65. void HTMLVideoElement::set_video_track(JS::GCPtr<HTML::VideoTrack> video_track)
  66. {
  67. set_needs_style_update(true);
  68. document().set_needs_layout();
  69. if (m_video_timer)
  70. m_video_timer->stop();
  71. m_video_track = video_track;
  72. }
  73. void HTMLVideoElement::on_playing()
  74. {
  75. if (!m_video_timer) {
  76. m_video_timer = Platform::Timer::create_repeating(s_frame_delay_ms, [this]() {
  77. if (auto frame = m_video_track->next_frame())
  78. m_current_frame = move(frame);
  79. else
  80. m_video_timer->stop();
  81. layout_node()->set_needs_display();
  82. });
  83. }
  84. m_video_timer->start();
  85. }
  86. void HTMLVideoElement::on_paused()
  87. {
  88. if (m_video_timer)
  89. m_video_timer->stop();
  90. }
  91. }