Handle missing Bold/Ital outline fonts
If the font face doesn't include a Bold or Italic version, we still want to display the font as bold/italic, so we fake it with freetype. This also prevents recurring error messages where the outline font warns about "substitutes" within the same font family. Also allows variants on the weight descriptor to be used without throwing a substitution warning Fixes https://gitlab.com/kicad/code/kicad/issues/13654
This commit is contained in:
parent
bd977fffa8
commit
cf52bfcc55
|
@ -61,9 +61,19 @@ FONTCONFIG* Fontconfig()
|
|||
}
|
||||
|
||||
|
||||
bool FONTCONFIG::FindFont( const wxString& aFontName, wxString& aFontFile )
|
||||
FONTCONFIG::FF_RESULT FONTCONFIG::FindFont( const wxString &aFontName, wxString &aFontFile,
|
||||
bool aBold, bool aItalic )
|
||||
{
|
||||
FcPattern* pat = FcNameParse( wxStringToFcChar8( aFontName ) );
|
||||
FF_RESULT retval = FF_RESULT::ERROR;
|
||||
wxString qualifiedFontName = aFontName;
|
||||
|
||||
if( aBold )
|
||||
qualifiedFontName << wxS( ":Bold" );
|
||||
|
||||
if( aItalic )
|
||||
qualifiedFontName << wxS( ":Italic" );
|
||||
|
||||
FcPattern* pat = FcNameParse( wxStringToFcChar8( qualifiedFontName ) );
|
||||
FcConfigSubstitute( nullptr, pat, FcMatchPattern );
|
||||
FcDefaultSubstitute( pat );
|
||||
|
||||
|
@ -71,8 +81,6 @@ bool FONTCONFIG::FindFont( const wxString& aFontName, wxString& aFontFile )
|
|||
FcPattern* font = FcFontMatch( nullptr, pat, &r );
|
||||
|
||||
wxString fontName;
|
||||
bool ok = false;
|
||||
bool substituted = false;
|
||||
|
||||
if( font )
|
||||
{
|
||||
|
@ -81,17 +89,19 @@ bool FONTCONFIG::FindFont( const wxString& aFontName, wxString& aFontFile )
|
|||
if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch )
|
||||
{
|
||||
aFontFile = wxString::FromUTF8( (char*) file );
|
||||
|
||||
wxString styleStr;
|
||||
FcChar8* family = nullptr;
|
||||
FcChar8* style = nullptr;
|
||||
|
||||
retval = FF_RESULT::SUBSTITUTE;
|
||||
|
||||
if( FcPatternGetString( font, FC_FAMILY, 0, &family ) == FcResultMatch )
|
||||
{
|
||||
fontName = wxString::FromUTF8( (char*) family );
|
||||
|
||||
if( FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch )
|
||||
{
|
||||
wxString styleStr = wxString::FromUTF8( (char*) style );
|
||||
styleStr = wxString::FromUTF8( (char*) style );
|
||||
|
||||
if( !styleStr.IsEmpty() )
|
||||
{
|
||||
|
@ -100,27 +110,51 @@ bool FONTCONFIG::FindFont( const wxString& aFontName, wxString& aFontFile )
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: report Regular vs Book, Italic vs Oblique, etc. or filter them out?
|
||||
bool has_bold = false;
|
||||
bool has_ital = false;
|
||||
wxString lower_style = styleStr.Lower();
|
||||
|
||||
if( aFontName.Contains( ":" ) )
|
||||
substituted = aFontName.CmpNoCase( fontName ) != 0;
|
||||
else
|
||||
substituted = !fontName.StartsWith( aFontName );
|
||||
if( lower_style.Contains( wxS( "bold" ) )
|
||||
|| lower_style.Contains( wxS( "black" ) )
|
||||
|| lower_style.Contains( wxS( "thick" ) )
|
||||
|| lower_style.Contains( wxS( "dark" ) ) )
|
||||
{
|
||||
has_bold = true;
|
||||
}
|
||||
|
||||
if( lower_style.Contains( wxS( "italic" ) )
|
||||
|| lower_style.Contains( wxS( "oblique" ) )
|
||||
|| lower_style.Contains( wxS( "slant" ) ) )
|
||||
{
|
||||
has_ital = true;
|
||||
}
|
||||
|
||||
if( fontName.Lower().StartsWith( aFontName.Lower() ) )
|
||||
{
|
||||
if( ( aBold && !has_bold ) && ( aItalic && !has_ital ) )
|
||||
retval = FF_RESULT::MISSING_BOLD_ITAL;
|
||||
else if( aBold && !has_bold )
|
||||
retval = FF_RESULT::MISSING_BOLD;
|
||||
else if( aItalic && !has_ital )
|
||||
retval = FF_RESULT::MISSING_ITAL;
|
||||
else if( ( aBold != has_bold ) || ( aItalic != has_ital ) )
|
||||
retval = FF_RESULT::SUBSTITUTE;
|
||||
else
|
||||
retval = FF_RESULT::OK;
|
||||
}
|
||||
}
|
||||
|
||||
ok = true;
|
||||
}
|
||||
|
||||
FcPatternDestroy( font );
|
||||
}
|
||||
|
||||
if( !ok )
|
||||
wxLogWarning( _( "Error loading font '%s'." ), aFontName );
|
||||
else if( substituted )
|
||||
wxLogWarning( _( "Font '%s' not found; substituting '%s'." ), aFontName, fontName );
|
||||
if( retval == FF_RESULT::ERROR )
|
||||
wxLogWarning( _( "Error loading font '%s'." ), qualifiedFontName );
|
||||
else if( retval == FF_RESULT::SUBSTITUTE )
|
||||
wxLogWarning( _( "Font '%s' not found; substituting '%s'." ), qualifiedFontName, fontName );
|
||||
|
||||
FcPatternDestroy( pat );
|
||||
return ok;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <bezier_curves.h>
|
||||
#include <geometry/shape_poly_set.h>
|
||||
#include <eda_text.h>
|
||||
#include <font/fontconfig.h>
|
||||
#include <font/outline_font.h>
|
||||
#include FT_GLYPH_H
|
||||
#include FT_BBOX_H
|
||||
|
@ -46,7 +47,9 @@ FT_Library OUTLINE_FONT::m_freeType = nullptr;
|
|||
|
||||
OUTLINE_FONT::OUTLINE_FONT() :
|
||||
m_face(NULL),
|
||||
m_faceSize( 16 )
|
||||
m_faceSize( 16 ),
|
||||
m_fakeBold( false ),
|
||||
m_fakeItal( false )
|
||||
{
|
||||
if( !m_freeType )
|
||||
FT_Init_FreeType( &m_freeType );
|
||||
|
@ -90,15 +93,17 @@ OUTLINE_FONT* OUTLINE_FONT::LoadFont( const wxString& aFontName, bool aBold, boo
|
|||
OUTLINE_FONT* font = new OUTLINE_FONT();
|
||||
|
||||
wxString fontFile;
|
||||
wxString qualifiedFontName = aFontName;
|
||||
using fc = fontconfig::FONTCONFIG;
|
||||
|
||||
if( aBold )
|
||||
qualifiedFontName << wxS( ":Bold" );
|
||||
fc::FF_RESULT retval = Fontconfig()->FindFont( aFontName, fontFile, aBold, aItalic );
|
||||
|
||||
if( aItalic )
|
||||
qualifiedFontName << wxS( ":Italic" );
|
||||
if( retval == fc::FF_RESULT::MISSING_BOLD || retval == fc::FF_RESULT::MISSING_BOLD_ITAL )
|
||||
font->SetFakeBold();
|
||||
|
||||
if( Fontconfig()->FindFont( qualifiedFontName, fontFile ) )
|
||||
if( retval == fc::FF_RESULT::MISSING_ITAL || retval == fc::FF_RESULT::MISSING_BOLD_ITAL )
|
||||
font->SetFakeItal();
|
||||
|
||||
if( retval != fc::FF_RESULT::ERROR )
|
||||
(void) font->loadFace( fontFile );
|
||||
|
||||
font->m_fontName = aFontName; // Keep asked-for name, even if we substituted.
|
||||
|
@ -357,8 +362,24 @@ VECTOR2I OUTLINE_FONT::getTextAsGlyphs( BOX2I* aBBox, std::vector<std::unique_pt
|
|||
|
||||
if( aGlyphs )
|
||||
{
|
||||
if( m_fakeItal )
|
||||
{
|
||||
FT_Matrix matrix;
|
||||
// Create a 12 degree slant
|
||||
const float angle = ( -M_PI * 12 ) / 180.0f;
|
||||
matrix.xx = (FT_Fixed) ( cos( angle ) * 0x10000L );
|
||||
matrix.xy = (FT_Fixed) ( -sin( angle ) * 0x10000L );
|
||||
matrix.yx = (FT_Fixed) ( 0 * 0x10000L ); // Don't rotate in the y direction
|
||||
matrix.yy = (FT_Fixed) ( 1 * 0x10000L );
|
||||
|
||||
FT_Set_Transform(face, &matrix,0);
|
||||
}
|
||||
|
||||
FT_Load_Glyph( face, glyphInfo[i].codepoint, FT_LOAD_NO_BITMAP );
|
||||
|
||||
if( m_fakeBold )
|
||||
FT_Outline_Embolden( &face->glyph->outline, 1 << 6 );
|
||||
|
||||
// contours is a collection of all outlines in the glyph; for example the 'o' glyph
|
||||
// generally contains 2 contours, one for the glyph outline and one for the hole
|
||||
CONTOURS contours;
|
||||
|
|
|
@ -36,13 +36,23 @@ public:
|
|||
|
||||
static wxString Version();
|
||||
|
||||
enum class FF_RESULT
|
||||
{
|
||||
OK,
|
||||
ERROR,
|
||||
SUBSTITUTE,
|
||||
MISSING_BOLD,
|
||||
MISSING_ITAL,
|
||||
MISSING_BOLD_ITAL
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a fully-qualified font name ("Times:Bold:Italic") find the closest matching font
|
||||
* and return its filepath in \a aFontFile.
|
||||
*
|
||||
* A return value of false indicates a serious error in the font system.
|
||||
*/
|
||||
bool FindFont( const wxString& aFontName, wxString& aFontFile );
|
||||
FF_RESULT FindFont( const wxString& aFontName, wxString& aFontFile, bool aBold, bool aItalic );
|
||||
|
||||
/**
|
||||
* List the current available font families.
|
||||
|
|
|
@ -63,12 +63,22 @@ public:
|
|||
|
||||
bool IsBold() const override
|
||||
{
|
||||
return m_face && ( m_face->style_flags & FT_STYLE_FLAG_BOLD );
|
||||
return m_face && ( m_fakeBold || ( m_face->style_flags & FT_STYLE_FLAG_BOLD ) );
|
||||
}
|
||||
|
||||
bool IsItalic() const override
|
||||
{
|
||||
return m_face && ( m_face->style_flags & FT_STYLE_FLAG_ITALIC );
|
||||
return m_face && ( m_fakeItal || ( m_face->style_flags & FT_STYLE_FLAG_ITALIC ) );
|
||||
}
|
||||
|
||||
void SetFakeBold()
|
||||
{
|
||||
m_fakeBold = true;
|
||||
}
|
||||
|
||||
void SetFakeItal()
|
||||
{
|
||||
m_fakeItal = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,6 +138,8 @@ private:
|
|||
static FT_Library m_freeType;
|
||||
FT_Face m_face;
|
||||
const int m_faceSize;
|
||||
bool m_fakeBold;
|
||||
bool m_fakeItal;
|
||||
|
||||
// cache for glyphs converted to straight segments
|
||||
// key is glyph index (FT_GlyphSlot field glyph_index)
|
||||
|
|
Loading…
Reference in New Issue