Skip to content

Commit f39d271

Browse files
author
Akash Pradhan
committed
Implement auto-scaling of fonts for ImGui backend
1 parent b0727d2 commit f39d271

8 files changed

+130
-92
lines changed

imrichtext.cpp

+22-22
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ namespace ImRichText
593593
StyleDescriptor result;
594594
result.font.family = config.DefaultFontFamily;
595595
result.font.size = config.DefaultFontSize * config.FontScale;
596-
result.font.font = GetFont(result.font.family, result.font.size, FT_Normal, config.UserData);
596+
result.font.font = GetFont(result.font.family, result.font.size, FT_Normal);
597597
result.fgcolor = config.DefaultFgColor;
598598
result.list.itemStyle = config.ListItemBullet;
599599
return result;
@@ -631,7 +631,7 @@ namespace ImRichText
631631
{
632632
auto width = bounds.x;
633633
width = (style.propsSpecified & StyleWidth) != 0 ? std::min(width, style.width) : width;
634-
auto sz = config.Renderer->EllipsisWidth(style.font.font);
634+
auto sz = config.Renderer->EllipsisWidth(style.font.font, style.font.size);
635635
width -= sz;
636636

637637
if ((style.font.flags & FontStyleOverflowEllipsis) != 0 && width > 0.f)
@@ -653,7 +653,7 @@ namespace ImRichText
653653
while (startx > width)
654654
{
655655
auto partial = token.Content.substr(revidx, 1);
656-
startx -= config.Renderer->GetTextSize(partial, style.font.font).x;
656+
startx -= config.Renderer->GetTextSize(partial, style.font.font, style.font.size).x;
657657
token.VisibleTextSize -= (int16_t)1;
658658
--revidx;
659659
}
@@ -909,8 +909,7 @@ namespace ImRichText
909909
else if ((style.font.flags & FontStyleBold) != 0) fstyle = FT_Bold;
910910
else if ((style.font.flags & FontStyleItalics) != 0) fstyle = FT_Italics;
911911
else if ((style.font.flags & FontStyleLight) != 0) fstyle = FT_Light;
912-
style.font.font = GetFont(style.font.family, style.font.size,
913-
fstyle, config.UserData);
912+
style.font.font = GetFont(style.font.family, style.font.size, fstyle);
914913
}
915914
}
916915

@@ -1348,7 +1347,7 @@ namespace ImRichText
13481347

13491348
if (token.Type == TokenType::ElidedText)
13501349
{
1351-
auto ewidth = config.Renderer->EllipsisWidth(style.font.font);
1350+
auto ewidth = config.Renderer->EllipsisWidth(style.font.font, style.font.size);
13521351
config.Renderer->DrawText("...", ImVec2{ startpos.x + token.Bounds.width - ewidth, startpos.y }, style.fgcolor);
13531352
}
13541353

@@ -1408,7 +1407,7 @@ namespace ImRichText
14081407

14091408
if (style.font.font != nullptr)
14101409
{
1411-
popFont = config.Renderer->SetCurrentFont(style.font.font);
1410+
popFont = config.Renderer->SetCurrentFont(style.font.font, style.font.size);
14121411
}
14131412

14141413
auto drawTokens = true;
@@ -1598,7 +1597,7 @@ namespace ImRichText
15981597

15991598
if (token.Type == TokenType::Text)
16001599
{
1601-
auto sz = _config.Renderer->GetTextSize(token.Content, style.font.font);
1600+
auto sz = _config.Renderer->GetTextSize(token.Content, style.font.font, style.font.size);
16021601
token.VisibleTextSize = (int16_t)token.Content.size();
16031602
token.Bounds.width = sz.x;
16041603
token.Bounds.height = sz.y;
@@ -1641,7 +1640,7 @@ namespace ImRichText
16411640
}
16421641

16431642
std::string_view input{ listItem.NestedListItemIndex, (size_t)currbuf };
1644-
auto sz = _config.Renderer->GetTextSize(input, style.font.font);
1643+
auto sz = _config.Renderer->GetTextSize(input, style.font.font, style.font.size);
16451644
token.Bounds.width = sz.x;
16461645
token.Bounds.height = sz.y;
16471646
}
@@ -1765,7 +1764,7 @@ namespace ImRichText
17651764
[](int wordIdx, void* userdata) {
17661765
const auto& data = *reinterpret_cast<UserData*>(userdata);
17671766
const auto& style = data.styles[data.tokenIndexes[wordIdx].styleIdx + 1];
1768-
return ITextShaper::WordProperty{ style.font.font, style.wbbhv };
1767+
return ITextShaper::WordProperty{ style.font.font, style.font.size, style.wbbhv };
17691768
},
17701769
[](int wordIdx, void* userdata) {
17711770
const auto& data = *reinterpret_cast<UserData*>(userdata);
@@ -2039,6 +2038,7 @@ namespace ImRichText
20392038
std::pair<int, int> linesModified;
20402039
_result.ForegroundLines.emplace_back(_currLine);
20412040
auto lineIdx = (int)_result.ForegroundLines.size() - 1;
2041+
const auto& style = _result.StyleDescriptors[_currStyleIdx + 1];
20422042

20432043
if (_currLine.Segments.size() == 1u && _currLine.Segments.front().Tokens.size() == 1u &&
20442044
_currLine.Segments.front().Tokens.front().Type == TokenType::HorizontalRule)
@@ -2049,9 +2049,10 @@ namespace ImRichText
20492049
{
20502050
linesModified = std::make_pair(lineIdx, 1);
20512051
UpdateLineGeometry(linesModified, depth);
2052+
auto xwidth = _currStyle.propsSpecified & StyleWidth ? _currStyle.width : _bounds.x;
20522053

2053-
if (!_currLine.Marquee && _bounds.x > 0.f && (_result.StyleDescriptors[_currStyleIdx + 1].font.flags & FontStyleNoWrap) == 0 &&
2054-
_result.ForegroundLines.back().width() > _bounds.x)
2054+
if (!_currLine.Marquee && xwidth > 0.f && (style.font.flags & FontStyleNoWrap) == 0 &&
2055+
_result.ForegroundLines.back().width() > xwidth)
20552056
{
20562057
auto remapping = PerformWordWrap(lineIdx);
20572058
UpdateBackgroundSpan(depth, lineIdx, remapping);
@@ -2073,7 +2074,6 @@ namespace ImRichText
20732074
else if (_currBlockquoteDepth < lastline.BlockquoteDepth) lastline.Offset.bottom = _config.BlockquotePadding;
20742075

20752076
UpdateLineGeometry(linesModified, depth);
2076-
const auto& style = _result.StyleDescriptors[_currStyleIdx + 1];
20772077
CreateElidedTextToken(_result.ForegroundLines.back(), style, _config, _bounds);
20782078

20792079
newline.Content.left = ((float)(_currListDepth + 1) * _config.ListItemIndent) +
@@ -2213,14 +2213,14 @@ namespace ImRichText
22132213
_currStyle = _result.StyleDescriptors[_currStyleIdx + 1];
22142214
if ((_currentStackPos - 1) < IM_RICHTEXT_MAXDEPTH) _styleIndexStack[_currentStackPos + 1] = -2;
22152215

2216-
if (_currTagType != TagType::LineBreak)
2217-
{
2218-
// This reset is necessary as we are popping the style, and CreateNewStyle will create
2219-
// a new style instead if not unset
2220-
// TODO: Restore this value once popping is done
2221-
_currStyle.propsSpecified = 0;
2222-
_currStyle.superscriptOffset = _currStyle.subscriptOffset = 0.f;
2223-
}
2216+
//if (_currTagType != TagType::LineBreak)
2217+
//{
2218+
// // This reset is necessary as we are popping the style, and CreateNewStyle will create
2219+
// // a new style instead if not unset
2220+
// // TODO: Restore this value once popping is done
2221+
// _currStyle.propsSpecified = 0;
2222+
// _currStyle.superscriptOffset = _currStyle.subscriptOffset = 0.f;
2223+
//}
22242224
}
22252225

22262226
bool DefaultTagVisitor::TagStart(std::string_view tag)
@@ -2292,7 +2292,7 @@ namespace ImRichText
22922292
if (_currTagType == TagType::Paragraph && _config.ParagraphStop > 0)
22932293
_currLine.Offset.left += _config.Renderer->GetTextSize(std::string_view{ LineSpaces,
22942294
(std::size_t)std::min(_config.ParagraphStop, IM_RICHTEXT_MAXTABSTOP) },
2295-
currentStyle.font.font).x;
2295+
currentStyle.font.font, currentStyle.font.size).x;
22962296
else if (_currTagType == TagType::ListItem)
22972297
{
22982298
_listItemCountByDepths[_currListDepth]++;

imrichtext.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ namespace ImRichText
198198

199199
struct DrawableBlock
200200
{
201-
ImVec2 Start{ -1.f, -1.f }, End{ -1.f, -1.f };
201+
ImVec2 Start{ -1.f, -1.f }, End{ -1.f, -1.f }, ViewportPos{ 0.f, 0.f };
202202
uint32_t Color = IM_COL32_BLACK_TRANS;
203203
FourSidedMeasure padding;
204204
FourSidedMeasure margin;

imrichtextfont.cpp

+45-33
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ namespace ImFontManager
108108
BLFontFace FontFace[FT_Total];
109109
#endif
110110
FontCollectionFile Files;
111+
bool AutoScale = false;
111112
};
112113

113114
struct FontMatchInfo
@@ -170,12 +171,13 @@ namespace ImFontManager
170171
}
171172
}
172173

173-
bool LoadFonts(std::string_view family, const FontCollectionFile& files, float size, ImFontConfig config)
174+
bool LoadFonts(std::string_view family, const FontCollectionFile& files, float size, ImFontConfig config, bool autoScale)
174175
{
175176
ImGuiIO& io = ImGui::GetIO();
176177
FontStore[family].Files = files;
177178

178179
auto& ffamily = FontStore[family];
180+
ffamily.AutoScale = autoScale;
179181
LoadFont(io, ffamily, FT_Normal, size, config, 0);
180182

181183
#ifdef IMGUI_ENABLE_FREETYPE
@@ -234,10 +236,10 @@ namespace ImFontManager
234236
#endif
235237

236238
#ifdef IM_RICHTEXT_TARGET_IMGUI
237-
static void LoadDefaultProportionalFont(float sz, const ImFontConfig& fconfig)
239+
static void LoadDefaultProportionalFont(float sz, const ImFontConfig& fconfig, bool autoScale)
238240
{
239241
#ifdef _WIN32
240-
LoadFonts(IM_RICHTEXT_DEFAULT_FONTFAMILY, { WINDOWS_DEFAULT_FONT }, sz, fconfig);
242+
LoadFonts(IM_RICHTEXT_DEFAULT_FONTFAMILY, { WINDOWS_DEFAULT_FONT }, sz, fconfig, autoScale);
241243
#elif __linux__
242244
std::filesystem::path fedoradir = "/usr/share/fonts/open-sans";
243245
std::filesystem::path ubuntudir = "/usr/share/fonts/truetype/freefont";
@@ -250,10 +252,10 @@ namespace ImFontManager
250252
// TODO: Add default fonts for other platforms
251253
}
252254

253-
static void LoadDefaultMonospaceFont(float sz, const ImFontConfig& fconfig)
255+
static void LoadDefaultMonospaceFont(float sz, const ImFontConfig& fconfig, bool autoScale)
254256
{
255257
#ifdef _WIN32
256-
LoadFonts(IM_RICHTEXT_MONOSPACE_FONTFAMILY, { WINDOWS_DEFAULT_MONOFONT }, sz, fconfig);
258+
LoadFonts(IM_RICHTEXT_MONOSPACE_FONTFAMILY, { WINDOWS_DEFAULT_MONOFONT }, sz, fconfig, autoScale);
257259
#elif __linux__
258260
std::filesystem::path fedoradir = "/usr/share/fonts/liberation-mono";
259261
std::filesystem::path ubuntudir = "/usr/share/fonts/truetype/freefont";
@@ -305,7 +307,8 @@ namespace ImFontManager
305307
using ImWchar = uint32_t;
306308
#endif
307309

308-
static bool LoadDefaultFonts(float sz, const FontFileNames* names, bool skipProportional, bool skipMonospace, const ImWchar* glyphs)
310+
static bool LoadDefaultFonts(float sz, const FontFileNames* names, bool skipProportional, bool skipMonospace,
311+
bool autoScale, const ImWchar* glyphs)
309312
{
310313
#ifdef IM_RICHTEXT_TARGET_IMGUI
311314
ImFontConfig fconfig;
@@ -328,8 +331,8 @@ namespace ImFontManager
328331
if (names == nullptr)
329332
{
330333
#ifdef IM_RICHTEXT_TARGET_IMGUI
331-
if (!skipProportional) LoadDefaultProportionalFont(sz, fconfig);
332-
if (!skipMonospace) LoadDefaultMonospaceFont(sz, fconfig);
334+
if (!skipProportional) LoadDefaultProportionalFont(sz, fconfig, autoScale);
335+
if (!skipMonospace) LoadDefaultMonospaceFont(sz, fconfig, autoScale);
333336
#endif
334337
#ifdef IM_RICHTEXT_TARGET_BLEND2D
335338
if (!skipProportional) LoadDefaultProportionalFont(sz);
@@ -367,7 +370,7 @@ namespace ImFontManager
367370
files.Files[FT_Italics] = copyFileName(names->Proportional.Files[FT_Italics], baseFontPath, startidx);
368371
files.Files[FT_BoldItalics] = copyFileName(names->Proportional.Files[FT_BoldItalics], baseFontPath, startidx);
369372
#ifdef IM_RICHTEXT_TARGET_IMGUI
370-
LoadFonts(IM_RICHTEXT_DEFAULT_FONTFAMILY, files, sz, fconfig);
373+
LoadFonts(IM_RICHTEXT_DEFAULT_FONTFAMILY, files, sz, fconfig, autoScale);
371374
#endif
372375
#ifdef IM_RICHTEXT_TARGET_BLEND2D
373376
LoadFonts(IM_RICHTEXT_DEFAULT_FONTFAMILY, files, sz);
@@ -376,7 +379,7 @@ namespace ImFontManager
376379
else
377380
{
378381
#ifdef IM_RICHTEXT_TARGET_IMGUI
379-
if (!skipProportional) LoadDefaultProportionalFont(sz, fconfig);
382+
if (!skipProportional) LoadDefaultProportionalFont(sz, fconfig, autoScale);
380383
#endif
381384
#ifdef IM_RICHTEXT_TARGET_BLEND2D
382385
if (!skipProportional) LoadDefaultProportionalFont(sz);
@@ -390,7 +393,7 @@ namespace ImFontManager
390393
files.Files[FT_Italics] = copyFileName(names->Monospace.Files[FT_Italics], baseFontPath, startidx);
391394
files.Files[FT_BoldItalics] = copyFileName(names->Monospace.Files[FT_BoldItalics], baseFontPath, startidx);
392395
#ifdef IM_RICHTEXT_TARGET_IMGUI
393-
LoadFonts(IM_RICHTEXT_MONOSPACE_FONTFAMILY, files, sz, fconfig);
396+
LoadFonts(IM_RICHTEXT_MONOSPACE_FONTFAMILY, files, sz, fconfig, autoScale);
394397
#endif
395398
#ifdef IM_RICHTEXT_TARGET_BLEND2D
396399
LoadFonts(IM_RICHTEXT_MONOSPACE_FONTFAMILY, files, sz);
@@ -399,7 +402,7 @@ namespace ImFontManager
399402
else
400403
{
401404
#ifdef IM_RICHTEXT_TARGET_IMGUI
402-
if (!skipMonospace) LoadDefaultMonospaceFont(sz, fconfig);
405+
if (!skipMonospace) LoadDefaultMonospaceFont(sz, fconfig, autoScale);
403406
#endif
404407
#ifdef IM_RICHTEXT_TARGET_BLEND2D
405408
if (!skipMonospace) LoadDefaultMonospaceFont(sz);
@@ -439,7 +442,8 @@ namespace ImFontManager
439442

440443
for (auto sz : sizes)
441444
{
442-
LoadDefaultFonts(sz, names, !(flt & FLT_Proportional), !(flt & FLT_Monospace), glyphrange);
445+
LoadDefaultFonts(sz, names, !(flt & FLT_Proportional), !(flt & FLT_Monospace),
446+
flt & FLT_AutoScale, glyphrange);
443447
}
444448

445449
#ifdef IM_RICHTEXT_TARGET_IMGUI
@@ -451,21 +455,22 @@ namespace ImFontManager
451455
#ifndef IM_FONTMANAGER_STANDALONE
452456
std::vector<float> GetFontSizes(const RenderConfig& config, uint64_t flt)
453457
{
454-
std::unordered_set<float> sizes;
455-
sizes.insert(config.DefaultFontSize * config.FontScale);
456-
457-
if (flt & FLT_HasSubscript) sizes.insert(config.DefaultFontSize * config.ScaleSubscript * config.FontScale);
458-
if (flt & FLT_HasSuperscript) sizes.insert(config.DefaultFontSize * config.ScaleSuperscript * config.FontScale);
459-
if (flt & FLT_HasSmall) sizes.insert(config.DefaultFontSize * 0.8f * config.FontScale);
460-
if (flt & FLT_HasH1) sizes.insert(config.HFontSizes[0] * config.FontScale);
461-
if (flt & FLT_HasH2) sizes.insert(config.HFontSizes[1] * config.FontScale);
462-
if (flt & FLT_HasH3) sizes.insert(config.HFontSizes[2] * config.FontScale);
463-
if (flt & FLT_HasH4) sizes.insert(config.HFontSizes[3] * config.FontScale);
464-
if (flt & FLT_HasH5) sizes.insert(config.HFontSizes[4] * config.FontScale);
465-
if (flt & FLT_HasH6) sizes.insert(config.HFontSizes[5] * config.FontScale);
466-
if (flt & FLT_HasHeaders) for (auto sz : config.HFontSizes) sizes.insert(sz * config.FontScale);
467-
468-
return std::vector<float>{ sizes.begin(), sizes.end() };
458+
std::vector<float> sizes;
459+
sizes.push_back(config.DefaultFontSize * config.FontScale);
460+
461+
if (flt & FLT_HasSubscript) sizes.push_back(config.DefaultFontSize * config.ScaleSubscript * config.FontScale);
462+
if (flt & FLT_HasSuperscript) sizes.push_back(config.DefaultFontSize * config.ScaleSuperscript * config.FontScale);
463+
if (flt & FLT_HasSmall) sizes.push_back(config.DefaultFontSize * 0.8f * config.FontScale);
464+
if (flt & FLT_HasH1) sizes.push_back(config.HFontSizes[0] * config.FontScale);
465+
if (flt & FLT_HasH2) sizes.push_back(config.HFontSizes[1] * config.FontScale);
466+
if (flt & FLT_HasH3) sizes.push_back(config.HFontSizes[2] * config.FontScale);
467+
if (flt & FLT_HasH4) sizes.push_back(config.HFontSizes[3] * config.FontScale);
468+
if (flt & FLT_HasH5) sizes.push_back(config.HFontSizes[4] * config.FontScale);
469+
if (flt & FLT_HasH6) sizes.push_back(config.HFontSizes[5] * config.FontScale);
470+
if (flt & FLT_HasHeaders) for (auto sz : config.HFontSizes) sizes.push_back(sz * config.FontScale);
471+
std::sort(sizes.begin(), sizes.end());
472+
473+
return (flt & FLT_AutoScale) ? std::vector<float>{ *(--sizes.end()) } : sizes;
469474
}
470475
#endif
471476

@@ -904,7 +909,7 @@ namespace ImFontManager
904909
{
905910
for (const auto& entry : std::filesystem::directory_iterator{ path })
906911
{
907-
if (entry.is_regular_file() && entry.path().extension() == ".TTF")
912+
if (entry.is_regular_file() && entry.path().extension() == ".ttf")
908913
{
909914
ProcessFileEntry(entry, false);
910915

@@ -968,16 +973,23 @@ namespace ImFontManager
968973
return famit;
969974
}
970975

971-
void* GetFont(std::string_view family, float size, FontType ft, void*)
976+
void* GetFont(std::string_view family, float size, FontType ft)
972977
{
973978
auto famit = LookupFontFamily(family);
974979
const auto& fonts = famit->second.FontPtrs[ft];
975980
auto szit = fonts.find(size);
976981

977982
if (szit == fonts.end() && !fonts.empty())
978983
{
979-
szit = fonts.lower_bound(size);
980-
szit = szit == fonts.begin() ? szit : std::prev(szit);
984+
if (famit->second.AutoScale)
985+
{
986+
return fonts.begin()->second;
987+
}
988+
else
989+
{
990+
szit = fonts.lower_bound(size);
991+
szit = szit == fonts.begin() ? szit : std::prev(szit);
992+
}
981993
}
982994

983995
return szit->second;
@@ -1004,7 +1016,7 @@ namespace ImFontManager
10041016
PreloadFontLookupInfoImpl(timeoutMs, nullptr, 0);
10051017
}
10061018

1007-
void* GetFont(std::string_view family, float size, FontType type, FontExtraInfo extra, void*)
1019+
void* GetFont(std::string_view family, float size, FontType type, FontExtraInfo extra)
10081020
{
10091021
auto famit = FontStore.find(family);
10101022

imrichtextfont.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ namespace ImFontManager
5656
{
5757
FLT_Proportional = 1,
5858
FLT_Monospace = 2,
59+
5960
FLT_HasSmall = 4,
6061
FLT_HasSuperscript = 8,
6162
FLT_HasSubscript = 16,
@@ -65,6 +66,12 @@ namespace ImFontManager
6566
FLT_HasH4 = 256,
6667
FLT_HasH5 = 512,
6768
FLT_HasH6 = 1024,
69+
70+
// Use this to auto-scale fonts, loading the largest size for a family
71+
// NOTE: For ImGui backend, this will save on memory from texture
72+
FLT_AutoScale = 2048,
73+
74+
// Include all <h*> tags
6875
FLT_HasHeaders = FLT_HasH1 | FLT_HasH2 | FLT_HasH3 | FLT_HasH4 | FLT_HasH5 | FLT_HasH6,
6976

7077
// TODO: Handle absolute size font-size fonts (Look at imrichtext.cpp: PopulateSegmentStyle function)
@@ -109,7 +116,7 @@ namespace ImFontManager
109116
// ImFont* cast to void* to better fit overall library.
110117
// NOTE: size matching happens with lower_bound calls, this is done because all fonts
111118
// should be preloaded for ImGui, dynamic font atlas updates are not supported.
112-
[[nodiscard]] void* GetFont(std::string_view family, float size, FontType type, void*);
119+
[[nodiscard]] void* GetFont(std::string_view family, float size, FontType type);
113120

114121
#ifndef IM_FONTMANAGER_STANDALONE
115122
// Get font to display overlay i.e. style info in side panel
@@ -131,6 +138,6 @@ namespace ImFontManager
131138
// BLFont* cast to void* to better fit overall library.
132139
// NOTE: The FontExtraInfo::mapper can be assigned to a function which loads fonts based
133140
// con content codepoints and can perform better fallback.
134-
[[nodiscard]] void* GetFont(std::string_view family, float size, FontType type, FontExtraInfo extra, void*);
141+
[[nodiscard]] void* GetFont(std::string_view family, float size, FontType type, FontExtraInfo extra);
135142
#endif
136143
}

0 commit comments

Comments
 (0)