Make tabular numbers a font option and apply it to:

* Timestamp in chat history
* Clock
* Seen & range columns in radar
This commit is contained in:
Ansariel
2026-08-05 11:57:44 +02:00
parent fd939e47ce
commit 395d5018bb
11 changed files with 97 additions and 29 deletions
+22 -7
View File
@@ -173,7 +173,9 @@ LLFontFreetype::~LLFontFreetype()
// mFallbackFonts cleaned up by LLPointer destructor
}
bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags)
// <FS:Ansariel> Optional tabular numeric font rendering
//bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags)
bool LLFontFreetype::loadFace(const std::string & filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags, bool tabnum)
{
// Don't leak face objects. This is also needed to deal with
// changed font file names.
@@ -200,6 +202,7 @@ bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
mHinting = hinting;
mFontFlags = flags;
mWeight = weight;
mTabnum = tabnum; // <FS:Ansariel> Optional tabular numeric font rendering
bool variable_font = false;
if (weight >= 0)
@@ -346,7 +349,9 @@ F32 LLFontFreetype::getXAdvance(llwchar wch) const
LLFontGlyphInfo* gi = getGlyphInfo(wch, EFontGlyphType::Unspecified);
if (gi)
{
if (wch >= '0' && wch <= '9' && mMaxDigitWidth > 0.0f)
// <FS:Ansariel> Optional tabular numeric font rendering
//if (wch >= '0' && wch <= '9' && mMaxDigitWidth > 0.0f)
if (mTabnum && wch >= '0' && wch <= '9' && mMaxDigitWidth > 0.0f)
{
return mMaxDigitWidth;
}
@@ -371,7 +376,9 @@ F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const
return 0.0;
// Use max digit width for tabular numbers
if (mWeight > 0 && glyph->mChar >= '0' && glyph->mChar <= '9' && mMaxDigitWidth > 0.0f)
// <FS:Ansariel> Optional tabular numeric font rendering
//if (mWeight > 0 && glyph->mChar >= '0' && glyph->mChar <= '9' && mMaxDigitWidth > 0.0f)
if (mTabnum && mWeight > 0 && glyph->mChar >= '0' && glyph->mChar <= '9' && mMaxDigitWidth > 0.0f)
{
return mMaxDigitWidth;
}
@@ -402,7 +409,9 @@ F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LL
if (left_glyph_info)
{
if (mWeight > 0 && left_glyph_info->mChar >= '0' && left_glyph_info->mChar <= '9')
// <FS:Ansariel> Optional tabular numeric font rendering
//if (mWeight > 0 && left_glyph_info->mChar >= '0' && left_glyph_info->mChar <= '9')
if (mTabnum && mWeight > 0 && left_glyph_info->mChar >= '0' && left_glyph_info->mChar <= '9')
{
// Disable kerning for digits when using tabular numbers
return 0.0;
@@ -411,7 +420,9 @@ F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LL
}
if (right_glyph_info)
{
if (mWeight > 0 && right_glyph_info->mChar >= '0' && right_glyph_info->mChar <= '9')
// <FS:Ansariel> Optional tabular numeric font rendering
//if (mWeight > 0 && right_glyph_info->mChar >= '0' && right_glyph_info->mChar <= '9')
if (mTabnum && mWeight > 0 && right_glyph_info->mChar >= '0' && right_glyph_info->mChar <= '9')
{
// Disable kerning for digits when using tabular numbers
return 0.0;
@@ -597,7 +608,9 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f;
gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f;
if (mWeight > 0 && wch >= '0' && wch <= '9')
// <FS:Ansariel> Optional tabular numeric font rendering
//if (mWeight > 0 && wch >= '0' && wch <= '9')
if (mTabnum && mWeight > 0 && wch >= '0' && wch <= '9')
{
// Digits are supposed to be preloaded, and buffers
// refresh when new chars get added, so this lazy load
@@ -778,7 +791,9 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, ll
void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
{
resetBitmapCache();
loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mWeight, mIsFallback, 0, mHinting, mFontFlags);
// <FS:Ansariel> Optional tabular numeric font rendering
//loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mWeight, mIsFallback, 0, mHinting, mFontFlags);
loadFace(mName, mPointSize, vert_dpi, horz_dpi, mWeight, mIsFallback, 0, mHinting, mFontFlags, mTabnum);
if (!mIsFallback)
{
// This is the head of the list - need to rebuild ourself and all fallbacks.
+9 -1
View File
@@ -105,7 +105,9 @@ public:
// is_fallback should be true for fallback fonts that aren't used
// to render directly (Unicode backup, primarily)
bool loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags);
// <FS:Ansariel> Optional tabular numeric font rendering
//bool loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags);
bool loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags, bool tabnum);
S32 getNumFaces(const std::string& filename);
@@ -152,6 +154,11 @@ public:
F32 getMaxDigitWidth() const { return mMaxDigitWidth; }
S32 getFontWeight() const { return mWeight; }
// <FS:Ansariel> Optional tabular numeric font rendering
bool isTabnum() const { return mTabnum; }
void setTabnum(bool value) { mTabnum = value; }
// </FS:Ansariel>
LLFontGlyphInfo* getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const;
void reset(F32 vert_dpi, F32 horz_dpi);
@@ -197,6 +204,7 @@ private:
EFontHinting mHinting;
S32 mFontFlags;
S32 mWeight = -1;
bool mTabnum{ false }; // <FS:Ansariel> Optional tabular numeric font rendering
typedef std::pair<LLPointer<LLFontFreetype>, char_functor_t> fallback_font_t;
typedef std::vector<fallback_font_t> fallback_font_vector_t;
fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
+15 -3
View File
@@ -90,14 +90,18 @@ void LLFontGL::destroyGL()
mFontFreetype->destroyGL();
}
bool LLFontGL::loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags)
// <FS:Ansariel> Optional tabular numeric font rendering
//bool LLFontGL::loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags)
bool LLFontGL::loadFace(const std::string & filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags, bool tabnum)
{
if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
{
mFontFreetype = new LLFontFreetype;
}
return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, weight, is_fallback, face_n, hinting, flags);
// <FS:Ansariel> Optional tabular numeric font rendering
//return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, weight, is_fallback, face_n, hinting, flags);
return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, weight, is_fallback, face_n, hinting, flags, tabnum);
}
S32 LLFontGL::getNumFaces(const std::string& filename)
@@ -348,7 +352,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
// Calculate horizontal offset for tabular numbers (center narrow digits)
F32 x_offset = 0.0f;
if (mFontFreetype->getFontWeight() > 0 && fgi->mChar >= '0' && fgi->mChar <= '9' && mFontFreetype->getMaxDigitWidth() > 0.0f)
// <FS:Ansariel> Optional tabular numeric font rendering
//if (mFontFreetype->getFontWeight() > 0 && fgi->mChar >= '0' && fgi->mChar <= '9' && mFontFreetype->getMaxDigitWidth() > 0.0f)
if (mFontFreetype->isTabnum() && mFontFreetype->getFontWeight() > 0 && fgi->mChar >= '0' && fgi->mChar <= '9' && mFontFreetype->getMaxDigitWidth() > 0.0f)
{
// use mXAdvance directly here, since we don't want to get max width instead.
x_offset = (mFontFreetype->getMaxDigitWidth() - fgi->mXAdvance) * 0.5f;
@@ -1300,6 +1306,12 @@ LLFontGL* LLFontGL::getFontByName(const std::string& name)
// Does "SMALL" mean "SERIF"?
return getFontMonospace();
}
// <FS:Ansariel> Optional tabular numeric font rendering
else if (name == "Tabnum")
{
return getFont(LLFontDescriptor("SansSerif", "Default", 0, true));
}
// </FS:Ansariel>
// <FS:CR> Advanced script editor
else if (name == "OCRA")
{
+3 -1
View File
@@ -87,7 +87,9 @@ public:
void destroyGL();
bool loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags);
// <FS:Ansariel> Optional tabular numeric font rendering
//bool loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags);
bool loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags, bool tabnum);
S32 getNumFaces(const std::string& filename);
S32 getCacheGeneration() const;
+26 -2
View File
@@ -113,6 +113,18 @@ LLFontDescriptor::LLFontDescriptor(const std::string& name,
{
}
// <FS:Ansariel> Optional tabular numeric font rendering
LLFontDescriptor::LLFontDescriptor(const std::string& name,
const std::string& size,
const U8 style,
const bool tabnum) :
mName(name),
mSize(size),
mStyle(style),
mTabnum(tabnum)
{}
// </FS:Ansariel>
bool LLFontDescriptor::operator<(const LLFontDescriptor& b) const
{
if (mName < b.mName)
@@ -127,8 +139,14 @@ bool LLFontDescriptor::operator<(const LLFontDescriptor& b) const
if (mSize < b.mSize)
return true;
else
// <FS:Ansariel> Optional tabular numeric font rendering
//else
// return false;
else if (mSize > b.mSize)
return false;
return mTabnum && !b.mTabnum;
// </FS:Ansariel>
}
static const std::string s_template_string("TEMPLATE");
@@ -519,6 +537,7 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
// First decipher the requested size.
LLFontDescriptor norm_desc = desc.normalize();
norm_desc.setTabnum(desc.isTabnum()); // <FS:Ansariel> Optional tabular numeric font rendering
F32 point_size;
bool found_size = nameToSize(norm_desc.getSize(),point_size);
if (!found_size)
@@ -532,6 +551,7 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
// Find corresponding font template (based on same descriptor with no size specified)
LLFontDescriptor template_desc(norm_desc);
template_desc.setSize(s_template_string);
template_desc.setTabnum(desc.isTabnum()); // <FS:Ansariel> Optional tabular numeric font rendering
const LLFontDescriptor *match_desc = getClosestFontTemplate(template_desc);
if (!match_desc)
{
@@ -543,6 +563,7 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
// See whether this best-match font has already been instantiated in the requested size.
LLFontDescriptor nearest_exact_desc = *match_desc;
nearest_exact_desc.setSize(norm_desc.getSize());
nearest_exact_desc.setTabnum(desc.isTabnum()); // <FS:Ansariel> Optional tabular numeric font rendering
font_reg_map_t::iterator it = mFontMap.find(nearest_exact_desc);
// If we fail to find a font in the fonts directory, it->second might be NULL.
// We shouldn't construcnt a font with a NULL mFontFreetype.
@@ -555,6 +576,7 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
LLFontGL *font = new LLFontGL;
font->mFontDescriptor = desc;
font->mFontFreetype = it->second->mFontFreetype;
font->mFontFreetype->setTabnum(desc.isTabnum()); // <FS:Ansariel> Optional tabular numeric font rendering
mFontMap[desc] = font;
return font;
@@ -639,7 +661,9 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
fontp = new LLFontGL;
}
if (fontp->loadFace(font_path, point_size_scale + font_file_it->mSizeDelta,
LLFontGL::sVertDPI, LLFontGL::sHorizDPI, font_file_it->mWeight, is_fallback, i, font_file_it->mHinting, font_file_it->mFlags))
// <FS:Ansariel> Optional tabular numeric font rendering
//LLFontGL::sVertDPI, LLFontGL::sHorizDPI, font_file_it->mWeight, is_fallback, i, font_file_it->mHinting, font_file_it->mFlags))
LLFontGL::sVertDPI, LLFontGL::sHorizDPI, font_file_it->mWeight, is_fallback, i, font_file_it->mHinting, font_file_it->mFlags, desc.isTabnum()))
{
is_font_loaded = true;
if (is_first_found)
+7
View File
@@ -81,6 +81,8 @@ class LLFontDescriptor
public:
LLFontDescriptor();
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style);
// <FS:Ansariel> Optional tabular numeric font rendering
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const bool tabnum);
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list);
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list, const font_file_info_vec_t& font_collection_list);
LLFontDescriptor normalize() const;
@@ -104,12 +106,17 @@ public:
const U8 getStyle() const { return mStyle; }
void setStyle(U8 style) { mStyle = style; }
// <FS:Ansariel> Optional tabular numeric font rendering
bool isTabnum() const { return mTabnum; }
void setTabnum(bool value) { mTabnum = value; }
private:
std::string mName;
std::string mSize;
font_file_info_vec_t mFontFiles;
font_file_info_vec_t mFontCollectionFiles;
U8 mStyle;
bool mTabnum{ false }; // <FS:Ansariel> Optional tabular numeric font rendering
typedef std::map<std::string, std::function<bool(llwchar)>> char_functor_map_t;
static char_functor_map_t mCharFunctors;
+4 -6
View File
@@ -1641,17 +1641,15 @@ void FSChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
LLUIColor timestamp_color = LLUIColorTable::instance().getColor("ChatTimestampColor");
timestamp_style.color(timestamp_color);
timestamp_style.readonly_color(timestamp_color);
LLFontDescriptor fdesc(body_message_params.font.name(), body_message_params.font.size(), moderator_style_active ? LLFontGL::getStyleFromString(moderator_timestamp_style) : LLFontGL::getStyleFromString(body_message_params.font.style()), true);
timestamp_style.font(LLFontGL::getFont(fdesc));
if (message_from_log && !is_conversation_log)
{
timestamp_style.color.alpha = FSIMChatHistoryFade;
timestamp_style.readonly_color.alpha = FSIMChatHistoryFade;
}
//<FS:HG> FS-1734 seperate name and text styles for moderator
if ( moderator_style_active )
{
timestamp_style.font.style(moderator_timestamp_style);
}
//</FS:HG> FS-1734 seperate name and text styles for moderator
appendText("[" + chat.mTimeStr + "] ", prependNewLineState, timestamp_style);
prependNewLineState = false;
}
+8 -6
View File
@@ -330,7 +330,8 @@ void FSPanelRadar::updateList(const std::vector<LLSD>& entries, const LLSD& stat
mRadarList->clearRows();
for (const auto& avdata : entries)
{
constexpr char font_name[] = "SANSSERIF_SMALL";
constexpr char default_font[] = "SANSSERIF_SMALL";
constexpr char tabnum_font[] = "Tabnum";
LLSD entry = avdata["entry"];
LLSD options = avdata["options"];
@@ -339,12 +340,12 @@ void FSPanelRadar::updateList(const std::vector<LLSD>& entries, const LLSD& stat
row_data["value"] = entry["id"];
row_data["columns"][0]["column"] = "name";
row_data["columns"][0]["value"] = entry["name"];
row_data["columns"][0]["font"] = font_name;
row_data["columns"][0]["font"] = default_font;
row_data["columns"][1]["column"] = "voice_level";
row_data["columns"][1]["type"] = "icon";
row_data["columns"][1]["value"] = ""; // Need to set it after the row has been created because it's to big for the row
row_data["columns"][1]["font"] = font_name;
row_data["columns"][1]["font"] = default_font;
row_data["columns"][2]["column"] = "in_region";
row_data["columns"][2]["type"] = "icon";
@@ -380,16 +381,17 @@ void FSPanelRadar::updateList(const std::vector<LLSD>& entries, const LLSD& stat
row_data["columns"][7]["column"] = "age";
row_data["columns"][7]["value"] = entry["age"];
row_data["columns"][7]["halign"] = "right";
row_data["columns"][7]["font"] = font_name;
row_data["columns"][7]["font"] = default_font;
row_data["columns"][8]["column"] = "seen";
row_data["columns"][8]["value"] = entry["seen"];
row_data["columns"][8]["halign"] = "right";
row_data["columns"][8]["font"] = font_name;
row_data["columns"][8]["font"] = tabnum_font;
row_data["columns"][9]["column"] = "range";
row_data["columns"][9]["value"] = entry["range"];
row_data["columns"][9]["font"] = font_name;
row_data["columns"][9]["halign"] = "right";
row_data["columns"][9]["font"] = tabnum_font;
row_data["columns"][10]["column"] = "seen_sort";
row_data["columns"][10]["value"] = entry["seen"].asString() + "_" + entry["name"].asString();
@@ -360,7 +360,7 @@
bg_opaque_color="MouseGray">
<text
type="string"
font="SansSerifSmall"
font="Tabnum"
text_color="TimeTextColor"
follows="right|top"
halign="center"
@@ -383,7 +383,7 @@
<text
type="string"
font="SansSerifSmall"
font="Tabnum"
text_color="TimeTextColor"
follows="right|top"
halign="center"
@@ -379,7 +379,7 @@
<text
type="string"
font="SansSerifSmall"
font="Tabnum"
text_color="TimeTextColor"
follows="right|top"
halign="center"