From 395d5018bb6f1506e70840fd85cff4d59f60f46c Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 5 Aug 2026 11:57:44 +0200 Subject: [PATCH] Make tabular numbers a font option and apply it to: * Timestamp in chat history * Clock * Seen & range columns in radar --- indra/llrender/llfontfreetype.cpp | 29 ++++++++++++++----- indra/llrender/llfontfreetype.h | 10 ++++++- indra/llrender/llfontgl.cpp | 18 ++++++++++-- indra/llrender/llfontgl.h | 4 ++- indra/llrender/llfontregistry.cpp | 28 ++++++++++++++++-- indra/llrender/llfontregistry.h | 7 +++++ indra/newview/fschathistory.cpp | 10 +++---- indra/newview/fspanelradar.cpp | 14 +++++---- .../skins/default/xui/en/panel_status_bar.xml | 2 +- .../starlight/xui/en/panel_status_bar.xml | 2 +- .../starlightcui/xui/en/panel_status_bar.xml | 2 +- 11 files changed, 97 insertions(+), 29 deletions(-) diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index b45aa18a9c..78c101fff0 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -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) +// 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; // 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) + // 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) + // 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') + // 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') + // 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') + // 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); + // 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. diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index 461e064766..d04da848c1 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -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); + // 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; } + // Optional tabular numeric font rendering + bool isTabnum() const { return mTabnum; } + void setTabnum(bool value) { mTabnum = value; } + // + 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 }; // Optional tabular numeric font rendering typedef std::pair, char_functor_t> fallback_font_t; typedef std::vector fallback_font_vector_t; fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars) diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index c10dd4ae1f..10cf44a6d9 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -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) +// 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(NULL)) { mFontFreetype = new LLFontFreetype; } - return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, weight, is_fallback, face_n, hinting, flags); + // 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) + // 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(); } + // Optional tabular numeric font rendering + else if (name == "Tabnum") + { + return getFont(LLFontDescriptor("SansSerif", "Default", 0, true)); + } + // // Advanced script editor else if (name == "OCRA") { diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 2926085563..dcc278d649 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -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); + // 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; diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 321886a280..00e8eac464 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -113,6 +113,18 @@ LLFontDescriptor::LLFontDescriptor(const std::string& name, { } +// 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) +{} +// + 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 + // Optional tabular numeric font rendering + //else + // return false; + else if (mSize > b.mSize) return false; + + return mTabnum && !b.mTabnum; + // } 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()); // 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()); // 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()); // 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()); // 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)) + // 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) diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h index b70792f9aa..5cf2a69c02 100644 --- a/indra/llrender/llfontregistry.h +++ b/indra/llrender/llfontregistry.h @@ -81,6 +81,8 @@ class LLFontDescriptor public: LLFontDescriptor(); LLFontDescriptor(const std::string& name, const std::string& size, const U8 style); + // 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; } + // 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 }; // Optional tabular numeric font rendering typedef std::map> char_functor_map_t; static char_functor_map_t mCharFunctors; diff --git a/indra/newview/fschathistory.cpp b/indra/newview/fschathistory.cpp index 348930201c..bd13370ca9 100644 --- a/indra/newview/fschathistory.cpp +++ b/indra/newview/fschathistory.cpp @@ -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-1734 seperate name and text styles for moderator - if ( moderator_style_active ) - { - timestamp_style.font.style(moderator_timestamp_style); - } - // FS-1734 seperate name and text styles for moderator + appendText("[" + chat.mTimeStr + "] ", prependNewLineState, timestamp_style); prependNewLineState = false; } diff --git a/indra/newview/fspanelradar.cpp b/indra/newview/fspanelradar.cpp index 3f5b39ead3..5330ee770b 100644 --- a/indra/newview/fspanelradar.cpp +++ b/indra/newview/fspanelradar.cpp @@ -330,7 +330,8 @@ void FSPanelRadar::updateList(const std::vector& 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& 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& 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(); diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index 87a3adf86f..2b9082d0ca 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -360,7 +360,7 @@ bg_opaque_color="MouseGray">