ladybird/Libraries/LibWeb/HTML/MediaControls.h
Zaggy1024 f213ef455d LibWeb: Cancel the animation frame callback in MediaControls destructor
Otherwise, when hiding controls, we would get a UAF on MediaControls::
update_timeline() and crash.
2026-03-17 06:00:40 -05:00

102 lines
3 KiB
C++

/*
* Copyright (c) 2026, Gregory Bertilson <gregory@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/FlyString.h>
#include <AK/Optional.h>
#include <AK/Vector.h>
#include <LibCore/Timer.h>
#include <LibGC/Weak.h>
#include <LibWeb/Forward.h>
#include <LibWeb/HTML/MediaControlsDOM.h>
namespace Web::HTML {
class HTMLMediaElement;
class MediaControls {
public:
explicit MediaControls(HTMLMediaElement&);
~MediaControls();
private:
void create_shadow_tree();
enum class ListenOnce : bool {
No,
Yes,
};
template<typename T, CallableAs<bool, T&> Handler>
GC::Ref<DOM::IDLEventListener> add_event_listener(JS::Realm&, DOM::EventTarget&, FlyString const& event_name, ListenOnce, Handler);
template<CallableAs<bool> Handler>
GC::Ref<DOM::IDLEventListener> add_event_listener(JS::Realm&, DOM::EventTarget&, FlyString const& event_nam, Handler);
template<CallableAs<bool, UIEvents::MouseEvent const&> Handler>
GC::Ref<DOM::IDLEventListener> add_event_listener(JS::Realm&, DOM::EventTarget&, FlyString const& event_name, Handler);
template<CallableAs<bool, UIEvents::MouseEvent const&> Handler>
GC::Ref<DOM::IDLEventListener> add_event_listener(JS::Realm&, DOM::EventTarget&, FlyString const& event_name, ListenOnce, Handler);
template<CallableAs<bool, UIEvents::KeyboardEvent const&> Handler>
GC::Ref<DOM::IDLEventListener> add_event_listener(JS::Realm&, DOM::EventTarget&, FlyString const& event_name, Handler);
void remove_event_listeners();
void set_up_event_listeners();
void toggle_playback();
void set_current_time(double);
void set_volume(double);
void toggle_mute();
void toggle_fullscreen();
void update_play_pause_icon();
void update_timeline();
void update_timestamp();
void update_volume_and_mute_indicator();
void update_fullscreen_icon();
void update_placeholder_visibility();
bool should_show_placeholder() const;
void show_controls();
void hide_controls();
GC::Weak<HTMLMediaElement> m_media_element;
Optional<MediaControlsDOM> m_dom;
struct RegisteredEventListener {
GC::Weak<DOM::EventTarget> target;
FlyString event_name;
GC::Weak<DOM::IDLEventListener> listener;
};
Vector<RegisteredEventListener> m_registered_event_listeners;
GC::Weak<WebIDL::CallbackType> m_request_animation_frame_callback;
u32 m_request_animation_frame_id { 0 };
enum class Scrubbing : u8 {
No,
WhilePaused,
WhilePlaying,
};
Scrubbing m_scrubbing_timeline { Scrubbing::No };
bool m_scrubbing_volume { false };
bool m_hovering_controls { false };
RefPtr<Core::Timer> m_hover_timer;
bool m_had_audio { true };
bool m_was_muted { false };
enum class MuteIconState : u8 {
Empty,
Low,
High,
};
MuteIconState m_mute_icon_state { MuteIconState::Empty };
double m_last_timeline_percentage { 0.0 };
};
}