summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authorKitty Barnett <develop@catznip.com>2019-11-07 17:15:21 +0100
committerKitty Barnett <develop@catznip.com>2019-11-07 17:15:21 +0100
commit5a6ddb2ea666e895890d3cb690cce5101cf12652 (patch)
tree451cac9c7912f9f1997ecee9dd5dac58f01d6b18 /indra/llrender
parent418308bc7ce4e9924d6280f784222ba45172eea4 (diff)
Fallback fonts can have first crack at adding an unknown character + set Twemoji as the viewer's fallback for all emoji blocks
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/llfontfreetype.cpp42
-rw-r--r--indra/llrender/llfontfreetype.h12
-rw-r--r--indra/llrender/llfontgl.cpp4
-rw-r--r--indra/llrender/llfontgl.h2
-rw-r--r--indra/llrender/llfontregistry.cpp150
-rw-r--r--indra/llrender/llfontregistry.h42
6 files changed, 151 insertions, 101 deletions
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index 7d66965e57..25740a5f87 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -175,7 +175,7 @@ void ft_close_cb(FT_Stream stream) {
}
#endif
-BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool use_color, bool is_fallback, S32 face_n)
+BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n)
{
// Don't leak face objects. This is also needed to deal with
// changed font file names.
@@ -345,14 +345,11 @@ void LLFontFreetype::clearFontStreams()
}
#endif
-void LLFontFreetype::setFallbackFonts(const font_vector_t &font)
+void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor)
{
- mFallbackFonts = font;
-}
-
-const LLFontFreetype::font_vector_t &LLFontFreetype::getFallbackFonts() const
-{
- return mFallbackFonts;
+ // Insert functor fallbacks before generic fallbacks
+ mFallbackFonts.insert((functor) ? std::find_if(mFallbackFonts.begin(), mFallbackFonts.end(), [](const fallback_font_t& fe) { return !fe.second; }) : mFallbackFonts.end(),
+ std::make_pair(fallback_font, functor));
}
F32 LLFontFreetype::getLineHeight() const
@@ -453,18 +450,31 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type
FT_UInt glyph_index;
+ // Fallback fonts with a functor have precedence over everything else
+ fallback_font_vector_t::const_iterator it_fallback = mFallbackFonts.cbegin();
+ for (; it_fallback != mFallbackFonts.cend() && it_fallback->second; ++it_fallback)
+ {
+ if (it_fallback->second(wch))
+ {
+ glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch);
+ if (glyph_index)
+ {
+ return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type);
+ }
+ }
+ }
+
// Initialize char to glyph map
glyph_index = FT_Get_Char_Index(mFTFace, wch);
if (glyph_index == 0)
{
//LL_INFOS() << "Trying to add glyph from fallback font!" << LL_ENDL;
- font_vector_t::const_iterator iter;
- for(iter = mFallbackFonts.begin(); iter != mFallbackFonts.end(); iter++)
+ for (; it_fallback != mFallbackFonts.cend(); ++it_fallback)
{
- glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
+ glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch);
if (glyph_index)
{
- return addGlyphFromFont(*iter, wch, glyph_index, glyph_type);
+ return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type);
}
}
}
@@ -653,7 +663,7 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) co
void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
{
resetBitmapCache();
- loadFace(mName, mPointSize, vert_dpi ,horz_dpi, true, mIsFallback, 0);
+ loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0);
if (!mIsFallback)
{
// This is the head of the list - need to rebuild ourself and all fallbacks.
@@ -663,11 +673,9 @@ void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
}
else
{
- for(font_vector_t::iterator it = mFallbackFonts.begin();
- it != mFallbackFonts.end();
- ++it)
+ for (fallback_font_vector_t::iterator it = mFallbackFonts.begin(); it != mFallbackFonts.end(); ++it)
{
- (*it)->reset(vert_dpi, horz_dpi);
+ it->first->reset(vert_dpi, horz_dpi);
}
}
}
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index 8c2d2bc491..8afc5e3ed5 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -86,7 +86,7 @@ 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, bool use_color, bool is_fallback, S32 face_n);
+ BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n);
S32 getNumFaces(const std::string& filename);
@@ -95,10 +95,8 @@ public:
void clearFontStreams();
#endif
- typedef std::vector<LLPointer<LLFontFreetype> > font_vector_t;
-
- void setFallbackFonts(const font_vector_t &font);
- const font_vector_t &getFallbackFonts() const;
+ typedef std::function<bool(llwchar)> char_functor_t;
+ void addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor = nullptr);
// Global font metrics - in units of pixels
F32 getLineHeight() const;
@@ -178,7 +176,9 @@ private:
#endif
BOOL mIsFallback;
- font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
+ 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)
// *NOTE: the same glyph can be present with multiple representations (but the pointer is always unique)
typedef boost::unordered_multimap<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 78017ecb3d..4770f79395 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -89,14 +89,14 @@ void LLFontGL::destroyGL()
mFontFreetype->destroyGL();
}
-BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool use_color, bool is_fallback, S32 face_n)
+BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n)
{
if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
{
mFontFreetype = new LLFontFreetype;
}
- return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, use_color, is_fallback, face_n);
+ return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, is_fallback, face_n);
}
S32 LLFontGL::getNumFaces(const std::string& filename)
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 68bf5db668..a60feb87cb 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -87,7 +87,7 @@ public:
void destroyGL();
- BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool use_color, bool is_fallback, S32 face_n);
+ BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n);
S32 getNumFaces(const std::string& filename);
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
index 426b10b016..ac2b695a3e 100644
--- a/indra/llrender/llfontregistry.cpp
+++ b/indra/llrender/llfontregistry.cpp
@@ -46,6 +46,10 @@ bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node);
const std::string MACOSX_FONT_PATH_LIBRARY = "/Library/Fonts/";
+LLFontDescriptor::char_functor_map_t LLFontDescriptor::mCharFunctors({
+ { "is_emoji", LLStringOps::isEmoji }
+});
+
LLFontDescriptor::LLFontDescriptor():
mStyle(0)
{
@@ -54,22 +58,22 @@ LLFontDescriptor::LLFontDescriptor():
LLFontDescriptor::LLFontDescriptor(const std::string& name,
const std::string& size,
const U8 style,
- const string_vec_t& file_names):
+ const font_file_info_vec_t& font_files):
mName(name),
mSize(size),
mStyle(style),
- mFileNames(file_names)
+ mFontFiles(font_files)
{
}
LLFontDescriptor::LLFontDescriptor(const std::string& name,
const std::string& size,
const U8 style,
- const string_vec_t& file_names,
- const string_vec_t& ft_collection_listections) :
- LLFontDescriptor(name, size, style, file_names)
+ const font_file_info_vec_t& font_list,
+ const font_file_info_vec_t& font_collection_files) :
+ LLFontDescriptor(name, size, style, font_list)
{
- mFontCollectionsList = ft_collection_listections;
+ mFontCollectionFiles = font_collection_files;
}
LLFontDescriptor::LLFontDescriptor(const std::string& name,
@@ -81,7 +85,6 @@ LLFontDescriptor::LLFontDescriptor(const std::string& name,
{
}
-
bool LLFontDescriptor::operator<(const LLFontDescriptor& b) const
{
if (mName < b.mName)
@@ -174,7 +177,19 @@ LLFontDescriptor LLFontDescriptor::normalize() const
if (removeSubString(new_name,"Italic"))
new_style |= LLFontGL::ITALIC;
- return LLFontDescriptor(new_name,new_size,new_style,getFileNames(),getFontCollectionsList());
+ return LLFontDescriptor(new_name,new_size,new_style, getFontFiles(), getFontCollectionFiles());
+}
+
+void LLFontDescriptor::addFontFile(const std::string& file_name, const std::string& char_functor)
+{
+ char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor);
+ mFontFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr));
+}
+
+void LLFontDescriptor::addFontCollectionFile(const std::string& file_name, const std::string& char_functor)
+{
+ char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor);
+ mFontCollectionFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr));
}
LLFontRegistry::LLFontRegistry(bool create_gl_textures)
@@ -272,17 +287,24 @@ bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc)
if (child->hasName("file"))
{
std::string font_file_name = child->getTextContents();
- desc.getFileNames().push_back(font_file_name);
-
+ std::string char_functor;
+
+ if (child->hasAttribute("functor"))
+ {
+ child->getAttributeString("functor", char_functor);
+ }
+
if (child->hasAttribute("load_collection"))
{
BOOL col = FALSE;
child->getAttributeBOOL("load_collection", col);
if (col)
{
- desc.getFontCollectionsList().push_back(font_file_name);
+ desc.addFontCollectionFile(font_file_name, char_functor);
}
}
+
+ desc.addFontFile(font_file_name, char_functor);
}
else if (child->hasName("os"))
{
@@ -325,19 +347,19 @@ bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node)
// A little roundabout because the map key is const,
// so we have to fetch it, make a new map key, and
// replace the old entry.
- string_vec_t match_file_names = match_desc->getFileNames();
- match_file_names.insert(match_file_names.begin(),
- desc.getFileNames().begin(),
- desc.getFileNames().end());
+ font_file_info_vec_t font_files = match_desc->getFontFiles();
+ font_files.insert(font_files.begin(),
+ desc.getFontFiles().begin(),
+ desc.getFontFiles().end());
- string_vec_t collections_list = match_desc->getFontCollectionsList();
- collections_list.insert(collections_list.begin(),
- desc.getFontCollectionsList().begin(),
- desc.getFontCollectionsList().end());
+ font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles();
+ font_collection_files.insert(font_collection_files.begin(),
+ desc.getFontCollectionFiles().begin(),
+ desc.getFontCollectionFiles().end());
LLFontDescriptor new_desc = *match_desc;
- new_desc.getFileNames() = match_file_names;
- new_desc.getFontCollectionsList() = collections_list;
+ new_desc.setFontFiles(font_files);
+ new_desc.setFontCollectionFiles(font_collection_files);
registry->mFontMap.erase(*match_desc);
registry->mFontMap[new_desc] = NULL;
}
@@ -422,80 +444,78 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
// Build list of font names to look for.
// Files specified for this font come first, followed by those from the default descriptor.
- string_vec_t file_names = match_desc->getFileNames();
- string_vec_t ft_collection_list = match_desc->getFontCollectionsList();
- string_vec_t default_file_names;
+ font_file_info_vec_t font_files = match_desc->getFontFiles();
+ font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles();
LLFontDescriptor default_desc("default",s_template_string,0);
const LLFontDescriptor *match_default_desc = getMatchingFontDesc(default_desc);
if (match_default_desc)
{
- file_names.insert(file_names.end(),
- match_default_desc->getFileNames().begin(),
- match_default_desc->getFileNames().end());
- ft_collection_list.insert(ft_collection_list.end(),
- match_default_desc->getFontCollectionsList().begin(),
- match_default_desc->getFontCollectionsList().end());
+ font_files.insert(font_files.end(),
+ match_default_desc->getFontFiles().begin(),
+ match_default_desc->getFontFiles().end());
+ font_collection_files.insert(font_collection_files.end(),
+ match_default_desc->getFontCollectionFiles().begin(),
+ match_default_desc->getFontCollectionFiles().end());
}
// Add ultimate fallback list - generated dynamically on linux,
// null elsewhere.
- file_names.insert(file_names.end(),
- getUltimateFallbackList().begin(),
- getUltimateFallbackList().end());
+ std::transform(getUltimateFallbackList().begin(), getUltimateFallbackList().end(), std::back_inserter(font_files),
+ [](const std::string& file_name) { return LLFontFileInfo(file_name); });
// Load fonts based on names.
- if (file_names.empty())
+ if (font_files.empty())
{
LL_WARNS() << "createFont failed, no file names specified" << LL_ENDL;
return NULL;
}
- LLFontFreetype::font_vector_t fontlist;
LLFontGL *result = NULL;
- // Snarf all fonts we can into fontlist. First will get pulled
- // off the list and become the "head" font, set to non-fallback.
+ // The first font will get pulled will be the "head" font, set to non-fallback.
// Rest will consitute the fallback list.
BOOL is_first_found = TRUE;
- std::string local_path = LLFontGL::getFontPathLocal();
- std::string sys_path = LLFontGL::getFontPathSystem();
-
+ string_vec_t font_search_paths;
+ font_search_paths.push_back(LLFontGL::getFontPathLocal());
+ font_search_paths.push_back(LLFontGL::getFontPathSystem());
+#if LL_DARWIN
+ font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY);
+#endif
+
// The fontname string may contain multiple font file names separated by semicolons.
// Break it apart and try loading each one, in order.
- for(string_vec_t::iterator file_name_it = file_names.begin();
- file_name_it != file_names.end();
- ++file_name_it)
+ for(font_file_info_vec_t::iterator font_file_it = font_files.begin();
+ font_file_it != font_files.end();
+ ++font_file_it)
{
LLFontGL *fontp = NULL;
- string_vec_t font_paths;
- font_paths.push_back(local_path + *file_name_it);
- font_paths.push_back(sys_path + *file_name_it);
-#if LL_DARWIN
- font_paths.push_back(MACOSX_FONT_PATH_LIBRARY + *file_name_it);
-#endif
-
- bool is_ft_collection = (std::find(ft_collection_list.begin(), ft_collection_list.end(), *file_name_it) != ft_collection_list.end());
+
+ bool is_ft_collection = (std::find_if(font_collection_files.begin(), font_collection_files.end(),
+ [&font_file_it](const LLFontFileInfo& ffi) { return font_file_it->FileName == ffi.FileName; }) != font_collection_files.end());
+
// *HACK: Fallback fonts don't render, so we can use that to suppress
// creation of OpenGL textures for test apps. JC
BOOL is_fallback = !is_first_found || !mCreateGLTextures;
F32 extra_scale = (is_fallback)?fallback_scale:1.0;
F32 point_size_scale = extra_scale * point_size;
bool is_font_loaded = false;
- for(string_vec_t::iterator font_paths_it = font_paths.begin();
- font_paths_it != font_paths.end();
- ++font_paths_it)
+ for(string_vec_t::iterator font_search_path_it = font_search_paths.begin();
+ font_search_path_it != font_search_paths.end();
+ ++font_search_path_it)
{
+ const std::string font_path = *font_search_path_it + font_file_it->FileName;
+
fontp = new LLFontGL;
- S32 num_faces = is_ft_collection ? fontp->getNumFaces(*font_paths_it) : 1;
+ S32 num_faces = is_ft_collection ? fontp->getNumFaces(font_path) : 1;
for (S32 i = 0; i < num_faces; i++)
{
if (fontp == NULL)
{
fontp = new LLFontGL;
}
- if (fontp->loadFace(*font_paths_it, point_size_scale,
- LLFontGL::sVertDPI, LLFontGL::sHorizDPI, true, is_fallback, i))
+ if (fontp->loadFace(font_path, point_size_scale,
+ LLFontGL::sVertDPI, LLFontGL::sHorizDPI, is_fallback, i))
{
is_font_loaded = true;
if (is_first_found)
@@ -505,7 +525,8 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
}
else
{
- fontlist.push_back(fontp->mFontFreetype);
+ result->mFontFreetype->addFallbackFont(fontp->mFontFreetype, font_file_it->CharFunctor);
+
delete fontp;
fontp = NULL;
}
@@ -520,17 +541,12 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
}
if(!is_font_loaded)
{
- LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << *file_name_it << LL_ENDL;
+ LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << font_file_it->FileName << LL_ENDL;
delete fontp;
fontp = NULL;
}
}
- if (result && !fontlist.empty())
- {
- result->mFontFreetype->setFallbackFonts(fontlist);
- }
-
if (result)
{
result->mFontDescriptor = desc;
@@ -712,11 +728,11 @@ void LLFontRegistry::dump()
<< " size=[" << desc.getSize() << "]"
<< " fileNames="
<< LL_ENDL;
- for (string_vec_t::const_iterator file_it=desc.getFileNames().begin();
- file_it != desc.getFileNames().end();
+ for (font_file_info_vec_t::const_iterator file_it=desc.getFontFiles().begin();
+ file_it != desc.getFontFiles().end();
++file_it)
{
- LL_INFOS() << " file: " << *file_it <<LL_ENDL;
+ LL_INFOS() << " file: " << file_it->FileName << LL_ENDL;
}
}
}
diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h
index b1259ef4e7..b0ef72c5de 100644
--- a/indra/llrender/llfontregistry.h
+++ b/indra/llrender/llfontregistry.h
@@ -34,13 +34,32 @@ class LLFontGL;
typedef std::vector<std::string> string_vec_t;
+struct LLFontFileInfo
+{
+ LLFontFileInfo(const std::string& file_name, const std::function<bool(llwchar)>& char_functor = nullptr)
+ : FileName(file_name)
+ , CharFunctor(char_functor)
+ {
+ }
+
+ LLFontFileInfo(const LLFontFileInfo& ffi)
+ : FileName(ffi.FileName)
+ , CharFunctor(ffi.CharFunctor)
+ {
+ }
+
+ std::string FileName;
+ std::function<bool(llwchar)> CharFunctor;
+};
+typedef std::vector<LLFontFileInfo> font_file_info_vec_t;
+
class LLFontDescriptor
{
public:
LLFontDescriptor();
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style);
- LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const string_vec_t& file_names);
- LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const string_vec_t& file_names, const string_vec_t& font_collections);
+ 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;
bool operator<(const LLFontDescriptor& b) const;
@@ -51,19 +70,26 @@ public:
void setName(const std::string& name) { mName = name; }
const std::string& getSize() const { return mSize; }
void setSize(const std::string& size) { mSize = size; }
- const std::vector<std::string>& getFileNames() const { return mFileNames; }
- std::vector<std::string>& getFileNames() { return mFileNames; }
- const std::vector<std::string>& getFontCollectionsList() const { return mFontCollectionsList; }
- std::vector<std::string>& getFontCollectionsList() { return mFontCollectionsList; }
+
+ void addFontFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null);
+ const font_file_info_vec_t & getFontFiles() const { return mFontFiles; }
+ void setFontFiles(const font_file_info_vec_t& font_files) { mFontFiles = font_files; }
+ void addFontCollectionFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null);
+ const font_file_info_vec_t& getFontCollectionFiles() const { return mFontCollectionFiles; }
+ void setFontCollectionFiles(const font_file_info_vec_t& font_collection_files) { mFontCollectionFiles = font_collection_files; }
+
const U8 getStyle() const { return mStyle; }
void setStyle(U8 style) { mStyle = style; }
private:
std::string mName;
std::string mSize;
- string_vec_t mFileNames;
- string_vec_t mFontCollectionsList;
+ font_file_info_vec_t mFontFiles;
+ font_file_info_vec_t mFontCollectionFiles;
U8 mStyle;
+
+ typedef std::map<std::string, std::function<bool(llwchar)>> char_functor_map_t;
+ static char_functor_map_t mCharFunctors;
};
class LLFontRegistry