ladybird/Libraries/LibWeb/HTML/TextTrack.cpp
Timothy Flynn de34143a4e
Some checks are pending
CI / macOS, arm64, Sanitizer_CI, Clang (push) Waiting to run
CI / Linux, x86_64, Fuzzers_CI, Clang (push) Waiting to run
CI / Linux, x86_64, Sanitizer_CI, GNU (push) Waiting to run
CI / Linux, x86_64, Sanitizer_CI, Clang (push) Waiting to run
Package the js repl as a binary artifact / macOS, arm64 (push) Waiting to run
Package the js repl as a binary artifact / Linux, x86_64 (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
LibWeb: Do not spin the event loop awaiting text track state changes
The text track processing model would previously spin forever waiting
for the track URL to change. It would then recursively invoke itself
to handle the new URL, again entering the spin loop. This meant that
tracks could easily cause event loop hangs.

We now have an observer system to be notified when the track state
changes instead. This lets us exit the processing model and move on.
2025-06-12 12:25:23 -04:00

153 lines
3.6 KiB
C++

/*
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/HTML/TextTrack.h>
#include <LibWeb/HTML/TextTrackObserver.h>
namespace Web::HTML {
GC_DEFINE_ALLOCATOR(TextTrack);
GC::Ref<TextTrack> TextTrack::create(JS::Realm& realm)
{
return realm.create<TextTrack>(realm);
}
TextTrack::TextTrack(JS::Realm& realm)
: DOM::EventTarget(realm)
{
}
TextTrack::~TextTrack() = default;
void TextTrack::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(TextTrack);
Base::initialize(realm);
}
void TextTrack::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_observers);
}
// https://html.spec.whatwg.org/multipage/media.html#dom-texttrack-kind
Bindings::TextTrackKind TextTrack::kind()
{
return m_kind;
}
void TextTrack::set_kind(Bindings::TextTrackKind kind)
{
m_kind = kind;
}
// https://html.spec.whatwg.org/multipage/media.html#dom-texttrack-label
String TextTrack::label()
{
return m_label;
}
void TextTrack::set_label(String label)
{
m_label = label;
}
// https://html.spec.whatwg.org/multipage/media.html#dom-texttrack-language
String TextTrack::language()
{
return m_language;
}
void TextTrack::set_language(String language)
{
m_language = language;
}
// https://html.spec.whatwg.org/multipage/media.html#dom-texttrack-id
String TextTrack::id()
{
return m_id;
}
void TextTrack::set_id(String id)
{
m_id = id;
}
// https://html.spec.whatwg.org/multipage/media.html#dom-texttrack-mode
Bindings::TextTrackMode TextTrack::mode()
{
return m_mode;
}
void TextTrack::set_mode(Bindings::TextTrackMode mode)
{
m_mode = mode;
}
// https://html.spec.whatwg.org/multipage/media.html#handler-texttrack-oncuechange
void TextTrack::set_oncuechange(WebIDL::CallbackType* event_handler)
{
set_event_handler_attribute(HTML::EventNames::cuechange, event_handler);
}
// https://html.spec.whatwg.org/multipage/media.html#handler-texttrack-oncuechange
WebIDL::CallbackType* TextTrack::oncuechange()
{
return event_handler_attribute(HTML::EventNames::cuechange);
}
void TextTrack::set_readiness_state(ReadinessState readiness_state)
{
m_readiness_state = readiness_state;
for (auto observer : m_observers) {
if (auto callback = observer->track_readiness_observer())
callback->function()(m_readiness_state);
}
}
void TextTrack::register_observer(Badge<TextTrackObserver>, TextTrackObserver& observer)
{
auto result = m_observers.set(observer);
VERIFY(result == AK::HashSetResult::InsertedNewEntry);
}
void TextTrack::unregister_observer(Badge<TextTrackObserver>, TextTrackObserver& observer)
{
bool was_removed = m_observers.remove(observer);
VERIFY(was_removed);
}
Bindings::TextTrackKind text_track_kind_from_string(String value)
{
// https://html.spec.whatwg.org/multipage/media.html#attr-track-kind
if (value.is_empty() || value.equals_ignoring_ascii_case("subtitles"sv)) {
return Bindings::TextTrackKind::Subtitles;
}
if (value.equals_ignoring_ascii_case("captions"sv)) {
return Bindings::TextTrackKind::Captions;
}
if (value.equals_ignoring_ascii_case("descriptions"sv)) {
return Bindings::TextTrackKind::Descriptions;
}
if (value.equals_ignoring_ascii_case("chapters"sv)) {
return Bindings::TextTrackKind::Chapters;
}
if (value.equals_ignoring_ascii_case("metadata"sv)) {
return Bindings::TextTrackKind::Metadata;
}
return Bindings::TextTrackKind::Metadata;
}
}