2022-09-08 13:44:17 +03:00
/*
* Copyright ( c ) 2022 , Andreas Kling < kling @ serenityos . org >
2023-01-11 23:34:59 +03:00
* Copyright ( c ) 2023 , Linus Groh < linusg @ serenityos . org >
2022-09-08 13:44:17 +03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "FontPluginQt.h"
2022-12-04 21:43:54 +03:00
# include <AK/DeprecatedString.h>
2023-01-11 23:34:59 +03:00
# include <AK/String.h>
# include <LibCore/StandardPaths.h>
2023-03-01 16:44:34 +03:00
# include <LibGfx/Font/Emoji.h>
2022-09-08 13:44:17 +03:00
# include <LibGfx/Font/FontDatabase.h>
# include <QFont>
# include <QFontInfo>
2022-12-04 21:43:54 +03:00
extern DeprecatedString s_serenity_resource_root ;
2022-09-08 13:44:17 +03:00
namespace Ladybird {
FontPluginQt : : FontPluginQt ( )
{
// Load the default SerenityOS fonts...
2022-12-04 21:43:54 +03:00
Gfx : : FontDatabase : : set_default_fonts_lookup_path ( DeprecatedString : : formatted ( " {}/res/fonts " , s_serenity_resource_root ) ) ;
2022-09-08 13:44:17 +03:00
2023-01-11 23:34:59 +03:00
// ...and also anything we can find in the system's font directories
for ( auto const & path : Core : : StandardPaths : : font_directories ( ) . release_value_but_fixme_should_propagate_errors ( ) )
Gfx : : FontDatabase : : the ( ) . load_all_fonts_from_path ( path . to_deprecated_string ( ) ) ;
2022-09-08 13:44:17 +03:00
Gfx : : FontDatabase : : set_default_font_query ( " Katica 10 400 0 " ) ;
Gfx : : FontDatabase : : set_fixed_width_font_query ( " Csilla 10 400 0 " ) ;
2023-03-01 16:44:34 +03:00
Gfx : : Emoji : : set_emoji_lookup_path ( String : : formatted ( " {}/res/emoji " , s_serenity_resource_root ) . release_value_but_fixme_should_propagate_errors ( ) ) ;
2022-09-08 13:44:17 +03:00
update_generic_fonts ( ) ;
2022-09-17 22:25:15 +03:00
auto default_font_name = generic_font_name ( Web : : Platform : : GenericFont : : UiSansSerif ) ;
2023-02-04 23:00:34 +03:00
m_default_font = Gfx : : FontDatabase : : the ( ) . get ( default_font_name , 12.0 , 400 , Gfx : : FontWidth : : Normal , 0 ) ;
2022-09-17 22:25:15 +03:00
VERIFY ( m_default_font ) ;
2022-09-18 03:11:48 +03:00
auto default_fixed_width_font_name = generic_font_name ( Web : : Platform : : GenericFont : : UiMonospace ) ;
2023-02-04 23:00:34 +03:00
m_default_fixed_width_font = Gfx : : FontDatabase : : the ( ) . get ( default_fixed_width_font_name , 12.0 , 400 , Gfx : : FontWidth : : Normal , 0 ) ;
2022-09-18 03:11:48 +03:00
VERIFY ( m_default_fixed_width_font ) ;
2022-09-08 13:44:17 +03:00
}
FontPluginQt : : ~ FontPluginQt ( ) = default ;
2022-09-17 22:25:15 +03:00
Gfx : : Font & FontPluginQt : : default_font ( )
{
return * m_default_font ;
}
Gfx : : Font & FontPluginQt : : default_fixed_width_font ( )
{
return * m_default_fixed_width_font ;
}
2022-09-08 13:44:17 +03:00
void FontPluginQt : : update_generic_fonts ( )
{
// How we choose which system font to use for each CSS font:
// 1. Ask Qt via the QFont::StyleHint mechanism for the user's preferred font.
// 2. Try loading that font through Gfx::FontDatabase
// 3. If we don't support that font for whatever reason (e.g missing TrueType features in LibGfx)...
// 1. Try a list of known-suitable fallback fonts with their names hard-coded below
// 2. If that didn't work, fall back to Gfx::FontDatabase::default_font() (or default_fixed_width_font())
// This is rather weird, but it's how things work right now, as we can only draw with fonts loaded by LibGfx.
m_generic_font_names . resize ( static_cast < size_t > ( Web : : Platform : : GenericFont : : __Count ) ) ;
2023-04-26 15:17:40 +03:00
auto update_mapping = [ & ] ( Web : : Platform : : GenericFont generic_font , QFont : : StyleHint qfont_style_hint , ReadonlySpan < DeprecatedString > fallbacks ) {
2022-09-08 13:44:17 +03:00
QFont qt_font ;
qt_font . setStyleHint ( qfont_style_hint ) ;
2023-04-26 15:17:40 +03:00
// NOTE: This is a workaround for setStyleHint being a no-op on X11 systems. See:
// https://doc.qt.io/qt-6/qfont.html#setStyleHint
if ( generic_font = = Web : : Platform : : GenericFont : : Monospace )
qt_font . setFamily ( " monospace " ) ;
else if ( generic_font = = Web : : Platform : : GenericFont : : Fantasy )
qt_font . setFamily ( " fantasy " ) ;
else if ( generic_font = = Web : : Platform : : GenericFont : : Cursive )
qt_font . setFamily ( " cursive " ) ;
2022-09-08 13:44:17 +03:00
QFontInfo qt_info ( qt_font ) ;
auto qt_font_family = qt_info . family ( ) ;
2023-02-04 23:00:34 +03:00
auto gfx_font = Gfx : : FontDatabase : : the ( ) . get ( qt_font_family . toUtf8 ( ) . data ( ) , 16 , 400 , Gfx : : FontWidth : : Normal , 0 , Gfx : : Font : : AllowInexactSizeMatch : : Yes ) ;
2022-09-08 13:44:17 +03:00
if ( ! gfx_font ) {
for ( auto & fallback : fallbacks ) {
2023-02-04 23:00:34 +03:00
gfx_font = Gfx : : FontDatabase : : the ( ) . get ( fallback , 16 , 400 , Gfx : : FontWidth : : Normal , 0 , Gfx : : Font : : AllowInexactSizeMatch : : Yes ) ;
2022-09-08 13:44:17 +03:00
if ( gfx_font )
break ;
}
}
if ( ! gfx_font ) {
if ( generic_font = = Web : : Platform : : GenericFont : : Monospace | | generic_font = = Web : : Platform : : GenericFont : : UiMonospace )
gfx_font = Gfx : : FontDatabase : : default_fixed_width_font ( ) ;
else
gfx_font = Gfx : : FontDatabase : : default_font ( ) ;
}
m_generic_font_names [ static_cast < size_t > ( generic_font ) ] = gfx_font - > family ( ) ;
} ;
// Fallback fonts to look for if Gfx::Font can't load the font suggested by Qt.
// The lists are basically arbitrary, taken from https://www.w3.org/Style/Examples/007/fonts.en.html
2022-12-04 21:43:54 +03:00
Vector < DeprecatedString > cursive_fallbacks { " Comic Sans MS " , " Comic Sans " , " Apple Chancery " , " Bradley Hand " , " Brush Script MT " , " Snell Roundhand " , " URW Chancery L " } ;
Vector < DeprecatedString > fantasy_fallbacks { " Impact " , " Luminari " , " Chalkduster " , " Jazz LET " , " Blippo " , " Stencil Std " , " Marker Felt " , " Trattatello " } ;
Vector < DeprecatedString > monospace_fallbacks { " Andale Mono " , " Courier New " , " Courier " , " FreeMono " , " OCR A Std " , " DejaVu Sans Mono " , " Liberation Mono " , " Csilla " } ;
Vector < DeprecatedString > sans_serif_fallbacks { " Arial " , " Helvetica " , " Verdana " , " Trebuchet MS " , " Gill Sans " , " Noto Sans " , " Avantgarde " , " Optima " , " Arial Narrow " , " Liberation Sans " , " Katica " } ;
Vector < DeprecatedString > serif_fallbacks { " Times " , " Times New Roman " , " Didot " , " Georgia " , " Palatino " , " Bookman " , " New Century Schoolbook " , " American Typewriter " , " Liberation Serif " , " Roman " } ;
2022-09-08 13:44:17 +03:00
update_mapping ( Web : : Platform : : GenericFont : : Cursive , QFont : : StyleHint : : Cursive , cursive_fallbacks ) ;
update_mapping ( Web : : Platform : : GenericFont : : Fantasy , QFont : : StyleHint : : Fantasy , fantasy_fallbacks ) ;
update_mapping ( Web : : Platform : : GenericFont : : Monospace , QFont : : StyleHint : : Monospace , monospace_fallbacks ) ;
update_mapping ( Web : : Platform : : GenericFont : : SansSerif , QFont : : StyleHint : : SansSerif , sans_serif_fallbacks ) ;
update_mapping ( Web : : Platform : : GenericFont : : Serif , QFont : : StyleHint : : Serif , serif_fallbacks ) ;
update_mapping ( Web : : Platform : : GenericFont : : UiMonospace , QFont : : StyleHint : : Monospace , monospace_fallbacks ) ;
update_mapping ( Web : : Platform : : GenericFont : : UiRounded , QFont : : StyleHint : : SansSerif , sans_serif_fallbacks ) ;
update_mapping ( Web : : Platform : : GenericFont : : UiSansSerif , QFont : : StyleHint : : SansSerif , sans_serif_fallbacks ) ;
update_mapping ( Web : : Platform : : GenericFont : : UiSerif , QFont : : StyleHint : : Serif , serif_fallbacks ) ;
}
2022-12-04 21:43:54 +03:00
DeprecatedString FontPluginQt : : generic_font_name ( Web : : Platform : : GenericFont generic_font )
2022-09-08 13:44:17 +03:00
{
return m_generic_font_names [ static_cast < size_t > ( generic_font ) ] ;
}
}