Improve bitmap fonts support in UICodeEditor.

Refactor font loading.
This commit is contained in:
Martín Lucas Golini
2025-12-20 23:09:31 -03:00
parent 97ed873daa
commit a696c95d75
9 changed files with 109 additions and 60 deletions

View File

@@ -230,6 +230,7 @@ class EE_API FontTrueType : public Font {
bool mIsEmojiFont{ false };
bool mHasSvgGlyphs{ false };
bool mHasColrGlyphs{ false };
bool mIsBitmapOnly{ false };
mutable bool mIsMonospace{ false };
mutable bool mIsMonospaceComplete{ false };
mutable bool mUsingFallback{ false };

View File

@@ -442,6 +442,10 @@ class EE_API Node : public Transformable {
bool inParentTreeOf( Node* child ) const;
bool inParentTreeOfType( Uint32 type ) const;
Node* getParentOfType( Uint32 type ) const;
void setLoadingState( bool loading );
bool isLoadingState() const;

View File

@@ -238,7 +238,7 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
UICodeEditor* setFont( Font* font );
UICodeEditor* setFontSize( const Float& size );
bool setFontSize( const Float& size );
const Float& getFontSize() const;
@@ -1183,6 +1183,8 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
inline Uint32 getWidgetTextDrawHints() const {
return mKerningEnabled ? 0 : TextHints::NoKerning;
}
bool setInternalFontSize( const Float& size );
};
}} // namespace EE::UI

View File

@@ -425,6 +425,7 @@ bool FontTrueType::setFontFace( void* _face ) {
mIsColorEmojiFont = checkIsColorEmojiFont( face ); // For CBDT (COLRv0)
mHasSvgGlyphs = checkHasSvgTable( face ); // For SVG table
mHasColrGlyphs = checkHasColrTable( face ); // For COLR table (COLRv1)
mIsBitmapOnly = !FT_IS_SCALABLE( face ) && ( face->num_fixed_sizes > 0 );
mIsEmojiFont = FT_Get_Char_Index( face, 0x1F600 ) != 0;
mIsBold = face->style_flags & FT_STYLE_FLAG_BOLD;
mIsItalic = face->style_flags & FT_STYLE_FLAG_ITALIC;
@@ -1409,21 +1410,22 @@ bool FontTrueType::setCurrentSize( unsigned int characterSize ) const {
FT_UShort currentSize = face->size->metrics.x_ppem;
if ( currentSize != characterSize ) {
if ( mIsColorEmojiFont ) {
int bestMatch = 0;
int diff = eeabs( characterSize - face->available_sizes[0].width );
if ( mIsColorEmojiFont || mIsBitmapOnly ) {
int bestMatch = face->available_sizes[0].height;
int diff = eeabs( characterSize - face->available_sizes[0].height );
for ( int i = 1; i < face->num_fixed_sizes; ++i ) {
int ndiff = eeabs( characterSize - face->available_sizes[i].width );
int ndiff = eeabs( characterSize - face->available_sizes[i].height );
if ( ndiff < diff ) {
bestMatch = i;
bestMatch = face->available_sizes[i].height;
diff = ndiff;
}
}
characterSize = bestMatch;
}
FT_Error result = mIsColorEmojiFont ? FT_Select_Size( face, characterSize )
: FT_Set_Pixel_Sizes( face, 0, characterSize );
FT_Error result = mIsColorEmojiFont
? FT_Select_Size( face, characterSize )
: FT_Set_Pixel_Sizes( face, 0, characterSize );
if ( result == FT_Err_Invalid_Pixel_Size ) {
// In the case of bitmap fonts, resizing can

View File

@@ -885,6 +885,26 @@ bool Node::inParentTreeOf( Node* child ) const {
return false;
}
bool Node::inParentTreeOfType( Uint32 type ) const {
Node* node = mParentNode;
while ( NULL != node ) {
if ( node->isType( type ) )
return true;
node = node->mParentNode;
}
return false;
}
Node* Node::getParentOfType( Uint32 type ) const {
Node* node = mParentNode;
while ( NULL != node ) {
if ( node->isType( type ) )
return node;
node = node->mParentNode;
}
return nullptr;
}
void Node::setLoadingState( bool loading ) {
writeNodeFlag( NODE_FLAG_LOADING, loading ? 1 : 0 );
}

View File

@@ -624,6 +624,7 @@ UICodeEditor* UICodeEditor::setFont( Font* font ) {
if ( mFont != font ) {
mFont = font;
mFontStyleConfig.Font = mFont;
setFontSize( mFontSize );
invalidateDraw();
invalidateEditor();
onFontChanged();
@@ -767,14 +768,28 @@ void UICodeEditor::setShowIndentationGuides( bool showIndentationGuides ) {
}
}
UICodeEditor* UICodeEditor::setFontSize( const Float& size ) {
if ( mFontStyleConfig.CharacterSize != size ) {
mFontStyleConfig.CharacterSize =
eeabs( size - (int)size ) == 0.5f || (int)size == size ? size : eefloor( size );
mFontSize = mFontStyleConfig.CharacterSize;
onFontChanged();
bool UICodeEditor::setInternalFontSize( const Float& size ) {
Float initialSize = mFontStyleConfig.CharacterSize;
if ( NULL != mFontStyleConfig.Font && mFontStyleConfig.CharacterSize != size ) {
mFontStyleConfig.CharacterSize = size;
if ( !mFontStyleConfig.Font->isScalable() ) {
Float realSize = mFontStyleConfig.Font->getFontHeight( mFontStyleConfig.CharacterSize );
if ( realSize != mFontStyleConfig.CharacterSize )
mFontStyleConfig.CharacterSize = realSize;
}
}
return this;
if ( initialSize != mFontStyleConfig.CharacterSize ) {
onFontChanged();
return true;
}
return false;
}
bool UICodeEditor::setFontSize( const Float& size ) {
bool set = setInternalFontSize( size );
if ( set )
mFontSize = mFontStyleConfig.CharacterSize;
return set;
}
const Float& UICodeEditor::getFontSize() const {
@@ -3639,34 +3654,35 @@ void UICodeEditor::paste() {
}
void UICodeEditor::fontSizeGrow() {
Float line = mScroll.y / getLineHeight();
Float col = mScroll.x / getGlyphWidth();
mFontStyleConfig.CharacterSize = eemin<Float>( 96, mFontStyleConfig.CharacterSize + 1 );
onFontChanged();
updateLongestLineWidth();
setScrollY( getLineHeight() * line );
setScrollX( getGlyphWidth() * col );
invalidateDraw();
if ( setInternalFontSize( eemin<Float>( 96, mFontStyleConfig.CharacterSize + 1 ) ) ) {
Float line = mScroll.y / getLineHeight();
Float col = mScroll.x / getGlyphWidth();
updateLongestLineWidth();
setScrollY( getLineHeight() * line );
setScrollX( getGlyphWidth() * col );
invalidateDraw();
}
}
void UICodeEditor::fontSizeShrink() {
Float line = mScroll.y / getLineHeight();
Float col = mScroll.x / getGlyphWidth();
mFontStyleConfig.CharacterSize = eemax<Float>( 4, mFontStyleConfig.CharacterSize - 1 );
onFontChanged();
updateLongestLineWidth();
setScrollY( getLineHeight() * line );
setScrollX( getGlyphWidth() * col );
invalidateDraw();
if ( setInternalFontSize( eemax<Float>( 4, mFontStyleConfig.CharacterSize - 1 ) ) ) {
Float line = mScroll.y / getLineHeight();
Float col = mScroll.x / getGlyphWidth();
updateLongestLineWidth();
setScrollY( getLineHeight() * line );
setScrollX( getGlyphWidth() * col );
invalidateDraw();
}
}
void UICodeEditor::fontSizeReset() {
Float line = mScroll.y / getLineHeight();
Float col = mScroll.x / getGlyphWidth();
setFontSize( mFontSize );
updateLongestLineWidth();
setScrollY( getLineHeight() * line );
setScrollX( getGlyphWidth() * col );
if ( setInternalFontSize( mFontSize ) ) {
Float line = mScroll.y / getLineHeight();
Float col = mScroll.x / getGlyphWidth();
updateLongestLineWidth();
setScrollY( getLineHeight() * line );
setScrollX( getGlyphWidth() * col );
}
}
const bool& UICodeEditor::getShowWhitespaces() const {

View File

@@ -5,6 +5,7 @@ TextInput#search_find,
TextInput#search_replace,
TextInput#locate_find,
TextInput#global_search_find,
TextInput#global_search_where,
TextInput.small_input,
.search_str {
padding-top: 0;

View File

@@ -448,8 +448,10 @@ void App::openFontDialog( std::string& fontPath, bool loadingMonoFont, bool term
dialog->setCloseShortcut( KEY_ESCAPE );
dialog->setSingleClickNavigation( mConfig.editor.singleClickNavigation );
dialog->on( Event::OnWindowClose, [this]( const Event* ) {
if ( mSplitter && mSplitter->getCurWidget() && !SceneManager::instance()->isShuttingDown() )
if ( mSplitter && mSplitter->getCurWidget() &&
!SceneManager::instance()->isShuttingDown() ) {
mSplitter->getCurWidget()->setFocus();
}
} );
dialog->on( Event::OpenFile, [this, &fontPath, loadingMonoFont, terminalFont,
onFinish]( const Event* event ) {
@@ -487,30 +489,31 @@ void App::openFontDialog( std::string& fontPath, bool loadingMonoFont, bool term
mSplitter->forEachEditor( [fontMono]( UICodeEditor* editor ) {
editor->setFont( fontMono );
} );
if ( auto buildOutputEditor =
mUISceneNode->find<UICodeEditor>( "build_output_output" ) )
buildOutputEditor->setFont( fontMono );
if ( auto appOutputEditor =
mUISceneNode->find<UICodeEditor>( "app_output_output" ) )
appOutputEditor->setFont( fontMono );
if ( auto locateFind =
mUISceneNode->find<UITextInput>( "locate_find" ) )
locateFind->setFont( fontMono );
if ( auto globalSearchFind =
mUISceneNode->find<UITextInput>( "global_search_find" ) )
globalSearchFind->setFont( fontMono );
if ( auto globalSearchWhere =
mUISceneNode->find<UITextInput>( "global_search_where" ) )
globalSearchWhere->setFont( fontMono );
}
}
};
if ( !fontMono->isMonospace() ) {
auto* msgBox = UIMessageBox::New(
UIMessageBox::YES_NO,
i18n(
"confirm_loading_none_monospace_font",
"The editor only supports monospaced fonts and the selected font isn't "
"flagged as monospace.\nDo you want to load it anyways?\nPerformance "
"and memory usage will be awful without a monospaced font." )
.unescape() );
msgBox->on( Event::OnConfirm, [loadMonoFont, fontMono]( const Event* ) {
loadMonoFont( fontMono );
} );
msgBox->on( Event::OnDiscard, [fontMono]( const Event* ) {
FontManager::instance()->remove( fontMono );
} );
msgBox->setTitle( i18n( "confirm_loading_font", "Font loading confirmation" ) );
msgBox->center();
msgBox->showWhenReady();
} else {
loadMonoFont( fontMono );
}
loadMonoFont( fontMono );
}
}
} );

View File

@@ -1072,7 +1072,7 @@ void LinterPlugin::drawAfterLineText( UICodeEditor* editor, const Int64& index,
{ editor->getTextWidth( string, std::optional<Float>{}, TextHints::AllAscii ),
lineHeight } );
match.box[editor] = box;
line.draw( pos.x, pos.y + lineHeight * 0.5f );
line.draw( pos.x, eeceil( pos.y + lineHeight * 0.5f + editor->getLineOffset() ) );
}
if ( match.range.start().line() != match.range.end().line() )