diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt index 63421da93cc..235ef988edd 100644 --- a/Tests/LibWeb/Text/expected/all-window-properties.txt +++ b/Tests/LibWeb/Text/expected/all-window-properties.txt @@ -363,6 +363,7 @@ Uint32Array Uint8Array Uint8ClampedArray UserActivation +VTTCue VTTRegion ValidityState VideoTrack diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 30b8ea3b301..c90f1540dca 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -755,6 +755,7 @@ set(SOURCES WebIDL/Promise.cpp WebIDL/Tracing.cpp WebSockets/WebSocket.cpp + WebVTT/VTTCue.cpp WebVTT/VTTRegion.cpp XHR/EventNames.cpp XHR/FormData.cpp diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index ee88ea6c5aa..a3875d41bf1 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -791,6 +791,7 @@ class WebSocket; } namespace Web::WebVTT { +class VTTCue; class VTTRegion; } diff --git a/Userland/Libraries/LibWeb/WebVTT/VTTCue.cpp b/Userland/Libraries/LibWeb/WebVTT/VTTCue.cpp new file mode 100644 index 00000000000..ea371e54eb6 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebVTT/VTTCue.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2024, Jamie Mansfield + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Web::WebVTT { + +JS_DEFINE_ALLOCATOR(VTTCue); + +// https://w3c.github.io/webvtt/#dom-vttcue-vttcue +WebIDL::ExceptionOr> VTTCue::construct_impl(JS::Realm& realm, double start_time, double end_time, String const& text) +{ + // 1. Create a new WebVTT cue. Let cue be that WebVTT cue. + auto cue = realm.heap().allocate(realm, realm, nullptr); + + // 2. Let cue’s text track cue start time be the value of the startTime argument. + cue->m_start_time = start_time; + + // 3. If the value of the endTime argument is negative Infinity or a Not-a-Number (NaN) value, then throw a TypeError exception. + // Otherwise, let cue’s text track cue end time be the value of the endTime argument. + if (end_time == -AK::Infinity || isnan(end_time)) + return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "End time is negative infinity or NaN"_string }; + cue->m_end_time = end_time; + + // 4. Let cue’s cue text be the value of the text argument, and let the rules for extracting the chapter title be the WebVTT rules + // for extracting the chapter title. + cue->m_text = text; + // FIXME: let the rules for extracting the chapter title be the WebVTT rules for extracting the chapter title. + + // 5. Let cue’s text track cue identifier be the empty string. + cue->m_identifier = ""_string; + + // 6. Let cue’s text track cue pause-on-exit flag be false. + cue->m_pause_on_exit = false; + + // 7. Let cue’s WebVTT cue region be null. + cue->m_region = nullptr; + + // 8. Let cue’s WebVTT cue writing direction be horizontal. + cue->m_writing_direction = WritingDirection::Horizontal; + + // 9. Let cue’s WebVTT cue snap-to-lines flag be true. + cue->m_snap_to_lines = true; + + // FIXME: 10. Let cue’s WebVTT cue line be auto. + + // 11. Let cue’s WebVTT cue line alignment be start alignment. + cue->m_line_alignment = Bindings::LineAlignSetting::Start; + + // FIXME: 12. Let cue’s WebVTT cue position be auto. + + // 13. Let cue’s WebVTT cue position alignment be auto. + cue->m_position_alignment = Bindings::PositionAlignSetting::Auto; + + // 14. Let cue’s WebVTT cue size be 100. + cue->m_size = 100; + + // 15. Let cue’s WebVTT cue text alignment be center alignment. + cue->m_text_alignment = Bindings::AlignSetting::Center; + + // 16. Return the VTTCue object representing cue. + return cue; +} + +VTTCue::VTTCue(JS::Realm& realm, JS::GCPtr track) + : HTML::TextTrackCue(realm, track) +{ +} + +void VTTCue::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + WEB_SET_PROTOTYPE_FOR_INTERFACE(VTTCue); +} + +void VTTCue::visit_edges(Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_region); +} + +// https://w3c.github.io/webvtt/#dom-vttcue-vertical +Bindings::DirectionSetting VTTCue::vertical() const +{ + switch (m_writing_direction) { + case WritingDirection::Horizontal: + return Bindings::DirectionSetting::Empty; + case WritingDirection::VerticalGrowingLeft: + return Bindings::DirectionSetting::Rl; + case WritingDirection::VerticalGrowingRight: + return Bindings::DirectionSetting::Lr; + } + VERIFY_NOT_REACHED(); +} + +// https://w3c.github.io/webvtt/#dom-vttcue-vertical +void VTTCue::set_vertical(Bindings::DirectionSetting vertical) +{ + switch (vertical) { + case Bindings::DirectionSetting::Empty: + m_writing_direction = WritingDirection::Horizontal; + break; + case Bindings::DirectionSetting::Rl: + m_writing_direction = WritingDirection::VerticalGrowingLeft; + break; + case Bindings::DirectionSetting::Lr: + m_writing_direction = WritingDirection::VerticalGrowingRight; + break; + } +} + +// https://w3c.github.io/webvtt/#cue-computed-position-alignment +Bindings::PositionAlignSetting VTTCue::computed_position_alignment() +{ + // 1. If the WebVTT cue position alignment is not auto, then return the value of the WebVTT cue position alignment and abort these + // steps. + if (m_position_alignment != Bindings::PositionAlignSetting::Auto) + return m_position_alignment; + + // 2. If the WebVTT cue text alignment is left, return line-left and abort these steps. + if (m_text_alignment == Bindings::AlignSetting::Left) + return Bindings::PositionAlignSetting::LineLeft; + + // 3. If the WebVTT cue text alignment is right, return line-right and abort these steps. + if (m_text_alignment == Bindings::AlignSetting::Right) + return Bindings::PositionAlignSetting::LineRight; + + // FIXME: 4. If the WebVTT cue text alignment is start, return line-left if the base direction of the cue text is left-to-right, line-right + // otherwise. + + // FIXME: 5. If the WebVTT cue text alignment is end, return line-right if the base direction of the cue text is left-to-right, line-left + // otherwise. + + // 6. Otherwise, return center. + return Bindings::PositionAlignSetting::Center; +} + +} diff --git a/Userland/Libraries/LibWeb/WebVTT/VTTCue.h b/Userland/Libraries/LibWeb/WebVTT/VTTCue.h new file mode 100644 index 00000000000..71aeb50eb03 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebVTT/VTTCue.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024, Jamie Mansfield + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::WebVTT { + +// https://w3c.github.io/webvtt/#vttcue +class VTTCue final : public HTML::TextTrackCue { + WEB_PLATFORM_OBJECT(VTTCue, HTML::TextTrackCue); + JS_DECLARE_ALLOCATOR(VTTCue); + +public: + enum class WritingDirection : u8 { + // https://w3c.github.io/webvtt/#webvtt-cue-horizontal-writing-direction + Horizontal, + + // https://w3c.github.io/webvtt/#webvtt-cue-vertical-growing-left-writing-direction + VerticalGrowingLeft, + + // https://w3c.github.io/webvtt/#webvtt-cue-vertical-growing-right-writing-direction + VerticalGrowingRight, + }; + + static WebIDL::ExceptionOr> construct_impl(JS::Realm&, double start_time, double end_time, String const& text); + virtual ~VTTCue() override = default; + + JS::GCPtr region() const { return m_region; } + void set_region(JS::GCPtr region) { m_region = region; } + + Bindings::DirectionSetting vertical() const; + void set_vertical(Bindings::DirectionSetting); + + bool snap_to_lines() const { return m_snap_to_lines; } + void set_snap_to_lines(bool snap_to_lines) { m_snap_to_lines = snap_to_lines; } + + Bindings::LineAlignSetting line_align() const { return m_line_alignment; } + void set_line_align(Bindings::LineAlignSetting line_align) { m_line_alignment = line_align; } + + Bindings::PositionAlignSetting position_align() const { return m_position_alignment; } + void set_position_align(Bindings::PositionAlignSetting position_align) { m_position_alignment = position_align; } + + double size() const { return m_size; } + void set_size(double size) { m_size = size; } + + Bindings::AlignSetting align() const { return m_text_alignment; } + void set_align(Bindings::AlignSetting align) { m_text_alignment = align; } + + String const& text() const { return m_text; } + void set_text(String const& text) { m_text = text; } + +protected: + Bindings::PositionAlignSetting computed_position_alignment(); + +private: + VTTCue(JS::Realm&, JS::GCPtr); + + virtual void initialize(JS::Realm&) override; + virtual void visit_edges(Visitor&) override; + + // https://w3c.github.io/webvtt/#cue-text + String m_text; + + // https://w3c.github.io/webvtt/#webvtt-cue-writing-direction + WritingDirection m_writing_direction { WritingDirection::Horizontal }; + + // https://w3c.github.io/webvtt/#webvtt-cue-snap-to-lines-flag + bool m_snap_to_lines { true }; + + // https://w3c.github.io/webvtt/#webvtt-cue-line-alignment + Bindings::LineAlignSetting m_line_alignment { Bindings::LineAlignSetting::Start }; + + // https://w3c.github.io/webvtt/#webvtt-cue-position-alignment + Bindings::PositionAlignSetting m_position_alignment { Bindings::PositionAlignSetting::Auto }; + + // https://w3c.github.io/webvtt/#webvtt-cue-size + double m_size { 100 }; + + // https://w3c.github.io/webvtt/#webvtt-cue-text-alignment + Bindings::AlignSetting m_text_alignment { Bindings::AlignSetting::Center }; + + // https://w3c.github.io/webvtt/#webvtt-cue-region + JS::GCPtr m_region; +}; + +} diff --git a/Userland/Libraries/LibWeb/WebVTT/VTTCue.idl b/Userland/Libraries/LibWeb/WebVTT/VTTCue.idl new file mode 100644 index 00000000000..30f7e46e30a --- /dev/null +++ b/Userland/Libraries/LibWeb/WebVTT/VTTCue.idl @@ -0,0 +1,26 @@ +#import +#import + +enum AutoKeyword { "auto" }; +typedef (double or AutoKeyword) LineAndPositionSetting; +enum DirectionSetting { "", "rl", "lr" }; +enum LineAlignSetting { "start", "center", "end" }; +enum PositionAlignSetting { "line-left", "center", "line-right", "auto" }; +enum AlignSetting { "start", "center", "end", "left", "right" }; + +// https://w3c.github.io/webvtt/#vttcue +[Exposed=Window] +interface VTTCue : TextTrackCue { + constructor(double startTime, unrestricted double endTime, DOMString text); + attribute VTTRegion? region; + attribute DirectionSetting vertical; + attribute boolean snapToLines; + [FIXME] attribute LineAndPositionSetting line; + attribute LineAlignSetting lineAlign; + [FIXME] attribute LineAndPositionSetting position; + attribute PositionAlignSetting positionAlign; + attribute double size; + attribute AlignSetting align; + attribute DOMString text; + [FIXME] DocumentFragment getCueAsHTML(); +}; diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index 9340a6aaf15..edd9fa7d4fd 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -345,6 +345,7 @@ libweb_js_bindings(WebGL/WebGLContextEvent) libweb_js_bindings(WebGL/WebGLRenderingContext) libweb_js_bindings(WebIDL/DOMException) libweb_js_bindings(WebSockets/WebSocket) +libweb_js_bindings(WebVTT/VTTCue) libweb_js_bindings(WebVTT/VTTRegion) libweb_js_bindings(XHR/FormData ITERABLE) libweb_js_bindings(XHR/ProgressEvent)