From fd7b0e19da95bf099c1769df8c72c719c2c379f2 Mon Sep 17 00:00:00 2001
From: maxim_productengine <mnikolenko@productengine.com>
Date: Tue, 19 Mar 2019 11:16:24 +0200
Subject: [PATCH] SL-10610 FIXED Floaters fails to display certain symbols.
 Added ability to load font collections.

---
 indra/llrender/llfontfreetype.cpp            | 120 ++++++++++++-------
 indra/llrender/llfontfreetype.h              |   9 +-
 indra/llrender/llfontgl.cpp                  |  14 ++-
 indra/llrender/llfontgl.h                    |   4 +-
 indra/llrender/llfontregistry.cpp            |  86 +++++++++----
 indra/llrender/llfontregistry.h              |   4 +
 indra/newview/skins/default/xui/en/fonts.xml |   1 +
 7 files changed, 169 insertions(+), 69 deletions(-)

diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index ab668dc192d..e9d852c2880 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -157,7 +157,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, S32 components, BOOL is_fallback)
+BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n)
 {
 	// Don't leak face objects.  This is also needed to deal with
 	// changed font file names.
@@ -168,40 +168,8 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
 	}
 	
 	int error;
-
 #ifdef LL_WINDOWS
-	pFileStream = new llifstream(filename, std::ios::binary);
-	if (pFileStream->is_open())
-	{
-		std::streampos beg = pFileStream->tellg();
-		pFileStream->seekg(0, std::ios::end);
-		std::streampos end = pFileStream->tellg();
-		std::size_t file_size = end - beg;
-		pFileStream->seekg(0, std::ios::beg);
-
-		pFtStream = new LLFT_Stream();
-		pFtStream->base = 0;
-		pFtStream->pos = 0;
-		pFtStream->size = file_size;
-		pFtStream->descriptor.pointer = pFileStream;
-		pFtStream->read = ft_read_cb;
-		pFtStream->close = ft_close_cb;
-
-		FT_Open_Args args;
-		args.flags = FT_OPEN_STREAM;
-		args.stream = (FT_StreamRec*)pFtStream;
-
-		error = FT_Open_Face(gFTLibrary,
-							 &args,
-							 0,
-							 &mFTFace);
-	}
-	else
-	{
-		delete pFileStream;
-		pFileStream = NULL;
-		return FALSE;
-	}
+	error = ftOpenFace(filename, face_n);
 #else
 	error = FT_New_Face( gFTLibrary,
 						 filename.c_str(),
@@ -212,11 +180,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
 	if (error)
 	{
 #ifdef LL_WINDOWS
-		pFileStream->close();
-		delete pFileStream;
-		delete pFtStream;
-		pFileStream = NULL;
-		pFtStream = NULL;
+		clearFontStreams();
 #endif
 		return FALSE;
 	}
@@ -235,11 +199,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
 		// Clean up freetype libs.
 		FT_Done_Face(mFTFace);
 #ifdef LL_WINDOWS
-		pFileStream->close();
-		delete pFileStream;
-		delete pFtStream;
-		pFileStream = NULL;
-		pFtStream = NULL;
+		clearFontStreams();
 #endif
 		mFTFace = NULL;
 		return FALSE;
@@ -297,6 +257,78 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
 	return TRUE;
 }
 
+S32 LLFontFreetype::getNumFaces(const std::string& filename)
+{
+	if (mFTFace)
+	{
+		FT_Done_Face(mFTFace);
+		mFTFace = NULL;
+	}
+
+	S32 num_faces = 1;
+
+#ifdef LL_WINDOWS
+	int error = ftOpenFace(filename, 0);
+		
+	if (error)
+	{
+		return 0;
+	}
+	else
+	{
+		num_faces = mFTFace->num_faces;
+	}
+	
+	FT_Done_Face(mFTFace);
+	clearFontStreams();
+	mFTFace = NULL;
+#endif
+
+	return num_faces;
+}
+
+#ifdef LL_WINDOWS
+S32 LLFontFreetype::ftOpenFace(const std::string& filename, S32 face_n)
+{
+	S32 error = -1;
+	pFileStream = new llifstream(filename, std::ios::binary);
+	if (pFileStream->is_open())
+	{
+		std::streampos beg = pFileStream->tellg();
+		pFileStream->seekg(0, std::ios::end);
+		std::streampos end = pFileStream->tellg();
+		std::size_t file_size = end - beg;
+		pFileStream->seekg(0, std::ios::beg);
+
+		pFtStream = new LLFT_Stream();
+		pFtStream->base = 0;
+		pFtStream->pos = 0;
+		pFtStream->size = file_size;
+		pFtStream->descriptor.pointer = pFileStream;
+		pFtStream->read = ft_read_cb;
+		pFtStream->close = ft_close_cb;
+
+		FT_Open_Args args;
+		args.flags = FT_OPEN_STREAM;
+		args.stream = (FT_StreamRec*)pFtStream;
+		error = FT_Open_Face(gFTLibrary, &args, face_n, &mFTFace);
+	}
+	return error;
+}
+
+void LLFontFreetype::clearFontStreams()
+{
+	if (pFileStream)
+	{
+		pFileStream->close();
+	}
+	delete pFileStream;
+	delete pFtStream;
+	pFileStream = NULL;
+	pFtStream = NULL;
+}
+#endif
+
 void LLFontFreetype::setFallbackFonts(const font_vector_t &font)
 {
 	mFallbackFonts = font;
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index aadebf5e70b..1afe84e770f 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -84,7 +84,14 @@ class LLFontFreetype : public LLRefCount, public LLTrace::MemTrackable<LLFontFre
 
 	// 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 components, BOOL is_fallback);
+	BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n = 0);
+
+	S32 getNumFaces(const std::string& filename);
+
+#ifdef LL_WINDOWS
+	S32 ftOpenFace(const std::string& filename, S32 face_n);
+	void clearFontStreams();
+#endif
 
 	typedef std::vector<LLPointer<LLFontFreetype> > font_vector_t;
 
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 8cd18c5fa19..b79615e7302 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -89,14 +89,24 @@ void LLFontGL::destroyGL()
 	mFontFreetype->destroyGL();
 }
 
-BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback)
+BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, 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, components, is_fallback);
+	return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback, face_n);
+}
+
+S32 LLFontGL::getNumFaces(const std::string& filename)
+{
+	if (mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
+	{
+		mFontFreetype = new LLFontFreetype;
+	}
+
+	return mFontFreetype->getNumFaces(filename);
 }
 
 static LLTrace::BlockTimerStatHandle FTM_RENDER_FONTS("Fonts");
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 7d0e53f60f1..10891faed9c 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -87,7 +87,9 @@ class LLFontGL
 
 	void destroyGL();
 
-	BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback);
+	BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback, S32 face_n = 0);
+
+	S32 getNumFaces(const std::string& filename);
 
 	S32 render(const LLWString &text, S32 begin_offset, 
 				const LLRect& rect, 
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
index 10896ecb5d4..dbe71e2882e 100644
--- a/indra/llrender/llfontregistry.cpp
+++ b/indra/llrender/llfontregistry.cpp
@@ -62,6 +62,16 @@ LLFontDescriptor::LLFontDescriptor(const std::string& name,
 {
 }
 
+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)
+{
+	mFontCollectionsList = ft_collection_listections;
+}
+
 LLFontDescriptor::LLFontDescriptor(const std::string& name,
 								   const std::string& size, 
 								   const U8 style):
@@ -164,7 +174,7 @@ LLFontDescriptor LLFontDescriptor::normalize() const
 	if (removeSubString(new_name,"Italic"))
 		new_style |= LLFontGL::ITALIC;
 
-	return LLFontDescriptor(new_name,new_size,new_style,getFileNames());
+	return LLFontDescriptor(new_name,new_size,new_style,getFileNames(),getFontCollectionsList());
 }
 
 LLFontRegistry::LLFontRegistry(bool create_gl_textures)
@@ -215,6 +225,7 @@ bool LLFontRegistry::parseFontInfo(const std::string& xml_filename)
 			success = success || init_succ;
 		}
 	}
+
 	//if (success)
 	//	dump();
 
@@ -262,6 +273,16 @@ bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc)
 		{
 			std::string font_file_name = child->getTextContents();
 			desc.getFileNames().push_back(font_file_name);
+			
+			if (child->hasAttribute("load_collection"))
+			{
+				BOOL col = FALSE;
+				child->getAttributeBOOL("load_collection", col);
+				if (col)
+				{
+					desc.getFontCollectionsList().push_back(font_file_name);
+				}
+			}
 		}
 		else if (child->hasName("os"))
 		{
@@ -308,8 +329,15 @@ bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node)
 					match_file_names.insert(match_file_names.begin(),
 											desc.getFileNames().begin(),
 											desc.getFileNames().end());
+
+					string_vec_t collections_list = match_desc->getFontCollectionsList();
+					collections_list.insert(collections_list.begin(),
+						desc.getFontCollectionsList().begin(),
+						desc.getFontCollectionsList().end());
+
 					LLFontDescriptor new_desc = *match_desc;
 					new_desc.getFileNames() = match_file_names;
+					new_desc.getFontCollectionsList() = collections_list;
 					registry->mFontMap.erase(*match_desc);
 					registry->mFontMap[new_desc] = NULL;
 				}
@@ -395,6 +423,7 @@ 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;
 	LLFontDescriptor default_desc("default",s_template_string,0);
 	const LLFontDescriptor *match_default_desc = getMatchingFontDesc(default_desc);
@@ -403,6 +432,9 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& 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());
 	}
 
 	// Add ultimate fallback list - generated dynamically on linux,
@@ -435,13 +467,15 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
 		file_name_it != file_names.end(); 
 		++file_name_it)
 	{
-		LLFontGL *fontp = new LLFontGL;
+		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());
 		// *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;
@@ -452,12 +486,37 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
 			font_paths_it != font_paths.end();
 			++font_paths_it)
 		{
-			if (fontp->loadFace(*font_paths_it, point_size_scale,
-								 LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback))
+			fontp = new LLFontGL;
+			S32 num_faces = is_ft_collection ? fontp->getNumFaces(*font_paths_it) : 1;
+			for (S32 i = 0; i < num_faces; i++)
 			{
-				is_font_loaded = true;
-				break;
+				if (fontp == NULL)
+				{
+					fontp = new LLFontGL;
+				}
+				if (fontp->loadFace(*font_paths_it, point_size_scale,
+								 LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback, i))
+				{
+					is_font_loaded = true;
+					if (is_first_found)
+					{
+						result = fontp;
+						is_first_found = false;
+					}
+					else
+					{
+						fontlist.push_back(fontp->mFontFreetype);
+						delete fontp;
+						fontp = NULL;
+					}
+				}
+				else
+				{
+					delete fontp;
+					fontp = NULL;
+				}
 			}
+			if (is_font_loaded) break;
 		}
 		if(!is_font_loaded)
 		{
@@ -465,21 +524,6 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
 			delete fontp;
 			fontp = NULL;
 		}
-		
-		if(fontp)
-		{
-			if (is_first_found)
-			{
-				result = fontp;
-				is_first_found = false;
-			}
-			else
-			{
-				fontlist.push_back(fontp->mFontFreetype);
-				delete fontp;
-				fontp = NULL;
-			}
-		}
 	}
 
 	if (result && !fontlist.empty())
diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h
index 177eb6c8a5d..e30c81c6301 100644
--- a/indra/llrender/llfontregistry.h
+++ b/indra/llrender/llfontregistry.h
@@ -40,6 +40,7 @@ class LLFontDescriptor
 	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 normalize() const;
 
 	bool operator<(const LLFontDescriptor& b) const;
@@ -52,6 +53,8 @@ class LLFontDescriptor
 	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; }
 	const U8 getStyle() const { return mStyle; }
 	void setStyle(U8 style) { mStyle = style; }
 
@@ -59,6 +62,7 @@ class LLFontDescriptor
 	std::string mName;
 	std::string mSize;
 	string_vec_t mFileNames;
+	string_vec_t mFontCollectionsList;
 	U8 mStyle;
 };
 
diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml
index 6ef7195ebf9..87c39b10246 100644
--- a/indra/newview/skins/default/xui/en/fonts.xml
+++ b/indra/newview/skins/default/xui/en/fonts.xml
@@ -10,6 +10,7 @@
       <file>simhei.ttf</file>
       <file>ArialUni.ttf</file>
       <file>msyh.ttc</file>
+      <file load_collection="true">Cambria.ttc</file>
     </os>
     <os name="Mac">
       <file>ヒラギノ角ゴシック W3.ttc</file>  
-- 
GitLab