2024-05-07 14:49:31 -06:00
/*
* Copyright ( c ) 2024 , Andrew Kaster < akaster @ serenityos . org >
2024-06-06 19:58:47 +01:00
* Copyright ( c ) 2024 , Jamie Mansfield < jmansfield @ cadixdev . org >
2024-05-07 14:49:31 -06:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <LibJS/Heap/Heap.h>
# include <LibJS/Runtime/Realm.h>
2024-05-21 21:05:36 -06:00
# include <LibJS/Runtime/Set.h>
2024-05-07 14:49:31 -06:00
# include <LibWeb/Bindings/FontFaceSetPrototype.h>
# include <LibWeb/Bindings/Intrinsics.h>
2024-05-21 21:05:36 -06:00
# include <LibWeb/CSS/FontFace.h>
2024-05-07 14:49:31 -06:00
# include <LibWeb/CSS/FontFaceSet.h>
2024-06-06 19:58:47 +01:00
# include <LibWeb/HTML/EventNames.h>
2024-05-07 14:49:31 -06:00
# include <LibWeb/WebIDL/Promise.h>
namespace Web : : CSS {
JS_DEFINE_ALLOCATOR ( FontFaceSet ) ;
2024-05-21 21:05:36 -06:00
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-fontfaceset
JS : : NonnullGCPtr < FontFaceSet > FontFaceSet : : construct_impl ( JS : : Realm & realm , Vector < JS : : Handle < FontFace > > const & initial_faces )
2024-05-07 14:49:31 -06:00
{
2024-05-21 21:05:36 -06:00
auto ready_promise = WebIDL : : create_promise ( realm ) ;
auto set_entries = JS : : Set : : create ( realm ) ;
// The FontFaceSet constructor, when called, must iterate its initialFaces argument and add each value to its set entries.
for ( auto const & face : initial_faces )
set_entries - > set_add ( face ) ;
return realm . heap ( ) . allocate < FontFaceSet > ( realm , realm , ready_promise , set_entries ) ;
2024-05-07 14:49:31 -06:00
}
JS : : NonnullGCPtr < FontFaceSet > FontFaceSet : : create ( JS : : Realm & realm )
{
return construct_impl ( realm , { } ) ;
}
2024-05-21 21:05:36 -06:00
FontFaceSet : : FontFaceSet ( JS : : Realm & realm , JS : : NonnullGCPtr < WebIDL : : Promise > ready_promise , JS : : NonnullGCPtr < JS : : Set > set_entries )
2024-06-06 19:55:53 +01:00
: DOM : : EventTarget ( realm )
2024-05-21 21:05:36 -06:00
, m_set_entries ( set_entries )
2024-05-13 13:55:43 -06:00
, m_ready_promise ( ready_promise )
2024-09-29 23:38:49 +02:00
, m_status ( Bindings : : FontFaceSetLoadStatus : : Loaded )
2024-05-07 14:49:31 -06:00
{
}
void FontFaceSet : : initialize ( JS : : Realm & realm )
{
Base : : initialize ( realm ) ;
WEB_SET_PROTOTYPE_FOR_INTERFACE ( FontFaceSet ) ;
}
2024-05-13 13:55:43 -06:00
void FontFaceSet : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
2024-05-21 21:05:36 -06:00
visitor . visit ( m_set_entries ) ;
2024-05-13 13:55:43 -06:00
visitor . visit ( m_ready_promise ) ;
2024-09-26 10:52:54 +01:00
visitor . visit ( m_loading_fonts ) ;
visitor . visit ( m_loaded_fonts ) ;
visitor . visit ( m_failed_fonts ) ;
2024-05-13 13:55:43 -06:00
}
2024-05-07 14:49:31 -06:00
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-add
2024-09-26 10:52:54 +01:00
WebIDL : : ExceptionOr < JS : : NonnullGCPtr < FontFaceSet > >
FontFaceSet : : add ( JS : : Handle < FontFace > face )
2024-05-07 14:49:31 -06:00
{
2024-09-26 10:52:54 +01:00
// 1. If font is already in the FontFaceSet’ s set entries, skip to the last step of this algorithm immediately.
if ( m_set_entries - > set_has ( face ) )
return JS : : NonnullGCPtr < FontFaceSet > ( * this ) ;
// 2. If font is CSS-connected, throw an InvalidModificationError exception and exit this algorithm immediately.
if ( face - > is_css_connected ( ) ) {
return WebIDL : : InvalidModificationError : : create ( realm ( ) , " Cannot add a CSS-connected FontFace to a FontFaceSet " _fly_string ) ;
}
// 3. Add the font argument to the FontFaceSet’ s set entries.
2024-05-21 21:05:36 -06:00
m_set_entries - > set_add ( face ) ;
2024-09-26 10:52:54 +01:00
// 4. If font’ s status attribute is "loading"
if ( face - > status ( ) = = Bindings : : FontFaceLoadStatus : : Loading ) {
// 1. If the FontFaceSet’ s [[LoadingFonts]] list is empty, switch the FontFaceSet to loading.
if ( m_loading_fonts . is_empty ( ) ) {
m_status = Bindings : : FontFaceSetLoadStatus : : Loading ;
}
// 2. Append font to the FontFaceSet’ s [[LoadingFonts]] list.
m_loading_fonts . append ( * face ) ;
}
// 5. Return the FontFaceSet.
return JS : : NonnullGCPtr < FontFaceSet > ( * this ) ;
2024-05-07 14:49:31 -06:00
}
2024-05-21 21:05:36 -06:00
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-delete
bool FontFaceSet : : delete_ ( JS : : Handle < FontFace > face )
{
2024-10-03 14:49:25 +01:00
// 1. If font is CSS-connected, return false and exit this algorithm immediately.
if ( face - > is_css_connected ( ) ) {
return false ;
}
// 2. Let deleted be the result of removing font from the FontFaceSet’ s set entries.
bool deleted = m_set_entries - > set_remove ( face ) ;
// 3. If font is present in the FontFaceSet’ s [[LoadedFonts]], or [[FailedFonts]] lists, remove it.
m_loaded_fonts . remove_all_matching ( [ face ] ( auto const & entry ) { return entry = = face ; } ) ;
m_failed_fonts . remove_all_matching ( [ face ] ( auto const & entry ) { return entry = = face ; } ) ;
// 4. If font is present in the FontFaceSet’ s [[LoadingFonts]] list, remove it. If font was the last item in that list (and so the list is now empty), switch the FontFaceSet to loaded.
m_loading_fonts . remove_all_matching ( [ face ] ( auto const & entry ) { return entry = = face ; } ) ;
if ( m_loading_fonts . is_empty ( ) ) {
m_status = Bindings : : FontFaceSetLoadStatus : : Loaded ;
}
return deleted ;
2024-05-21 21:05:36 -06:00
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-clear
void FontFaceSet : : clear ( )
{
// FIXME: Do the actual spec steps
m_set_entries - > set_clear ( ) ;
}
2024-06-06 19:58:47 +01:00
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloading
void FontFaceSet : : set_onloading ( WebIDL : : CallbackType * event_handler )
{
set_event_handler_attribute ( HTML : : EventNames : : loading , event_handler ) ;
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloading
WebIDL : : CallbackType * FontFaceSet : : onloading ( )
{
return event_handler_attribute ( HTML : : EventNames : : loading ) ;
}
2024-06-06 20:01:39 +01:00
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloadingdone
void FontFaceSet : : set_onloadingdone ( WebIDL : : CallbackType * event_handler )
{
set_event_handler_attribute ( HTML : : EventNames : : loadingdone , event_handler ) ;
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloadingdone
WebIDL : : CallbackType * FontFaceSet : : onloadingdone ( )
{
return event_handler_attribute ( HTML : : EventNames : : loadingdone ) ;
}
2024-06-06 20:02:55 +01:00
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloadingerror
void FontFaceSet : : set_onloadingerror ( WebIDL : : CallbackType * event_handler )
{
set_event_handler_attribute ( HTML : : EventNames : : loadingerror , event_handler ) ;
}
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-onloadingerror
WebIDL : : CallbackType * FontFaceSet : : onloadingerror ( )
{
return event_handler_attribute ( HTML : : EventNames : : loadingerror ) ;
}
2024-05-07 14:49:31 -06:00
// https://drafts.csswg.org/css-font-loading/#dom-fontfaceset-load
JS : : ThrowCompletionOr < JS : : NonnullGCPtr < JS : : Promise > > FontFaceSet : : load ( String const & , String const & )
{
// FIXME: Do the steps
auto promise = WebIDL : : create_rejected_promise ( realm ( ) , WebIDL : : NotSupportedError : : create ( realm ( ) , " FontFaceSet::load is not yet implemented " _fly_string ) ) ;
return verify_cast < JS : : Promise > ( * promise - > promise ( ) ) ;
}
2024-05-13 13:55:43 -06:00
// https://drafts.csswg.org/css-font-loading/#font-face-set-ready
JS : : NonnullGCPtr < JS : : Promise > FontFaceSet : : ready ( ) const
{
return verify_cast < JS : : Promise > ( * m_ready_promise - > promise ( ) ) ;
}
2024-09-29 23:38:49 +02:00
void FontFaceSet : : resolve_ready_promise ( )
{
WebIDL : : resolve_promise ( realm ( ) , * m_ready_promise ) ;
}
2024-05-07 14:49:31 -06:00
}