diff options
author | Kitty Barnett <develop@catznip.com> | 2019-11-07 17:15:21 +0100 |
---|---|---|
committer | Kitty Barnett <develop@catznip.com> | 2019-11-07 17:15:21 +0100 |
commit | 5a6ddb2ea666e895890d3cb690cce5101cf12652 (patch) | |
tree | 451cac9c7912f9f1997ecee9dd5dac58f01d6b18 | |
parent | 418308bc7ce4e9924d6280f784222ba45172eea4 (diff) |
Fallback fonts can have first crack at adding an unknown character + set Twemoji as the viewer's fallback for all emoji blocks
-rw-r--r-- | autobuild.xml | 90 | ||||
-rw-r--r-- | indra/cmake/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/cmake/FindICU4C.cmake | 33 | ||||
-rw-r--r-- | indra/cmake/ICU4C.cmake | 22 | ||||
-rw-r--r-- | indra/llcommon/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llcommon/llstring.cpp | 26 | ||||
-rw-r--r-- | indra/llcommon/llstring.h | 2 | ||||
-rw-r--r-- | indra/llrender/llfontfreetype.cpp | 42 | ||||
-rw-r--r-- | indra/llrender/llfontfreetype.h | 12 | ||||
-rw-r--r-- | indra/llrender/llfontgl.cpp | 4 | ||||
-rw-r--r-- | indra/llrender/llfontgl.h | 2 | ||||
-rw-r--r-- | indra/llrender/llfontregistry.cpp | 150 | ||||
-rw-r--r-- | indra/llrender/llfontregistry.h | 42 | ||||
-rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/fonts.xml | 1 | ||||
-rw-r--r-- | indra/win_crash_logger/CMakeLists.txt | 2 |
16 files changed, 333 insertions, 101 deletions
diff --git a/autobuild.xml b/autobuild.xml index 8bd6491edd..131c7614c0 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1519,6 +1519,96 @@ <key>version</key> <string>2012.1-2</string> </map> + <key>icu4c</key> + <map> + <key>copyright</key> + <string>Copyright (c) 1995-2011 International Business Machines Corporation and others <http://source.icu-project.org></string> + <key>description</key> + <string>ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.</string> + <key>license</key> + <string>ICU, permissive non-copyleft free software license</string> + <key>license_file</key> + <string>LICENSES/icu.txt</string> + <key>name</key> + <string>icu4c</string> + <key>platforms</key> + <map> + <key>darwin</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>910edfc0b936389bc8804c42d1008aa8</string> + <key>url</key> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/icu4c_3p-update-icu4c/rev/295486/arch/Darwin/installer/icu4c-4.8.1-darwin-295486.tar.bz2</string> + </map> + <key>name</key> + <string>windows64</string> + </map> + <key>darwin64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>2c34cb4e62d1f155d5dad798e69d03c8</string> + <key>url</key> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/466/1005/icu4c-4.8.1-darwin64-500388.tar.bz2</string> + </map> + <key>name</key> + <string>windows64</string> + </map> + <key>linux</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>0a4423cfd26409f33ae81fb9806a9972</string> + <key>url</key> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-icu4c/rev/314152/arch/Linux/installer/icu4c-4.8.1-linux-314152.tar.bz2</string> + </map> + <key>name</key> + <string>windows64</string> + </map> + <key>linux64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>b327031733c36efe2eee4582aefb2d66</string> + <key>url</key> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/462/995/icu4c-4.8.1-linux64-500388.tar.bz2</string> + </map> + <key>name</key> + <string>windows64</string> + </map> + <key>windows</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>af354f6ab6d2cecf266c79031977e3e0</string> + <key>url</key> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/492/1078/icu4c-4.8.1-windows-500388.tar.bz2</string> + </map> + <key>name</key> + <string>windows64</string> + </map> + <key>windows64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>e8b20cea748b90ea18bb63dfba06e059</string> + <key>url</key> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/491/1075/icu4c-4.8.1-windows64-500388.tar.bz2</string> + </map> + <key>name</key> + <string>windows64</string> + </map> + </map> + <key>version</key> + <string>4.8.1</string> + </map> <key>jpeglib</key> <map> <key>copyright</key> diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 84e1c5d6fd..d64c38b1b3 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -32,6 +32,7 @@ set(cmake_SOURCE_FILES FindGLH.cmake FindGoogleBreakpad.cmake FindHUNSPELL.cmake + FindICU4C.cmake FindJsonCpp.cmake FindNDOF.cmake FindOpenJPEG.cmake @@ -49,6 +50,7 @@ set(cmake_SOURCE_FILES GoogleMock.cmake Havok.cmake Hunspell.cmake + ICU4C.cmake JPEG.cmake JsonCpp.cmake LLAddBuildTest.cmake diff --git a/indra/cmake/FindICU4C.cmake b/indra/cmake/FindICU4C.cmake new file mode 100644 index 0000000000..327d761a88 --- /dev/null +++ b/indra/cmake/FindICU4C.cmake @@ -0,0 +1,33 @@ +# -*- cmake -*- + +# - Find ICU4C +# This module defines +# ICU4C_INCLUDE_DIR, where to find headers +# ICU4C_LIBRARY, the library needed to use ICU4C. +# ICU4C_FOUND, If false, do not try to use ICU4C. + +find_path(ICU4C_INCLUDE_DIR uchar.h + PATH_SUFFIXES unicode + ) + +set(ICU4C_NAMES ${ICU4C_NAMES} icuuc) +find_library(ICU4C_LIBRARY + NAMES ${ICU4C_NAMES} + ) + +if (ICU4C_LIBRARY AND ICU4C_INCLUDE_DIR) + set(ICU4C_FOUND "YES") +else (ICU4C_LIBRARY AND ICU4C_INCLUDE_DIR) + set(ICU4C_FOUND "NO") +endif (ICU4C_LIBRARY AND ICU4C_INCLUDE_DIR) + +if (ICU4C_FOUND) + message(STATUS "Found ICU4C: Library in '${ICU4C_LIBRARY}' and header in '${ICU4C_INCLUDE_DIR}' ") +else (ICU4C_FOUND) + message(FATAL_ERROR " * * *\nCould not find ICU4C library! * * *") +endif (ICU4C_FOUND) + +mark_as_advanced( + ICU4C_LIBRARY + ICU4C_INCLUDE_DIR + ) diff --git a/indra/cmake/ICU4C.cmake b/indra/cmake/ICU4C.cmake new file mode 100644 index 0000000000..007a9b6937 --- /dev/null +++ b/indra/cmake/ICU4C.cmake @@ -0,0 +1,22 @@ +# -*- cmake -*- +include(Prebuilt) + +set(ICU4C_FIND_QUIETLY ON) +set(ICU4C_FIND_REQUIRED ON) + +if (USESYSTEMLIBS) + include(FindICU4C) +else (USESYSTEMLIBS) + use_prebuilt_binary(icu4c) + if (WINDOWS) + set(ICU4C_LIBRARY icuuc) + #elseif(DARWIN) + # set(ICU4C_LIBRARY ...) + #elseif(LINUX) + # set(ICU4C_LIBRARY ...) + else() + message(FATAL_ERROR "Invalid platform") + endif() + set(ICU4C_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/unicode) + use_prebuilt_binary(dictionaries) +endif (USESYSTEMLIBS) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index af41b9e460..ba87d93fec 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -4,6 +4,7 @@ project(llcommon) include(00-Common) +include(ICU4C) include(LLCommon) include(Linking) include(Boost) @@ -288,6 +289,7 @@ target_link_libraries( ${APRUTIL_LIBRARIES} ${APR_LIBRARIES} ${EXPAT_LIBRARIES} + ${ICU4C_LIBRARY} ${JSONCPP_LIBRARIES} ${ZLIB_LIBRARIES} ${WINDOWS_LIBRARIES} diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 0174c411b4..b272728200 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -30,6 +30,7 @@ #include "llerror.h" #include "llfasttimer.h" #include "llsd.h" +#include <unicode/uchar.h> #include <vector> #if LL_WINDOWS @@ -888,6 +889,31 @@ std::string LLStringOps::sDayFormat; std::string LLStringOps::sAM; std::string LLStringOps::sPM; +// static +bool LLStringOps::isEmoji(llwchar wch) +{ + switch (ublock_getCode(wch)) + { + case UBLOCK_MISCELLANEOUS_SYMBOLS: + case UBLOCK_DINGBATS: + case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS: + case UBLOCK_EMOTICONS: + case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS: +#if U_ICU_VERSION_MAJOR_NUM > 56 + // Boost uses ICU so we can't update it independently + case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS: +#endif // U_ICU_VERSION_MAJOR_NUM > 56 + return true; + default: +#if U_ICU_VERSION_MAJOR_NUM > 56 + return false; +#else + // See https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs + return wch >= 0x1F900 && wch <= 0x1F9FF; +#endif // U_ICU_VERSION_MAJOR_NUM > 56 + } +} + S32 LLStringOps::collate(const llwchar* a, const llwchar* b) { diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index b619a9e48c..d31d0cafc7 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -193,6 +193,8 @@ public: static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } + static bool isEmoji(llwchar wch); + static S32 collate(const char* a, const char* b) { return strcoll(a, b); } static S32 collate(const llwchar* a, const llwchar* b); 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 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b83d3afadd..f03dcb4066 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -21,6 +21,7 @@ include(EXPAT) include(FMODEX) include(GLOD) include(Hunspell) +include(ICU4C) include(JsonCpp) include(LLAppearance) include(LLAudio) @@ -2003,6 +2004,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${NDOF_LIBRARY} ${NVAPI_LIBRARY} ${HUNSPELL_LIBRARY} + ${ICU4C_LIBRARY} ${viewer_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml index 2d5263b78f..6df666a700 100644 --- a/indra/newview/skins/default/xui/en/fonts.xml +++ b/indra/newview/skins/default/xui/en/fonts.xml @@ -3,6 +3,7 @@ <font name="default" comment="default font files (global fallbacks)"> <file>DejaVuSans.ttf</file> + <file functor="is_emoji">Twemoji.ttf</file> <os name="Windows"> <file>meiryo.TTC</file> <file>MSGOTHIC.TTC</file> diff --git a/indra/win_crash_logger/CMakeLists.txt b/indra/win_crash_logger/CMakeLists.txt index 4fba26ab2f..d1de20a6a0 100644 --- a/indra/win_crash_logger/CMakeLists.txt +++ b/indra/win_crash_logger/CMakeLists.txt @@ -3,6 +3,7 @@ project(win_crash_logger) include(00-Common) +include(ICU4C) include(LLCommon) include(LLCoreHttp) include(LLCrashLogger) @@ -74,6 +75,7 @@ add_executable(windows-crash-logger WIN32 ${win_crash_logger_SOURCE_FILES}) target_link_libraries(windows-crash-logger ${BREAKPAD_EXCEPTION_HANDLER_LIBRARIES} + ${ICU4C_LIBRARY} ${LLCRASHLOGGER_LIBRARIES} ${LLWINDOW_LIBRARIES} ${LLVFS_LIBRARIES} |