diff options
Diffstat (limited to 'indra')
164 files changed, 4847 insertions, 1033 deletions
| diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index f0b35c08f3..286ef3d411 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -30,6 +30,7 @@ set(cmake_SOURCE_FILES          GoogleMock.cmake          Havok.cmake          Hunspell.cmake +        ICU4C.cmake          JsonCpp.cmake          LLAddBuildTest.cmake          LLAppearance.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index d43cc30706..ae15e8be34 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -63,6 +63,15 @@ if(WINDOWS)          uriparser.dll          ) +    # ICU4C (same filenames for 32 and 64 bit builds) +    set(release_files ${release_files} icudt48.dll) +    set(release_files ${release_files} icuin48.dll) +    set(release_files ${release_files} icuio48.dll) +    set(release_files ${release_files} icule48.dll) +    set(release_files ${release_files} iculx48.dll) +    set(release_files ${release_files} icutu48.dll) +    set(release_files ${release_files} icuuc48.dll) +      # OpenSSL      if(ADDRESS_SIZE EQUAL 64)          set(release_files ${release_files} libcrypto-1_1-x64.dll) diff --git a/indra/cmake/ICU4C.cmake b/indra/cmake/ICU4C.cmake new file mode 100644 index 0000000000..7b27665483 --- /dev/null +++ b/indra/cmake/ICU4C.cmake @@ -0,0 +1,23 @@ +# -*- cmake -*- +include(Prebuilt) + +include_guard() + +add_library( ll::icu4c INTERFACE IMPORTED ) + + +use_system_binary(icu4c) +use_prebuilt_binary(icu4c) +if (WINDOWS) +  target_link_libraries( ll::icu4c INTERFACE  icuuc) +elseif(DARWIN) +  target_link_libraries( ll::icu4c INTERFACE  icuuc) +#elseif(LINUX) +##  target_link_libraries( ll::icu4c INTERFACE  ) +else() +  message(FATAL_ERROR "Invalid platform") +endif() + +target_include_directories( ll::icu4c SYSTEM INTERFACE  ${LIBS_PREBUILT_DIR}/include/unicode ) + +use_prebuilt_binary(dictionaries) diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake index 00f8b77106..cae68fbc11 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -18,3 +18,6 @@ endif()  use_prebuilt_binary(slvoice) +use_prebuilt_binary(nanosvg) +use_prebuilt_binary(viewer-fonts) +use_prebuilt_binary(emoji_shortcodes) diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index 793a33cc87..1fbe19ddd1 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -37,7 +37,7 @@ class LLWearableType : public LLParamSingleton<LLWearableType>  {  	LLSINGLETON(LLWearableType, LLTranslationBridge::ptr_t &trans);  	~LLWearableType(); -	void initSingleton(); +	void initSingleton() override;  public:   	enum EType  	{ diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index 117d408b21..5b1b28bf4f 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -1352,7 +1352,6 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)  		dp.packS32(joint->mNumRotKeys, "num_rot_keys");  		LLQuaternion::Order order = bvhStringToOrder( joint->mOrder ); -		S32 outcount = 0;  		S32 frame = 0;  		for (Key& key : joint->mKeys)  		{ @@ -1418,7 +1417,6 @@ BOOL LLBVHLoader::serialize(LLDataPacker& dp)  			dp.packU16(x, "rot_angle_x");  			dp.packU16(y, "rot_angle_y");  			dp.packU16(z, "rot_angle_z"); -			outcount++;  			frame++;  		} diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index ef4899978e..6c571b8e07 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -3,6 +3,7 @@  project(llcommon)  include(00-Common) +include(ICU4C)  include(LLCommon)  include(bugsplat)  include(Linking) @@ -272,6 +273,7 @@ target_link_libraries(          ll::uriparser          ll::oslibraries          ll::tracy +        ll::icu4c      )  target_include_directories(llcommon INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 966ce03296..fd878f20ad 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -92,7 +92,7 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>      LLSINGLETON(LLCoros);      ~LLCoros(); -    void cleanupSingleton(); +    void cleanupSingleton() override;  public:      /// The viewer's use of the term "coroutine" became deeply embedded before      /// the industry term "fiber" emerged to distinguish userland threads from diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index b7e316da10..f66c4ff843 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -2193,7 +2193,7 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,  LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32 size)  {  	U8* result = NULL; -	U32 cur_size = 0; +	llssize cur_size = 0;  	z_stream strm;  	constexpr U32 CHUNK = 1024 * 512; @@ -2388,7 +2388,7 @@ U8* unzip_llsdNavMesh( bool& valid, size_t& outsize, std::istream& is, S32 size  	return result;  } -char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size) +char* strip_deprecated_header(char* in, llssize& cur_size, U32* header_size)  {  	const char* deprecated_header = "<? LLSD/Binary ?>";  	constexpr size_t deprecated_header_size = 17; diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 2f12c6d1ff..5ddf0ff552 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -873,5 +873,5 @@ LL_COMMON_API std::string zip_llsd(LLSD& data);  LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, size_t& outsize,std::istream& is, S32 size);  // returns a pointer to the array or past the array if the deprecated header exists -LL_COMMON_API char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size = nullptr); +LL_COMMON_API char* strip_deprecated_header(char* in, llssize& cur_size, U32* header_size = nullptr);  #endif // LL_LLSDSERIALIZE_H diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 51ef514cf7..cbe5ab6406 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -802,7 +802,7 @@ public:  private:                                                                \      /* implement LLSingleton pure virtual method whose sole purpose */  \      /* is to remind people to use this macro */                         \ -    virtual void you_must_use_LLSINGLETON_macro() {}                    \ +    virtual void you_must_use_LLSINGLETON_macro() override {}                    \      friend class LLSingleton<DERIVED_CLASS>;                            \      DERIVED_CLASS(__VA_ARGS__) diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index f6629803ee..d68cbaa22c 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 @@ -833,6 +834,40 @@ std::string LLStringOps::sDayFormat;  std::string LLStringOps::sAM;  std::string LLStringOps::sPM; +// static +bool LLStringOps::isEmoji(llwchar wch) +{ +	int ublock = ublock_getCode(wch); +	switch (ublock) +	{ +		case UBLOCK_GENERAL_PUNCTUATION: +		case UBLOCK_LETTERLIKE_SYMBOLS: +		case UBLOCK_ARROWS: +		case UBLOCK_MISCELLANEOUS_TECHNICAL: +		case UBLOCK_ENCLOSED_ALPHANUMERICS: +		case UBLOCK_GEOMETRIC_SHAPES: +		case UBLOCK_MISCELLANEOUS_SYMBOLS: +		case UBLOCK_DINGBATS: +		case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: +		case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS: +		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 1fd6cac14a..62403969e4 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -189,6 +189,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); @@ -355,6 +357,8 @@ public:  	static void	replaceNonstandardASCII( string_type& string, T replacement );  	static void	replaceChar( string_type& string, T target, T replacement );  	static void replaceString( string_type& string, string_type target, string_type replacement ); +	static string_type capitalize(const string_type& str); +	static void capitalize(string_type& str);  	static BOOL	containsNonprintable(const string_type& string);  	static void	stripNonprintable(string_type& string); @@ -1594,6 +1598,29 @@ void LLStringUtilBase<T>::replaceTabsWithSpaces( string_type& str, size_type spa  }  //static +template<class T> +std::basic_string<T> LLStringUtilBase<T>::capitalize(const string_type& str) +{ +	string_type result(str); +	capitalize(result); +	return result; +} + +//static +template<class T> +void LLStringUtilBase<T>::capitalize(string_type& str) +{ +	if (str.size()) +	{ +		auto last = str[0] = toupper(str[0]); +		for (U32 i = 1; i < str.size(); ++i) +		{ +			last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i]; +		} +	} +} + +//static  template<class T>   BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string)  { diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp index 15ffe68e67..6f8aaaa0cb 100644 --- a/indra/llcommon/tests/llsingleton_test.cpp +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -47,8 +47,8 @@ public:                                             \          DEP_INIT  /* dependency in initSingleton */ \      } sDepFlag;                                     \                                                      \ -    void initSingleton();                           \ -    void cleanupSingleton();                        \ +    void initSingleton() override;                  \ +    void cleanupSingleton() override;               \  };                                                  \                                                      \  CLS::dep_flag CLS::sDepFlag = DEP_NONE @@ -300,7 +300,7 @@ namespace tut      {          LLSINGLETON_EMPTY_CTOR(CircularPInit);      public: -        virtual void initSingleton() +        virtual void initSingleton() override          {              // never mind indirection, just go straight for the circularity              CircularPInit *pt = getInstance(); diff --git a/indra/llinventory/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp index 675da65af2..818a8b5cc3 100644 --- a/indra/llinventory/llfoldertype.cpp +++ b/indra/llinventory/llfoldertype.cpp @@ -60,7 +60,7 @@ class LLFolderDictionary : public LLSingleton<LLFolderDictionary>,  {  	LLSINGLETON(LLFolderDictionary);  protected: -	virtual LLFolderType::EType notFound() const +	virtual LLFolderType::EType notFound() const override  	{  		return LLFolderType::FT_NONE;  	} diff --git a/indra/llinventory/llinventorysettings.cpp b/indra/llinventory/llinventorysettings.cpp index 81485b3a97..bc604097da 100644 --- a/indra/llinventory/llinventorysettings.cpp +++ b/indra/llinventory/llinventorysettings.cpp @@ -62,7 +62,7 @@ class LLSettingsDictionary : public LLSingleton<LLSettingsDictionary>,  {      LLSINGLETON(LLSettingsDictionary); -    void initSingleton(); +    void initSingleton() override;  };  LLSettingsDictionary::LLSettingsDictionary()  diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 40f7b1e9fb..1879ff2a05 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5482,14 +5482,12 @@ bool LLVolumeFace::cacheOptimize()  	new_indices.push_back(tri->mVertex[2]->mIdx);  	tri->complete(); -	U32 breaks = 0;  	for (U32 i = 1; i < mNumIndices/3; ++i)  	{  		cache.updateScores();  		tri = cache.mBestTriangle;  		if (!tri)  		{ -			breaks++;  			for (U32 j = 0; j < triangle_data.size(); ++j)  			{  				if (triangle_data[j].mActive) diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index 8baa2e328b..a9a292958f 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -271,7 +271,6 @@ void LLCircuitData::ackReliablePacket(TPACKETID packet_num)  S32 LLCircuitData::resendUnackedPackets(const F64Seconds now)  { -	S32 resent_packets = 0;  	LLReliablePacket *packetp; @@ -375,7 +374,6 @@ S32 LLCircuitData::resendUnackedPackets(const F64Seconds now)  				// Don't remove it yet, it still gets to try to resend at least once.  				++iter;  			} -			resent_packets++;  		}  		else  		{ diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h index 1c97133723..8be4c64dfc 100644 --- a/indra/llmessage/llexperiencecache.h +++ b/indra/llmessage/llexperiencecache.h @@ -106,7 +106,7 @@ public:  private:      virtual ~LLExperienceCache(); -    virtual void initSingleton(); +    virtual void initSingleton() override;      typedef boost::function<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, LLCore::HttpRequest::ptr_t, std::string)> permissionInvoker_fn; diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h index 25f6977e14..8a64cdbfaa 100644 --- a/indra/llmessage/llproxy.h +++ b/indra/llmessage/llproxy.h @@ -226,7 +226,7 @@ class LLProxy: public LLSingleton<LLProxy>  	LLSINGLETON(LLProxy);  	LOG_CLASS(LLProxy); -    /*virtual*/ void initSingleton(); +    /*virtual*/ void initSingleton() override;  public:  	// Static check for enabled status for UDP packets. Call from main thread only. diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index c5cf1100d5..2bc09accb2 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -14,6 +14,7 @@ set(llrender_SOURCE_FILES      llcubemap.cpp      llfontbitmapcache.cpp      llfontfreetype.cpp +    llfontfreetypesvg.cpp      llfontgl.cpp      llfontregistry.cpp      llgl.cpp @@ -41,6 +42,7 @@ set(llrender_HEADER_FILES      llcubemap.h      llfontgl.h      llfontfreetype.h +    llfontfreetypesvg.h      llfontbitmapcache.h      llfontregistry.h      llgl.h diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index c71e24c83a..42b0045cf3 100644 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp @@ -30,14 +30,7 @@  #include "llfontbitmapcache.h"  LLFontBitmapCache::LLFontBitmapCache() -:	mNumComponents(0), -	mBitmapWidth(0), -	mBitmapHeight(0), -	mBitmapNum(-1), -	mMaxCharWidth(0), -	mMaxCharHeight(0), -	mCurrentOffsetX(1), -	mCurrentOffsetY(1) +  {  } @@ -45,121 +38,149 @@ LLFontBitmapCache::~LLFontBitmapCache()  {  } -void LLFontBitmapCache::init(S32 num_components, -							 S32 max_char_width, +void LLFontBitmapCache::init(S32 max_char_width,  							 S32 max_char_height)  {  	reset(); -	mNumComponents = num_components;  	mMaxCharWidth = max_char_width;  	mMaxCharHeight = max_char_height; + +	S32 image_width = mMaxCharWidth * 20; +	S32 pow_iw = 2; +	while (pow_iw < image_width) +	{ +		pow_iw <<= 1; +	} +	image_width = pow_iw; +	image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever. + +	mBitmapWidth = image_width; +	mBitmapHeight = image_width;  } -LLImageRaw *LLFontBitmapCache::getImageRaw(U32 bitmap_num) const +LLImageRaw *LLFontBitmapCache::getImageRaw(EFontGlyphType bitmap_type, U32 bitmap_num) const  { -	if (bitmap_num >= mImageRawVec.size()) -		return NULL; +	const U32 bitmap_idx = static_cast<U32>(bitmap_type); +	if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageRawVec[bitmap_idx].size()) +		return nullptr; -	return mImageRawVec[bitmap_num]; +	return mImageRawVec[bitmap_idx][bitmap_num];  } -LLImageGL *LLFontBitmapCache::getImageGL(U32 bitmap_num) const +LLImageGL *LLFontBitmapCache::getImageGL(EFontGlyphType bitmap_type, U32 bitmap_num) const  { -	if (bitmap_num >= mImageGLVec.size()) -		return NULL; +	const U32 bitmap_idx = static_cast<U32>(bitmap_type); +	if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageGLVec[bitmap_idx].size()) +		return nullptr; -	return mImageGLVec[bitmap_num]; +	return mImageGLVec[bitmap_idx][bitmap_num];  } -BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32 &pos_x, S32 &pos_y, S32& bitmap_num) +BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyphType bitmap_type, U32& bitmap_num)  { -	if ((mBitmapNum<0) || (mCurrentOffsetX + width + 1) > mBitmapWidth) +	if (bitmap_type >= EFontGlyphType::Count) +	{ +		return FALSE; +	} + +	const U32 bitmap_idx = static_cast<U32>(bitmap_type); +	if (mImageRawVec[bitmap_idx].empty() || (mCurrentOffsetX[bitmap_idx] + width + 1) > mBitmapWidth)  	{ -		if ((mBitmapNum<0) || (mCurrentOffsetY + 2*mMaxCharHeight + 2) > mBitmapHeight) +		if ((mImageRawVec[bitmap_idx].empty()) || (mCurrentOffsetY[bitmap_idx] + 2*mMaxCharHeight + 2) > mBitmapHeight)  		{  			// We're out of space in the current image, or no image  			// has been allocated yet.  Make a new one. -			 -			mImageRawVec.push_back(new LLImageRaw); -			mBitmapNum = mImageRawVec.size()-1; -			LLImageRaw *image_raw = getImageRaw(mBitmapNum); - -			// Make corresponding GL image. -			mImageGLVec.push_back(new LLImageGL(FALSE)); -			LLImageGL *image_gl = getImageGL(mBitmapNum); -			 -			S32 image_width = mMaxCharWidth * 20; -			S32 pow_iw = 2; -			while (pow_iw < image_width) +             +            S32 image_width = mMaxCharWidth * 20; +            S32 pow_iw = 2; +            while (pow_iw < image_width) +            { +                pow_iw *= 2; +            } +            image_width = pow_iw; +            image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever. +            S32 image_height = image_width; +             +            mBitmapWidth = image_width; +            mBitmapHeight = image_height; +             +			S32 num_components = getNumComponents(bitmap_type); +			mImageRawVec[bitmap_idx].push_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components)); +			bitmap_num = mImageRawVec[bitmap_idx].size() - 1; + +			LLImageRaw* image_raw = getImageRaw(bitmap_type, bitmap_num); +			if (EFontGlyphType::Grayscale == bitmap_type)  			{ -				pow_iw *= 2; +				image_raw->clear(255, 0);  			} -			image_width = pow_iw; -			image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever. -			S32 image_height = image_width; - -			image_raw->resize(image_width, image_height, mNumComponents); - -			mBitmapWidth = image_width; -			mBitmapHeight = image_height; -			switch (mNumComponents) -			{ -				case 1: -					image_raw->clear(); -				break; -				case 2: -					image_raw->clear(255, 0); -				break; -			} +			// Make corresponding GL image. +			mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false)); +			LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num);  			// Start at beginning of the new image. -			mCurrentOffsetX = 1; -			mCurrentOffsetY = 1; +			mCurrentOffsetX[bitmap_idx] = 1; +			mCurrentOffsetY[bitmap_idx] = 1; -			// Attach corresponding GL texture. -			image_gl->createGLTexture(0, image_raw); +			// Attach corresponding GL texture. (*TODO: is this needed?)  			gGL.getTexUnit(0)->bind(image_gl);  			image_gl->setFilteringOption(LLTexUnit::TFO_POINT); // was setMipFilterNearest(TRUE, TRUE);  		}  		else  		{  			// Move to next row in current image. -			mCurrentOffsetX = 1; -			mCurrentOffsetY += mMaxCharHeight + 1; +			mCurrentOffsetX[bitmap_idx] = 1; +			mCurrentOffsetY[bitmap_idx] += mMaxCharHeight + 1;  		}  	} -	pos_x = mCurrentOffsetX; -	pos_y = mCurrentOffsetY; -	bitmap_num = mBitmapNum; +	pos_x = mCurrentOffsetX[bitmap_idx]; +	pos_y = mCurrentOffsetY[bitmap_idx]; +	bitmap_num = getNumBitmaps(bitmap_type) - 1; -	mCurrentOffsetX += width + 1; +	mCurrentOffsetX[bitmap_idx] += width + 1;  	return TRUE;  }  void LLFontBitmapCache::destroyGL()  { -	for (std::vector<LLPointer<LLImageGL> >::iterator it = mImageGLVec.begin(); -		 it != mImageGLVec.end(); ++it) +	for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++)  	{ -		(*it)->destroyGLTexture(); +		for (LLImageGL* image_gl : mImageGLVec[idx]) +		{ +			image_gl->destroyGLTexture(); +		}  	}  }  void LLFontBitmapCache::reset()  { -	mImageRawVec.clear(); - -	mImageGLVec.clear(); +	for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++) +	{ +		mImageRawVec[idx].clear(); +		mImageGLVec[idx].clear(); +		mCurrentOffsetX[idx] = 1; +		mCurrentOffsetY[idx] = 1; +	}  	mBitmapWidth = 0;  	mBitmapHeight = 0; -	mBitmapNum = -1; -	mCurrentOffsetX = 1; -	mCurrentOffsetY = 1;  } +//static +U32 LLFontBitmapCache::getNumComponents(EFontGlyphType bitmap_type) +{ +	switch (bitmap_type) +	{ +		case EFontGlyphType::Grayscale: +			return 2; +		case EFontGlyphType::Color: +			return 4; +		default: +			llassert(false); +			return 2; +	} +} diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h index 7de3a6b56f..c63281ab70 100644 --- a/indra/llrender/llfontbitmapcache.h +++ b/indra/llrender/llfontbitmapcache.h @@ -30,6 +30,14 @@  #include <vector>  #include "lltrace.h" +enum class EFontGlyphType : U32 +{ +	Grayscale = 0, +	Color, +	Count, +	Unspecified, +}; +  // Maintain a collection of bitmaps containing rendered glyphs.  // Generalizes the single-bitmap logic from LLFontFreetype and LLFontGL.  class LLFontBitmapCache @@ -39,35 +47,35 @@ public:  	~LLFontBitmapCache();  	// Need to call this once, before caching any glyphs. - 	void init(S32 num_components, -			  S32 max_char_width, + 	void init(S32 max_char_width,  			  S32 max_char_height);  	void reset(); -	BOOL nextOpenPos(S32 width, S32 &posX, S32 &posY, S32 &bitmapNum); +	BOOL nextOpenPos(S32 width, S32& posX, S32& posY, EFontGlyphType bitmapType, U32& bitmapNum);  	void destroyGL(); - 	LLImageRaw *getImageRaw(U32 bitmapNum = 0) const; - 	LLImageGL *getImageGL(U32 bitmapNum = 0) const; -	 + 	LLImageRaw* getImageRaw(EFontGlyphType bitmapType, U32 bitmapNum) const; + 	LLImageGL* getImageGL(EFontGlyphType bitmapType, U32 bitmapNum) const; +  	S32 getMaxCharWidth() const { return mMaxCharWidth; } -	S32 getNumComponents() const { return mNumComponents; } +	U32 getNumBitmaps(EFontGlyphType bitmapType) const { return (bitmapType < EFontGlyphType::Count) ? mImageRawVec[static_cast<U32>(bitmapType)].size() : 0; }  	S32 getBitmapWidth() const { return mBitmapWidth; }  	S32 getBitmapHeight() const { return mBitmapHeight; } +protected: +	static U32 getNumComponents(EFontGlyphType bitmap_type); +  private: -	S32 mNumComponents; -	S32 mBitmapWidth; -	S32 mBitmapHeight; -	S32 mBitmapNum; -	S32 mMaxCharWidth; -	S32 mMaxCharHeight; -	S32 mCurrentOffsetX; -	S32 mCurrentOffsetY; -	std::vector<LLPointer<LLImageRaw> >	mImageRawVec; -	std::vector<LLPointer<LLImageGL> > mImageGLVec; +	S32 mBitmapWidth = 0; +	S32 mBitmapHeight = 0; +	S32 mCurrentOffsetX[static_cast<U32>(EFontGlyphType::Count)] = { 1 }; +	S32 mCurrentOffsetY[static_cast<U32>(EFontGlyphType::Count)] = { 1 }; +	S32 mMaxCharWidth = 0; +	S32 mMaxCharHeight = 0; +	std::vector<LLPointer<LLImageRaw>> mImageRawVec[static_cast<U32>(EFontGlyphType::Count)]; +	std::vector<LLPointer<LLImageGL>> mImageGLVec[static_cast<U32>(EFontGlyphType::Count)];  };  #endif //LL_LLFONTBITMAPCACHE_H diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index e964d1586f..ca9f2ed778 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -34,14 +34,17 @@  #ifdef LL_WINDOWS  #include <freetype2\freetype\ftsystem.h>  #endif +#include "llfontfreetypesvg.h"  // For some reason, this won't work if it's not wrapped in the ifdef  #ifdef FT_FREETYPE_H  #include FT_FREETYPE_H  #endif +#include "lldir.h"  #include "llerror.h"  #include "llimage.h" +#include "llimagepng.h"  //#include "llimagej2c.h"  #include "llmath.h"	// Linden math  #include "llstring.h" @@ -49,6 +52,8 @@  #include "llfontbitmapcache.h"  #include "llgl.h" +#define ENABLE_OT_SVG_SUPPORT +  FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;  LLFontManager *gFontManagerp = NULL; @@ -81,6 +86,16 @@ LLFontManager::LLFontManager()  		LL_ERRS() << "Freetype initialization failure!" << LL_ENDL;  		FT_Done_FreeType(gFTLibrary);  	} + +#ifdef ENABLE_OT_SVG_SUPPORT +	SVG_RendererHooks hooks = { +		LLFontFreeTypeSvgRenderer::OnInit, +		LLFontFreeTypeSvgRenderer::OnFree, +		LLFontFreeTypeSvgRenderer::OnRender, +		LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot, +	}; +	FT_Property_Set(gFTLibrary, "ot-svg", "svg-hooks", &hooks); +#endif  }  LLFontManager::~LLFontManager() @@ -89,8 +104,9 @@ LLFontManager::~LLFontManager()  } -LLFontGlyphInfo::LLFontGlyphInfo(U32 index) +LLFontGlyphInfo::LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type)  :	mGlyphIndex(index), +	mGlyphType(glyph_type),  	mWidth(0),			// In pixels  	mHeight(0),			// In pixels  	mXAdvance(0.f),		// In pixels @@ -99,10 +115,25 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index)  	mYBitmapOffset(0), 	// Offset to the origin in the bitmap  	mXBearing(0),		// Distance from baseline to left in pixels  	mYBearing(0),		// Distance from baseline to top in pixels -	mBitmapNum(0) // Which bitmap in the bitmap cache contains this glyph +	mBitmapEntry(std::make_pair(EFontGlyphType::Unspecified, -1)) // Which bitmap in the bitmap cache contains this glyph  {  } +LLFontGlyphInfo::LLFontGlyphInfo(const LLFontGlyphInfo& fgi) +	: mGlyphIndex(fgi.mGlyphIndex) +	, mGlyphType(fgi.mGlyphType) +	, mWidth(fgi.mWidth) +	, mHeight(fgi.mHeight) +	, mXAdvance(fgi.mXAdvance) +	, mYAdvance(fgi.mYAdvance) +	, mXBitmapOffset(fgi.mXBitmapOffset) +	, mYBitmapOffset(fgi.mYBitmapOffset) +	, mXBearing(fgi.mXBearing) +	, mYBearing(fgi.mYBearing) +{ +	mBitmapEntry = fgi.mBitmapEntry; +} +  LLFontFreetype::LLFontFreetype()  :	mFontBitmapCachep(new LLFontBitmapCache),  	mAscender(0.f), @@ -156,7 +187,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, 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. @@ -220,7 +251,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v  	S32 max_char_width = ll_round(0.5f + (x_max - x_min));  	S32 max_char_height = ll_round(0.5f + (y_max - y_min)); -	mFontBitmapCachep->init(components, max_char_width, max_char_height); +	mFontBitmapCachep->init(max_char_width, max_char_height);  	if (!mFTFace->charmap)  	{ @@ -231,7 +262,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v  	if (!mIsFallback)  	{  		// Add the default glyph -		addGlyphFromFont(this, 0, 0); +		addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale);  	}  	mName = filename; @@ -323,14 +354,11 @@ void LLFontFreetype::clearFontStreams()  }  #endif -void LLFontFreetype::setFallbackFonts(const font_vector_t &font) -{ -	mFallbackFonts = font; -} - -const LLFontFreetype::font_vector_t &LLFontFreetype::getFallbackFonts() const +void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor)  { -	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 @@ -354,7 +382,7 @@ F32 LLFontFreetype::getXAdvance(llwchar wch) const  		return 0.0;  	// Return existing info only if it is current -	LLFontGlyphInfo* gi = getGlyphInfo(wch); +	LLFontGlyphInfo* gi = getGlyphInfo(wch, EFontGlyphType::Unspecified);  	if (gi)  	{  		return gi->mXAdvance; @@ -386,10 +414,10 @@ F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const  		return 0.0;  	//llassert(!mIsFallback); -	LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left);; +	LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left, EFontGlyphType::Unspecified);;  	U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;  	// Kern this puppy. -	LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right); +	LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right, EFontGlyphType::Unspecified);  	U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0;  	FT_Vector  delta; @@ -420,60 +448,94 @@ BOOL LLFontFreetype::hasGlyph(llwchar wch) const  	return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end());  } -LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch) const +LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type) const  {  	if (mFTFace == NULL)  		return FALSE;  	llassert(!mIsFallback); +	llassert(glyph_type < EFontGlyphType::Count);  	//LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL;  	FT_UInt glyph_index; +	// Fallback fonts with a functor have precedence over everything else +	fallback_font_vector_t::const_iterator it_fallback = mFallbackFonts.cbegin(); +	/* This leads to a bug SL-19831 "Check marks in the menu are less visible." +	** Also, LLFontRegistry::createFont() says: "Fallback fonts don't render" +	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); +				return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type);  			}  		}  	} -	char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); -	if (iter == mCharGlyphInfoMap.end()) +	std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); +	char_glyph_info_map_t::iterator iter =  +		std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }); +	if (iter == range_it.second)  	{ -		return addGlyphFromFont(this, wch, glyph_index); +		return addGlyphFromFont(this, wch, glyph_index, glyph_type);  	}  	return NULL;  } -LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const +LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType requested_glyph_type) const  {      LL_PROFILE_ZONE_SCOPED;  	if (mFTFace == NULL)  		return NULL;  	llassert(!mIsFallback); -	fontp->renderGlyph(glyph_index); +	fontp->renderGlyph(requested_glyph_type, glyph_index); + +	EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified; +	switch (fontp->mFTFace->glyph->bitmap.pixel_mode) +	{ +		case FT_PIXEL_MODE_MONO: +		case FT_PIXEL_MODE_GRAY: +			bitmap_glyph_type = EFontGlyphType::Grayscale; +			break; +		case FT_PIXEL_MODE_BGRA: +			bitmap_glyph_type = EFontGlyphType::Color; +			break; +		default: +			llassert_always(true); +			break; +	}  	S32 width = fontp->mFTFace->glyph->bitmap.width;  	S32 height = fontp->mFTFace->glyph->bitmap.rows;  	S32 pos_x, pos_y; -	S32 bitmap_num; -	mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_num); +	U32 bitmap_num; +	mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_glyph_type, bitmap_num);  	mAddGlyphCount++; -	LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index); +	LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index, requested_glyph_type);  	gi->mXBitmapOffset = pos_x;  	gi->mYBitmapOffset = pos_y; -	gi->mBitmapNum = bitmap_num; +	gi->mBitmapEntry = std::make_pair(bitmap_glyph_type, bitmap_num);  	gi->mWidth = width;  	gi->mHeight = height;  	gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; @@ -484,8 +546,12 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l  	insertGlyphInfo(wch, gi); -	llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO -	    || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); +	if (requested_glyph_type != bitmap_glyph_type) +	{ +		LLFontGlyphInfo* gi_temp = new LLFontGlyphInfo(*gi); +		gi_temp->mGlyphType = bitmap_glyph_type; +		insertGlyphInfo(wch, gi_temp); +	}  	if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO  	    || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) @@ -520,78 +586,86 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l  			buffer_row_stride = width;  		} -		switch (mFontBitmapCachep->getNumComponents()) -		{ -		case 1: -			mFontBitmapCachep->getImageRaw(bitmap_num)->setSubImage(pos_x, -																	pos_y, -																	width, -																	height, -																	buffer_data, -																	buffer_row_stride, -																	TRUE); -			break; -		case 2: -			setSubImageLuminanceAlpha(pos_x,	 -									  pos_y, -									  bitmap_num, -									  width, -									  height, -									  buffer_data, -									  buffer_row_stride); -			break; -		default: -			break; -		} +		setSubImageLuminanceAlpha(pos_x, +									pos_y, +									bitmap_num, +									width, +									height, +									buffer_data, +									buffer_row_stride);  		if (tmp_graydata)  			delete[] tmp_graydata; +	} +	else if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) +	{ +		setSubImageBGRA(pos_x, +		                pos_y, +		                bitmap_num, +		                fontp->mFTFace->glyph->bitmap.width, +		                fontp->mFTFace->glyph->bitmap.rows, +		                fontp->mFTFace->glyph->bitmap.buffer, +		                llabs(fontp->mFTFace->glyph->bitmap.pitch));  	} else { -		// we don't know how to handle this pixel format from FreeType; -		// omit it from the font-image. +		llassert(false);  	} -	LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num); -	LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); +	LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_glyph_type, bitmap_num); +	LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_glyph_type, bitmap_num);  	image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());  	return gi;  } -LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch) const +LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const  { -	char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); -	if (iter != mCharGlyphInfoMap.end()) +	std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); + +	char_glyph_info_map_t::iterator iter = (EFontGlyphType::Unspecified != glyph_type) +		? std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }) +		: range_it.first; +	if (iter != range_it.second)  	{  		return iter->second;  	}  	else  	{  		// this glyph doesn't yet exist, so render it and return the result -		return addGlyph(wch); +		return addGlyph(wch, (EFontGlyphType::Unspecified != glyph_type) ? glyph_type : EFontGlyphType::Grayscale);  	}  }  void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const  { -	char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); -	if (iter != mCharGlyphInfoMap.end()) +	llassert(gi->mGlyphType < EFontGlyphType::Count); +	std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); + +	char_glyph_info_map_t::iterator iter = +		std::find_if(range_it.first, range_it.second, [&gi](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == gi->mGlyphType; }); +	if (iter != range_it.second)  	{  		delete iter->second;  		iter->second = gi;  	}  	else  	{ -		mCharGlyphInfoMap[wch] = gi; +		mCharGlyphInfoMap.insert(std::make_pair(wch, gi));  	}  } -void LLFontFreetype::renderGlyph(U32 glyph_index) const +void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const  {  	if (mFTFace == NULL)  		return; -	llassert_always(! FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT) ); +	FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT; +	if (EFontGlyphType::Color == bitmap_type) +	{ +		// We may not actually get a color render so our caller should always examine mFTFace->glyph->bitmap.pixel_mode +		load_flags |= FT_LOAD_COLOR; +	} + +	llassert_always(! FT_Load_Glyph(mFTFace, glyph_index, load_flags) );  	llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) ); @@ -601,7 +675,7 @@ void LLFontFreetype::renderGlyph(U32 glyph_index) const  void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)  {  	resetBitmapCache();  -	loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mFontBitmapCachep->getNumComponents(), mIsFallback); +	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. @@ -611,11 +685,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);  			}  		}  	} @@ -637,7 +709,7 @@ void LLFontFreetype::resetBitmapCache()  	if(!mIsFallback)  	{  		// Add the empty glyph -		addGlyphFromFont(this, 0, 0); +		addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale);  	}  } @@ -651,6 +723,34 @@ const std::string &LLFontFreetype::getName() const  	return mName;  } +static void dumpFontBitmap(const LLImageRaw* image_raw, const std::string& file_name) +{ +	LLPointer<LLImagePNG> tmpImage = new LLImagePNG(); +	if ( (tmpImage->encode(image_raw, 0.0f)) && (tmpImage->save(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name))) ) +	{ +		LL_INFOS("Font") << "Successfully saved " << file_name << LL_ENDL; +	} +	else +	{ +		LL_WARNS("Font") << "Failed to save " << file_name << LL_ENDL; +	} +} + +void LLFontFreetype::dumpFontBitmaps() const +{ +	// Dump all the regular bitmaps (if any) +	for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Grayscale); idx < cnt; idx++) +	{ +		dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, idx), llformat("%s_%d_%d_%d.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); +	} + +	// Dump all the color bitmaps (if any) +	for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Color); idx < cnt; idx++) +	{ +		dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, idx), llformat("%s_%d_%d_%d_clr.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); +	} +} +  const LLFontBitmapCache* LLFontFreetype::getFontBitmapCache() const  {  	return mFontBitmapCachep; @@ -666,17 +766,46 @@ U8 LLFontFreetype::getStyle() const  	return mStyle;  } +bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const +{ +	LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num); +	llassert(!mIsFallback); +	llassert(image_raw && (image_raw->getComponents() == 4)); + +	// NOTE: inspired by LLImageRaw::setSubImage() +	U32* image_data = (U32*)image_raw->getData(); +	if (!image_data) +	{ +		return false; +	} + +	for (U32 idxRow = 0; idxRow < height; idxRow++) +	{ +		const U32 nSrcRow = height - 1 - idxRow; +		const U32 nSrcOffset = nSrcRow * width * image_raw->getComponents(); +		const U32 nDstOffset = (y + idxRow) * image_raw->getWidth() + x; + +		for (U32 idxCol = 0; idxCol < width; idxCol++) +		{ +			U32 nTemp = nSrcOffset + idxCol * 4; +			image_data[nDstOffset + idxCol] = data[nTemp + 3] << 24 | data[nTemp] << 16 | data[nTemp + 1] << 8 | data[nTemp + 2]; +		} +	} + +	return true; +} +  void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const  { -	LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); +	LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, bitmap_num);  	llassert(!mIsFallback);  	llassert(image_raw && (image_raw->getComponents() == 2)); -  	U8 *target = image_raw->getData(); +    llassert(target); -	if (!data) +	if (!data || !target)  	{  		return;  	} diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index f61f169987..b036d337ba 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -56,9 +56,11 @@ private:  struct LLFontGlyphInfo  { -	LLFontGlyphInfo(U32 index); +	LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type); +	LLFontGlyphInfo(const LLFontGlyphInfo& fgi);  	U32 mGlyphIndex; +	EFontGlyphType mGlyphType;  	// Metrics  	S32 mWidth;			// In pixels @@ -71,7 +73,7 @@ struct LLFontGlyphInfo  	S32 mYBitmapOffset; // Offset to the origin in the bitmap  	S32 mXBearing;	// Distance from baseline to left in pixels  	S32 mYBearing;	// Distance from baseline to top in pixels -	S32 mBitmapNum; // Which bitmap in the bitmap cache contains this glyph +	std::pair<EFontGlyphType, S32> mBitmapEntry; // Which bitmap in the bitmap cache contains this glyph  };  extern LLFontManager *gFontManagerp; @@ -84,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, S32 components, BOOL is_fallback, S32 face_n = 0); +	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); @@ -93,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; @@ -135,7 +135,7 @@ public:  	F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters  	F32 getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const; // Get the kerning between the two characters -	LLFontGlyphInfo* getGlyphInfo(llwchar wch) const; +	LLFontGlyphInfo* getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const;  	void reset(F32 vert_dpi, F32 horz_dpi); @@ -143,6 +143,7 @@ public:  	const std::string& getName() const; +	void       dumpFontBitmaps() const;  	const LLFontBitmapCache* getFontBitmapCache() const;  	void setStyle(U8 style); @@ -151,10 +152,11 @@ public:  private:  	void resetBitmapCache();  	void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const; +	bool setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const;  	BOOL hasGlyph(llwchar wch) const;		// Has a glyph for this character -	LLFontGlyphInfo* addGlyph(llwchar wch) const;		// Add a new character to the font if necessary -	LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const;	// Add a glyph from this font to the other (returns the glyph_index, 0 if not found) -	void renderGlyph(U32 glyph_index) const; +	LLFontGlyphInfo* addGlyph(llwchar wch, EFontGlyphType glyph_type) const;		// Add a new character to the font if necessary +	LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType bitmap_type) const;	// Add a glyph from this font to the other (returns the glyph_index, 0 if not found) +	void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const;  	void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const;  	std::string mName; @@ -174,9 +176,12 @@ 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) -	typedef boost::unordered_map<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t; +	// *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;  	mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap  	mutable LLFontBitmapCache* mFontBitmapCachep; diff --git a/indra/llrender/llfontfreetypesvg.cpp b/indra/llrender/llfontfreetypesvg.cpp new file mode 100644 index 0000000000..19d327a4c9 --- /dev/null +++ b/indra/llrender/llfontfreetypesvg.cpp @@ -0,0 +1,205 @@ +/** + * @file llfontfreetypesvg.cpp + * @brief Freetype font library SVG glyph rendering + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llfontfreetypesvg.h" + +#if LL_WINDOWS +#pragma warning (push) +#pragma warning (disable : 4702) +#endif + +#define NANOSVG_IMPLEMENTATION +#include <nanosvg/nanosvg.h> +#define NANOSVGRAST_IMPLEMENTATION +#include <nanosvg/nanosvgrast.h> + +#if LL_WINDOWS +#pragma warning (pop) +#endif + +struct LLSvgRenderData +{ +	FT_UInt    GlyphIndex = 0; +	FT_Error   Error = FT_Err_Ok; // FreeType currently (@2.12.1) ignores the error value returned by the preset glyph slot callback so we return it at render time +	// (See https://github.com/freetype/freetype/blob/5faa1df8b93ebecf0f8fd5fe8fda7b9082eddced/src/base/ftobjs.c#L1170) +	NSVGimage* pNSvgImage = nullptr; +	float      Scale = 0.f; +}; + +// static +FT_Error LLFontFreeTypeSvgRenderer::OnInit(FT_Pointer* state) +{ +	// The SVG driver hook state is shared across all callback invocations; since our state is lightweight +	// we store it in the glyph instead. +	*state = nullptr; + +	return FT_Err_Ok; +} + +// static +void LLFontFreeTypeSvgRenderer::OnFree(FT_Pointer* state) +{ +} + +// static +void LLFontFreeTypeSvgRenderer::OnDataFinalizer(void* objectp) +{ +	FT_GlyphSlot glyph_slot = static_cast<FT_GlyphSlot>(objectp); + +	LLSvgRenderData* pData = static_cast<LLSvgRenderData*>(glyph_slot->generic.data); +	glyph_slot->generic.data = nullptr; +	glyph_slot->generic.finalizer = nullptr; +	delete(pData); +} + +//static +FT_Error LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer*) +{ +	FT_SVG_Document document = static_cast<FT_SVG_Document>(glyph_slot->other); + +	llassert(!glyph_slot->generic.data || !cache || glyph_slot->glyph_index == ((LLSvgRenderData*)glyph_slot->generic.data)->GlyphIndex); +	if (!glyph_slot->generic.data) +	{ +		glyph_slot->generic.data = new LLSvgRenderData(); +		glyph_slot->generic.finalizer = LLFontFreeTypeSvgRenderer::OnDataFinalizer; +	} +	LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data); +	if (!cache) +	{ +		datap->GlyphIndex = glyph_slot->glyph_index; +		datap->Error = FT_Err_Ok; +	} + +	// NOTE: nsvgParse modifies the input string so we need a temporary copy +	llassert(!datap->pNSvgImage || cache); +	if (!datap->pNSvgImage) +	{ +		char* document_buffer = new char[document->svg_document_length + 1]; +		memcpy(document_buffer, document->svg_document, document->svg_document_length); +		document_buffer[document->svg_document_length] = '\0'; + +		datap->pNSvgImage = nsvgParse(document_buffer, "px", 0.); + +		delete[] document_buffer; +	} + +	if (!datap->pNSvgImage) +	{ +		datap->Error = FT_Err_Invalid_SVG_Document; +		return FT_Err_Invalid_SVG_Document; +	} + +	// We don't (currently) support transformations so test for an identity rotation matrix + zero translation +	if (document->transform.xx != 1 << 16 || document->transform.yx != 0 || +		document->transform.xy != 0 || document->transform.yy != 1 << 16 || +		document->delta.x > 0 || document->delta.y > 0) +	{ +		datap->Error = FT_Err_Unimplemented_Feature; +		return FT_Err_Unimplemented_Feature; +	} + +	float svg_width = datap->pNSvgImage->width; +	float svg_height = datap->pNSvgImage->height; +	if (svg_width == 0.f || svg_height == 0.f) +	{ +		svg_width = document->units_per_EM; +		svg_height = document->units_per_EM; +	} + +	float svg_x_scale = (float)document->metrics.x_ppem / floorf(svg_width); +	float svg_y_scale = (float)document->metrics.y_ppem / floorf(svg_height); +	float svg_scale = llmin(svg_x_scale, svg_y_scale); +	datap->Scale = svg_scale; + +	glyph_slot->bitmap.width = floorf(svg_width) * svg_scale; +	glyph_slot->bitmap.rows = floorf(svg_height) * svg_scale; +	glyph_slot->bitmap_left = (document->metrics.x_ppem - glyph_slot->bitmap.width) / 2; +	glyph_slot->bitmap_top = glyph_slot->face->size->metrics.ascender / 64.f; +	glyph_slot->bitmap.pitch = glyph_slot->bitmap.width * 4; +	glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; + +	/* Copied as-is from fcft (MIT license) */ + +	// Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box. +	float horiBearingX = 0.; +	float horiBearingY = -glyph_slot->bitmap_top; + +	// XXX parentheses correct? +	float vertBearingX = glyph_slot->metrics.horiBearingX / 64.0f - glyph_slot->metrics.horiAdvance / 64.0f / 2; +	float vertBearingY = (glyph_slot->metrics.vertAdvance / 64.0f - glyph_slot->metrics.height / 64.0f) / 2; + +	// Do conversion in two steps to avoid 'bad function cast' warning +	glyph_slot->metrics.width = glyph_slot->bitmap.width * 64; +	glyph_slot->metrics.height = glyph_slot->bitmap.rows * 64; +	glyph_slot->metrics.horiBearingX = horiBearingX * 64; +	glyph_slot->metrics.horiBearingY = horiBearingY * 64; +	glyph_slot->metrics.vertBearingX = vertBearingX * 64; +	glyph_slot->metrics.vertBearingY = vertBearingY * 64; +	if (glyph_slot->metrics.vertAdvance == 0) +	{ +		glyph_slot->metrics.vertAdvance = glyph_slot->bitmap.rows * 1.2f * 64; +	} + +	return FT_Err_Ok; +} + +// static +FT_Error LLFontFreeTypeSvgRenderer::OnRender(FT_GlyphSlot glyph_slot, FT_Pointer*) +{ +	LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data); +	llassert(FT_Err_Ok == datap->Error); +	if (FT_Err_Ok != datap->Error) +	{ +		return datap->Error; +	} + +	// Render to glyph bitmap +	NSVGrasterizer* nsvgRasterizer = nsvgCreateRasterizer(); +	nsvgRasterize(nsvgRasterizer, datap->pNSvgImage, 0, 0, datap->Scale, glyph_slot->bitmap.buffer, glyph_slot->bitmap.width, glyph_slot->bitmap.rows, glyph_slot->bitmap.pitch); +	nsvgDeleteRasterizer(nsvgRasterizer); +	nsvgDelete(datap->pNSvgImage); +	datap->pNSvgImage = nullptr; + +	// Convert from RGBA to BGRA +	U32* pixel_buffer = (U32*)glyph_slot->bitmap.buffer; U8* byte_buffer = glyph_slot->bitmap.buffer; +	for (size_t y = 0, h = glyph_slot->bitmap.rows; y < h; y++) +	{ +		for (size_t x = 0, w = glyph_slot->bitmap.pitch / 4; x < w; x++) +		{ +			size_t pixel_idx = y * w + x; +			size_t byte_idx = pixel_idx * 4; +			U8 alpha = byte_buffer[byte_idx + 3]; +			// Store as ARGB (*TODO - do we still have to care about endianness?) +			pixel_buffer[y * w + x] = alpha << 24 | (byte_buffer[byte_idx] * alpha / 0xFF) << 16 | (byte_buffer[byte_idx + 1] * alpha / 0xFF) << 8 | (byte_buffer[byte_idx + 2] * alpha / 0xFF); +		} +	} + +	glyph_slot->format = FT_GLYPH_FORMAT_BITMAP; +	glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; +	return FT_Err_Ok; +} diff --git a/indra/llrender/llfontfreetypesvg.h b/indra/llrender/llfontfreetypesvg.h new file mode 100644 index 0000000000..b5f541991a --- /dev/null +++ b/indra/llrender/llfontfreetypesvg.h @@ -0,0 +1,54 @@ +/** + * @file llfontfreetypesvg.h + * @brief Freetype font library SVG glyph rendering + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#pragma once + +#include <ft2build.h> +#include FT_TYPES_H +#include FT_MODULE_H +#include FT_OTSVG_H + + // See https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html +class LLFontFreeTypeSvgRenderer +{ +public: +	// Called when the very first OT-SVG glyph is rendered (across the entire lifetime of our FT_Library object) +	static FT_Error OnInit(FT_Pointer* state); + +	// Called when the ot-svg module is being freed (but only called if the init hook was called previously) +	static void     OnFree(FT_Pointer* state); + +	// Called to preset the glyph slot, twice per glyph: +	//   - when FT_Load_Glyph needs to preset the glyph slot (with cache == false) +	//   - right before the svg module calls the render callback hook. (with cache == true) +	static FT_Error OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer* state); + +	// Called to render an OT-SVG glyph (right after the preset hook OnPresetGlypthSlot was called with cache set to TRUE) +	static FT_Error OnRender(FT_GlyphSlot glyph_slot, FT_Pointer* state); + +	// Called to deallocate our per glyph slot data +	static void OnDataFinalizer(void* objectp); +}; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 6f4f2ec62c..165d83992b 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, F32 vert_dpi, F32 horz_dpi, S32 components, 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, components, 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) @@ -110,14 +110,14 @@ S32 LLFontGL::getNumFaces(const std::string& filename)  }  S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, -    ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const +    ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses, BOOL use_color) const  {      LLRectf rect_float(rect.mLeft, rect.mTop, rect.mRight, rect.mBottom); -    return render(wstr, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses); +    return render(wstr, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses, use_color);  }  S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,  -					 ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const +					 ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses, BOOL use_color) const  {  	F32 x = rect.mLeft;  	F32 y = 0.f; @@ -138,12 +138,12 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rec  		y = rect.mBottom;  		break;  	} -	return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses); +	return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses, use_color);  }  S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,  -					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const +					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses, BOOL use_color) const  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; @@ -193,7 +193,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  	if (-1 == max_chars)  	{ -		length = (S32)wstr.length() - begin_offset; +		max_chars = length = (S32)wstr.length() - begin_offset;  	}  	else  	{ @@ -254,7 +254,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; -  	BOOL draw_ellipses = FALSE;  	if (use_ellipses)  	{ @@ -278,7 +277,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  	LLColor4U text_color(color); -	S32 bitmap_num = -1; +	std::pair<EFontGlyphType, S32> bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1);  	S32 glyph_count = 0;  	for (i = begin_offset; i < begin_offset + length; i++)  	{ @@ -288,7 +287,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  		next_glyph = NULL;  		if(!fgi)  		{ -			fgi = mFontFreetype->getGlyphInfo(wch); +			fgi = mFontFreetype->getGlyphInfo(wch, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color);  		}  		if (!fgi)  		{ @@ -296,8 +295,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  			break;  		}  		// Per-glyph bitmap texture. -		S32 next_bitmap_num = fgi->mBitmapNum; -		if (next_bitmap_num != bitmap_num) +		std::pair<EFontGlyphType, S32> next_bitmap_entry = fgi->mBitmapEntry; +		if (next_bitmap_entry != bitmap_entry)  		{  			// Actually draw the queued glyphs before switching their texture;  			// otherwise the queued glyphs will be taken from wrong textures. @@ -311,8 +310,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  				glyph_count = 0;  			} -			bitmap_num = next_bitmap_num; -			LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num); +			bitmap_entry = next_bitmap_entry; +			LLImageGL* font_image = font_bitmap_cache->getImageGL(bitmap_entry.first, bitmap_entry.second);  			gGL.getTexUnit(0)->bind(font_image);  		} @@ -345,7 +344,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  			glyph_count = 0;  		} -		drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength); +		drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, (bitmap_entry.first == EFontGlyphType::Grayscale) ? text_color : LLColor4U::white, style_to_add, shadow, drop_shadow_strength);  		chars_drawn++;  		cur_x += fgi->mXAdvance; @@ -355,7 +354,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  		if (next_char && (next_char < LAST_CHARACTER))  		{  			// Kern this puppy. -			next_glyph = mFontFreetype->getGlyphInfo(next_char); +			next_glyph = mFontFreetype->getGlyphInfo(next_char, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color);  			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);  		} @@ -409,7 +408,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons  				shadow,  				S32_MAX, max_pixels,  				right_x, -				FALSE);  +				FALSE, +				use_color);   		gGL.popUIMatrix();  	} @@ -423,19 +423,19 @@ S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, cons  	return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);  } -S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign,  VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels,  F32* right_x, BOOL use_ellipses) const +S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign,  VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels,  F32* right_x, BOOL use_ellipses, BOOL use_color) const  { -	return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses); +	return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);  }  S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const  { -	return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +	return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE, FALSE);  }  S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const  { -	return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE); +	return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE, FALSE);  }  // font metrics - override for LLFontFreetype that returns units of virtual pixels @@ -512,7 +512,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars  		next_glyph = NULL;  		if(!fgi)  		{ -			fgi = mFontFreetype->getGlyphInfo(wch); +			fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);  		}  		F32 advance = mFontFreetype->getXAdvance(fgi); @@ -535,7 +535,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars  			&& (next_char < LAST_CHARACTER))  		{  			// Kern this puppy. -			next_glyph = mFontFreetype->getGlyphInfo(next_char); +			next_glyph = mFontFreetype->getGlyphInfo(next_char, EFontGlyphType::Unspecified);  			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);  		}  		// Round after kerning. @@ -556,7 +556,7 @@ void LLFontGL::generateASCIIglyphs()      LL_PROFILE_ZONE_SCOPED_CATEGORY_UI      for (U32 i = 32; (i < 127); i++)      { -        mFontFreetype->getGlyphInfo(i); +        mFontFreetype->getGlyphInfo(i, EFontGlyphType::Grayscale);      }  } @@ -630,7 +630,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch  		next_glyph = NULL;  		if(!fgi)  		{ -			fgi = mFontFreetype->getGlyphInfo(wch); +			fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);  			if (NULL == fgi)  			{ @@ -655,7 +655,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch  		if (((i+1) < max_chars) && wchars[i+1])  		{  			// Kern this puppy. -			next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1]); +			next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1], EFontGlyphType::Unspecified);  			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);  		} @@ -702,7 +702,7 @@ S32	LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_  	{  		llwchar wch = wchars[i]; -		const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); +		const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);  		// last character uses character width, since the whole character needs to be visible  		// other characters just use advance @@ -777,7 +777,7 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t  		next_glyph = NULL;  		if(!glyph)  		{ -			glyph = mFontFreetype->getGlyphInfo(wch); +			glyph = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);  		}  		F32 char_width = mFontFreetype->getXAdvance(glyph); @@ -807,7 +807,7 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t  			&& (wchars[(pos + 1)]))  		{  			// Kern this puppy. -			next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1]); +			next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1], EFontGlyphType::Unspecified);  			cur_x += mFontFreetype->getXKerning(glyph, next_glyph);  		} @@ -847,6 +847,26 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st  	LLFontGL::loadDefaultFonts();  } +void LLFontGL::dumpTextures() +{ +	if (mFontFreetype.notNull()) +	{ +		mFontFreetype->dumpFontBitmaps(); +	} +} + +// static +void LLFontGL::dumpFonts() +{ +	sFontRegistry->dump(); +} + +// static +void LLFontGL::dumpFontTextures() +{ +	sFontRegistry->dumpTextures(); +} +  // Force standard fonts to get generated up front.  // This is primarily for error detection purposes.  // Don't do this during initClass because it can be slow and we want to get @@ -1010,6 +1030,20 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)  }  //static +LLFontGL* LLFontGL::getFontEmoji() +{ +	static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Large", 0)); +	return fontp;; +} + +//static +LLFontGL* LLFontGL::getFontEmojiHuge() +{ +	static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Huge", 0)); +	return fontp;; +} + +//static  LLFontGL* LLFontGL::getFontMonospace()  {  	static LLFontGL* fontp = getFont(LLFontDescriptor("Monospace","Monospace",0)); diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 93c6b78ce8..4d4f564033 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, const S32 components, BOOL is_fallback, S32 face_n = 0); +	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); @@ -98,7 +98,8 @@ public:  				U8 style = NORMAL, ShadowType shadow = NO_SHADOW,   				S32 max_chars = S32_MAX,  				F32* right_x=NULL,  -				BOOL use_ellipses = FALSE) const; +				BOOL use_ellipses = FALSE, +				BOOL use_color = FALSE) const;  	S32 render(const LLWString &text, S32 begin_offset,   				const LLRectf& rect,  @@ -107,7 +108,8 @@ public:  				U8 style = NORMAL, ShadowType shadow = NO_SHADOW,   				S32 max_chars = S32_MAX,  				F32* right_x=NULL,  -				BOOL use_ellipses = FALSE) const; +				BOOL use_ellipses = FALSE, +				BOOL use_color = FALSE) const;  	S32 render(const LLWString &text, S32 begin_offset,   				F32 x, F32 y,  @@ -116,12 +118,13 @@ public:  				U8 style = NORMAL, ShadowType shadow = NO_SHADOW,   				S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,   				F32* right_x=NULL,  -				BOOL use_ellipses = FALSE) const; +				BOOL use_ellipses = FALSE, +				BOOL use_color = FALSE) const;  	S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const;  	// renderUTF8 does a conversion, so is slower! -	S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign,  VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels,  F32* right_x, BOOL use_ellipses) const; +	S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign,  VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels,  F32* right_x, BOOL use_ellipses, BOOL use_color) const;  	S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const;  	S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const; @@ -165,6 +168,10 @@ public:  	static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures = true); +	       void dumpTextures(); +	static void dumpFonts(); +	static void dumpFontTextures(); +  	// Load sans-serif, sans-serif-small, etc.  	// Slow, requires multiple seconds to load fonts.  	static bool loadDefaultFonts(); @@ -187,6 +194,8 @@ public:  	static void setFontDisplay(BOOL flag) { sDisplayFont = flag; } +	static LLFontGL* getFontEmoji(); +	static LLFontGL* getFontEmojiHuge();  	static LLFontGL* getFontMonospace();  	static LLFontGL* getFontSansSerifSmall();  	static LLFontGL* getFontSansSerif(); diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 9750bd4fa1..d2c7e466e6 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -47,6 +47,10 @@ bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node);  const std::string MACOSX_FONT_PATH_LIBRARY = "/Library/Fonts/";  const std::string MACOSX_FONT_SUPPLEMENTAL = "Supplemental/"; +LLFontDescriptor::char_functor_map_t LLFontDescriptor::mCharFunctors({ +	{ "is_emoji", LLStringOps::isEmoji } +}); +  LLFontDescriptor::LLFontDescriptor():  	mStyle(0)  { @@ -55,22 +59,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, @@ -82,7 +86,6 @@ LLFontDescriptor::LLFontDescriptor(const std::string& name,  {  } -  bool LLFontDescriptor::operator<(const LLFontDescriptor& b) const  {  	if (mName < b.mName) @@ -175,7 +178,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) @@ -273,17 +288,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"))  		{ @@ -326,19 +348,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;  				} @@ -423,82 +445,80 @@ 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); +	font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY + MACOSX_FONT_SUPPLEMENTAL); +	font_search_paths.push_back(LLFontGL::getFontPathSystem() + MACOSX_FONT_SUPPLEMENTAL); +#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); -		font_paths.push_back(MACOSX_FONT_PATH_LIBRARY + MACOSX_FONT_SUPPLEMENTAL + *file_name_it); -		font_paths.push_back(sys_path +  MACOSX_FONT_SUPPLEMENTAL + *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, 2, 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) @@ -508,7 +528,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;  					} @@ -523,17 +544,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; @@ -720,11 +736,22 @@ 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; +		} +	} +} + +void LLFontRegistry::dumpTextures() +{ +	for (const auto& fontEntry : mFontMap) +	{ +		if (fontEntry.second) +		{ +			fontEntry.second->dumpTextures();  		}  	}  } diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h index e30c81c630..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 @@ -94,6 +120,7 @@ public:  	bool nameToSize(const std::string& size_name, F32& size);  	void dump(); +	void dumpTextures();  	const string_vec_t& getUltimateFallbackList() const; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 193cfa64b8..88402730c9 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -2330,8 +2330,6 @@ void LLGLSyncFence::wait()  	{  		while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)  		{ //track the number of times we've waited here -			static S32 waits = 0; -			waits++;  		}  	}  #endif diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 9108c6143c..a0314cb5f2 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -29,6 +29,8 @@ set(llui_SOURCE_FILES      lldockcontrol.cpp      lldraghandle.cpp      lleditmenuhandler.cpp +    llemojidictionary.cpp +    llemojihelper.cpp      llf32uictrl.cpp      llfiltereditor.cpp      llflashtimer.cpp @@ -139,6 +141,8 @@ set(llui_HEADER_FILES      lldockablefloater.h      lldockcontrol.h      lleditmenuhandler.h +    llemojidictionary.h +    llemojihelper.h      llf32uictrl.h      llfiltereditor.h       llflashtimer.h diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 8028f397f3..aeeff0b36f 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -68,6 +68,7 @@ LLButton::Params::Params()  	label_shadow("label_shadow", true),  	auto_resize("auto_resize", false),  	use_ellipses("use_ellipses", false), +	use_font_color("use_font_color", false),  	image_unselected("image_unselected"),  	image_selected("image_selected"),  	image_hover_selected("image_hover_selected"), @@ -160,6 +161,7 @@ LLButton::LLButton(const LLButton::Params& p)  	mDropShadowedText(p.label_shadow),  	mAutoResize(p.auto_resize),  	mUseEllipses( p.use_ellipses ), +	mUseFontColor( p.use_font_color),  	mHAlign(p.font_halign),  	mLeftHPad(p.pad_left),  	mRightHPad(p.pad_right), @@ -942,11 +944,8 @@ void LLButton::draw()  			break;  		} -		S32 y_offset = 2 + (getRect().getHeight() - 20)/2; -	  		if (pressed && mDisplayPressedState)  		{ -			y_offset--;  			x++;  		} @@ -963,7 +962,7 @@ void LLButton::draw()  			LLFontGL::NORMAL,  			mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW,  			S32_MAX, text_width, -			NULL, mUseEllipses); +			NULL, mUseEllipses, mUseFontColor);  	}  	LLUICtrl::draw(); @@ -1023,6 +1022,16 @@ BOOL LLButton::toggleState()  	return flipped;   } +void LLButton::setLabel( const std::string& label ) +{ +	mUnselectedLabel = mSelectedLabel = label; +} + +void LLButton::setLabel( const LLUIString& label ) +{ +	mUnselectedLabel = mSelectedLabel = label; +} +  void LLButton::setLabel( const LLStringExplicit& label )  {  	setLabelUnselected(label); @@ -1054,14 +1063,7 @@ bool LLButton::labelIsTruncated() const  const LLUIString& LLButton::getCurrentLabel() const  { -	if( getToggleState() ) -	{ -		return mSelectedLabel; -	} -	else -	{ -		return mUnselectedLabel; -	} +	return getToggleState() ? mSelectedLabel : mUnselectedLabel;  }  void LLButton::setImageUnselected(LLPointer<LLUIImage> image) diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index ccd31e90c0..257159f64f 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -73,6 +73,7 @@ public:  		Optional<bool>			label_shadow;  		Optional<bool>			auto_resize;  		Optional<bool>			use_ellipses; +		Optional<bool>			use_font_color;  		// images  		Optional<LLUIImage*>	image_unselected, @@ -174,6 +175,7 @@ public:  	void			setUnselectedLabelColor( const LLColor4& c )		{ mUnselectedLabelColor = c; }  	void			setSelectedLabelColor( const LLColor4& c )			{ mSelectedLabelColor = c; }  	void			setUseEllipses( BOOL use_ellipses )					{ mUseEllipses = use_ellipses; } +	void			setUseFontColor( BOOL use_font_color)				{ mUseFontColor = use_font_color; }  	boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); @@ -238,6 +240,8 @@ public:  	void            autoResize();	// resize with label of current btn state   	void            resize(LLUIString label); // resize with label input +	void			setLabel(const std::string& label); +	void			setLabel(const LLUIString& label);  	void			setLabel( const LLStringExplicit& label);  	virtual BOOL	setLabelArg( const std::string& key, const LLStringExplicit& text );  	void			setLabelUnselected(const LLStringExplicit& label); @@ -353,6 +357,7 @@ protected:  	bool						mDropShadowedText;  	bool						mAutoResize;  	bool						mUseEllipses; +	bool						mUseFontColor;  	bool						mBorderEnabled;  	bool						mFlashing; diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp new file mode 100644 index 0000000000..cdcf5a93d6 --- /dev/null +++ b/indra/llui/llemojidictionary.cpp @@ -0,0 +1,405 @@ +/** +* @file llemojidictionary.cpp +* @brief Implementation of LLEmojiDictionary +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#include "linden_common.h" + +#include "lldir.h" +#include "llemojidictionary.h" +#include "llsdserialize.h" + +#include <boost/algorithm/string.hpp> +#include <boost/range/adaptor/filtered.hpp> +#include <boost/range/algorithm/transform.hpp> + +// ============================================================================ +// Constants +// + +static const std::string SKINNED_EMOJI_FILENAME("emoji_characters.xml"); +static const std::string SKINNED_CATEGORY_FILENAME("emoji_categories.xml"); +static const std::string COMMON_GROUP_FILENAME("emoji_groups.xml"); +static const std::string GROUP_NAME_ALL("all"); +static const std::string GROUP_NAME_OTHERS("others"); +static const std::string GROUP_NAME_SKIP("skip"); + +// ============================================================================ +// Helper functions +// + +template<class T> +std::list<T> llsd_array_to_list(const LLSD& sd, std::function<void(T&)> mutator = {}); + +template<> +std::list<std::string> llsd_array_to_list(const LLSD& sd, std::function<void(std::string&)> mutator) +{ +    std::list<std::string> result; +    for (LLSD::array_const_iterator it = sd.beginArray(), end = sd.endArray(); it != end; ++it) +    { +        const LLSD& entry = *it; +        if (!entry.isString()) +            continue; + +        result.push_back(entry.asStringRef()); +        if (mutator) +        { +            mutator(result.back()); +        } +    } +    return result; +} + +struct emoji_filter_base +{ +    emoji_filter_base(const std::string& needle) +    { +        // Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category +        mNeedle = (boost::starts_with(needle, ":")) ? needle.substr(1) : needle; +        LLStringUtil::toLower(mNeedle); +    } + +protected: +    std::string mNeedle; +}; + +struct emoji_filter_shortcode_or_category_contains : public emoji_filter_base +{ +    emoji_filter_shortcode_or_category_contains(const std::string& needle) : emoji_filter_base(needle) {} + +    bool operator()(const LLEmojiDescriptor& descr) const +    { +        for (const auto& short_code : descr.ShortCodes) +        { +            if (boost::icontains(short_code, mNeedle)) +                return true; +        } + +        if (boost::icontains(descr.Category, mNeedle)) +            return true; + +        return false; +    } +}; + +std::string LLEmojiDescriptor::getShortCodes() const +{ +    std::string result; +    for (const std::string& shortCode : ShortCodes) +    { +        if (!result.empty()) +        { +            result += ", "; +        } +        result += shortCode; +    } +    return result; +} + +// ============================================================================ +// LLEmojiDictionary class +// + +LLEmojiDictionary::LLEmojiDictionary() +{ +} + +// static +void LLEmojiDictionary::initClass() +{ +    LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton(); + +    pThis->loadTranslations(); +    pThis->loadGroups(); +    pThis->loadEmojis(); +} + +LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const +{ +    LLWString result; +    boost::transform(mEmojis | boost::adaptors::filtered(emoji_filter_shortcode_or_category_contains(needle)), +                     std::back_inserter(result), [](const auto& descr) { return descr.Character; }); +    return result; +} + +const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromEmoji(llwchar emoji) const +{ +    const auto it = mEmoji2Descr.find(emoji); +    return (mEmoji2Descr.end() != it) ? it->second : nullptr; +} + +const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromShortCode(const std::string& short_code) const +{ +    const auto it = mShortCode2Descr.find(short_code); +    return (mShortCode2Descr.end() != it) ? it->second : nullptr; +} + +std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) const +{ +    const auto it = mEmoji2Descr.find(ch); +    return (mEmoji2Descr.end() != it) ? it->second->ShortCodes.front() : LLStringUtil::null; +} + +bool LLEmojiDictionary::isEmoji(llwchar ch) const +{ +    // Currently used codes: A9,AE,203C,2049,2122,...,2B55,3030,303D,3297,3299,1F004,...,1FAF6 +    if (ch == 0xA9 || ch == 0xAE || (ch >= 0x2000 && ch < 0x3300) || (ch >= 0x1F000 && ch < 0x20000)) +    { +        return mEmoji2Descr.find(ch) != mEmoji2Descr.end(); +    } + +    return false; +} + +void LLEmojiDictionary::loadTranslations() +{ +    std::vector<std::string> filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_CATEGORY_FILENAME, LLDir::CURRENT_SKIN); +    if (filenames.empty()) +    { +        LL_WARNS() << "Emoji file categories not found" << LL_ENDL; +        return; +    } + +    const std::string filename = filenames.back(); +    llifstream file(filename.c_str()); +    if (!file.is_open()) +    { +        LL_WARNS() << "Emoji file categories failed to open" << LL_ENDL; +        return; +    } + +    LL_DEBUGS() << "Loading emoji categories file at " << filename << LL_ENDL; + +    LLSD data; +    LLSDSerialize::fromXML(data, file); +    if (data.isUndefined()) +    { +        LL_WARNS() << "Emoji file categories missing or ill-formed" << LL_ENDL; +        return; +    } + +    // Register translations for all categories +    for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it) +    { +        const LLSD& sd = *it; +        const std::string& name = sd["Name"].asStringRef(); +        const std::string& category = sd["Category"].asStringRef(); +        if (!name.empty() && !category.empty()) +        { +            mTranslations[name] = category; +        } +        else +        { +            LL_WARNS() << "Skipping invalid emoji category '" << name << "' => '" << category << "'" << LL_ENDL; +        } +    } +} + +void LLEmojiDictionary::loadGroups() +{ +    const std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, COMMON_GROUP_FILENAME); +    llifstream file(filename.c_str()); +    if (!file.is_open()) +    { +        LL_WARNS() << "Emoji file groups failed to open" << LL_ENDL; +        return; +    } + +    LL_DEBUGS() << "Loading emoji groups file at " << filename << LL_ENDL; + +    LLSD data; +    LLSDSerialize::fromXML(data, file); +    if (data.isUndefined()) +    { +        LL_WARNS() << "Emoji file groups missing or ill-formed" << LL_ENDL; +        return; +    } + +    mGroups.clear(); +    // Add group "all" +    mGroups.emplace_back(); +    // https://www.compart.com/en/unicode/U+1F50D +    mGroups.front().Character = 0x1F50D; +    // https://www.compart.com/en/unicode/U+1F302 +    llwchar iconOthers = 0x1F302; + +    // Register all groups +    for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it) +    { +        const LLSD& sd = *it; +        const std::string& name = sd["Name"].asStringRef(); +        if (name == GROUP_NAME_ALL) +        { +            mGroups.front().Character = loadIcon(sd); +        } +        else if (name == GROUP_NAME_OTHERS) +        { +            iconOthers = loadIcon(sd); +        } +        else if (name == GROUP_NAME_SKIP) +        { +            mSkipCategories = loadCategories(sd); +            translateCategories(mSkipCategories); +        } +        else +        { +            // Add new group +            mGroups.emplace_back(); +            LLEmojiGroup& group = mGroups.back(); +            group.Character = loadIcon(sd); +            group.Categories = loadCategories(sd); +            translateCategories(group.Categories); + +            for (const std::string& category : group.Categories) +            { +                mCategory2Group.insert(std::make_pair(category, &group)); +            } +        } +    } + +    // Add group "others" +    mGroups.emplace_back(); +    mGroups.back().Character = iconOthers; +} + +void LLEmojiDictionary::loadEmojis() +{ +    std::vector<std::string> filenames = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN); +    if (filenames.empty()) +    { +        LL_WARNS() << "Emoji file characters not found" << LL_ENDL; +        return; +    } + +    const std::string filename = filenames.back(); +    llifstream file(filename.c_str()); +    if (!file.is_open()) +    { +        LL_WARNS() << "Emoji file characters failed to open" << LL_ENDL; +        return; +    } + +    LL_DEBUGS() << "Loading emoji characters file at " << filename << LL_ENDL; + +    LLSD data; +    LLSDSerialize::fromXML(data, file); +    if (data.isUndefined()) +    { +        LL_WARNS() << "Emoji file characters missing or ill-formed" << LL_ENDL; +        return; +    } + +    for (LLSD::array_const_iterator it = data.beginArray(), end = data.endArray(); it != end; ++it) +    { +        const LLSD& sd = *it; + +        llwchar icon = loadIcon(sd); +        if (!icon) +        { +            LL_WARNS() << "Skipping invalid emoji descriptor (no icon)" << LL_ENDL; +            continue; +        } + +        std::list<std::string> categories = loadCategories(sd); +        if (categories.empty()) +        { +            LL_WARNS() << "Skipping invalid emoji descriptor (no categories)" << LL_ENDL; +            continue; +        } + +        std::string category = categories.front(); + +        if (std::find(mSkipCategories.begin(), mSkipCategories.end(), category) != mSkipCategories.end()) +        { +            // This category is listed for skip +            continue; +        } + +        std::list<std::string> shortCodes = loadShortCodes(sd); +        if (shortCodes.empty()) +        { +            LL_WARNS() << "Skipping invalid emoji descriptor (no shortCodes)" << LL_ENDL; +            continue; +        } + +        if (mCategory2Group.find(category) == mCategory2Group.end()) +        { +            // Add unknown category to "others" group +            mGroups.back().Categories.push_back(category); +            mCategory2Group.insert(std::make_pair(category, &mGroups.back())); +        } + +        mEmojis.emplace_back(); +        LLEmojiDescriptor& emoji = mEmojis.back(); +        emoji.Character = icon; +        emoji.Category = category; +        emoji.ShortCodes = std::move(shortCodes); + +        mEmoji2Descr.insert(std::make_pair(icon, &emoji)); +        mCategory2Descrs[category].push_back(&emoji); +        for (const std::string& shortCode : emoji.ShortCodes) +        { +            mShortCode2Descr.insert(std::make_pair(shortCode, &emoji)); +        } +    } +} + +llwchar LLEmojiDictionary::loadIcon(const LLSD& sd) +{ +    // We don't currently support character composition +    const LLWString icon = utf8str_to_wstring(sd["Character"].asString()); +    return (1 == icon.size()) ? icon[0] : L'\0'; +} + +static inline std::list<std::string> loadStrings(const LLSD& sd, const std::string key) +{ +    auto toLower = [](std::string& str) { LLStringUtil::toLower(str); }; +    return llsd_array_to_list<std::string>(sd[key], toLower); +} + +std::list<std::string> LLEmojiDictionary::loadCategories(const LLSD& sd) +{ +    static const std::string categoriesKey("Categories"); +    return loadStrings(sd, categoriesKey); +} + +std::list<std::string> LLEmojiDictionary::loadShortCodes(const LLSD& sd) +{ +    static const std::string shortCodesKey("ShortCodes"); +    return loadStrings(sd, shortCodesKey); +} + +void LLEmojiDictionary::translateCategories(std::list<std::string>& categories) +{ +    for (std::string& category : categories) +    { +        auto it = mTranslations.find(category); +        if (it != mTranslations.end()) +        { +            category = it->second; +        } +    } +} + +// ============================================================================ diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h new file mode 100644 index 0000000000..f6442684a7 --- /dev/null +++ b/indra/llui/llemojidictionary.h @@ -0,0 +1,105 @@ +/** +* @file llemojidictionary.h +* @brief Header file for LLEmojiDictionary +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#pragma once + +#include "lldictionary.h" +#include "llinitdestroyclass.h" +#include "llsingleton.h" + +// ============================================================================ +// LLEmojiDescriptor class +// + +struct LLEmojiDescriptor +{ +    llwchar Character; +    std::string Category; +    std::list<std::string> ShortCodes; +    std::string getShortCodes() const; +}; + +// ============================================================================ +// LLEmojiGroup class +// + +struct LLEmojiGroup +{ +    llwchar Character; +    std::list<std::string> Categories; +}; + +// ============================================================================ +// LLEmojiDictionary class +// + +class LLEmojiDictionary : public LLParamSingleton<LLEmojiDictionary>, public LLInitClass<LLEmojiDictionary> +{ +    LLSINGLETON(LLEmojiDictionary); +    ~LLEmojiDictionary() override {}; + +public: +    typedef std::map<std::string, std::string> cat2cat_map_t; +    typedef std::map<std::string, const LLEmojiGroup*> cat2group_map_t; +    typedef std::map<llwchar, const LLEmojiDescriptor*> emoji2descr_map_t; +    typedef std::map<std::string, const LLEmojiDescriptor*> code2descr_map_t; +    typedef std::map<std::string, std::vector<const LLEmojiDescriptor*>> cat2descrs_map_t; + +    static void initClass(); +    LLWString findMatchingEmojis(const std::string& needle) const; +    const LLEmojiDescriptor* getDescriptorFromEmoji(llwchar emoji) const; +    const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const; +    std::string getNameFromEmoji(llwchar ch) const; +    bool isEmoji(llwchar ch) const; + +    const std::vector<LLEmojiGroup>& getGroups() const { return mGroups; } +    const emoji2descr_map_t& getEmoji2Descr() const { return mEmoji2Descr; } +    const cat2descrs_map_t& getCategory2Descrs() const { return mCategory2Descrs; } +    const code2descr_map_t& getShortCode2Descr() const { return mShortCode2Descr; } + +private: +    void loadTranslations(); +    void loadGroups(); +    void loadEmojis(); + +    static llwchar loadIcon(const LLSD& sd); +    static std::list<std::string> loadCategories(const LLSD& sd); +    static std::list<std::string> loadShortCodes(const LLSD& sd); +    void translateCategories(std::list<std::string>& categories); + +private: +    std::vector<LLEmojiGroup> mGroups; +    std::list<LLEmojiDescriptor> mEmojis; +    std::list<std::string> mSkipCategories; + +    cat2cat_map_t mTranslations; +    cat2group_map_t mCategory2Group; +    emoji2descr_map_t mEmoji2Descr; +    cat2descrs_map_t mCategory2Descrs; +    code2descr_map_t mShortCode2Descr; +}; + +// ============================================================================ diff --git a/indra/llui/llemojihelper.cpp b/indra/llui/llemojihelper.cpp new file mode 100644 index 0000000000..fb660a9e5b --- /dev/null +++ b/indra/llui/llemojihelper.cpp @@ -0,0 +1,166 @@ +/** +* @file llemojihelper.h +* @brief Header file for LLEmojiHelper +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#include "linden_common.h" + +#include "llemojidictionary.h" +#include "llemojihelper.h" +#include "llfloater.h" +#include "llfloaterreg.h" +#include "lluictrl.h" + +// ============================================================================ +// Constants +// + +constexpr char DEFAULT_EMOJI_HELPER_FLOATER[] = "emoji_complete"; +constexpr S32 HELPER_FLOATER_OFFSET_X = 20; +constexpr S32 HELPER_FLOATER_OFFSET_Y = 0; + +// ============================================================================ +// LLEmojiHelper +// + +std::string LLEmojiHelper::getToolTip(llwchar ch) const +{ +	return LLEmojiDictionary::instance().getNameFromEmoji(ch); +} + +bool LLEmojiHelper::isActive(const LLUICtrl* ctrl_p) const +{ +	return mHostHandle.get() == ctrl_p; +} + +// static +bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S32* pShortCodePos) +{ +	// If the cursor is currently on a colon start the check one character further back +	S32 shortCodePos = (cursorPos == 0 || L':' != wtext[cursorPos - 1]) ? cursorPos : cursorPos - 1; + +	auto isPartOfShortcode = [](llwchar ch) { +		switch (ch) +		{ +			case L'-': +			case L'_': +			case L'+': +				return true; +			default: +				return LLStringOps::isAlnum(ch); +		} +	}; +	while (shortCodePos > 1 && isPartOfShortcode(wtext[shortCodePos - 1])) +	{ +		shortCodePos--; +	} + +	bool isShortCode = (L':' == wtext[shortCodePos - 1]) && (cursorPos - shortCodePos >= 2); +	if (pShortCodePos) +		*pShortCodePos = (isShortCode) ? shortCodePos - 1 : -1; +	return isShortCode; +} + +void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(llwchar)> cb) +{ +	// Commit immediately if the user already typed a full shortcode +	if (const auto* emojiDescrp = LLEmojiDictionary::instance().getDescriptorFromShortCode(short_code)) +	{ +		cb(emojiDescrp->Character); +		hideHelper(); +		return; +	} + +	if (mHelperHandle.isDead()) +	{ +		LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER); +		mHelperHandle = pHelperFloater->getHandle(); +		mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())[0]); }, std::placeholders::_2)); +	} +	setHostCtrl(hostctrl_p); +	mEmojiCommitCb = cb; + +	S32 floater_x, floater_y; +	if (!hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView)) +	{ +		LL_ERRS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL; +		return; +	} + +	LLFloater* pHelperFloater = mHelperHandle.get(); +	LLRect rct = pHelperFloater->getRect(); +	rct.setLeftTopAndSize(floater_x - HELPER_FLOATER_OFFSET_X, floater_y - HELPER_FLOATER_OFFSET_Y + rct.getHeight(), rct.getWidth(), rct.getHeight()); +	pHelperFloater->setRect(rct); +	pHelperFloater->openFloater(LLSD().with("hint", short_code)); +} + +void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p) +{ +	if (ctrl_p && !isActive(ctrl_p)) +	{ +		return; +	} + +	setHostCtrl(nullptr); +} + +bool LLEmojiHelper::handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask) +{ +	if (mHelperHandle.isDead() || !isActive(ctrl_p)) +	{ +		return false; +	} + +	return mHelperHandle.get()->handleKey(key, mask, true); +} + +void LLEmojiHelper::onCommitEmoji(llwchar emoji) +{ +	if (!mHostHandle.isDead() && mEmojiCommitCb) +	{ +		mEmojiCommitCb(emoji); +	} +} + +void LLEmojiHelper::setHostCtrl(LLUICtrl* hostctrl_p) +{ +	const LLUICtrl* pCurHostCtrl = mHostHandle.get(); +	if (pCurHostCtrl != hostctrl_p) +	{ +		mHostCtrlFocusLostConn.disconnect(); +		mHostHandle.markDead(); +		mEmojiCommitCb = {}; + +		if (!mHelperHandle.isDead()) +		{ +			mHelperHandle.get()->closeFloater(); +		} + +		if (hostctrl_p) +		{ +			mHostHandle = hostctrl_p->getHandle(); +			mHostCtrlFocusLostConn = hostctrl_p->setFocusLostCallback(std::bind([&]() { hideHelper(getHostCtrl()); })); +		} +	} +} diff --git a/indra/llui/llemojihelper.h b/indra/llui/llemojihelper.h new file mode 100644 index 0000000000..58f68d12a4 --- /dev/null +++ b/indra/llui/llemojihelper.h @@ -0,0 +1,64 @@ +/** +* @file llemojihelper.h +* @brief Header file for LLEmojiHelper +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#pragma once + +#include "llhandle.h" +#include "llsingleton.h" + +#include <boost/signals2.hpp> + +class LLFloater; +class LLUICtrl; + +class LLEmojiHelper : public LLSingleton<LLEmojiHelper> +{ +	LLSINGLETON(LLEmojiHelper) {} +	~LLEmojiHelper() override {} + +public: +	// General +	std::string getToolTip(llwchar ch) const; +	bool        isActive(const LLUICtrl* ctrl_p) const; +	static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr); +	void        showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(llwchar)> commit_cb); +	void        hideHelper(const LLUICtrl* ctrl_p = nullptr); + +	// Eventing +	bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask); +	void onCommitEmoji(llwchar emoji); + +protected: +	LLUICtrl* getHostCtrl() const { return mHostHandle.get(); } +	void      setHostCtrl(LLUICtrl* hostctrl_p); + +private: +	LLHandle<LLUICtrl>  mHostHandle; +	LLHandle<LLFloater> mHelperHandle; +	boost::signals2::connection mHostCtrlFocusLostConn; +	boost::signals2::connection mHelperCommitConn; +	std::function<void(llwchar)> mEmojiCommitCb; +}; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 2303cd24b7..98895d56dd 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1509,14 +1509,24 @@ BOOL LLFloater::isFrontmost()  				&& floater_view->getFrontmost() == this);  } -void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition) +void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition, BOOL resize)  {  	mDependents.insert(floaterp->getHandle());  	floaterp->mDependeeHandle = getHandle();  	if (reposition)  	{ -		floaterp->setRect(gFloaterView->findNeighboringPosition(this, floaterp)); +		LLRect rect = gFloaterView->findNeighboringPosition(this, floaterp); +		if (resize) +		{ +			const LLRect& base = getRect(); +			if (rect.mTop == base.mTop) +				rect.mBottom = base.mBottom; +			else if (rect.mLeft == base.mLeft) +				rect.mRight = base.mRight; +			floaterp->reshape(rect.getWidth(), rect.getHeight(), FALSE); +		} +		floaterp->setRect(rect);  		floaterp->setSnapTarget(getHandle());  	}  	gFloaterView->adjustToFitScreen(floaterp, FALSE, TRUE); @@ -1527,12 +1537,12 @@ void LLFloater::addDependentFloater(LLFloater* floaterp, BOOL reposition)  	}  } -void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, BOOL reposition) +void LLFloater::addDependentFloater(LLHandle<LLFloater> dependent, BOOL reposition, BOOL resize)  {  	LLFloater* dependent_floaterp = dependent.get();  	if(dependent_floaterp)  	{ -		addDependentFloater(dependent_floaterp, reposition); +		addDependentFloater(dependent_floaterp, reposition, resize);  	}  } @@ -2488,7 +2498,7 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore  	if (mFrontChild == child)  	{ -		if (give_focus && !gFocusMgr.childHasKeyboardFocus(child)) +		if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child))  		{  			child->setFocus(TRUE);  		} @@ -3041,7 +3051,34 @@ void LLFloaterView::syncFloaterTabOrder()  			LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it);  			if (gFocusMgr.childHasKeyboardFocus(floaterp))  			{ -				bringToFront(floaterp, FALSE); +                if (mFrontChild != floaterp) +                { +                    // Grab a list of the top floaters that want to stay on top of the focused floater +					std::list<LLFloater*> listTop; +					if (mFrontChild && !mFrontChild->canFocusStealFrontmost()) +                    { +                        for (LLView* childp : *getChildList()) +                        { +							LLFloater* child_floaterp = static_cast<LLFloater*>(childp); +                            if (child_floaterp->canFocusStealFrontmost()) +                                break; +							listTop.push_back(child_floaterp); +                        } +                    } + +                    bringToFront(floaterp, FALSE); + +                    // Restore top floaters +					if (!listTop.empty()) +					{ +						for (LLView* childp : listTop) +						{ +							sendChildToFront(childp); +						} +						mFrontChild = listTop.back(); +					} +                } +  				break;  			}  		} diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 668cd208a9..3699629ef8 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -255,8 +255,8 @@ public:  	std::string		getShortTitle() const;  	virtual void	setMinimized(BOOL b);  	void			moveResizeHandlesToFront(); -	void			addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE); -	void			addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE); +	void			addDependentFloater(LLFloater* dependent, BOOL reposition = TRUE, BOOL resize = FALSE); +	void			addDependentFloater(LLHandle<LLFloater> dependent_handle, BOOL reposition = TRUE, BOOL resize = FALSE);  	LLFloater*		getDependee() { return (LLFloater*)mDependeeHandle.get(); }  	void		removeDependentFloater(LLFloater* dependent);  	BOOL			isMinimized() const				{ return mMinimized; } @@ -313,6 +313,9 @@ public:  	/*virtual*/ void setVisible(BOOL visible); // do not override  	/*virtual*/ void onVisibilityChange ( BOOL new_visibility ); // do not override +	bool            canFocusStealFrontmost() const { return mFocusStealsFrontmost; } +	void            setFocusStealsFrontmost(bool wants_frontmost) { mFocusStealsFrontmost = wants_frontmost; } +  	void			setFrontmost(BOOL take_focus = TRUE, BOOL restore = TRUE);       virtual void	setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD()); @@ -481,6 +484,7 @@ private:  	BOOL			mCanTearOff;  	BOOL			mCanMinimize;  	BOOL			mCanClose; +    bool            mFocusStealsFrontmost = true;	// FALSE if we don't want the currently focused floater to cover this floater without user interaction  	BOOL			mDragOnLeft;  	BOOL			mResizable; diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index e2b5279aab..674d8a6fe8 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -874,7 +874,7 @@ void LLFolderViewItem::drawLabel(const LLFontGL * font, const F32 x, const F32 y      //      font->renderUTF8(mLabel, 0, x, y, color,          LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -        S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, TRUE); +        S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, /*use_ellipses*/TRUE, /*use_color*/FALSE);  }  void LLFolderViewItem::draw() @@ -953,7 +953,7 @@ void LLFolderViewItem::draw()  	{  		font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,  						  LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -						  S32_MAX, S32_MAX, &right_x, FALSE ); +						  S32_MAX, S32_MAX, &right_x, /*use_ellipses*/FALSE, /*use_color*/FALSE );  	}  	//--------------------------------------------------------------------------------// @@ -966,7 +966,7 @@ void LLFolderViewItem::draw()          F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;          font->renderUTF8( combined_string, filter_offset, match_string_left, yy,              sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -            filter_string_length, S32_MAX, &right_x, FALSE ); +            filter_string_length, S32_MAX, &right_x, /*use_ellipses*/FALSE, /*use_color*/FALSE );      }      //Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 940cf398c0..7d13d731e2 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -89,6 +89,7 @@ LLLineEditor::Params::Params()  	background_image_disabled("background_image_disabled"),  	background_image_focused("background_image_focused"),  	bg_image_always_focused("bg_image_always_focused", false), +	show_label_focused("show_label_focused", false),  	select_on_focus("select_on_focus", false),  	revert_on_esc("revert_on_esc", true),  	spellcheck("spellcheck", false), @@ -152,6 +153,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)  	mBgImageDisabled( p.background_image_disabled ),  	mBgImageFocused( p.background_image_focused ),  	mShowImageFocused( p.bg_image_always_focused ), +	mShowLabelFocused( p.show_label_focused ),  	mUseBgColor(p.use_bg_color),  	mHaveHistory(FALSE),  	mReplaceNewlinesWithSpaces( TRUE ), @@ -2068,7 +2070,7 @@ void LLLineEditor::draw()  		//draw label if no text is provided  		//but we should draw it in a different color  		//to give indication that it is not text you typed in -		if (0 == mText.length() && mReadOnly) +		if (0 == mText.length() && (mReadOnly || mShowLabelFocused))  		{  			mGLFont->render(mLabel.getWString(), 0,  							mTextLeftEdge, (F32)text_bottom, diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index ae4e05c065..624371ebda 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -91,6 +91,7 @@ public:  										commit_on_focus_lost,  										ignore_tab,  										bg_image_always_focused, +										show_label_focused,  										is_password,  										use_bg_color; @@ -395,6 +396,7 @@ protected:  	BOOL		mReadOnly;  	BOOL 		mShowImageFocused; +	BOOL 		mShowLabelFocused;  	bool		mUseBgColor; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 33c4b6ec73..16c27da56a 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -487,9 +487,6 @@ void LLMenuItemGL::draw( void )  	// let disabled items be highlighted, just don't draw them as such  	if( getEnabled() && getHighlight() && !mBriefItem)  	{ -		int debug_count = 0; -		if (dynamic_cast<LLMenuItemCallGL*>(this)) -			debug_count++;  		gGL.color4fv( mHighlightBackground.get().mV );  		gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0 ); diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 921398a693..4d9a33f1d7 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -913,7 +913,7 @@ public:  	/* virtual */ LLNotificationPtr add(const std::string& name,   						const LLSD& substitutions,   						const LLSD& payload,  -						LLNotificationFunctorRegistry::ResponseFunctor functor); +						LLNotificationFunctorRegistry::ResponseFunctor functor) override;  	LLNotificationPtr add(const LLNotification::Params& p);  	void add(const LLNotificationPtr pNotif); @@ -964,8 +964,8 @@ public:  	bool isVisibleByRules(LLNotificationPtr pNotification);  private: -	/*virtual*/ void initSingleton(); -	/*virtual*/ void cleanupSingleton(); +	/*virtual*/ void initSingleton() override; +	/*virtual*/ void cleanupSingleton() override;  	void loadPersistentNotifications(); diff --git a/indra/llui/llscrollingpanellist.cpp b/indra/llui/llscrollingpanellist.cpp index b6f2eb8ba2..3a819e7d06 100644 --- a/indra/llui/llscrollingpanellist.cpp +++ b/indra/llui/llscrollingpanellist.cpp @@ -37,53 +37,44 @@ static LLDefaultChildRegistry::Register<LLScrollingPanelList> r("scrolling_panel  // This could probably be integrated with LLScrollContainer -SJB +LLScrollingPanelList::Params::Params() +	: is_horizontal("is_horizontal") +	, padding("padding") +	, spacing("spacing") +{ +} + +LLScrollingPanelList::LLScrollingPanelList(const Params& p) +	: LLUICtrl(p) +	, mIsHorizontal(p.is_horizontal) +	, mPadding(p.padding.isProvided() ? p.padding : DEFAULT_PADDING) +	, mSpacing(p.spacing.isProvided() ? p.spacing : DEFAULT_SPACING) +{ +} +  void LLScrollingPanelList::clearPanels()  {  	deleteAllChildren();  	mPanelList.clear(); - -	LLRect rc = getRect(); -	rc.setLeftTopAndSize(rc.mLeft, rc.mTop, 1, 1); -	setRect(rc); - -	notifySizeChanged(rc.getHeight()); +	rearrange();  } -S32 LLScrollingPanelList::addPanel( LLScrollingPanel* panel ) +S32 LLScrollingPanelList::addPanel(LLScrollingPanel* panel, bool back)  { -	addChildInBack( panel ); -	mPanelList.push_front( panel ); - -	// Resize this view -	S32 total_height = 0; -	S32 max_width = 0; -	S32 cur_gap = 0; -	for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); -		 iter != mPanelList.end(); ++iter) +	if (back)  	{ -		LLScrollingPanel *childp = *iter; -		total_height += childp->getRect().getHeight() + cur_gap; -		max_width = llmax( max_width, childp->getRect().getWidth() ); -		cur_gap = GAP_BETWEEN_PANELS; +		addChild(panel); +		mPanelList.push_back(panel);  	} - 	LLRect rc = getRect(); - 	rc.setLeftTopAndSize(rc.mLeft, rc.mTop, max_width, total_height); - 	setRect(rc); - -	notifySizeChanged(rc.getHeight()); - -	// Reposition each of the child views -	S32 cur_y = total_height; -	for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); -		 iter != mPanelList.end(); ++iter) +	else  	{ -		LLScrollingPanel *childp = *iter; -		cur_y -= childp->getRect().getHeight(); -		childp->translate( -childp->getRect().mLeft, cur_y - childp->getRect().mBottom); -		cur_y -= GAP_BETWEEN_PANELS; +		addChildInBack(panel); +		mPanelList.push_front(panel);  	} -	return total_height; +	rearrange(); + +	return mIsHorizontal ? getRect().getWidth() : getRect().getHeight();  }  void LLScrollingPanelList::removePanel(LLScrollingPanel* panel)  @@ -100,7 +91,7 @@ void LLScrollingPanelList::removePanel(LLScrollingPanel* panel)  				break;  			}  		} -		if(iter != mPanelList.end()) +		if (iter != mPanelList.end())  		{  			removePanel(index);  		} @@ -120,62 +111,104 @@ void LLScrollingPanelList::removePanel( U32 panel_index )  		mPanelList.erase( mPanelList.begin() + panel_index );  	} -	const S32 GAP_BETWEEN_PANELS = 6; +	rearrange(); +} -	// Resize this view -	S32 total_height = 0; -	S32 max_width = 0; -	S32 cur_gap = 0; -	for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); +void LLScrollingPanelList::updatePanels(BOOL allow_modify) +{ +    for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin();  		 iter != mPanelList.end(); ++iter) -	{ +    {  		LLScrollingPanel *childp = *iter; -		total_height += childp->getRect().getHeight() + cur_gap; -		max_width = llmax( max_width, childp->getRect().getWidth() ); -		cur_gap = GAP_BETWEEN_PANELS; +		childp->updatePanel(allow_modify); +    } +} + +void LLScrollingPanelList::rearrange() +{ +	// Resize this view +	S32 new_width, new_height; +	if (!mPanelList.empty()) +	{ +		new_width = new_height = mPadding * 2; +		for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); +			iter != mPanelList.end(); ++iter) +		{ +			LLScrollingPanel* childp = *iter; +			const LLRect& rect = childp->getRect(); +			if (mIsHorizontal) +			{ +				new_width += rect.getWidth() + mSpacing; +				new_height = llmax(new_height, rect.getHeight()); +			} +			else +			{ +				new_height += rect.getHeight() + mSpacing; +				new_width = llmax(new_width, rect.getWidth()); +			} +		} + +		if (mIsHorizontal) +		{ +			new_width -= mSpacing; +		} +		else +		{ +			new_height -= mSpacing; +		}  	} +	else +	{ +		new_width = new_height = 1; +	} +  	LLRect rc = getRect(); -	rc.setLeftTopAndSize(rc.mLeft, rc.mTop, max_width, total_height); -	setRect(rc); +	if (mIsHorizontal || !followsRight()) +	{ +		rc.mRight = rc.mLeft + new_width; +	} +	if (!mIsHorizontal || !followsBottom()) +	{ +		rc.mBottom = rc.mTop - new_height; +	} -	notifySizeChanged(rc.getHeight()); +	if (rc.mRight != getRect().mRight || rc.mBottom != getRect().mBottom) +	{ +		setRect(rc); +		notifySizeChanged(); +	}  	// Reposition each of the child views -	S32 cur_y = total_height; +	S32 pos = mIsHorizontal ? mPadding : rc.getHeight() - mPadding;  	for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); -		 iter != mPanelList.end(); ++iter) +		iter != mPanelList.end(); ++iter)  	{ -		LLScrollingPanel *childp = *iter; -		cur_y -= childp->getRect().getHeight(); -		childp->translate( -childp->getRect().mLeft, cur_y - childp->getRect().mBottom); -		cur_y -= GAP_BETWEEN_PANELS; +		LLScrollingPanel* childp = *iter; +		const LLRect& rect = childp->getRect(); +		if (mIsHorizontal) +		{ +			childp->translate(pos - rect.mLeft, rc.getHeight() - mPadding - rect.mTop); +			pos += rect.getWidth() + mSpacing; +		} +		else +		{ +			childp->translate(mPadding - rect.mLeft, pos - rect.mTop); +			pos -= rect.getHeight() + mSpacing; +		}  	}  } -void LLScrollingPanelList::updatePanels(BOOL allow_modify) -{ -    for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); -		 iter != mPanelList.end(); ++iter) -    { -		LLScrollingPanel *childp = *iter; -		childp->updatePanel(allow_modify); -    } -} -  void LLScrollingPanelList::updatePanelVisiblilty()  {  	// Determine visibility of children. -	S32 BORDER_WIDTH = 2;  // HACK -	LLRect parent_local_rect = getParent()->getRect(); -	parent_local_rect.stretch( -BORDER_WIDTH ); -	  	LLRect parent_screen_rect; -	getParent()->localPointToScreen(  -		BORDER_WIDTH, 0,  +	getParent()->localPointToScreen( +		mPadding, mPadding,  		&parent_screen_rect.mLeft, &parent_screen_rect.mBottom ); -	getParent()->localPointToScreen(  -		parent_local_rect.getWidth() - BORDER_WIDTH, parent_local_rect.getHeight() - BORDER_WIDTH, +	getParent()->localPointToScreen( +		getParent()->getRect().getWidth() - mPadding, +		getParent()->getRect().getHeight() - mPadding,  		&parent_screen_rect.mRight, &parent_screen_rect.mTop );  	for (std::deque<LLScrollingPanel*>::iterator iter = mPanelList.begin(); @@ -207,11 +240,12 @@ void LLScrollingPanelList::draw()  	LLUICtrl::draw();  } -void LLScrollingPanelList::notifySizeChanged(S32 height) +void LLScrollingPanelList::notifySizeChanged()  {  	LLSD info;  	info["action"] = "size_changes"; -	info["height"] = height; +	info["height"] = getRect().getHeight(); +	info["width"] = getRect().getWidth();  	notifyParent(info);  } diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h index e8df176ec3..9dc65dabb5 100644 --- a/indra/llui/llscrollingpanellist.h +++ b/indra/llui/llscrollingpanellist.h @@ -51,12 +51,18 @@ class LLScrollingPanelList : public LLUICtrl  {  public:  	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> -	{}; -	LLScrollingPanelList(const Params& p) -	:	LLUICtrl(p)  -	{} +	{ +		Optional<bool> is_horizontal; +		Optional<S32> padding; +		Optional<S32> spacing; + +		Params(); +	}; + +	LLScrollingPanelList(const Params& p); -	static const S32 GAP_BETWEEN_PANELS = 6; +	static const S32 DEFAULT_SPACING = 6; +	static const S32 DEFAULT_PADDING = 2;  	typedef std::deque<LLScrollingPanel*>	panel_list_t; @@ -65,11 +71,18 @@ public:  	virtual void		draw();  	void				clearPanels(); -	S32					addPanel( LLScrollingPanel* panel ); -	void				removePanel( LLScrollingPanel* panel ); -	void				removePanel( U32 panel_index ); +	S32					addPanel(LLScrollingPanel* panel, bool back = false); +	void				removePanel(LLScrollingPanel* panel); +	void				removePanel(U32 panel_index);  	void				updatePanels(BOOL allow_modify); -	const panel_list_t&	getPanelList() { return mPanelList; } +	void				rearrange(); + +	const panel_list_t&	getPanelList() const { return mPanelList; } +	bool				getIsHorizontal() const { return mIsHorizontal; } +	void				setPadding(S32 padding) { mPadding = padding; rearrange(); } +	void				setSpacing(S32 spacing) { mSpacing = spacing; rearrange(); } +	S32					getPadding() const { return mPadding; } +	S32					getSpacing() const { return mSpacing; }  private:  	void				updatePanelVisiblilty(); @@ -77,7 +90,11 @@ private:  	/**  	 * Notify parent about size change, makes sense when used inside accordion  	 */ -	void				notifySizeChanged(S32 height); +	void				notifySizeChanged(); + +	bool				mIsHorizontal; +	S32					mPadding; +	S32					mSpacing;  	panel_list_t		mPanelList;  }; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 219667f766..f982dc99e8 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -411,7 +411,7 @@ void LLScrollListCtrl::clearRows()  LLScrollListItem* LLScrollListCtrl::getFirstSelected() const  {  	item_list::const_iterator iter; -	for(iter = mItemList.begin(); iter != mItemList.end(); iter++) +	for (iter = mItemList.begin(); iter != mItemList.end(); iter++)  	{  		LLScrollListItem* item  = *iter;  		if (item->getSelected()) @@ -1269,7 +1269,7 @@ BOOL LLScrollListCtrl::selectItemByLabel(const std::string& label, BOOL case_sen  	LLScrollListItem* item = getItemByLabel(label, case_sensitive, column);  	bool found = NULL != item; -	if(found) +	if (found)  	{  		selectItem(item, -1);  	} @@ -2747,7 +2747,7 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending)  S32	LLScrollListCtrl::getLinesPerPage()  {  	//if mPageLines is NOT provided display all item -	if(mPageLines) +	if (mPageLines)  	{  		return mPageLines;  	} diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 73b4fb036a..326589a329 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -253,7 +253,7 @@ public:  	S32				getItemIndex( LLScrollListItem* item ) const;  	S32				getItemIndex( const LLUUID& item_id ) const; -	void setCommentText( const std::string& comment_text); +	void			setCommentText( const std::string& comment_text);  	LLScrollListItem* addSeparator(EAddPosition pos);  	// "Simple" interface: use this when you're creating a list that contains only unique strings, only @@ -263,7 +263,7 @@ public:  	BOOL			selectItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 );		// FALSE if item not found  	BOOL			selectItemByPrefix(const std::string& target, BOOL case_sensitive = TRUE, S32 column = -1);  	BOOL			selectItemByPrefix(const LLWString& target, BOOL case_sensitive = TRUE, S32 column = -1); -	LLScrollListItem*  getItemByLabel( const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0 ); +	LLScrollListItem*	getItemByLabel(const std::string& item, BOOL case_sensitive = TRUE, S32 column = 0);  	const std::string	getSelectedItemLabel(S32 column = 0) const;  	LLSD			getSelectedValue(); @@ -322,7 +322,7 @@ public:  	virtual S32		getScrollPos() const;  	virtual void	setScrollPos( S32 pos ); -	S32 getSearchColumn(); +	S32				getSearchColumn();  	void			setSearchColumn(S32 column) { mSearchColumn = column; }  	S32				getColumnIndexFromOffset(S32 x);  	S32				getColumnOffsetFromIndex(S32 index); @@ -371,13 +371,13 @@ public:  	// Used "internally" by the scroll bar.  	void			onScrollChange( S32 new_pos, LLScrollbar* src ); -	static void onClickColumn(void *userdata); +	static void		onClickColumn(void *userdata); -	virtual void updateColumns(bool force_update = false); -	S32 calcMaxContentWidth(); -	bool updateColumnWidths(); +	virtual void	updateColumns(bool force_update = false); +	S32				calcMaxContentWidth(); +	bool			updateColumnWidths(); -	void setHeadingHeight(S32 heading_height); +	void			setHeadingHeight(S32 heading_height);  	/**  	 * Sets  max visible  lines without scroolbar, if this value equals to 0,  	 * then display all items. @@ -398,18 +398,20 @@ public:  	virtual void	deselect();  	virtual BOOL	canDeselect() const; -	void setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; } -	void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); -	S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; } +	void			setNumDynamicColumns(S32 num) { mNumDynamicWidthColumns = num; } +	void			updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); +	S32				getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; }  	std::string     getSortColumnName();  	BOOL			getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; }  	BOOL			hasSortOrder() const;  	void			clearSortOrder(); -	void			setAlternateSort() { mAlternateSort = true; } +	void			setAlternateSort() { mAlternateSort = TRUE; } -	S32		selectMultiple( uuid_vec_t ids ); +	void			selectPrevItem(BOOL extend_selection = FALSE); +	void			selectNextItem(BOOL extend_selection = FALSE); +	S32				selectMultiple(uuid_vec_t ids);  	// conceptually const, but mutates mItemList  	void			updateSort() const;  	// sorts a list without affecting the permanent sort order (so further list insertions can be unsorted, for example) @@ -454,8 +456,6 @@ protected:  	void			updateLineHeight();  private: -	void			selectPrevItem(BOOL extend_selection); -	void			selectNextItem(BOOL extend_selection);  	void			drawItems();  	void            updateLineHeightInsert(LLScrollListItem* item); diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h index 3da5e30955..14f9b44fe4 100644 --- a/indra/llui/llspellcheck.h +++ b/indra/llui/llspellcheck.h @@ -47,7 +47,7 @@ public:  protected:  	void addToDictFile(const std::string& dict_path, const std::string& word);  	void initHunspell(const std::string& dict_language); -	void initSingleton(); +	void initSingleton() override;  public:  	typedef std::list<std::string> dict_list_t; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 8732a7ce45..4ca1879be6 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -29,6 +29,8 @@  #include "lltextbase.h" +#include "llemojidictionary.h" +#include "llemojihelper.h"  #include "lllocalcliprect.h"  #include "llmenugl.h"  #include "llscrollcontainer.h" @@ -161,10 +163,12 @@ LLTextBase::Params::Params()  	line_spacing("line_spacing"),  	max_text_length("max_length", 255),  	font_shadow("font_shadow"), +	text_valign("text_valign"),  	wrap("wrap"),  	trusted_content("trusted_content", true),  	always_show_icons("always_show_icons", false),  	use_ellipses("use_ellipses", false), +	use_color("use_color", false),  	parse_urls("parse_urls", false),  	force_urls_external("force_urls_external", false),  	parse_highlights("parse_highlights", false) @@ -208,6 +212,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)  	mVPad(p.v_pad),  	mHAlign(p.font_halign),  	mVAlign(p.font_valign), +	mTextVAlign(p.text_valign.isProvided() ? p.text_valign.getValue() : p.font_valign.getValue()),  	mLineSpacingMult(p.line_spacing.multiple),  	mLineSpacingPixels(p.line_spacing.pixels),  	mClip(p.clip), @@ -222,6 +227,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)  	mPlainText ( p.plain_text ),  	mWordWrap(p.wrap),  	mUseEllipses( p.use_ellipses ), +	mUseColor(p.use_color),  	mParseHTML(p.parse_urls),  	mForceUrlsExternal(p.force_urls_external),  	mParseHighlights(p.parse_highlights), @@ -582,7 +588,7 @@ void LLTextBase::drawCursor()  				fontp = segmentp->getStyle()->getFont();  				fontp->render(text, mCursorPos, cursor_rect,   					LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha), -					LLFontGL::LEFT, mVAlign, +					LLFontGL::LEFT, mTextVAlign,  					LLFontGL::NORMAL,  					LLFontGL::NO_SHADOW,  					1); @@ -896,6 +902,28 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s  		}  	} +	// Insert special segments where necessary (insertSegment takes care of splitting normal text segments around them for us) +	{ +		LLStyleSP emoji_style; +		LLEmojiDictionary* ed = LLEmojiDictionary::instanceExists() ? LLEmojiDictionary::getInstance() : NULL; +		for (S32 text_kitty = 0, text_len = wstr.size(); text_kitty < text_len; text_kitty++) +		{ +			llwchar code = wstr[text_kitty]; +			bool isEmoji = ed ? ed->isEmoji(code) : LLStringOps::isEmoji(code); +			if (isEmoji) +			{ +				if (!emoji_style) +				{ +					emoji_style = new LLStyle(getStyleParams()); +					emoji_style->setFont(LLFontGL::getFontEmoji()); +				} + +				S32 new_seg_start = pos + text_kitty; +				insertSegment(new LLEmojiTextSegment(emoji_style, new_seg_start, new_seg_start + 1, *this)); +			} +		} +	} +  	getViewModel()->getEditableDisplay().insert(pos, wstr);  	if ( truncate() ) @@ -1979,21 +2007,8 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getEditableSegIterContaini  LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)  { -  	static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment(); -	S32 text_len = 0; -	if (!useLabel()) -	{ -		text_len = getLength(); -	} -	else -	{ -		text_len = mLabel.getWString().length(); -	} - -	if (index > text_len) { return mSegments.end(); } -  	// when there are no segments, we return the end iterator, which must be checked by caller  	if (mSegments.size() <= 1) { return mSegments.begin(); } @@ -2007,18 +2022,6 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 i  {  	static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment(); -	S32 text_len = 0; -	if (!useLabel()) -	{ -		text_len = getLength(); -	} -	else -	{ -		text_len = mLabel.getWString().length(); -	} - -	if (index > text_len) { return mSegments.end(); } -  	// when there are no segments, we return the end iterator, which must be checked by caller  	if (mSegments.size() <= 1) { return mSegments.begin(); } @@ -2182,8 +2185,8 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para  		S32 start=0,end=0;  		LLUrlMatch match;  		std::string text = new_text; -		while ( LLUrlRegistry::instance().findUrl(text, match, -				boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted() || mAlwaysShowIcons)) +		while (LLUrlRegistry::instance().findUrl(text, match, +				boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3), isContentTrusted() || mAlwaysShowIcons))  		{  			start = match.getStart();  			end = match.getEnd()+1; @@ -2431,18 +2434,18 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig  			LLStyle::Params normal_style_params(style_params);  			normal_style_params.font.style("NORMAL");  			LLStyleConstSP normal_sp(new LLStyle(normal_style_params)); -			segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this )); +			segments.push_back(new LLOnHoverChangeableTextSegment(sp, normal_sp, segment_start, segment_end, *this));  		}  		else  		{ -		segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this )); +			segments.push_back(new LLNormalTextSegment(sp, segment_start, segment_end, *this));  		}  		insertStringNoUndo(getLength(), wide_text, &segments);  	}  	// Set the cursor and scroll position -	if( selection_start != selection_end ) +	if (selection_start != selection_end)  	{  		mSelectionStart = selection_start;  		mSelectionEnd = selection_end; @@ -2450,7 +2453,7 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig  		mIsSelecting = was_selecting;  		setCursorPos(cursor_pos);  	} -	else if( cursor_was_at_end ) +	else if (cursor_was_at_end)  	{  		setCursorPos(getLength());  	} @@ -2462,25 +2465,28 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig  void LLTextBase::appendAndHighlightText(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only)  { -	if (new_text.empty()) return;  +	if (new_text.empty()) +	{ +		return;  +	}  	std::string::size_type start = 0; -	std::string::size_type pos = new_text.find("\n",start); +	std::string::size_type pos = new_text.find("\n", start); -	while(pos!=-1) +	while (pos != std::string::npos)  	{ -		if(pos!=start) +		if (pos != start)  		{  			std::string str = std::string(new_text,start,pos-start); -			appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only); +			appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only);  		}  		appendLineBreakSegment(style_params);  		start = pos+1; -		pos = new_text.find("\n",start); +		pos = new_text.find("\n", start);  	} -	std::string str = std::string(new_text,start,new_text.length()-start); -	appendAndHighlightTextImpl(str,highlight_part, style_params, underline_on_hover_only); +	std::string str = std::string(new_text, start, new_text.length() - start); +	appendAndHighlightTextImpl(str, highlight_part, style_params, underline_on_hover_only);  } @@ -3312,12 +3318,13 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele  		font->render(text, start,   				 rect,   				 color,  -				 LLFontGL::LEFT, mEditor.mVAlign,  +				 LLFontGL::LEFT, mEditor.mTextVAlign,  				 LLFontGL::NORMAL,   				 mStyle->getShadowType(),   				 length,  				 &right_x,  -				 mEditor.getUseEllipses()); +				 mEditor.getUseEllipses(), +				 mEditor.getUseColor());  	}  	rect.mLeft = right_x; @@ -3331,12 +3338,13 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele  		font->render(text, start,   				 rect,  				 mStyle->getSelectedColor().get(), -				 LLFontGL::LEFT, mEditor.mVAlign,  +				 LLFontGL::LEFT, mEditor.mTextVAlign,  				 LLFontGL::NORMAL,   				 LLFontGL::NO_SHADOW,   				 length,  				 &right_x,  -				 mEditor.getUseEllipses()); +				 mEditor.getUseEllipses(), +				 mEditor.getUseColor());  	}  	rect.mLeft = right_x;  	if( selection_end < seg_end ) @@ -3348,12 +3356,13 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele  		font->render(text, start,   				 rect,   				 color,  -				 LLFontGL::LEFT, mEditor.mVAlign,  +				 LLFontGL::LEFT, mEditor.mTextVAlign,  				 LLFontGL::NORMAL,   				 mStyle->getShadowType(),   				 length,  				 &right_x,  -				 mEditor.getUseEllipses()); +				 mEditor.getUseEllipses(), +				 mEditor.getUseColor());  	}      return right_x;  } @@ -3585,6 +3594,33 @@ const S32 LLLabelTextSegment::getLength() const  }  // +// LLEmojiTextSegment +// +LLEmojiTextSegment::LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor) +	: LLNormalTextSegment(style, start, end, editor) +{ +} + +LLEmojiTextSegment::LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible) +	: LLNormalTextSegment(color, start, end, editor, is_visible) +{ +} + +BOOL LLEmojiTextSegment::handleToolTip(S32 x, S32 y, MASK mask) +{ +	if (mTooltip.empty()) +	{ +		LLWString emoji = getWText().substr(getStart(), getEnd() - getStart()); +		if (!emoji.empty()) +		{ +			mTooltip = LLEmojiHelper::instance().getToolTip(emoji[0]); +		} +	} + +	return LLNormalTextSegment::handleToolTip(x, y, mask); +} + +//  // LLOnHoverChangeableTextSegment  // diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 3611ab0499..37ab798a1d 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -178,6 +178,18 @@ protected:  	/*virtual*/	const S32			getLength()	const;  }; +// Text segment that represents a single emoji character that has a different style (=font size) than the rest of +// the document it belongs to +class LLEmojiTextSegment : public LLNormalTextSegment +{ +public: +	LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor); +	LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE); + +	bool canEdit() const override { return false; } +	BOOL handleToolTip(S32 x, S32 y, MASK mask) override; +}; +  // Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment)  class LLOnHoverChangeableTextSegment : public LLNormalTextSegment  { @@ -316,6 +328,7 @@ public:  								plain_text,  								wrap,  								use_ellipses, +								use_color,  								parse_urls,  								force_urls_external,  								parse_highlights, @@ -335,6 +348,8 @@ public:  		Optional<LLFontGL::ShadowType>	font_shadow; +		Optional<LLFontGL::VAlign> text_valign; +  		Params();  	}; @@ -394,6 +409,7 @@ public:  	// used by LLTextSegment layout code  	bool					getWordWrap() { return mWordWrap; }  	bool					getUseEllipses() { return mUseEllipses; } +	bool					getUseColor() { return mUseColor; }  	bool					truncate(); // returns true of truncation occurred  	bool					isContentTrusted() {return mTrustedContent;} @@ -687,8 +703,9 @@ protected:  	// configuration  	S32							mHPad;				// padding on left of text  	S32							mVPad;				// padding above text -	LLFontGL::HAlign			mHAlign; -	LLFontGL::VAlign			mVAlign; +	LLFontGL::HAlign			mHAlign;			// horizontal alignment of the document in its entirety +	LLFontGL::VAlign			mVAlign;			// vertical alignment of the document in its entirety +	LLFontGL::VAlign			mTextVAlign;		// vertical alignment of a text segment within a single line of text  	F32							mLineSpacingMult;	// multiple of line height used as space for a single line of text (e.g. 1.5 to get 50% padding)  	S32							mLineSpacingPixels;	// padding between lines  	bool						mBorderVisible; @@ -697,6 +714,7 @@ protected:  	bool						mParseHighlights;	// highlight user-defined keywords  	bool                		mWordWrap;  	bool						mUseEllipses; +	bool						mUseColor;  	bool						mTrackEnd;			// if true, keeps scroll position at end of document during resize  	bool						mReadOnly;  	bool						mBGVisible;			// render background? diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 3d2a426913..95d8b666ab 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -43,6 +43,7 @@  #include "llmath.h"  #include "llclipboard.h" +#include "llemojihelper.h"  #include "llscrollbar.h"  #include "llstl.h"  #include "llstring.h" @@ -238,6 +239,7 @@ LLTextEditor::Params::Params()  	default_color("default_color"),      commit_on_focus_lost("commit_on_focus_lost", false),  	show_context_menu("show_context_menu"), +	show_emoji_helper("show_emoji_helper"),  	enable_tooltip_paste("enable_tooltip_paste")  {  	addSynonym(prevalidate_callback, "text_type"); @@ -258,6 +260,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :  	mTabsToNextField(p.ignore_tab),  	mPrevalidateFunc(p.prevalidate_callback()),  	mShowContextMenu(p.show_context_menu), +	mShowEmojiHelper(p.show_emoji_helper),  	mEnableTooltipPaste(p.enable_tooltip_paste),  	mPassDelete(FALSE),  	mKeepSelectionOnReturn(false) @@ -505,6 +508,15 @@ void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out,  	}  } +void LLTextEditor::setShowEmojiHelper(bool show) { +	if (!mShowEmojiHelper) +	{ +		LLEmojiHelper::instance().hideHelper(this); +	} + +	mShowEmojiHelper = show; +} +  BOOL LLTextEditor::selectionContainsLineBreaks()  {  	if (hasSelection()) @@ -668,6 +680,27 @@ void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_p  	endSelection();  } +void LLTextEditor::insertEmoji(llwchar emoji) +{ +	auto styleParams = LLStyle::Params(); +	styleParams.font = LLFontGL::getFontEmoji(); +	auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); +	insert(mCursorPos, LLWString(1, emoji), false, segment); +	setCursorPos(mCursorPos + 1); +} + +void LLTextEditor::handleEmojiCommit(llwchar emoji) +{ +	S32 shortCodePos; +	if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) +	{ +		remove(shortCodePos, mCursorPos - shortCodePos, true); +		setCursorPos(shortCodePos); + +		insertEmoji(emoji); +	} +} +  BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)  {  	BOOL	handled = FALSE; @@ -934,6 +967,12 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)  S32 LLTextEditor::execute( TextCmd* cmd )  { +	if (!mReadOnly && mShowEmojiHelper) +	{ +		// Any change to our contents should always hide the helper +		LLEmojiHelper::instance().hideHelper(this); +	} +  	S32 delta = 0;  	if( cmd->execute(this, &delta) )  	{ @@ -1128,6 +1167,17 @@ void LLTextEditor::addChar(llwchar wc)  	setCursorPos(mCursorPos + addChar( mCursorPos, wc )); +	if (!mReadOnly && mShowEmojiHelper) +	{ +		LLWString wtext(getWText()); S32 shortCodePos; +		if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos)) +		{ +			const LLRect cursorRect = getLocalRectFromDocIndex(mCursorPos - 1); +			const LLWString shortCode = wtext.substr(shortCodePos, mCursorPos - shortCodePos); +			LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, wstring_to_utf8str(shortCode), std::bind(&LLTextEditor::handleEmojiCommit, this, std::placeholders::_1)); +		} +	} +  	if (!mReadOnly && mAutoreplaceCallback != NULL)  	{  		// autoreplace the text, if necessary @@ -1778,6 +1828,11 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )  	}  	else   	{ +		if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) +		{ +			return TRUE; +		} +  		if (mEnableTooltipPaste &&  			LLToolTipMgr::instance().toolTipVisible() &&   			KEY_TAB == key) @@ -1819,6 +1874,12 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )  	{  		resetCursorBlink();  		needsScroll(); + +		if (mShowEmojiHelper) +		{ +			// Dismiss the helper whenever we handled a key that it didn't +			LLEmojiHelper::instance().hideHelper(this); +		}  	}  	return handled; diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index f3939248c2..f830732cb8 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -60,6 +60,7 @@ public:  								ignore_tab,  								commit_on_focus_lost,  								show_context_menu, +								show_emoji_helper,  								enable_tooltip_paste,  								auto_indent; @@ -91,6 +92,9 @@ public:  	static S32		spacesPerTab(); +	void    insertEmoji(llwchar emoji); +	void    handleEmojiCommit(llwchar emoji); +  	// mousehandler overrides  	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask);  	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask); @@ -202,6 +206,9 @@ public:  	void			setShowContextMenu(bool show) { mShowContextMenu = show; }  	bool			getShowContextMenu() const { return mShowContextMenu; } +	void			setShowEmojiHelper(bool show); +	bool			getShowEmojiHelper() const { return mShowEmojiHelper; } +  	void			setPassDelete(BOOL b) { mPassDelete = b; }  protected: @@ -318,6 +325,7 @@ private:  	BOOL			mAllowEmbeddedItems;  	bool			mShowContextMenu; +	bool			mShowEmojiHelper;  	bool			mEnableTooltipPaste;  	bool			mPassDelete;  	bool			mKeepSelectionOnReturn;	// disabling of removing selected text after pressing of Enter diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index 67dd24341c..d71dc8d859 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -263,7 +263,7 @@ public:  	class LLTextInputFilter : public LLQueryFilter, public LLSingleton<LLTextInputFilter>  	{  		LLSINGLETON_EMPTY_CTOR(LLTextInputFilter); -		/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const  +		/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override  		{  			return filterResult_t(view->isCtrl() && static_cast<const LLUICtrl *>(view)->acceptsTextInput(), TRUE);  		} diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 3344300635..8716e6b338 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -1326,7 +1326,7 @@ void LLView::drawDebugRect()  										debug_rect.getWidth(), debug_rect.getHeight());  			LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,  												LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -												S32_MAX, S32_MAX, NULL, FALSE); +												S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);  		}  	}  	LLUI::popMatrix(); @@ -1955,7 +1955,7 @@ private:  class SortByTabOrder : public LLQuerySorter, public LLSingleton<SortByTabOrder>  {  	LLSINGLETON_EMPTY_CTOR(SortByTabOrder); -	/*virtual*/ void sort(LLView * parent, LLView::child_list_t &children) const  +	/*virtual*/ void sort(LLView * parent, LLView::child_list_t &children) const override  	{  		children.sort(CompareByTabOrder(parent->getTabOrder(), parent->getDefaultTabGroup()));  	} @@ -1979,7 +1979,7 @@ const LLViewQuery & LLView::getTabOrderQuery()  class LLFocusRootsFilter : public LLQueryFilter, public LLSingleton<LLFocusRootsFilter>  {  	LLSINGLETON_EMPTY_CTOR(LLFocusRootsFilter); -	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const  +	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override  	{  		return filterResult_t(view->isCtrl() && view->isFocusRoot(), !view->isFocusRoot());  	} diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 8aa97aac39..29dd523648 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -111,7 +111,7 @@ public:  		Alternative<std::string>	string;  		Alternative<U32>			flags; -        Follows(); +		Follows();  	};  	struct Params : public LLInitParam::Block<Params> @@ -657,8 +657,8 @@ public:  	// Draw debug rectangles around widgets to help with alignment and spacing  	static bool	sDebugRects; -    static bool sIsRectDirty; -    static LLRect sDirtyRect; +	static bool sIsRectDirty; +	static LLRect sDirtyRect;  	// Draw widget names and sizes when drawing debug rectangles, turning this  	// off is useful to make the rectangles themselves easier to see. @@ -701,20 +701,16 @@ template <class T> T* LLView::getChild(const std::string& name, BOOL recurse) co  		if (!result)  		{  			result = LLUICtrlFactory::getDefaultWidget<T>(name); - -			if (result) -			{ -				// *NOTE: You cannot call mFoo = getChild<LLFoo>("bar") -				// in a floater or panel constructor.  The widgets will not -				// be ready.  Instead, put it in postBuild(). -				LL_WARNS() << "Making dummy " << typeid(T).name() << " named \"" << name << "\" in " << getName() << LL_ENDL; -			} -			else +			if (!result)  			{ -				LL_WARNS() << "Failed to create dummy " << typeid(T).name() << LL_ENDL; -				return NULL; +				LL_ERRS() << "Failed to create dummy " << typeid(T).name() << LL_ENDL;  			} +			// *NOTE: You cannot call mFoo = getChild<LLFoo>("bar") +			// in a floater or panel constructor.  The widgets will not +			// be ready.  Instead, put it in postBuild(). +			LL_WARNS() << "Making dummy " << typeid(T).name() << " named \"" << name << "\" in " << getName() << LL_ENDL; +  			getDefaultWidgetContainer().addChild(result);  		}  	} diff --git a/indra/llui/llviewquery.h b/indra/llui/llviewquery.h index 21bb1be26f..4bc9c4a08e 100644 --- a/indra/llui/llviewquery.h +++ b/indra/llui/llviewquery.h @@ -55,37 +55,37 @@ public:  class LLLeavesFilter : public LLQueryFilter, public LLSingleton<LLLeavesFilter>  {  	LLSINGLETON_EMPTY_CTOR(LLLeavesFilter); -	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;  };  class LLRootsFilter : public LLQueryFilter, public LLSingleton<LLRootsFilter>  {  	LLSINGLETON_EMPTY_CTOR(LLRootsFilter); -	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;  };  class LLVisibleFilter : public LLQueryFilter, public LLSingleton<LLVisibleFilter>  {  	LLSINGLETON_EMPTY_CTOR(LLVisibleFilter); -	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;  };  class LLEnabledFilter : public LLQueryFilter, public LLSingleton<LLEnabledFilter>  {  	LLSINGLETON_EMPTY_CTOR(LLEnabledFilter); -	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;  };  class LLTabStopFilter : public LLQueryFilter, public LLSingleton<LLTabStopFilter>  {  	LLSINGLETON_EMPTY_CTOR(LLTabStopFilter); -	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;  };  class LLCtrlFilter : public LLQueryFilter, public LLSingleton<LLCtrlFilter>  {  	LLSINGLETON_EMPTY_CTOR(LLCtrlFilter); -	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const; +	/*virtual*/ filterResult_t operator() (const LLView* const view, const viewList_t & children) const override;  };  template <class T> diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index ead8634df4..ab5bca5d2a 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -774,7 +774,6 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require  		return 0;  	} -	U32		item = 0;  	U32		validitems = 0;  	S32 version; @@ -807,9 +806,6 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require  			continue;  		} -		// Got an item.  Load it up. -		item++; -  		// If not declared, assume it's a string  		if (!declared)  		{ diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index dbd1f1b4ac..aa839da69e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -18,6 +18,7 @@ include(DragDrop)  include(EXPAT)  include(FMODSTUDIO)  include(Hunspell) +include(ICU4C)  include(JPEGEncoderBasic)  include(JsonCpp)  include(LLAppearance) @@ -204,6 +205,7 @@ set(viewer_SOURCE_FILES      llfloaterdisplayname.cpp      llfloatereditenvironmentbase.cpp      llfloatereditextdaycycle.cpp +    llfloateremojipicker.cpp      llfloaterenvironmentadjust.cpp      llfloaterevent.cpp      llfloaterexperiencepicker.cpp @@ -410,6 +412,7 @@ set(viewer_SOURCE_FILES      llpaneleditsky.cpp      llpaneleditwater.cpp      llpaneleditwearable.cpp +    llpanelemojicomplete.cpp      llpanelenvironment.cpp      llpanelexperiencelisteditor.cpp      llpanelexperiencelog.cpp @@ -845,6 +848,7 @@ set(viewer_HEADER_FILES      llfloaterdisplayname.h      llfloatereditenvironmentbase.h      llfloatereditextdaycycle.h +    llfloateremojipicker.h      llfloaterenvironmentadjust.h      llfloaterevent.h      llfloaterexperiencepicker.h @@ -1043,6 +1047,7 @@ set(viewer_HEADER_FILES      llpaneleditsky.h      llpaneleditwater.h      llpaneleditwearable.h +    llpanelemojicomplete.h      llpanelenvironment.h      llpanelexperiencelisteditor.h      llpanelexperiencelog.h @@ -1901,6 +1906,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}          ${LLPHYSICSEXTENSIONS_LIBRARIES}          ll::bugsplat          ll::tracy +        ll::icu4c          )  if( TARGET ll::intel_memops ) @@ -1914,6 +1920,28 @@ endif()  set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH      "Path to artwork files.") +message("Copying fonts") +file(GLOB FONT_FILE_GLOB_LIST +  "${AUTOBUILD_INSTALL_DIR}/fonts/*" +) +file(COPY ${FONT_FILE_GLOB_LIST} DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/fonts") + +# Copy over the Emoji/shortcodes mapping XML files (and create dependency +# if they are changed, CMake will run again and copy over new versions) +message("Copying Emoji/shortcode mappings") +set(emoji_mapping_src_folder ${AUTOBUILD_INSTALL_DIR}/xui) +set(emoji_mapping_dst_folder ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui) + +# Note Turkey is missing from this set (not available in Emoji package yet) +set(country_codes "da;de;en;es;fr;it;ja;pl;pt;ru;zh") +foreach(elem ${country_codes}) +   set(emoji_mapping_src_file +      "${emoji_mapping_src_folder}/${elem}/emoji_characters.xml") +   set(emoji_mapping_dst_file +      "${emoji_mapping_dst_folder}/${elem}/emoji_characters.xml")       +   configure_file(${emoji_mapping_src_file} ${emoji_mapping_dst_file} COPYONLY) +endforeach() +  if (LINUX)    set(product SecondLife-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}) diff --git a/indra/newview/app_settings/emoji_groups.xml b/indra/newview/app_settings/emoji_groups.xml new file mode 100644 index 0000000000..b433927f91 --- /dev/null +++ b/indra/newview/app_settings/emoji_groups.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>all</string> +      <key>Character</key> +      <string>🔍</string> +    </map> +    <map> +      <key>Character</key> +      <string>😀</string> +      <key>Categories</key> +      <array> +        <string>smileys and emotion</string> +        <string>people and body</string> +      </array> +    </map> +    <map> +      <key>Character</key> +      <string>🥬</string> +      <key>Categories</key> +      <array> +        <string>animals and nature</string> +      </array> +    </map> +    <map> +      <key>Character</key> +      <string>🍔</string> +      <key>Categories</key> +      <array> +        <string>food and drink</string> +      </array> +    </map> +    <map> +      <key>Character</key> +      <string>🛩</string> +      <key>Categories</key> +      <array> +        <string>travel and places</string> +      </array> +    </map> +    <map> +      <key>Character</key> +      <string>🏈</string> +      <key>Categories</key> +      <array> +        <string>activities</string> +      </array> +    </map> +    <map> +      <key>Character</key> +      <string>💡</string> +      <key>Categories</key> +      <array> +        <string>objects</string> +      </array> +    </map> +    <map> +      <key>Character</key> +      <string>⚠</string> +      <key>Categories</key> +      <array> +        <string>symbols</string> +      </array> +    </map> +    <map> +      <key>Name</key> +      <string>others</string> +      <key>Character</key> +      <string>🌂</string> +    </map> +    <map> +      <key>Name</key> +      <string>skip</string> +      <key>Categories</key> +      <array> +        <string>components</string> +      </array> +    </map> +  </array> +</llsd> diff --git a/indra/newview/fonts/DejaVu-license.txt b/indra/newview/fonts/DejaVu-license.txt deleted file mode 100644 index 254e2cc42a..0000000000 --- a/indra/newview/fonts/DejaVu-license.txt +++ /dev/null @@ -1,99 +0,0 @@ -Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. -Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) - -Bitstream Vera Fonts Copyright ------------------------------- - -Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is -a trademark of Bitstream, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of the fonts accompanying this license ("Fonts") and associated -documentation files (the "Font Software"), to reproduce and distribute the -Font Software, including without limitation the rights to use, copy, merge, -publish, distribute, and/or sell copies of the Font Software, and to permit -persons to whom the Font Software is furnished to do so, subject to the -following conditions: - -The above copyright and trademark notices and this permission notice shall -be included in all copies of one or more of the Font Software typefaces. - -The Font Software may be modified, altered, or added to, and in particular -the designs of glyphs or characters in the Fonts may be modified and -additional glyphs or characters may be added to the Fonts, only if the fonts -are renamed to names not containing either the words "Bitstream" or the word -"Vera". - -This License becomes null and void to the extent applicable to Fonts or Font -Software that has been modified and is distributed under the "Bitstream -Vera" names. - -The Font Software may be sold as part of a larger software package but no -copy of one or more of the Font Software typefaces may be sold by itself. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, -TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME -FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING -ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF -THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE -FONT SOFTWARE. - -Except as contained in this notice, the names of Gnome, the Gnome -Foundation, and Bitstream Inc., shall not be used in advertising or -otherwise to promote the sale, use or other dealings in this Font Software -without prior written authorization from the Gnome Foundation or Bitstream -Inc., respectively. For further information, contact: fonts at gnome dot -org.  - -Arev Fonts Copyright ------------------------------- - -Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the fonts accompanying this license ("Fonts") and -associated documentation files (the "Font Software"), to reproduce -and distribute the modifications to the Bitstream Vera Font Software, -including without limitation the rights to use, copy, merge, publish, -distribute, and/or sell copies of the Font Software, and to permit -persons to whom the Font Software is furnished to do so, subject to -the following conditions: - -The above copyright and trademark notices and this permission notice -shall be included in all copies of one or more of the Font Software -typefaces. - -The Font Software may be modified, altered, or added to, and in -particular the designs of glyphs or characters in the Fonts may be -modified and additional glyphs or characters may be added to the -Fonts, only if the fonts are renamed to names not containing either -the words "Tavmjong Bah" or the word "Arev". - -This License becomes null and void to the extent applicable to Fonts -or Font Software that has been modified and is distributed under the  -"Tavmjong Bah Arev" names. - -The Font Software may be sold as part of a larger software package but -no copy of one or more of the Font Software typefaces may be sold by -itself. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL -TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. - -Except as contained in this notice, the name of Tavmjong Bah shall not -be used in advertising or otherwise to promote the sale, use or other -dealings in this Font Software without prior written authorization -from Tavmjong Bah. For further information, contact: tavmjong @ free -. fr. - -$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $ diff --git a/indra/newview/fonts/DejaVuSans-Bold.ttf b/indra/newview/fonts/DejaVuSans-Bold.ttfBinary files differ deleted file mode 100644 index ec1a2ebaf2..0000000000 --- a/indra/newview/fonts/DejaVuSans-Bold.ttf +++ /dev/null diff --git a/indra/newview/fonts/DejaVuSans-BoldOblique.ttf b/indra/newview/fonts/DejaVuSans-BoldOblique.ttfBinary files differ deleted file mode 100644 index 1a5576460d..0000000000 --- a/indra/newview/fonts/DejaVuSans-BoldOblique.ttf +++ /dev/null diff --git a/indra/newview/fonts/DejaVuSans-Oblique.ttf b/indra/newview/fonts/DejaVuSans-Oblique.ttfBinary files differ deleted file mode 100644 index becc549927..0000000000 --- a/indra/newview/fonts/DejaVuSans-Oblique.ttf +++ /dev/null diff --git a/indra/newview/fonts/DejaVuSans.ttf b/indra/newview/fonts/DejaVuSans.ttfBinary files differ deleted file mode 100644 index c1b19d8705..0000000000 --- a/indra/newview/fonts/DejaVuSans.ttf +++ /dev/null diff --git a/indra/newview/fonts/DejaVuSansMono.ttf b/indra/newview/fonts/DejaVuSansMono.ttfBinary files differ deleted file mode 100644 index 6bc854ddae..0000000000 --- a/indra/newview/fonts/DejaVuSansMono.ttf +++ /dev/null diff --git a/indra/newview/installers/windows/lang_zh.nsi b/indra/newview/installers/windows/lang_zh.nsiBinary files differ index 7922d9df52..0985663041 100755 --- a/indra/newview/installers/windows/lang_zh.nsi +++ b/indra/newview/installers/windows/lang_zh.nsi diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 8cc9be7244..4274982a41 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3708,7 +3708,6 @@ void LLAgent::processScriptControlChange(LLMessageSystem *msg, void **)  			// take controls  			msg->getU32("Data", "Controls", controls, block_index );  			msg->getBOOL("Data", "PassToAgent", passon, block_index ); -			U32 total_count = 0;  			for (i = 0; i < TOTAL_CONTROLS; i++)  			{  				if (controls & ( 1 << i)) @@ -3721,7 +3720,6 @@ void LLAgent::processScriptControlChange(LLMessageSystem *msg, void **)  					{  						gAgent.mControlsTakenCount[i]++;  					} -					total_count++;  				}  			}  		} diff --git a/indra/newview/llautoreplace.h b/indra/newview/llautoreplace.h index 23cc313646..a1eebf9dcb 100644 --- a/indra/newview/llautoreplace.h +++ b/indra/newview/llautoreplace.h @@ -203,7 +203,7 @@ public:      void setSettings(const LLAutoReplaceSettings& settings);  private: -    /*virtual*/ void initSingleton(); +    /*virtual*/ void initSingleton() override;      LLAutoReplaceSettings mSettings; ///< configuration information diff --git a/indra/newview/llchannelmanager.h b/indra/newview/llchannelmanager.h index 8abe350196..22ae595d66 100644 --- a/indra/newview/llchannelmanager.h +++ b/indra/newview/llchannelmanager.h @@ -46,7 +46,7 @@ class LLChannelManager : public LLSingleton<LLChannelManager>  	LLSINGLETON(LLChannelManager);  	virtual ~LLChannelManager(); -	void cleanupSingleton(); +	void cleanupSingleton() override;  public: diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 9a608fba8e..f29d7ec29b 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -1096,6 +1096,8 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)  	editor_params.enabled = false; // read only  	editor_params.show_context_menu = "true";  	editor_params.trusted_content = false; +	editor_params.text_valign = LLFontGL::VAlign::VCENTER; +	editor_params.use_color = true;  	mEditor = LLUICtrlFactory::create<LLTextEditor>(editor_params, this);  	mEditor->setIsFriendCallback(LLAvatarActions::isFriend);  	mEditor->setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0)); @@ -1213,9 +1215,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL  	llassert(mEditor);  	if (!mEditor) -	{  		return; -	}  	bool from_me = chat.mFromID == gAgent.getID();  	mEditor->setPlainText(use_plain_text_chat_history); @@ -1225,26 +1225,16 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL  		mUnreadChatSources.insert(chat.mFromName);  		mMoreChatPanel->setVisible(TRUE);  		std::string chatters; -		for (unread_chat_source_t::iterator it = mUnreadChatSources.begin(); -			it != mUnreadChatSources.end();) +		for (const std::string& source : mUnreadChatSources)  		{ -			chatters += *it; -			if (++it != mUnreadChatSources.end()) -			{ -				chatters += ", "; -			} +			chatters += chatters.size() ? ", " + source : source;  		}  		LLStringUtil::format_map_t args;  		args["SOURCES"] = chatters; -		if (mUnreadChatSources.size() == 1) -		{ -			mMoreChatText->setValue(LLTrans::getString("unread_chat_single", args)); -		} -		else -		{ -			mMoreChatText->setValue(LLTrans::getString("unread_chat_multiple", args)); -		} +		std::string xml_desc = mUnreadChatSources.size() == 1 ? +			"unread_chat_single" : "unread_chat_multiple"; +		mMoreChatText->setValue(LLTrans::getString(xml_desc, args));  		S32 height = mMoreChatText->getTextPixelHeight() + 5;  		mMoreChatPanel->reshape(mMoreChatPanel->getRect().getWidth(), height);  	} @@ -1292,11 +1282,11 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL  		body_message_params.font.style = "ITALIC";  	} -	if(chat.mChatType == CHAT_TYPE_WHISPER) +	if (chat.mChatType == CHAT_TYPE_WHISPER)  	{  		body_message_params.font.style = "ITALIC";  	} -	else if(chat.mChatType == CHAT_TYPE_SHOUT) +	else if (chat.mChatType == CHAT_TYPE_SHOUT)  	{  		body_message_params.font.style = "BOLD";  	} @@ -1343,10 +1333,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL  		}  		// names showing -		if (args["show_names_for_p2p_conv"].asBoolean() && utf8str_trim(chat.mFromName).size() != 0) +		if (args["show_names_for_p2p_conv"].asBoolean() && utf8str_trim(chat.mFromName).size())  		{  			// Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. -			if ( chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull()) +			if (chat.mSourceType == CHAT_SOURCE_OBJECT && chat.mFromID.notNull())  			{  				// for object IMs, create a secondlife:///app/objectim SLapp  				std::string url = LLViewerChat::getSenderSLURL(chat, args); @@ -1406,36 +1396,27 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL  			&& mIsLastMessageFromLog == message_from_log)  //distinguish between current and previous chat session's histories  		{  			view = getSeparator(); -			p.top_pad = mTopSeparatorPad; -			p.bottom_pad = mBottomSeparatorPad;              if (!view)              {                  // Might be wiser to make this LL_ERRS, getSeparator() should work in case of correct instalation.                  LL_WARNS() << "Failed to create separator from " << mMessageSeparatorFilename << ": can't append to history" << LL_ENDL;                  return;              } + +			p.top_pad = mTopSeparatorPad; +			p.bottom_pad = mBottomSeparatorPad;  		}  		else  		{  			view = getHeader(chat, name_params, args); -			if (mEditor->getLength() == 0) -				p.top_pad = 0; -			else -				p.top_pad = mTopHeaderPad; -            if (teleport_separator) -            { -                p.bottom_pad = mBottomSeparatorPad; -            } -            else -            { -                p.bottom_pad = mBottomHeaderPad; -            } -            if (!view) -            { -                LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL; -                return; -            } +			if (!view) +			{ +				LL_WARNS() << "Failed to create header from " << mMessageHeaderFilename << ": can't append to history" << LL_ENDL; +				return; +			} +			p.top_pad = mEditor->getLength() ? mTopHeaderPad : 0; +			p.bottom_pad = teleport_separator ? mBottomSeparatorPad : mBottomHeaderPad;  		}  		p.view = view; @@ -1508,11 +1489,10 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL  		}  	}  	// usual messages showing -	else if(!teleport_separator) +	else if (!teleport_separator)  	{  		std::string message = irc_me ? chat.mText.substr(3) : chat.mText; -  		//MESSAGE TEXT PROCESSING  		//*HACK getting rid of redundant sender names in system notifications sent using sender name (see EXT-5010)  		if (use_plain_text_chat_history && !from_me && chat.mFromID.notNull()) diff --git a/indra/newview/llchicletbar.h b/indra/newview/llchicletbar.h index 6c521dc1d5..c295b99962 100644 --- a/indra/newview/llchicletbar.h +++ b/indra/newview/llchicletbar.h @@ -43,11 +43,11 @@ class LLChicletBar  public: -	BOOL postBuild(); +	BOOL postBuild() override;  	LLChicletPanel*	getChicletPanel() { return mChicletPanel; } -	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent); +	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent) override;  	/** diff --git a/indra/newview/llconversationlog.h b/indra/newview/llconversationlog.h index 820a5db491..54aeedcf9a 100644 --- a/indra/newview/llconversationlog.h +++ b/indra/newview/llconversationlog.h @@ -125,11 +125,11 @@ public:  	void removeObserver(LLConversationLogObserver* observer);  	// LLIMSessionObserver triggers -	virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, BOOL has_offline_msg); -    virtual void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) {}; // Stub -	virtual void sessionRemoved(const LLUUID& session_id){}											// Stub -	virtual void sessionVoiceOrIMStarted(const LLUUID& session_id){};								// Stub -	virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id){};	// Stub +	virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id, BOOL has_offline_msg) override; +    virtual void sessionActivated(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) override {}; // Stub +	virtual void sessionRemoved(const LLUUID& session_id) override{}											// Stub +	virtual void sessionVoiceOrIMStarted(const LLUUID& session_id) override{};								// Stub +	virtual void sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id) override{};	// Stub  	void notifyObservers(); diff --git a/indra/newview/llexpandabletextbox.cpp b/indra/newview/llexpandabletextbox.cpp index 3395777aab..2d332f75f5 100644 --- a/indra/newview/llexpandabletextbox.cpp +++ b/indra/newview/llexpandabletextbox.cpp @@ -88,7 +88,7 @@ public:  									mStyle->getShadowType(),   									end - start, draw_rect.getWidth(),   									&right_x,  -									mEditor.getUseEllipses()); +									mEditor.getUseEllipses(), mEditor.getUseColor());  		return right_x;  	}  	/*virtual*/ bool	canEdit() const { return false; } diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index 651404d890..70c6c09e0d 100644 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -101,7 +101,7 @@ class LLFeatureManager : public LLFeatureList, public LLSingleton<LLFeatureManag  	~LLFeatureManager() {cleanupFeatureTables();}  	// initialize this by loading feature table and gpu table -	void initSingleton(); +	void initSingleton() override;  public: diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 2422596f60..42ef41017a 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -741,7 +741,6 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD&  	}  } -//static  void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller, void* user_data)  {  	getChildView("Find")->setEnabled(caller->getText().size() > 0); diff --git a/indra/newview/llfloateremojipicker.cpp b/indra/newview/llfloateremojipicker.cpp new file mode 100644 index 0000000000..808aca4bf4 --- /dev/null +++ b/indra/newview/llfloateremojipicker.cpp @@ -0,0 +1,906 @@ +/** + * @file llfloateremojipicker.cpp + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloateremojipicker.h" + +#include "llappviewer.h" +#include "llbutton.h" +#include "llcombobox.h" +#include "llemojidictionary.h" +#include "llfloaterreg.h" +#include "llkeyboard.h" +#include "lllineeditor.h" +#include "llscrollcontainer.h" +#include "llscrollingpanellist.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llsdserialize.h" +#include "lltextbox.h"  +#include "llviewerchat.h"  + +namespace { +// The following variables and constants are used for storing the floater state +// between different lifecycles of the floater and different sissions of the viewer + +// Floater state related variables +static U32 sSelectedGroupIndex = 0; +static std::string sFilterPattern; +static std::list<llwchar> sRecentlyUsed; +static std::list<std::pair<llwchar, U32>> sFrequentlyUsed; + +// State file related values +static std::string sStateFileName; +static const std::string sKeySelectedGroupIndex("SelectedGroupIndex"); +static const std::string sKeyFilterPattern("FilterPattern"); +static const std::string sKeyRecentlyUsed("RecentlyUsed"); +static const std::string sKeyFrequentlyUsed("FrequentlyUsed"); +} + +class LLEmojiGridRow : public LLScrollingPanel +{ +public: +    LLEmojiGridRow(const LLPanel::Params& panel_params, +        const LLScrollingPanelList::Params& list_params) +        : LLScrollingPanel(panel_params) +        , mList(new LLScrollingPanelList(list_params)) +    { +        addChild(mList); +    } + +    virtual void updatePanel(BOOL allow_modify) override {} + +public: +    LLScrollingPanelList* mList; +}; + +class LLEmojiGridDivider : public LLScrollingPanel +{ +public: +    LLEmojiGridDivider(const LLPanel::Params& panel_params, std::string text) +        : LLScrollingPanel(panel_params) +        , mText(utf8string_to_wstring(text)) +    { +    } + +    virtual void draw() override +    { +        LLScrollingPanel::draw(); + +        F32 x = 4; // padding-left +        F32 y = getRect().getHeight() / 2; +        LLFontGL::getFontSansSerif()->render( +            mText,                      // wstr +            0,                          // begin_offset +            x,                          // x +            y,                          // y +            LLColor4::white,            // color +            LLFontGL::LEFT,             // halign +            LLFontGL::VCENTER,          // valign +            LLFontGL::NORMAL,           // style +            LLFontGL::DROP_SHADOW_SOFT, // shadow +            mText.size(),               // max_chars +            S32_MAX,                    // max_pixels +            nullptr,                    // right_x +            false,                      // use_ellipses +            true);                      // use_color +    } + +    virtual void updatePanel(BOOL allow_modify) override {} + +private: +    const LLWString mText; +}; + +class LLEmojiGridIcon : public LLScrollingPanel +{ +public: +    LLEmojiGridIcon( +        const LLPanel::Params& panel_params +        , const LLEmojiDescriptor* descr +        , std::string category) +        : LLScrollingPanel(panel_params) +        , mDescr(descr) +        , mText(LLWString(1, descr->Character)) +    { +    } + +    virtual void draw() override +    { +        LLScrollingPanel::draw(); + +        F32 x = getRect().getWidth() / 2; +        F32 y = getRect().getHeight() / 2; +        LLFontGL::getFontEmoji()->render( +            mText,                      // wstr +            0,                          // begin_offset +            x,                          // x +            y,                          // y +            LLColor4::white,            // color +            LLFontGL::HCENTER,          // halign +            LLFontGL::VCENTER,          // valign +            LLFontGL::NORMAL,           // style +            LLFontGL::DROP_SHADOW_SOFT, // shadow +            1,                          // max_chars +            S32_MAX,                    // max_pixels +            nullptr,                    // right_x +            false,                      // use_ellipses +            true);                      // use_color +    } + +    virtual void updatePanel(BOOL allow_modify) override {} + +    const LLEmojiDescriptor* getDescr() const { return mDescr; } +    llwchar getEmoji() const { return mDescr->Character; } +    LLWString getText() const { return mText; } + +private: +    const LLEmojiDescriptor* mDescr; +    const LLWString mText; +}; + +class LLEmojiPreviewPanel : public LLPanel +{ +public: +    LLEmojiPreviewPanel() +        : LLPanel() +    { +    } + +    void setEmoji(const LLEmojiDescriptor* descr) +    { +        mDescr = descr; + +        if (!mDescr) +            return; + +        mEmojiText = LLWString(1, descr->Character); +    } + +    virtual void draw() override +    { +        LLPanel::draw(); + +        if (!mDescr) +            return; + +        S32 clientHeight = getRect().getHeight(); +        S32 clientWidth = getRect().getWidth(); +        S32 iconWidth = clientHeight; + +        F32 centerX = 0.5f * iconWidth; +        F32 centerY = 0.5f * clientHeight; +        drawIcon(centerX, centerY, iconWidth); + +        static LLColor4 defaultColor(0.75f, 0.75f, 0.75f, 1.0f); +        LLColor4 textColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", defaultColor); +        S32 max_pixels = clientWidth - iconWidth; +        size_t count = mDescr->ShortCodes.size(); +        if (count == 1) +        { +            drawName(mDescr->ShortCodes.front(), iconWidth, centerY, max_pixels, textColor); +        } +        else if (count > 1) +        { +            F32 quarterY = 0.5f * centerY; +            drawName(mDescr->ShortCodes.front(), iconWidth, centerY + quarterY, max_pixels, textColor); +            drawName(*++mDescr->ShortCodes.begin(), iconWidth, quarterY, max_pixels, textColor); +        } +    } + +protected: +    void drawIcon(F32 x, F32 y, S32 max_pixels) +    { +        LLFontGL::getFontEmojiHuge()->render( +            mEmojiText,                 // wstr +            0,                          // begin_offset +            x,                          // x +            y,                          // y +            LLColor4::white,            // color +            LLFontGL::HCENTER,          // halign +            LLFontGL::VCENTER,          // valign +            LLFontGL::NORMAL,           // style +            LLFontGL::DROP_SHADOW_SOFT, // shadow +            1,                          // max_chars +            max_pixels,                 // max_pixels +            nullptr,                    // right_x +            false,                      // use_ellipses +            true);                      // use_color +    } + +    void drawName(std::string name, F32 x, F32 y, S32 max_pixels, LLColor4& color) +    { +        LLFontGL::getFontEmoji()->renderUTF8( +            name,                       // wstr +            0,                          // begin_offset +            x,                          // x +            y,                          // y +            color,                      // color +            LLFontGL::LEFT,             // halign +            LLFontGL::VCENTER,          // valign +            LLFontGL::NORMAL,           // style +            LLFontGL::DROP_SHADOW_SOFT, // shadow +            -1,                         // max_chars +            max_pixels,                 // max_pixels +            nullptr,                    // right_x +            true,                       // use_ellipses +            false);                     // use_color +    } + +private: +    const LLEmojiDescriptor* mDescr { nullptr }; +    LLWString mEmojiText; +}; + +LLFloaterEmojiPicker* LLFloaterEmojiPicker::getInstance() +{ +    LLFloaterEmojiPicker* floater = LLFloaterReg::getTypedInstance<LLFloaterEmojiPicker>("emoji_picker"); +    if (!floater) +        LL_ERRS() << "Cannot instantiate emoji picker" << LL_ENDL; +    return floater; +} + +LLFloaterEmojiPicker* LLFloaterEmojiPicker::showInstance(pick_callback_t pick_callback, close_callback_t close_callback) +{ +    LLFloaterEmojiPicker* floater = getInstance(); +    floater->show(pick_callback, close_callback); +    return floater; +} + +void LLFloaterEmojiPicker::show(pick_callback_t pick_callback, close_callback_t close_callback) +{ +    mEmojiPickCallback = pick_callback; +    mFloaterCloseCallback = close_callback; +    openFloater(mKey); +    setFocus(TRUE); +} + +LLFloaterEmojiPicker::LLFloaterEmojiPicker(const LLSD& key) +: LLFloater(key) +{ +    loadState(); +} + +BOOL LLFloaterEmojiPicker::postBuild() +{ +    // Should be initialized first +    mPreview = new LLEmojiPreviewPanel(); +    mPreview->setVisible(FALSE); +    addChild(mPreview); + +    mGroups = getChild<LLPanel>("Groups"); +    mBadge = getChild<LLPanel>("Badge"); + +    mFilter = getChild<LLLineEditor>("Filter"); +    mFilter->setKeystrokeCallback([this](LLLineEditor*, void*) { onSearchKeystroke(); }, NULL); +    mFilter->setFont(LLViewerChat::getChatFont()); +    mFilter->setText(sFilterPattern); + +    mEmojiScroll = getChild<LLScrollContainer>("EmojiGridContainer"); +    mEmojiScroll->setMouseEnterCallback([this](LLUICtrl*, const LLSD&) { onGridMouseEnter(); }); +    mEmojiScroll->setMouseLeaveCallback([this](LLUICtrl*, const LLSD&) { onGridMouseLeave(); }); + +    mEmojiGrid = getChild<LLScrollingPanelList>("EmojiGrid"); + +    fillGroups(); +    fillEmojis(); + +    return TRUE; +} + +void LLFloaterEmojiPicker::dirtyRect() +{ +    super::dirtyRect(); + +    if (!mFilter) +        return; + +    const S32 PADDING = 4; +    LLRect rect(PADDING, mFilter->getRect().mTop, getRect().getWidth() - PADDING * 2, PADDING); +    if (mPreview->getRect() != rect) +    { +        mPreview->setRect(rect); +    } + +    if (mEmojiScroll && mEmojiScroll->getRect().getWidth() != mRecentGridWidth) +    { +        moveGroups(); +        fillEmojis(true); +    } +} + +LLFloaterEmojiPicker::~LLFloaterEmojiPicker() +{ +    gFocusMgr.releaseFocusIfNeeded( this ); +} + +void LLFloaterEmojiPicker::fillGroups() +{ +    LLButton::Params params; +    params.font = LLFontGL::getFontEmoji(); + +    LLRect rect; +    rect.mTop = mGroups->getRect().getHeight(); +    rect.mBottom = mBadge->getRect().getHeight(); + +    const std::vector<LLEmojiGroup>& groups = LLEmojiDictionary::instance().getGroups(); +    for (const LLEmojiGroup& group : groups) +    { +        LLButton* button = LLUICtrlFactory::create<LLButton>(params); +        button->setClickedCallback([this](LLUICtrl* ctrl, const LLSD&) { onGroupButtonClick(ctrl); }); +        button->setMouseEnterCallback([this](LLUICtrl* ctrl, const LLSD&) { onGroupButtonMouseEnter(ctrl); }); +        button->setMouseLeaveCallback([this](LLUICtrl* ctrl, const LLSD&) { onGroupButtonMouseLeave(ctrl); }); + +        button->setRect(rect); + +        LLUIString text; +        text.insert(0, LLWString(1, group.Character)); +        button->setLabel(text); + +        if (mGroupButtons.size() == sSelectedGroupIndex) +        { +            button->setToggleState(TRUE); +            button->setUseFontColor(TRUE); +        } + +        mGroupButtons.push_back(button); +        mGroups->addChild(button); +    } + +    moveGroups(); +} + +void LLFloaterEmojiPicker::moveGroups() +{ +    const std::vector<LLEmojiGroup>& groups = LLEmojiDictionary::instance().getGroups(); +    if (groups.empty()) +        return; + +    int badgeWidth = mGroups->getRect().getWidth() / groups.size(); +    if (badgeWidth == mRecentBadgeWidth) +        return; + +    mRecentBadgeWidth = badgeWidth; + +    for (int i = 0; i < mGroupButtons.size(); ++i) +    { +        LLRect rect = mGroupButtons[i]->getRect(); +        rect.mLeft = badgeWidth * i; +        rect.mRight = rect.mLeft + badgeWidth; +        mGroupButtons[i]->setRect(rect); +    } + +    LLRect rect = mBadge->getRect(); +    rect.mLeft = badgeWidth * sSelectedGroupIndex; +    rect.mRight = rect.mLeft + badgeWidth; +    mBadge->setRect(rect); +} + +void LLFloaterEmojiPicker::fillEmojis(bool fromResize) +{ +    mRecentGridWidth = mEmojiScroll->getRect().getWidth(); + +    S32 scrollbarSize = mEmojiScroll->getSize(); +    if (scrollbarSize < 0) +    { +        static LLUICachedControl<S32> scrollbar_size_control("UIScrollbarSize", 0); +        scrollbarSize = scrollbar_size_control; +    } + +    const S32 clientWidth = mRecentGridWidth - scrollbarSize - mEmojiScroll->getBorderWidth() * 2; +    const S32 gridPadding = mEmojiGrid->getPadding(); +    const S32 iconSpacing = mEmojiGrid->getSpacing(); +    const S32 rowWidth = clientWidth - gridPadding * 2; +    const S32 iconSize = 28; // icon width and height +    const S32 maxIcons = llmax(1, (rowWidth + iconSpacing) / (iconSize + iconSpacing)); + +    // Optimization: don't rearrange for different widths with the same maxIcons +    if (fromResize && (maxIcons == mRecentMaxIcons)) +        return; + +    mRecentMaxIcons = maxIcons; + +    mHoveredIcon = nullptr; +    mEmojiGrid->clearPanels(); +    mPreview->setEmoji(nullptr); + +    if (mEmojiGrid->getRect().getWidth() != clientWidth) +    { +        LLRect rect = mEmojiGrid->getRect(); +        rect.mRight = rect.mLeft + clientWidth; +        mEmojiGrid->setRect(rect); +    } + +    LLPanel::Params row_panel_params; +    row_panel_params.rect = LLRect(0, iconSize, rowWidth, 0); + +    LLScrollingPanelList::Params row_list_params; +    row_list_params.rect = row_panel_params.rect; +    row_list_params.is_horizontal = TRUE; +    row_list_params.padding = 0; +    row_list_params.spacing = iconSpacing; + +    LLPanel::Params icon_params; +    LLRect icon_rect(0, iconSize, iconSize, 0); + +    static LLColor4 defaultColor(0.75f, 0.75f, 0.75f, 1.0f); +    LLColor4 bgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", defaultColor); + +    auto matchesPattern = [](const LLEmojiDescriptor* descr) -> bool +    { +        for (const std::string& shortCode : descr->ShortCodes) +            if (shortCode.find(sFilterPattern) != std::string::npos) +                return true; +        return false; +    }; + +    auto listCategory = [&](std::string category, const std::vector<const LLEmojiDescriptor*>& emojis, int maxRows = 0) +    { +        int rowCount = 0; +        int iconIndex = 0; +        bool showDivider = true; +        bool mixedFolder = maxRows; +        LLEmojiGridRow* row = nullptr; +        if (!mixedFolder) +        { +            LLStringUtil::capitalize(category); +        } + +        for (const LLEmojiDescriptor* descr : emojis) +        { +            if (sFilterPattern.empty() || matchesPattern(descr)) +            { +                // Place a category title if needed +                if (showDivider) +                { +                    LLEmojiGridDivider* div = new LLEmojiGridDivider(row_panel_params, category); +                    mEmojiGrid->addPanel(div, true); +                    showDivider = false; +                } + +                // Place a new row each (maxIcons) icons +                if (!(iconIndex % maxIcons)) +                { +                    if (maxRows && ++rowCount > maxRows) +                        break; +                    row = new LLEmojiGridRow(row_panel_params, row_list_params); +                    mEmojiGrid->addPanel(row, true); +                } + +                // Place a new icon to the current row +                LLEmojiGridIcon* icon = new LLEmojiGridIcon(icon_params, descr, mixedFolder ? LLStringUtil::capitalize(descr->Category) : category); +                icon->setMouseEnterCallback([this](LLUICtrl* ctrl, const LLSD&) { onEmojiMouseEnter(ctrl); }); +                icon->setMouseLeaveCallback([this](LLUICtrl* ctrl, const LLSD&) { onEmojiMouseLeave(ctrl); }); +                icon->setMouseDownCallback([this](LLUICtrl* ctrl, S32, S32, MASK) { onEmojiMouseDown(ctrl); }); +                icon->setMouseUpCallback([this](LLUICtrl* ctrl, S32, S32, MASK) { onEmojiMouseUp(ctrl); }); +                icon->setBackgroundColor(bgColor); +                icon->setBackgroundOpaque(1); +                icon->setRect(icon_rect); +                row->mList->addPanel(icon, true); + +                iconIndex++; +            } +        } +    }; + +    const std::vector<LLEmojiGroup>& groups = LLEmojiDictionary::instance().getGroups(); +    const LLEmojiDictionary::emoji2descr_map_t& emoji2descr = LLEmojiDictionary::instance().getEmoji2Descr(); +    const LLEmojiDictionary::cat2descrs_map_t& category2Descr = LLEmojiDictionary::instance().getCategory2Descrs(); +    if (!sSelectedGroupIndex) +    { +        std::vector<const LLEmojiDescriptor*> recentlyUsed; +        for (llwchar emoji : sRecentlyUsed) +        { +            auto it = emoji2descr.find(emoji); +            if (it != emoji2descr.end()) +            { +                recentlyUsed.push_back(it->second); +            } +        } +        listCategory(getString("title_for_recently_used"), recentlyUsed, 1); + +        std::vector<const LLEmojiDescriptor*> frequentlyUsed; +        for (auto& emoji : sFrequentlyUsed) +        { +            auto it = emoji2descr.find(emoji.first); +            if (it != emoji2descr.end()) +            { +                frequentlyUsed.push_back(it->second); +            } +        } +        listCategory(getString("title_for_frequently_used"), frequentlyUsed, 1); + +        // List all groups +        for (const LLEmojiGroup& group : groups) +        { +            // List all categories in group +            for (const std::string& category : group.Categories) +            { +                // List all emojis in category +                const LLEmojiDictionary::cat2descrs_map_t::const_iterator& item = category2Descr.find(category); +                if (item != category2Descr.end()) +                { +                    listCategory(category, item->second); +                } +            } +        } +    } +    else +    { +        // List all categories in the selected group +        for (const std::string& category : groups[sSelectedGroupIndex].Categories) +        { +            // List all emojis in category +            const LLEmojiDictionary::cat2descrs_map_t::const_iterator& item = category2Descr.find(category); +            if (item != category2Descr.end()) +            { +                listCategory(category, item->second); +            } +        } +    } +} + +void LLFloaterEmojiPicker::onGroupButtonClick(LLUICtrl* ctrl) +{ +    if (LLButton* button = dynamic_cast<LLButton*>(ctrl)) +    { +        if (button == mGroupButtons[sSelectedGroupIndex] || button->getToggleState()) +            return; + +        auto it = std::find(mGroupButtons.begin(), mGroupButtons.end(), button); +        if (it == mGroupButtons.end()) +            return; + +        mGroupButtons[sSelectedGroupIndex]->setUseFontColor(FALSE); +        mGroupButtons[sSelectedGroupIndex]->setToggleState(FALSE); +        sSelectedGroupIndex = it - mGroupButtons.begin(); +        mGroupButtons[sSelectedGroupIndex]->setToggleState(TRUE); +        mGroupButtons[sSelectedGroupIndex]->setUseFontColor(TRUE); + +        LLRect rect = mBadge->getRect(); +        rect.mLeft = button->getRect().mLeft; +        rect.mRight = button->getRect().mRight; +        mBadge->setRect(rect); + +        mFilter->setFocus(TRUE); + +        fillEmojis(); +    } +} + +void LLFloaterEmojiPicker::onSearchKeystroke() +{ +    sFilterPattern = mFilter->getText(); +    fillEmojis(); +} + +void LLFloaterEmojiPicker::onGridMouseEnter() +{ +    mFilter->setVisible(FALSE); +    mPreview->setEmoji(nullptr); +    mPreview->setVisible(TRUE); +} + +void LLFloaterEmojiPicker::onGridMouseLeave() +{ +    mPreview->setVisible(FALSE); +    mFilter->setVisible(TRUE); +    mFilter->setFocus(TRUE); +} + +void LLFloaterEmojiPicker::onGroupButtonMouseEnter(LLUICtrl* ctrl) +{ +    if (LLButton* button = dynamic_cast<LLButton*>(ctrl)) +    { +        button->setUseFontColor(TRUE); +    } +} + +void LLFloaterEmojiPicker::onGroupButtonMouseLeave(LLUICtrl* ctrl) +{ +    if (LLButton* button = dynamic_cast<LLButton*>(ctrl)) +    { +        button->setUseFontColor(button->getToggleState()); +    } +} + +void LLFloaterEmojiPicker::onEmojiMouseEnter(LLUICtrl* ctrl) +{ +    if (ctrl) +    { +        if (mHoveredIcon && mHoveredIcon != ctrl) +        { +            unselectGridIcon(mHoveredIcon); +        } + +        selectGridIcon(ctrl); + +        mHoveredIcon = ctrl; +    } +} + +void LLFloaterEmojiPicker::onEmojiMouseLeave(LLUICtrl* ctrl) +{ +    if (ctrl) +    { +        if (ctrl == mHoveredIcon) +        { +            unselectGridIcon(ctrl); +        } +    } +} + +void LLFloaterEmojiPicker::onEmojiMouseDown(LLUICtrl* ctrl) +{ +    if (getSoundFlags() & MOUSE_DOWN) +    { +        make_ui_sound("UISndClick"); +    } +} + +void LLFloaterEmojiPicker::onEmojiMouseUp(LLUICtrl* ctrl) +{ +    if (getSoundFlags() & MOUSE_UP) +    { +        make_ui_sound("UISndClickRelease"); +    } + +    if (mEmojiPickCallback) +    { +        if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl)) +        { +            onEmojiUsed(icon->getEmoji()); +            if (mEmojiPickCallback) +            { +                mEmojiPickCallback(icon->getEmoji()); +            } +        } +    } +} + +void LLFloaterEmojiPicker::selectGridIcon(LLUICtrl* ctrl) +{ +    if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl)) +    { +        icon->setBackgroundVisible(TRUE); +        mPreview->setEmoji(icon->getDescr()); +    } +} + +void LLFloaterEmojiPicker::unselectGridIcon(LLUICtrl* ctrl) +{ +    if (LLEmojiGridIcon* icon = dynamic_cast<LLEmojiGridIcon*>(ctrl)) +    { +        icon->setBackgroundVisible(FALSE); +        mPreview->setEmoji(nullptr); +    } +} + +// virtual +BOOL LLFloaterEmojiPicker::handleKeyHere(KEY key, MASK mask) +{ +    if (mask == MASK_NONE) +    { +        switch (key) +        { +        case KEY_ESCAPE: +            closeFloater(); +            return TRUE; +        } +    } + +    return LLFloater::handleKeyHere(key, mask); +} + +// virtual +void LLFloaterEmojiPicker::closeFloater(bool app_quitting) +{ +    saveState(); +    LLFloater::closeFloater(app_quitting); +    if (mFloaterCloseCallback) +    { +        mFloaterCloseCallback(); +    } +} + +void LLFloaterEmojiPicker::onEmojiUsed(llwchar emoji) +{ +    // Update sRecentlyUsed +    auto itr = std::find(sRecentlyUsed.begin(), sRecentlyUsed.end(), emoji); +    if (itr == sRecentlyUsed.end()) +    { +        sRecentlyUsed.push_front(emoji); +    } +    else if (itr != sRecentlyUsed.begin()) +    { +        sRecentlyUsed.erase(itr); +        sRecentlyUsed.push_front(emoji); +    } + +    // Increment and reorder sFrequentlyUsed +    auto itf = sFrequentlyUsed.begin(); +    while (itf != sFrequentlyUsed.end()) +    { +        if (itf->first == emoji) +        { +            itf->second++; +            while (itf != sFrequentlyUsed.begin()) +            { +                auto prior = itf; +                prior--; +                if (prior->second > itf->second) +                    break; +                prior->swap(*itf); +                itf = prior; +            } +            break; +        } +        itf++; +    } +    // Append new if not found +    if (itf == sFrequentlyUsed.end()) +        sFrequentlyUsed.push_back(std::make_pair(emoji, 1)); +} + +void LLFloaterEmojiPicker::loadState() +{ +    if (!sStateFileName.empty()) +        return; // Already loaded + +    sStateFileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "emoji_floater_state.xml"); + +    llifstream file; +    file.open(sStateFileName.c_str()); +    if (!file.is_open()) +    { +        LL_WARNS() << "Emoji floater state file is missing or inaccessible: " << sStateFileName << LL_ENDL; +        return; +    } + +    LLSD state; +    LLSDSerialize::fromXML(state, file); +    if (state.isUndefined()) +    { +        LL_WARNS() << "Emoji floater state file is missing or ill-formed: " << sStateFileName << LL_ENDL; +        return; +    } + +    sSelectedGroupIndex = state[sKeySelectedGroupIndex].asInteger(); + +    sFilterPattern = state[sKeyFilterPattern].asString(); + +    // Load and parse sRecentlyUsed +    std::string recentlyUsed = state[sKeyRecentlyUsed]; +    std::vector<std::string> rtokens = LLStringUtil::getTokens(recentlyUsed, ","); +    int maxCountR = 20; +    for (const std::string& token : rtokens) +    { +        llwchar emoji = (llwchar)atoi(token.c_str()); +        if (std::find(sRecentlyUsed.begin(), sRecentlyUsed.end(), emoji) == sRecentlyUsed.end()) +        { +            sRecentlyUsed.push_back(emoji); +            if (!--maxCountR) +                break; +        } +    } + +    // Load and parse sFrequentlyUsed +    std::string frequentlyUsed = state[sKeyFrequentlyUsed]; +    std::vector<std::string> ftokens = LLStringUtil::getTokens(frequentlyUsed, ","); +    int maxCountF = 20; +    for (const std::string& token : ftokens) +    { +        std::vector<std::string> pair = LLStringUtil::getTokens(token, ":"); +        if (pair.size() == 2) +        { +            llwchar emoji = (llwchar)atoi(pair[0].c_str()); +            if (emoji) +            { +                U32 count = atoi(pair[1].c_str()); +                auto it = std::find_if(sFrequentlyUsed.begin(), sFrequentlyUsed.end(), +                    [emoji](std::pair<llwchar, U32>& it) { return it.first == emoji; }); +                if (it != sFrequentlyUsed.end()) +                { +                    it->second += count; +                } +                else +                { +                    sFrequentlyUsed.push_back(std::make_pair(emoji, count)); +                    if (!--maxCountF) +                        break; +                } +            } +        } +    } + +    // Normalize by minimum +    if (!sFrequentlyUsed.empty()) +    { +        U32 delta = sFrequentlyUsed.back().second; +        for (auto& it : sFrequentlyUsed) +        { +            it.second = std::max((U32)0, it.second - delta); +        } +    } +} + +void LLFloaterEmojiPicker::saveState() +{ +    if (sStateFileName.empty()) +        return; // Not loaded + +    if (LLAppViewer::instance()->isSecondInstance()) +        return; // Not allowed + +    LLSD state = LLSD::emptyMap(); + +    if (sSelectedGroupIndex) +    { +        state[sKeySelectedGroupIndex] = (int)sSelectedGroupIndex; +    } + +    if (!sFilterPattern.empty()) +    { +        state[sKeyFilterPattern] = sFilterPattern; +    } + +    if (!sRecentlyUsed.empty()) +    { +        U32 maxCount = 20; +        std::string recentlyUsed; +        for (llwchar emoji : sRecentlyUsed) +        { +            if (!recentlyUsed.empty()) +                recentlyUsed += ","; +            char buffer[32]; +            sprintf(buffer, "%u", (U32)emoji); +            recentlyUsed += buffer; +            if (!--maxCount) +                break; +        } +        state[sKeyRecentlyUsed] = recentlyUsed; +    } + +    if (!sFrequentlyUsed.empty()) +    { +        U32 maxCount = 20; +        std::string frequentlyUsed; +        for (auto& it : sFrequentlyUsed) +        { +            if (!frequentlyUsed.empty()) +                frequentlyUsed += ","; +            char buffer[32]; +            sprintf(buffer, "%u:%u", (U32)it.first, (U32)it.second); +            frequentlyUsed += buffer; +            if (!--maxCount) +                break; +        } +        state[sKeyFrequentlyUsed] = frequentlyUsed; +    } + +    llofstream stream(sStateFileName.c_str()); +    LLSDSerialize::toPrettyXML(state, stream); +} diff --git a/indra/newview/llfloateremojipicker.h b/indra/newview/llfloateremojipicker.h new file mode 100644 index 0000000000..e4b1216ce6 --- /dev/null +++ b/indra/newview/llfloateremojipicker.h @@ -0,0 +1,100 @@ +/** + * @file llfloateremojipicker.h + * @brief Header file for llfloateremojipicker + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#ifndef LLFLOATEREMOJIPICKER_H +#define LLFLOATEREMOJIPICKER_H + +#include "llfloater.h" + +struct LLEmojiDescriptor; + +class LLFloaterEmojiPicker : public LLFloater +{ +    using super = LLFloater; + +public: +    // The callback function will be called with an emoji char. +    typedef boost::function<void (llwchar)> pick_callback_t; +    typedef boost::function<void ()> close_callback_t; + +    // Call this to select an emoji. +    static LLFloaterEmojiPicker* getInstance(); +    static LLFloaterEmojiPicker* showInstance(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr); + +    LLFloaterEmojiPicker(const LLSD& key); +    virtual ~LLFloaterEmojiPicker(); + +    virtual	BOOL postBuild() override; +    virtual void dirtyRect() override; + +    void show(pick_callback_t pick_callback = nullptr, close_callback_t close_callback = nullptr); + +    virtual void closeFloater(bool app_quitting = false) override; + +private: +    void fillGroups(); +    void moveGroups(); +    void fillEmojis(bool fromResize = false); + +    void onGroupButtonClick(LLUICtrl* ctrl); +    void onSearchKeystroke(); +    void onGridMouseEnter(); +    void onGridMouseLeave(); +    void onGroupButtonMouseEnter(LLUICtrl* ctrl); +    void onGroupButtonMouseLeave(LLUICtrl* ctrl); +    void onEmojiMouseEnter(LLUICtrl* ctrl); +    void onEmojiMouseLeave(LLUICtrl* ctrl); +    void onEmojiMouseDown(LLUICtrl* ctrl); +    void onEmojiMouseUp(LLUICtrl* ctrl); + +    void selectGridIcon(LLUICtrl* ctrl); +    void unselectGridIcon(LLUICtrl* ctrl); + +    virtual BOOL handleKeyHere(KEY key, MASK mask) override; + +    void onEmojiUsed(llwchar emoji); +    void loadState(); +    void saveState(); + +    class LLPanel* mGroups { nullptr }; +    class LLPanel* mBadge { nullptr }; +    class LLLineEditor* mFilter { nullptr }; +    class LLScrollContainer* mEmojiScroll { nullptr }; +    class LLScrollingPanelList* mEmojiGrid { nullptr }; +    class LLEmojiPreviewPanel* mPreview { nullptr }; + +    pick_callback_t mEmojiPickCallback; +    close_callback_t mFloaterCloseCallback; + +    std::vector<class LLButton*> mGroupButtons; + +    S32 mRecentBadgeWidth { 0 }; +    S32 mRecentGridWidth { 0 }; +    S32 mRecentMaxIcons { 0 }; +    LLUICtrl* mHoveredIcon { nullptr }; +}; + +#endif diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 0d2c6d8e4c..8ee6c7ef2d 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -130,11 +130,12 @@ BOOL LLFloaterIMNearbyChat::postBuild()  	mInputEditor->setKeystrokeCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxKeystroke, this));  	mInputEditor->setFocusLostCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxFocusLost, this));  	mInputEditor->setFocusReceivedCallback(boost::bind(&LLFloaterIMNearbyChat::onChatBoxFocusReceived, this)); -	mInputEditor->setLabel(LLTrans::getString("NearbyChatTitle")); +	std::string nearbyChatTitle(LLTrans::getString("NearbyChatTitle")); +	mInputEditor->setLabel(nearbyChatTitle);  	// Title must be defined BEFORE call to addConversationListItem() because  	// it is used to show the item's name in the conversations list -	setTitle(LLTrans::getString("NearbyChatTitle")); +	setTitle(nearbyChatTitle);  	// obsolete, but may be needed for backward compatibility?  	gSavedSettings.declareS32("nearbychat_showicons_and_names", 2, "NearByChat header settings", LLControlVariable::PERSIST_NONDFT); diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index af4e7f5aff..8ab41b227b 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -40,6 +40,7 @@  #include "llchicletbar.h"  #include "lldraghandle.h"  #include "llfloaterreg.h" +#include "llfloateremojipicker.h"  #include "llfloaterimsession.h"  #include "llfloaterimcontainer.h" // to replace separate IM Floaters with multifloater container  #include "lllayoutstack.h" @@ -252,10 +253,13 @@ BOOL LLFloaterIMSessionTab::postBuild()  	mTearOffBtn = getChild<LLButton>("tear_off_btn");  	mTearOffBtn->setCommitCallback(boost::bind(&LLFloaterIMSessionTab::onTearOffClicked, this)); +	mEmojiBtn = getChild<LLButton>("emoji_panel_btn"); +	mEmojiBtn->setClickedCallback(boost::bind(&LLFloaterIMSessionTab::onEmojiPanelBtnClicked, this)); +  	mGearBtn = getChild<LLButton>("gear_btn");      mAddBtn = getChild<LLButton>("add_btn");  	mVoiceButton = getChild<LLButton>("voice_call_btn"); -     +  	mParticipantListPanel = getChild<LLLayoutPanel>("speakers_list_panel");  	mRightPartPanel = getChild<LLLayoutPanel>("right_part_holder"); @@ -426,53 +430,76 @@ void LLFloaterIMSessionTab::onInputEditorClicked()  	gToolBarView->flashCommand(LLCommandId("chat"), false);  } +void LLFloaterIMSessionTab::onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self) +{ +	if (LLFloaterEmojiPicker* picker = LLFloaterEmojiPicker::getInstance()) +	{ +		if (!picker->isShown()) +		{ +			picker->show( +				[self](llwchar emoji) { self->onEmojiPicked(emoji); }, +				[self]() { self->onEmojiPickerClosed(); }); +			if (LLFloater* root_floater = gFloaterView->getParentFloater(self)) +			{ +				root_floater->addDependentFloater(picker, TRUE, TRUE); +			} +		} +		else +		{ +			picker->closeFloater(); +		} +	} +} + +void LLFloaterIMSessionTab::onEmojiPicked(llwchar emoji) +{ +	mInputEditor->insertEmoji(emoji); +} + +void LLFloaterIMSessionTab::onEmojiPickerClosed() +{ +	mInputEditor->setFocus(TRUE); +} +  std::string LLFloaterIMSessionTab::appendTime()  { -	time_t utc_time; -	utc_time = time_corrected(); -	std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" -		+LLTrans::getString("TimeMin")+"]"; +	std::string timeStr = "[" + LLTrans::getString("TimeHour") + "]:" +						  "[" + LLTrans::getString("TimeMin") + "]";  	LLSD substitution; - -	substitution["datetime"] = (S32) utc_time; -	LLStringUtil::format (timeStr, substitution); +	substitution["datetime"] = (S32)time_corrected(); +	LLStringUtil::format(timeStr, substitution);  	return timeStr;  } -void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD &args) +void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD& args)  { +	if (chat.mMuted || !mChatHistory) +		return;  	// Update the participant activity time  	LLFloaterIMContainer* im_box = LLFloaterIMContainer::findInstance();  	if (im_box)  	{ -		im_box->setTimeNow(mSessionID,chat.mFromID); +		im_box->setTimeNow(mSessionID, chat.mFromID);  	} -  	LLChat& tmp_chat = const_cast<LLChat&>(chat); -	if(tmp_chat.mTimeStr.empty()) +	if (tmp_chat.mTimeStr.empty())  		tmp_chat.mTimeStr = appendTime(); -	if (!chat.mMuted) -	{ -		tmp_chat.mFromName = chat.mFromName; -		LLSD chat_args; -		if (args) chat_args = args; -		chat_args["use_plain_text_chat_history"] = -				gSavedSettings.getBOOL("PlainTextChatHistory"); -		chat_args["show_time"] = gSavedSettings.getBOOL("IMShowTime"); -		chat_args["show_names_for_p2p_conv"] = -				!mIsP2PChat || gSavedSettings.getBOOL("IMShowNamesForP2PConv"); - -		if (mChatHistory) -		{ -			mChatHistory->appendMessage(chat, chat_args); -		} -	} +	tmp_chat.mFromName = chat.mFromName; + +	LLSD chat_args = args; +	chat_args["use_plain_text_chat_history"] = +			gSavedSettings.getBOOL("PlainTextChatHistory"); +	chat_args["show_time"] = gSavedSettings.getBOOL("IMShowTime"); +	chat_args["show_names_for_p2p_conv"] = !mIsP2PChat || +			gSavedSettings.getBOOL("IMShowNamesForP2PConv"); + +	mChatHistory->appendMessage(chat, chat_args);  }  static LLTrace::BlockTimerStatHandle FTM_BUILD_CONVERSATION_VIEW_PARTICIPANT("Build Conversation View"); diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index d478922617..7babc92897 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -140,7 +140,7 @@ protected:  	/* virtual */ void onFocusReceived();  	// prepare chat's params and out one message to chatHistory -	void appendMessage(const LLChat& chat, const LLSD &args = 0); +	void appendMessage(const LLChat& chat, const LLSD& args = LLSD());  	std::string appendTime();  	void assignResizeLimits(); @@ -182,6 +182,7 @@ protected:  	LLButton* mExpandCollapseLineBtn;  	LLButton* mExpandCollapseBtn;  	LLButton* mTearOffBtn; +	LLButton* mEmojiBtn;  	LLButton* mCloseBtn;  	LLButton* mGearBtn;  	LLButton* mAddBtn; @@ -207,6 +208,10 @@ private:  	void onInputEditorClicked(); +	static void onEmojiPanelBtnClicked(LLFloaterIMSessionTab* self); +	void onEmojiPicked(llwchar emoji); +	void onEmojiPickerClosed(); +  	bool checkIfTornOff();      bool mIsHostAttached;      bool mHasVisibleBeenInitialized; diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index e67c79a3a0..9d16faf0b5 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -1601,7 +1601,7 @@ void LLOverlapPanel::draw()  		LLUI::translate(5,getRect().getHeight()-20);	// translate to top-5,left-5  		LLView::sDrawPreviewHighlights = FALSE;  		LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text, 0, 0, 0, text_color, -				LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +				LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);  	}  	else  	{ @@ -1619,7 +1619,7 @@ void LLOverlapPanel::draw()  			std::string current_selection = std::string(current_selection_text + LLView::sPreviewClickedElement->getName() + " (no elements overlap)");  			S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(current_selection) + 10;  			LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection, 0, 0, 0, text_color, -					LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +					LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);  			// widen panel enough to fit this text  			LLRect rect = getRect();  			setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); @@ -1685,7 +1685,7 @@ void LLOverlapPanel::draw()  		// draw currently-selected element at top of overlappers  		LLUI::translate(0,-mSpacing);  		LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text + LLView::sPreviewClickedElement->getName(), 0, 0, 0, text_color, -				LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +				LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);  		LLUI::translate(0,-mSpacing-LLView::sPreviewClickedElement->getRect().getHeight());	// skip spacing distance + height  		LLView::sPreviewClickedElement->draw(); @@ -1700,7 +1700,7 @@ void LLOverlapPanel::draw()  			// draw name  			LLUI::translate(0,-mSpacing);  			LLFontGL::getFontSansSerifSmall()->renderUTF8(overlapper_text + viewp->getName(), 0, 0, 0, text_color, -					LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +					LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);  			// draw element  			LLUI::translate(0,-mSpacing-viewp->getRect().getHeight());	// skip spacing distance + height diff --git a/indra/newview/llfriendcard.h b/indra/newview/llfriendcard.h index f5679d7d85..ef0dda7949 100644 --- a/indra/newview/llfriendcard.h +++ b/indra/newview/llfriendcard.h @@ -55,7 +55,7 @@ public:      };  	// LLFriendObserver implementation -	void changed(U32 mask) +	void changed(U32 mask) override  	{  		onFriendListUpdate(mask);  	} diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h index 7c8e8279c2..7bb60f00e2 100644 --- a/indra/newview/llgesturemgr.h +++ b/indra/newview/llgesturemgr.h @@ -135,7 +135,7 @@ public:  	void notifyObservers();  	// Overriding so we can update active gesture names and notify observers  -	void changed(U32 mask);  +	void changed(U32 mask) override;  	BOOL matchPrefix(const std::string& in_str, std::string* out_str); @@ -150,7 +150,7 @@ protected:  	void runStep(LLMultiGesture* gesture, LLGestureStep* step);  	// LLInventoryCompletionObserver trigger -	void done(); +	void done() override;  	// Used by loadGesture  	static void onLoadComplete(const LLUUID& asset_uuid, diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp index dff310ecf9..c1f17c9d33 100644 --- a/indra/newview/llhudrender.cpp +++ b/indra/newview/llhudrender.cpp @@ -138,7 +138,7 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,  	LLUI::translate((F32) winX*1.0f/LLFontGL::sScaleX, (F32) winY*1.0f/(LLFontGL::sScaleY), -(((F32) winZ*2.f)-1.f));  	F32 right_x; -	font.render(wstr, 0, 0, 1, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, wstr.length(), 1000, &right_x); +	font.render(wstr, 0, 0, 1, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, wstr.length(), 1000, &right_x, /*use_ellipses*/false, /*use_color*/true);  	LLUI::popMatrix();  	gGL.popMatrix(); diff --git a/indra/newview/llimagefiltersmanager.h b/indra/newview/llimagefiltersmanager.h index d06212d85a..05d1806da4 100644 --- a/indra/newview/llimagefiltersmanager.h +++ b/indra/newview/llimagefiltersmanager.h @@ -45,7 +45,7 @@ private:  	void loadAllFilters();  	void loadFiltersFromDir(const std::string& dir); -	/*virtual*/ void initSingleton(); +	/*virtual*/ void initSingleton() override;  	// List of filters : first is the user friendly localized name, second is the xml file name      std::map<std::string,std::string> mFiltersList; diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 946eb02f26..bace97d37a 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -537,7 +537,7 @@ public:  	static void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent);  private: -	void initSingleton(); +	void initSingleton() override;  	void onVoiceChannelChangedInt(const LLUUID &session_id);  	void onVoiceChannelStateChangedInt(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction, bool ended_by_agent); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index f937754368..18420a2356 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1865,7 +1865,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes  	U32 header_size = 0;  	if (data_size > 0)  	{ -		U32 dsize = data_size; +		llssize dsize = data_size;  		char* result_ptr = strip_deprecated_header((char*)data, dsize, &header_size);  		data_size = dsize; diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index e1a5b22490..495153981b 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -2685,9 +2685,6 @@ void LLModelPreview::clearBuffers()  void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)  { -    U32 mesh_count = 0; - -      LLModelLoader::model_list* model = NULL;      if (lod < 0 || lod > 4) @@ -2818,8 +2815,6 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)              vb->flush();              mVertexBuffer[lod][mdl].push_back(vb); - -            ++mesh_count;          }      }  } diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index 14840f1b2e..dda407e708 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -73,7 +73,7 @@ class LLMuteList : public LLSingleton<LLMuteList>  {  	LLSINGLETON(LLMuteList);  	~LLMuteList(); -	/*virtual*/ void cleanupSingleton(); +	/*virtual*/ void cleanupSingleton() override;  public:  	// reasons for auto-unmuting a resident  	enum EAutoReason  diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h index 11c671294a..4649f5bcb0 100755 --- a/indra/newview/llnavigationbar.h +++ b/indra/newview/llnavigationbar.h @@ -92,10 +92,10 @@ class LLNavigationBar  public: -	/*virtual*/ void	draw(); -	/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); -	/*virtual*/ BOOL	postBuild(); -	/*virtual*/ void	setVisible(BOOL visible); +	/*virtual*/ void	draw() override; +	/*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; +	/*virtual*/ BOOL	postBuild() override; +	/*virtual*/ void	setVisible(BOOL visible) override;  	void handleLoginComplete();  	void clearHistoryCache(); diff --git a/indra/newview/lloutfitobserver.h b/indra/newview/lloutfitobserver.h index 77041db68d..77bb3543aa 100644 --- a/indra/newview/lloutfitobserver.h +++ b/indra/newview/lloutfitobserver.h @@ -41,7 +41,7 @@ class LLOutfitObserver: public LLInventoryObserver, public LLSingleton<LLOutfitO  public: -	virtual void changed(U32 mask); +	virtual void changed(U32 mask) override;  	void notifyOutfitLockChanged() { mOutfitLockChanged();  } diff --git a/indra/newview/llpanelemojicomplete.cpp b/indra/newview/llpanelemojicomplete.cpp new file mode 100644 index 0000000000..8b89e3aa14 --- /dev/null +++ b/indra/newview/llpanelemojicomplete.cpp @@ -0,0 +1,321 @@ +/** +* @file llpanelemojicomplete.h +* @brief Header file for LLPanelEmojiComplete +* +* $LicenseInfo:firstyear=2012&license=lgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2011, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llemojidictionary.h" +#include "llemojihelper.h" +#include "llpanelemojicomplete.h" +#include "lluictrlfactory.h" + +constexpr U32 MIN_MOUSE_MOVE_DELTA = 4; + +// ============================================================================ +// LLPanelEmojiComplete +// + +static LLDefaultChildRegistry::Register<LLPanelEmojiComplete> r("emoji_complete"); + +LLPanelEmojiComplete::Params::Params() +	: autosize("autosize") +	, max_emoji("max_emoji") +	, padding("padding") +	, selected_image("selected_image") +{ +} + +LLPanelEmojiComplete::LLPanelEmojiComplete(const LLPanelEmojiComplete::Params& p) +	: LLUICtrl(p) +	, mAutoSize(p.autosize) +	, mMaxVisible(p.max_emoji) +	, mPadding(p.padding) +	, mSelectedImage(p.selected_image) +{ +	setFont(p.font); +} + +LLPanelEmojiComplete::~LLPanelEmojiComplete() +{ +} + +void LLPanelEmojiComplete::draw() +{ +	if (!mEmojis.empty()) +	{ +		const S32 centerY = mRenderRect.getCenterY(); +		const size_t firstVisibleIdx = mScrollPos, lastVisibleIdx = llmin(mScrollPos + mVisibleEmojis, mEmojis.size()) - 1; + +		if (mCurSelected >= firstVisibleIdx && mCurSelected <= lastVisibleIdx) +		{ +			const S32 emoji_left = mRenderRect.mLeft + (mCurSelected - firstVisibleIdx) * mEmojiWidth; +			const S32 emoji_height = mFont->getLineHeight() + mPadding; +			mSelectedImage->draw(emoji_left, centerY - emoji_height / 2, mEmojiWidth, emoji_height); +		} + +		U32 left = mRenderRect.mLeft + mPadding; +		for (U32 curIdx = firstVisibleIdx; curIdx <= lastVisibleIdx; curIdx++) +		{ +			mFont->render( +				mEmojis, curIdx, +				left, centerY, +				LLColor4::white, LLFontGL::LEFT, LLFontGL::VCENTER, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW_SOFT, +				1, S32_MAX, nullptr, false, true); +			left += mEmojiWidth; +		} +	} +} + +BOOL LLPanelEmojiComplete::handleHover(S32 x, S32 y, MASK mask) +{ +	LLVector2 curHover(x, y); +	if ((mLastHover - curHover).lengthSquared() > MIN_MOUSE_MOVE_DELTA) +	{ +		mCurSelected = posToIndex(x, y); +		mLastHover = curHover; +	} + +	return TRUE; +} + +BOOL LLPanelEmojiComplete::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ +	bool handled = false; +	if (MASK_NONE == mask) +	{ +		switch (key) +		{ +			case KEY_LEFT: +			case KEY_UP: +				selectPrevious(); +				handled = true; +				break; +			case KEY_RIGHT: +			case KEY_DOWN: +				selectNext(); +				handled = true; +				break; +			case KEY_RETURN: +				if (!mEmojis.empty()) +				{ +					onCommit(); +					handled = true; +				} +				break; +		} +	} + +	if (handled) +	{ +		return TRUE; +	} +	return LLUICtrl::handleKey(key, mask, called_from_parent); +} + +BOOL LLPanelEmojiComplete::handleMouseDown(S32 x, S32 y, MASK mask) +{ +	mCurSelected = posToIndex(x, y); +	mLastHover = LLVector2(x, y); + +	return TRUE; +} + +BOOL LLPanelEmojiComplete::handleMouseUp(S32 x, S32 y, MASK mask) +{ +	mCurSelected = posToIndex(x, y); +	onCommit(); + +	return TRUE; +} + +void LLPanelEmojiComplete::onCommit() +{ +	if (npos != mCurSelected) +	{ +		LLWString wstr; +		wstr.push_back(mEmojis.at(mCurSelected)); +		setValue(wstring_to_utf8str(wstr)); +		LLUICtrl::onCommit(); +	} +} + +void LLPanelEmojiComplete::reshape(S32 width, S32 height, BOOL called_from_parent) +{ +	LLUICtrl::reshape(width, height, called_from_parent); +	updateConstraints(); +} + +void LLPanelEmojiComplete::setEmojiHint(const std::string& hint) +{ +	llwchar curEmoji = (mCurSelected < mEmojis.size()) ? mEmojis.at(mCurSelected) : 0; + +	mEmojis = LLEmojiDictionary::instance().findMatchingEmojis(hint); +	size_t curEmojiIdx = (curEmoji) ? mEmojis.find(curEmoji) : std::string::npos; +	mCurSelected = (std::string::npos != curEmojiIdx) ? curEmojiIdx : 0; + +	if (mAutoSize) +	{ +		mVisibleEmojis = std::min(mEmojis.size(), mMaxVisible); +		reshape(mVisibleEmojis * mEmojiWidth, getRect().getHeight(), false); +	} +	else +	{ +		updateConstraints(); +	} + +	mScrollPos = llmin(mScrollPos, mEmojis.size()); +} + +size_t LLPanelEmojiComplete::posToIndex(S32 x, S32 y) const +{ +	if (mRenderRect.pointInRect(x, y)) +	{ +		return mScrollPos + llmin((size_t)x / mEmojiWidth, mEmojis.size() - 1); +	} +	return npos; +} + +void LLPanelEmojiComplete::select(size_t emoji_idx) +{ +	mCurSelected = llclamp<size_t>(emoji_idx, 0, mEmojis.size()); +	updateScrollPos(); +} + +void LLPanelEmojiComplete::selectNext() +{ +	select(mCurSelected + 1 < mEmojis.size() ? mCurSelected + 1 : 0); +} + +void LLPanelEmojiComplete::selectPrevious() +{ +	select(mCurSelected - 1 >= 0 ? mCurSelected - 1 : mEmojis.size() - 1); +} + +void LLPanelEmojiComplete::setFont(const LLFontGL* fontp) +{ +	mFont = fontp; +	updateConstraints(); +} + +void LLPanelEmojiComplete::updateConstraints() +{ +	const S32 ctrlWidth = getLocalRect().getWidth(); + +	mEmojiWidth = mFont->getWidthF32(u8"\U0001F431") + mPadding * 2; +	mVisibleEmojis = ctrlWidth / mEmojiWidth; +	mRenderRect = getLocalRect().stretch((ctrlWidth - mVisibleEmojis * mEmojiWidth) / -2, 0); + +	updateScrollPos(); +} + +void LLPanelEmojiComplete::updateScrollPos() +{ +	const size_t cntEmoji = mEmojis.size(); +	if (0 == cntEmoji || cntEmoji < mVisibleEmojis || 0 == mCurSelected) +	{ +		mScrollPos = 0; +	} +	else if (cntEmoji - 1 == mCurSelected) +	{ +		mScrollPos = mCurSelected - mVisibleEmojis + 1; +	} +	else +	{ +		mScrollPos = mCurSelected - ((float)mCurSelected / (cntEmoji - 2) * (mVisibleEmojis - 2)); +	} +} + +// ============================================================================ +// LLFloaterEmojiComplete +// + +LLFloaterEmojiComplete::LLFloaterEmojiComplete(const LLSD& sdKey) +	: LLFloater(sdKey) +{ +	// This floater should hover on top of our dependent (with the dependent having the focus) +	setFocusStealsFrontmost(false); +	setAutoFocus(false); +	setBackgroundVisible(false); +	setIsChrome(true); +} + +BOOL LLFloaterEmojiComplete::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ +	bool handled = false; +	if (MASK_NONE == mask) +	{ +		switch (key) +		{ +			case KEY_ESCAPE: +				LLEmojiHelper::instance().hideHelper(); +				handled = true; +				break; +		} + +	} + +	if (handled) +		return TRUE; +	return LLFloater::handleKey(key, mask, called_from_parent); +} + +void LLFloaterEmojiComplete::onOpen(const LLSD& key) +{ +	mEmojiCtrl->setEmojiHint(key["hint"].asString()); +	if (0 == mEmojiCtrl->getEmojiCount()) +	{ +		LLEmojiHelper::instance().hideHelper(); +	} +} + +BOOL LLFloaterEmojiComplete::postBuild() +{ +	mEmojiCtrl = findChild<LLPanelEmojiComplete>("emoji_complete_ctrl"); +	mEmojiCtrl->setCommitCallback( +		std::bind([&](const LLSD& sdValue) +		{ +			setValue(sdValue); +			onCommit(); +		}, std::placeholders::_2)); +	mEmojiCtrlHorz = getRect().getWidth() - mEmojiCtrl->getRect().getWidth(); + +	return LLFloater::postBuild(); +} + +void LLFloaterEmojiComplete::reshape(S32 width, S32 height, BOOL called_from_parent) +{ +	if (!called_from_parent) +	{ +		LLRect rctFloater = getRect(), rctCtrl = mEmojiCtrl->getRect(); +		rctFloater.mRight = rctFloater.mLeft + rctCtrl.getWidth() + mEmojiCtrlHorz; +		setRect(rctFloater); + +		return; +	} + +	LLFloater::reshape(width, height, called_from_parent); +} + +// ============================================================================ diff --git a/indra/newview/llpanelemojicomplete.h b/indra/newview/llpanelemojicomplete.h new file mode 100644 index 0000000000..aa0f806525 --- /dev/null +++ b/indra/newview/llpanelemojicomplete.h @@ -0,0 +1,115 @@ +/** +* @file llpanelemojicomplete.h +* @brief Header file for LLPanelEmojiComplete +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ + +#pragma once + +#include "llfloater.h" +#include "lluictrl.h" + +// ============================================================================ +// LLPanelEmojiComplete +// + +class LLPanelEmojiComplete : public LLUICtrl +{ +	friend class LLUICtrlFactory; +public: +	struct Params : public LLInitParam::Block<Params, LLUICtrl::Params> +	{ +		Optional<bool>       autosize; +		Optional<S32>        max_emoji, +		                     padding; + +		Optional<LLUIImage*> selected_image; + +		Params(); +	}; + +protected: +	LLPanelEmojiComplete(const LLPanelEmojiComplete::Params&); +public: +	virtual ~LLPanelEmojiComplete(); + +	void draw() override; +	BOOL handleHover(S32 x, S32 y, MASK mask) override; +	BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override; +	BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; +	BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; +	void onCommit() override; +	void reshape(S32 width, S32 height, BOOL called_from_parent) override; + +public: +	size_t getEmojiCount() const { return mEmojis.size(); } +	void   setEmojiHint(const std::string& hint); +protected: +	size_t posToIndex(S32 x, S32 y) const; +	void select(size_t emoji_idx); +	void selectNext(); +	void selectPrevious(); +	void setFont(const LLFontGL* fontp); +	void updateConstraints(); +	void updateScrollPos(); + +protected: +	static constexpr auto npos = std::numeric_limits<size_t>::max(); + +	bool            mAutoSize = false; +	const LLFontGL* mFont; +	U16             mEmojiWidth = 0; +	size_t          mMaxVisible = 0; +	S32             mPadding = 8; +	LLRect          mRenderRect; +	LLUIImagePtr	mSelectedImage; + +	LLWString       mEmojis; +	size_t          mVisibleEmojis = 0; +	size_t          mFirstVisible = 0; +	size_t          mScrollPos = 0; +	size_t          mCurSelected = 0; +	LLVector2       mLastHover; +}; + +// ============================================================================ +// LLFloaterEmojiComplete +// + +class LLFloaterEmojiComplete : public LLFloater +{ +public: +	LLFloaterEmojiComplete(const LLSD& sdKey); + +public: +	BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override; +	void onOpen(const LLSD& key) override; +	BOOL postBuild() override; +	void reshape(S32 width, S32 height, BOOL called_from_parent) override; + +protected: +	LLPanelEmojiComplete* mEmojiCtrl = nullptr; +	S32                   mEmojiCtrlHorz = 0; +}; + +// ============================================================================ diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index 02911313ed..c1eae27636 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -619,7 +619,6 @@ void LLPanelNearByMedia::refreshList()  	LLViewerMedia::impl_list impls = media_inst->getPriorityList();  	LLViewerMedia::impl_list::iterator priority_iter; -	U32 enabled_count = 0;  	U32 disabled_count = 0;  	// iterate over the impl list, creating rows as necessary. @@ -662,10 +661,7 @@ void LLPanelNearByMedia::refreshList()  			{  				disabled_count++;  			} -			else { -				enabled_count++;  		} -	}  	}	  	mDisableAllCtrl->setEnabled((gSavedSettings.getBOOL("AudioStreamingMusic") ||   		                         gSavedSettings.getBOOL("AudioStreamingMedia")) && diff --git a/indra/newview/llpaneltopinfobar.h b/indra/newview/llpaneltopinfobar.h index 78dd997029..b6c263e331 100644 --- a/indra/newview/llpaneltopinfobar.h +++ b/indra/newview/llpaneltopinfobar.h @@ -46,8 +46,8 @@ class LLPanelTopInfoBar : public LLPanel, public LLSingleton<LLPanelTopInfoBar>,  public:  	typedef boost::signals2::signal<void ()> resize_signal_t; -	/*virtual*/ BOOL postBuild(); -	/*virtual*/ void draw(); +	/*virtual*/ BOOL postBuild() override; +	/*virtual*/ void draw() override;  	/**  	 * Updates location and parcel icons on login complete @@ -83,7 +83,7 @@ private:  	 */  	void initParcelIcons(); -	BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); +	BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override;  	/**  	 * Handles clicks on the parcel icons. diff --git a/indra/newview/llpathfindingpathtool.h b/indra/newview/llpathfindingpathtool.h index 88cb3a15f8..f98624e30d 100644 --- a/indra/newview/llpathfindingpathtool.h +++ b/indra/newview/llpathfindingpathtool.h @@ -66,17 +66,17 @@ public:  	typedef boost::signals2::signal<void (void)> path_event_signal_t;  	typedef boost::signals2::connection          path_event_slot_t; -	virtual BOOL      handleMouseDown(S32 pX, S32 pY, MASK pMask); -	virtual BOOL      handleMouseUp(S32 pX, S32 pY, MASK pMask); -	virtual BOOL      handleMiddleMouseDown(S32 pX, S32 pY, MASK pMask); -	virtual BOOL      handleMiddleMouseUp(S32 pX, S32 pY, MASK pMask); -	virtual BOOL      handleRightMouseDown(S32 pX, S32 pY, MASK pMask); -	virtual BOOL      handleRightMouseUp(S32 pX, S32 pY, MASK pMask); -	virtual BOOL      handleDoubleClick(S32 x, S32 y, MASK mask); +	virtual BOOL      handleMouseDown(S32 pX, S32 pY, MASK pMask) override; +	virtual BOOL      handleMouseUp(S32 pX, S32 pY, MASK pMask) override; +	virtual BOOL      handleMiddleMouseDown(S32 pX, S32 pY, MASK pMask) override; +	virtual BOOL      handleMiddleMouseUp(S32 pX, S32 pY, MASK pMask) override; +	virtual BOOL      handleRightMouseDown(S32 pX, S32 pY, MASK pMask) override; +	virtual BOOL      handleRightMouseUp(S32 pX, S32 pY, MASK pMask) override; +	virtual BOOL      handleDoubleClick(S32 x, S32 y, MASK mask) override; -	virtual BOOL      handleHover(S32 pX, S32 pY, MASK pMask); +	virtual BOOL      handleHover(S32 pX, S32 pY, MASK pMask) override; -	virtual BOOL      handleKey(KEY pKey, MASK pMask); +	virtual BOOL      handleKey(KEY pKey, MASK pMask) override;  	EPathStatus       getPathStatus() const; diff --git a/indra/newview/llproductinforequest.h b/indra/newview/llproductinforequest.h index d1036374e8..0b94c39d11 100644 --- a/indra/newview/llproductinforequest.h +++ b/indra/newview/llproductinforequest.h @@ -46,7 +46,7 @@ public:  	std::string getDescriptionForSku(const std::string& sku);  private: -	/* virtual */ void initSingleton(); +	/* virtual */ void initSingleton() override;      void getLandDescriptionsCoro(std::string url);      LLSD mSkuDescriptions; diff --git a/indra/newview/llrecentpeople.h b/indra/newview/llrecentpeople.h index 1b322f2c0a..0c04222a9f 100644 --- a/indra/newview/llrecentpeople.h +++ b/indra/newview/llrecentpeople.h @@ -106,7 +106,7 @@ public:  	/**  	 * LLSimpleListener interface.  	 */ -	/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata); +	/*virtual*/ bool handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata) override;  	void updateAvatarsArrivalTime(uuid_vec_t& uuids);  	F32 getArrivalTimeByID(const LLUUID& id); diff --git a/indra/newview/llsceneview.cpp b/indra/newview/llsceneview.cpp index 5e339a52bf..2f55d4cdaf 100644 --- a/indra/newview/llsceneview.cpp +++ b/indra/newview/llsceneview.cpp @@ -99,9 +99,6 @@ void LLSceneView::draw()  	std::vector<F32> physics_cost[2];  	F32 total_physics[] = { 0.f, 0.f }; - -	U32 object_count = 0; -  	LLViewerRegion* region = gAgent.getRegion();  	if (region)  	{ @@ -116,7 +113,6 @@ void LLSceneView::draw()  				U32 idx = object->isAttachment() ? 1 : 0;  				LLVolume* volume = object->getVolume(); -				object_count++;  				F32 radius = object->getScale().magVec();  				size[idx].push_back(radius); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 86f7d2bf25..eea00da43e 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -5273,9 +5273,6 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle,  	LLSelectNode* linkset_root = NULL;  	LLViewerRegion*	last_region;  	LLViewerRegion*	current_region; - -	S32 objects_sent = 0; -	S32 packets_sent = 0;  	S32 objects_in_this_packet = 0;  	bool link_operation = message_name == "ObjectLink"; @@ -5407,7 +5404,6 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle,  			(*pack_body)(node, user_data);              // do any related logging              (*log_func)(node, user_data); -			++objects_sent;  			++objects_in_this_packet;  			// and on to the next object @@ -5425,7 +5421,6 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle,  		{  			// otherwise send current message and start new one  			gMessageSystem->sendReliable( last_region->getHost()); -			packets_sent++;  			objects_in_this_packet = 0;  			gMessageSystem->newMessage(message_name.c_str()); @@ -5442,7 +5437,6 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle,  				{  					// add root instance into new message  					(*pack_body)(linkset_root, user_data); -					++objects_sent;  					++objects_in_this_packet;  				}  			} @@ -5456,7 +5450,6 @@ void LLSelectMgr::sendListToRegions(LLObjectSelectionHandle selected_handle,  	if (gMessageSystem->getCurrentSendTotal() > 0)  	{  		gMessageSystem->sendReliable( current_region->getHost()); -		packets_sent++;  	}  	else  	{ diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index ed795b5155..22c9481687 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -338,7 +338,7 @@ class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeak  	LOG_CLASS(LLActiveSpeakerMgr);  protected: -	virtual void updateSpeakerList(); +	virtual void updateSpeakerList() override;  };  class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLLocalSpeakerMgr> @@ -347,7 +347,7 @@ class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLLocalSpeaker  	~LLLocalSpeakerMgr ();  	LOG_CLASS(LLLocalSpeakerMgr);  protected: -	virtual void updateSpeakerList(); +	virtual void updateSpeakerList() override;  };  #endif // LL_LLSPEAKERS_H diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp index 0111d8869c..c4c9673be3 100644 --- a/indra/newview/llspeakingindicatormanager.cpp +++ b/indra/newview/llspeakingindicatormanager.cpp @@ -53,7 +53,7 @@ class SpeakingIndicatorManager : public LLSingleton<SpeakingIndicatorManager>, L  	LOG_CLASS(SpeakingIndicatorManager);  protected: -    void                cleanupSingleton(); +    void                cleanupSingleton() override;  public: @@ -88,7 +88,7 @@ public:  	 * So, method does not calculate difference between these list it only switches off already   	 * switched on indicators and switches on indicators of voice channel participants  	 */ -	void onParticipantsChanged(); +	void onParticipantsChanged() override;  private:  	typedef std::set<LLUUID> speaker_ids_t; diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp index c3eb70f850..fd41cdf0d7 100644 --- a/indra/newview/llsprite.cpp +++ b/indra/newview/llsprite.cpp @@ -79,7 +79,6 @@ void LLSprite::updateFace(LLFace &face)  	// First, figure out how many vertices/indices we need.  	U32 num_vertices, num_indices; -	U32 vertex_count = 0;  	// Get the total number of vertices and indices  	if (mFollow) @@ -203,25 +202,21 @@ void LLSprite::updateFace(LLFace &face)  	*verticesp = mC;  	tex_coordsp++;  	verticesp++; -	vertex_count++;  	*tex_coordsp = LLVector2(0.f, 1.f);  	*verticesp = mB;  	tex_coordsp++;  	verticesp++; -	vertex_count++;  	*tex_coordsp = LLVector2(1.f, 1.f);  	*verticesp = mA;  	tex_coordsp++;  	verticesp++; -	vertex_count++;  	*tex_coordsp = LLVector2(1.f, 0.0f);  	*verticesp = mD;  	tex_coordsp++;  	verticesp++; -	vertex_count++;  	// Generate indices, since they're easy.  	// Just a series of quads. diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 75cbe94592..d96b8a099d 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3260,7 +3260,7 @@ LLSD transform_cert_args(LLPointer<LLCertificate> cert)  		// are actually arrays, and we want to format them as comma separated            		// strings, so special case those.                                               		LLSDSerialize::toXML(cert_info[iter->first], std::cout); -		if((iter->first== std::string(CERT_KEY_USAGE)) | +		if((iter->first== std::string(CERT_KEY_USAGE)) ||  		   (iter->first == std::string(CERT_EXTENDED_KEY_USAGE)))  		{  			value = ""; diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index cf9211767e..f0033692c0 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -613,7 +613,7 @@ void LLGLTexMemBar::draw()  	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3,  											 text_color, LLFontGL::LEFT, LLFontGL::TOP,  											 LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, -											 &x_right, FALSE); +											 &x_right, /*use_ellipses*/FALSE, /*use_color*/FALSE);  	F32Kilobits bandwidth(LLAppViewer::getTextureFetch()->getTextureBandwidth());  	F32Kilobits max_bandwidth(gSavedSettings.getF32("ThrottleBandwidthKBPS")); @@ -845,8 +845,6 @@ void LLTextureView::draw()  			if (imagep->getID() == LLAppViewer::getTextureFetch()->mDebugID)  			{ -				static S32 debug_count = 0; -				++debug_count; // for breakpoints  			}  			F32 pri; diff --git a/indra/newview/lltoolbrush.h b/indra/newview/lltoolbrush.h index c108d83256..6545ee3611 100644 --- a/indra/newview/lltoolbrush.h +++ b/indra/newview/lltoolbrush.h @@ -49,27 +49,27 @@ class LLToolBrushLand : public LLTool, public LLEditMenuHandler, public LLSingle  public:  	// x,y in window coords, 0,0 = left,bot -	virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); -	virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask );		 -	virtual BOOL handleHover( S32 x, S32 y, MASK mask ); -	virtual void handleSelect(); -	virtual void handleDeselect(); +	virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ) override; +	virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ) override; +	virtual BOOL handleHover( S32 x, S32 y, MASK mask ) override; +	virtual void handleSelect() override; +	virtual void handleDeselect() override;  	// isAlwaysRendered() - return true if this is a tool that should  	// always be rendered regardless of selection. -	virtual BOOL isAlwaysRendered() { return TRUE; } +	virtual BOOL isAlwaysRendered()  override { return TRUE; }  	// Draw the area that will be affected. -	virtual void render(); +	virtual void render() override;  	// on Idle is where the land modification actually occurs  	static void onIdle(void* brush_tool);   -	void			onMouseCaptureLost(); +	void onMouseCaptureLost() override;  	void modifyLandInSelectionGlobal(); -	virtual void	undo(); -	virtual BOOL	canUndo() const	{ return TRUE; } +	virtual void	undo() override; +	virtual BOOL	canUndo() const	 override { return TRUE; }  protected:  	void brush( void ); diff --git a/indra/newview/lltoolcomp.h b/indra/newview/lltoolcomp.h index 86506f725e..f539a045b7 100644 --- a/indra/newview/lltoolcomp.h +++ b/indra/newview/lltoolcomp.h @@ -108,11 +108,11 @@ class LLToolCompInspect : public LLToolComposite, public LLSingleton<LLToolCompI  public:  	// Overridden from LLToolComposite -    virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask); -    virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask); -	virtual BOOL		handleKey(KEY key, MASK mask); -	virtual void		onMouseCaptureLost(); +    virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask) override; +    virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleKey(KEY key, MASK mask) override; +	virtual void		onMouseCaptureLost() override;  			void		keyUp(KEY key, MASK mask);  	static void pickCallback(const LLPickInfo& pick_info); @@ -133,13 +133,13 @@ class LLToolCompTranslate : public LLToolComposite, public LLSingleton<LLToolCom  public:  	// Overridden from LLToolComposite -	virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask); -	virtual BOOL		handleHover(S32 x, S32 y, MASK mask); -	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask);			// Returns to the default tool -	virtual void		render(); +	virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleHover(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask) override;			// Returns to the default tool +	virtual void		render() override; -	virtual LLTool*		getOverrideTool(MASK mask); +	virtual LLTool*		getOverrideTool(MASK mask) override;  	static void pickCallback(const LLPickInfo& pick_info);  }; @@ -154,13 +154,13 @@ class LLToolCompScale : public LLToolComposite, public LLSingleton<LLToolCompSca  public:  	// Overridden from LLToolComposite -    virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask); -    virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask); -    virtual BOOL		handleHover(S32 x, S32 y, MASK mask); -	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask);			// Returns to the default tool -	virtual void		render(); +    virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask) override; +    virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask) override; +    virtual BOOL		handleHover(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask) override;			// Returns to the default tool +	virtual void		render() override; -	virtual LLTool*		getOverrideTool(MASK mask); +	virtual LLTool*		getOverrideTool(MASK mask) override;  	static void pickCallback(const LLPickInfo& pick_info);  }; @@ -176,13 +176,13 @@ class LLToolCompRotate : public LLToolComposite, public LLSingleton<LLToolCompRo  public:  	// Overridden from LLToolComposite -    virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask); -    virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask); -    virtual BOOL		handleHover(S32 x, S32 y, MASK mask); -	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask); -	virtual void		render(); +    virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask) override; +    virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask) override; +    virtual BOOL		handleHover(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask) override; +	virtual void		render() override; -	virtual LLTool*		getOverrideTool(MASK mask); +	virtual LLTool*		getOverrideTool(MASK mask) override;  	static void pickCallback(const LLPickInfo& pick_info); @@ -199,9 +199,9 @@ class LLToolCompCreate : public LLToolComposite, public LLSingleton<LLToolCompCr  public:  	// Overridden from LLToolComposite -    virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask); -    virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask); -	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask); +    virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask) override; +    virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask) override;  	static void pickCallback(const LLPickInfo& pick_info);  protected: @@ -224,16 +224,16 @@ class LLToolCompGun : public LLToolComposite, public LLSingleton<LLToolCompGun>  public:  	// Overridden from LLToolComposite -    virtual BOOL			handleHover(S32 x, S32 y, MASK mask); -	virtual BOOL			handleMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL			handleDoubleClick(S32 x, S32 y, MASK mask); -	virtual BOOL			handleRightMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL			handleMouseUp(S32 x, S32 y, MASK mask); -	virtual BOOL			handleScrollWheel(S32 x, S32 y, S32 clicks); -	virtual void			onMouseCaptureLost(); -	virtual void			handleSelect(); -	virtual void			handleDeselect(); -	virtual LLTool*			getOverrideTool(MASK mask) { return NULL; } +    virtual BOOL			handleHover(S32 x, S32 y, MASK mask) override; +	virtual BOOL			handleMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL			handleDoubleClick(S32 x, S32 y, MASK mask) override; +	virtual BOOL			handleRightMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL			handleMouseUp(S32 x, S32 y, MASK mask) override; +	virtual BOOL			handleScrollWheel(S32 x, S32 y, S32 clicks) override; +	virtual void			onMouseCaptureLost() override; +	virtual void			handleSelect() override; +	virtual void			handleDeselect() override; +	virtual LLTool*			getOverrideTool(MASK mask) override { return NULL; }  protected:  	LLToolGun*			mGun; diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 4537d73332..8ec027cb0e 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -48,12 +48,12 @@ public:  	typedef boost::signals2::signal<void ()> enddrag_signal_t;  	// overridden from LLTool -	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask); -	virtual BOOL	handleHover(S32 x, S32 y, MASK mask); -	virtual BOOL	handleKey(KEY key, MASK mask); -	virtual BOOL	handleToolTip(S32 x, S32 y, MASK mask); -	virtual void	onMouseCaptureLost(); -	virtual void	handleDeselect(); +	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask) override; +	virtual BOOL	handleHover(S32 x, S32 y, MASK mask) override; +	virtual BOOL	handleKey(KEY key, MASK mask) override; +	virtual BOOL	handleToolTip(S32 x, S32 y, MASK mask) override; +	virtual void	onMouseCaptureLost() override; +	virtual void	handleDeselect() override;  	void			setDragStart( S32 x, S32 y );			// In screen space  	BOOL			isOverThreshold( S32 x, S32 y );		// In screen space diff --git a/indra/newview/lltoolface.h b/indra/newview/lltoolface.h index e4b8ae12b8..7c8ff20480 100644 --- a/indra/newview/lltoolface.h +++ b/indra/newview/lltoolface.h @@ -39,11 +39,11 @@ class LLToolFace  	virtual ~LLToolFace();  public: -	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL	handleDoubleClick(S32 x, S32 y, MASK mask); -	virtual void	handleSelect(); -	virtual void	handleDeselect(); -	virtual void	render();			// draw face highlights +	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL	handleDoubleClick(S32 x, S32 y, MASK mask) override; +	virtual void	handleSelect() override; +	virtual void	handleDeselect() override; +	virtual void	render() override;			// draw face highlights  	static void pickCallback(const LLPickInfo& pick_info);  }; diff --git a/indra/newview/lltoolfocus.h b/indra/newview/lltoolfocus.h index ef71f9230a..54d9827ae6 100644 --- a/indra/newview/lltoolfocus.h +++ b/indra/newview/lltoolfocus.h @@ -38,16 +38,16 @@ class LLToolCamera  	virtual ~LLToolCamera();  public: -	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask); -	virtual BOOL	handleHover(S32 x, S32 y, MASK mask); +	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask) override; +	virtual BOOL	handleHover(S32 x, S32 y, MASK mask) override; -	virtual void	onMouseCaptureLost(); +	virtual void	onMouseCaptureLost() override; -	virtual void	handleSelect(); -	virtual void	handleDeselect(); +	virtual void	handleSelect() override; +	virtual void	handleDeselect() override; -	virtual LLTool*	getOverrideTool(MASK mask) { return NULL; } +	virtual LLTool*	getOverrideTool(MASK mask) override { return NULL; }      void setClickPickPending() { mClickPickPending = true; }  	static void pickCallback(const LLPickInfo& pick_info); diff --git a/indra/newview/lltoolindividual.h b/indra/newview/lltoolindividual.h index e7c2060fba..89dd9d9796 100644 --- a/indra/newview/lltoolindividual.h +++ b/indra/newview/lltoolindividual.h @@ -43,11 +43,9 @@ class LLToolIndividual : public LLTool, public LLSingleton<LLToolIndividual>  	virtual ~LLToolIndividual();  public: -	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); -	virtual void handleSelect(); -	//virtual void handleDeselect(); -	//virtual void render(); +	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override; +	virtual void handleSelect() override;  	static void pickCallback(const LLPickInfo& pick_info); diff --git a/indra/newview/lltoolobjpicker.h b/indra/newview/lltoolobjpicker.h index 5ad9b67e21..a55cd223de 100644 --- a/indra/newview/lltoolobjpicker.h +++ b/indra/newview/lltoolobjpicker.h @@ -38,16 +38,16 @@ class LLToolObjPicker : public LLTool, public LLSingleton<LLToolObjPicker>  	LLSINGLETON(LLToolObjPicker);  public: -	virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask); -	virtual BOOL		handleHover(S32 x, S32 y, MASK mask); +	virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleHover(S32 x, S32 y, MASK mask) override; -	virtual void 		handleSelect(); -	virtual void 		handleDeselect(); +	virtual void 		handleSelect() override; +	virtual void 		handleDeselect() override; -	virtual void		onMouseCaptureLost(); +	virtual void		onMouseCaptureLost() override; -	virtual void 		setExitCallback(void (*callback)(void *), void *callback_data); +	void 		setExitCallback(void (*callback)(void *), void *callback_data);  	LLUUID				getObjectID() const { return mHitObjectID; } diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 8f6100e4b4..dca0d12cf6 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -42,26 +42,26 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>  public:  	// Virtual functions inherited from LLMouseHandler -	virtual BOOL		handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); -	virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL		handleRightMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask); -	virtual BOOL		handleRightMouseUp(S32 x, S32 y, MASK mask); -	virtual BOOL		handleHover(S32 x, S32 y, MASK mask); -	virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask); +	virtual BOOL		handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) override; +	virtual BOOL		handleMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleRightMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleMouseUp(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleRightMouseUp(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleHover(S32 x, S32 y, MASK mask) override; +	virtual BOOL		handleDoubleClick(S32 x, S32 y, MASK mask) override;  	BOOL				handleScrollWheelAny(S32 x, S32 y, S32 clicks_x, S32 clicks_y); -	virtual BOOL		handleScrollWheel(S32 x, S32 y, S32 clicks); -	virtual BOOL		handleScrollHWheel(S32 x, S32 y, S32 clicks); -	virtual BOOL		handleToolTip(S32 x, S32 y, MASK mask); +	virtual BOOL		handleScrollWheel(S32 x, S32 y, S32 clicks) override; +	virtual BOOL		handleScrollHWheel(S32 x, S32 y, S32 clicks) override; +	virtual BOOL		handleToolTip(S32 x, S32 y, MASK mask) override; -	virtual void		render(); +	virtual void		render() override; -	virtual void		stopEditing(); +	virtual void		stopEditing() override; -	virtual void		onMouseCaptureLost(); -	virtual void		handleSelect(); -	virtual void		handleDeselect(); -	virtual LLTool*		getOverrideTool(MASK mask); +	virtual void		onMouseCaptureLost() override; +	virtual void		handleSelect() override; +	virtual void		handleDeselect() override; +	virtual LLTool*		getOverrideTool(MASK mask) override;  	LLPickInfo&			getPick() { return mPick; }  	U8					getClickAction() { return mClickAction; } diff --git a/indra/newview/lltoolpipette.h b/indra/newview/lltoolpipette.h index 7575d8ad18..2636811c66 100644 --- a/indra/newview/lltoolpipette.h +++ b/indra/newview/lltoolpipette.h @@ -47,10 +47,10 @@ class LLToolPipette  	virtual ~LLToolPipette();  public: -	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask); -	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask); -	virtual BOOL	handleHover(S32 x, S32 y, MASK mask); -	virtual BOOL	handleToolTip(S32 x, S32 y, MASK mask); +	virtual BOOL	handleMouseDown(S32 x, S32 y, MASK mask) override; +	virtual BOOL	handleMouseUp(S32 x, S32 y, MASK mask) override; +	virtual BOOL	handleHover(S32 x, S32 y, MASK mask) override; +	virtual BOOL	handleToolTip(S32 x, S32 y, MASK mask) override;  	// Note: Don't return connection; use boost::bind + boost::signals2::trackable to disconnect slots  	typedef boost::signals2::signal<void (const LLTextureEntry& te)> signal_t; diff --git a/indra/newview/lltoolselectland.h b/indra/newview/lltoolselectland.h index b5ba72f16d..88bc4e2e3d 100644 --- a/indra/newview/lltoolselectland.h +++ b/indra/newview/lltoolselectland.h @@ -39,15 +39,15 @@ class LLToolSelectLand  	virtual ~LLToolSelectLand();  public: -	/*virtual*/ BOOL		handleMouseDown(S32 x, S32 y, MASK mask); -	/*virtual*/ BOOL		handleDoubleClick(S32 x, S32 y, MASK mask); -	/*virtual*/ BOOL		handleMouseUp(S32 x, S32 y, MASK mask); -	/*virtual*/ BOOL		handleHover(S32 x, S32 y, MASK mask); -	/*virtual*/ void		render();				// draw the select rectangle -	/*virtual*/ BOOL		isAlwaysRendered()		{ return TRUE; } +	/*virtual*/ BOOL		handleMouseDown(S32 x, S32 y, MASK mask) override; +	/*virtual*/ BOOL		handleDoubleClick(S32 x, S32 y, MASK mask) override; +	/*virtual*/ BOOL		handleMouseUp(S32 x, S32 y, MASK mask) override; +	/*virtual*/ BOOL		handleHover(S32 x, S32 y, MASK mask) override; +	/*virtual*/ void		render() override;				// draw the select rectangle +	/*virtual*/ BOOL		isAlwaysRendered() override	{ return TRUE; } -	/*virtual*/ void		handleSelect(); -	/*virtual*/ void		handleDeselect(); +	/*virtual*/ void		handleSelect() override; +	/*virtual*/ void		handleDeselect() override;  protected:  	BOOL			outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y); diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h index 02ff0c094a..37382243f6 100644 --- a/indra/newview/llversioninfo.h +++ b/indra/newview/llversioninfo.h @@ -47,7 +47,7 @@ class LLStoreListener;  class LLVersionInfo: public LLSingleton<LLVersionInfo>  {  	LLSINGLETON(LLVersionInfo); -	void initSingleton(); +	void initSingleton() override;  public:  	~LLVersionInfo(); diff --git a/indra/newview/llviewerchat.cpp b/indra/newview/llviewerchat.cpp index 1c3c547bc1..0d2d62fd77 100644 --- a/indra/newview/llviewerchat.cpp +++ b/indra/newview/llviewerchat.cpp @@ -25,7 +25,7 @@   */  #include "llviewerprecompiledheaders.h" -#include "llviewerchat.h"  +#include "llviewerchat.h"  // newview includes  #include "llagent.h" 	// gAgent		 diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 92c862d530..efdf360949 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -65,6 +65,7 @@  #include "llfloaterdestinations.h"  #include "llfloaterdisplayname.h"  #include "llfloatereditextdaycycle.h" +#include "llfloateremojipicker.h"  #include "llfloaterenvironmentadjust.h"  #include "llfloaterexperienceprofile.h"  #include "llfloaterexperiences.h" @@ -160,6 +161,7 @@  #include "llfloaterimnearbychat.h"  #include "llpanelblockedlist.h"  #include "llpanelprofileclassifieds.h" +#include "llpanelemojicomplete.h"  #include "llpreviewanim.h"  #include "llpreviewgesture.h"  #include "llpreviewnotecard.h" @@ -330,7 +332,7 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("camera_presets", "floater_camera_presets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCameraPresets>);  	LLFloaterReg::add("chat_voice", "floater_voice_chat_volume.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterChatVoiceVolume>);  	LLFloaterReg::add("nearby_chat", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterIMNearbyChat::buildFloater); -    LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>); +	LLFloaterReg::add("classified", "floater_classified.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterClassified>);  	LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCompileQueue>);  	LLFloaterReg::add("conversation", "floater_conversation_log.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterConversationLog>);  	LLFloaterReg::add("add_landmark", "floater_create_landmark.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCreateLandmark>); @@ -338,18 +340,20 @@ void LLViewerFloaterReg::registerFloaters()  	LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>);  	LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>); +	LLFloaterReg::add("emoji_picker", "floater_emoji_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiPicker>); +	LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEmojiComplete>);  	LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>); -    LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>); -    LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentSky>); +	LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>); +	LLFloaterReg::add("env_fixed_environmentent_sky", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentSky>); -    LLFloaterReg::add("env_adjust_snapshot", "floater_adjust_environment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEnvironmentAdjust>); +	LLFloaterReg::add("env_adjust_snapshot", "floater_adjust_environment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEnvironmentAdjust>); -    LLFloaterReg::add("env_edit_extdaycycle", "floater_edit_ext_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditExtDayCycle>); -    LLFloaterReg::add("my_environments", "floater_my_environments.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyEnvironment>); +	LLFloaterReg::add("env_edit_extdaycycle", "floater_edit_ext_day_cycle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEditExtDayCycle>); +	LLFloaterReg::add("my_environments", "floater_my_environments.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMyEnvironment>); -    LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEvent>); -    LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiences>); +	LLFloaterReg::add("event", "floater_event.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterEvent>); +	LLFloaterReg::add("experiences", "floater_experiences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiences>);  	LLFloaterReg::add("experience_profile", "floater_experienceprofile.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperienceProfile>);  	LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiencePicker>); diff --git a/indra/newview/llviewerhelp.h b/indra/newview/llviewerhelp.h index da50e07a43..bbd20bc07e 100644 --- a/indra/newview/llviewerhelp.h +++ b/indra/newview/llviewerhelp.h @@ -43,21 +43,21 @@ class LLViewerHelp : public LLHelp, public LLSingleton<LLViewerHelp>   public:  	/// display the specified help topic in the help viewer -	/*virtual*/ void showTopic(const std::string &topic); +	/*virtual*/ void showTopic(const std::string &topic) override; -	std::string getURL(const std::string& topic); +	std::string getURL(const std::string& topic) override;  	// return topic derived from viewer UI focus, else default topic  	std::string getTopicFromFocus();  	/// return default (fallback) topic name suitable for showTopic() -	/*virtual*/ std::string defaultTopic(); +	/*virtual*/ std::string defaultTopic() override;  	// return topic to use before the user logs in -	/*virtual*/ std::string preLoginTopic(); +	/*virtual*/ std::string preLoginTopic() override;  	// return topic to use for the top-level help, invoked by F1 -	/*virtual*/ std::string f1HelpTopic(); +	/*virtual*/ std::string f1HelpTopic() override;  };  #endif // header guard diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index f1f42afd81..ad7c4bcefa 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -74,7 +74,7 @@ class LLViewerMedia: public LLSingleton<LLViewerMedia>  {  	LLSINGLETON(LLViewerMedia);  	~LLViewerMedia(); -	void initSingleton(); +	void initSingleton() override;  	LOG_CLASS(LLViewerMedia);  public: diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h index effd08a559..2310e4dbfc 100644 --- a/indra/newview/llviewermediafocus.h +++ b/indra/newview/llviewermediafocus.h @@ -54,10 +54,10 @@ public:  	void setHoverFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal = LLVector3::zero);  	void clearHover(); -	/*virtual*/ bool	getFocus(); -	/*virtual*/ BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent); -	/*virtual*/ BOOL	handleKeyUp(KEY key, MASK mask, BOOL called_from_parent); -	/*virtual*/ BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); +	bool	getFocus(); +	/*virtual*/ BOOL	handleKey(KEY key, MASK mask, BOOL called_from_parent) override; +	/*virtual*/ BOOL	handleKeyUp(KEY key, MASK mask, BOOL called_from_parent) override; +	/*virtual*/ BOOL	handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) override;  	BOOL handleScrollWheel(const LLVector2& texture_coords, S32 clicks_x, S32 clicks_y);  	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks_x, S32 clicks_y); @@ -92,12 +92,12 @@ public:  	LLUUID getControlsMediaID();      // The MoaP object wants keyup and keydown events.  Overridden to return true. -    virtual bool    wantsKeyUpKeyDown() const; -    virtual bool    wantsReturnKey() const; +    virtual bool    wantsKeyUpKeyDown() const override; +    virtual bool    wantsReturnKey() const override;  protected: -	/*virtual*/ void	onFocusReceived(); -	/*virtual*/ void	onFocusLost(); +	/*virtual*/ void	onFocusReceived() override; +	/*virtual*/ void	onFocusLost() override;  private: diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 84396c2c68..94ea130d42 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -9571,6 +9571,10 @@ void initialize_menus()  	//Develop (clear cache immediately)  	commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) ); +	// Develop (Fonts debugging) +	commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts)); +	commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures)); +  	// Admin >Object  	view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy");  	view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf"); diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index efc4ded79e..9666533db8 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -773,7 +773,6 @@ void LLViewerObjectList::dirtyAllObjectInventory()  void LLViewerObjectList::updateApparentAngles(LLAgent &agent)  {  	S32 i; -	S32 num_objects = 0;  	LLViewerObject *objectp;  	S32 num_updates, max_value; @@ -830,8 +829,6 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)  		objectp = mObjects[i];  		if (!objectp->isDead())  		{ -			num_objects++; -  			//  Update distance & gpw   			objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area  			objectp->updateTextures();	// Update the image levels of textures for this object. diff --git a/indra/newview/llviewerparcelaskplay.h b/indra/newview/llviewerparcelaskplay.h index dc711917d2..56faddae66 100644 --- a/indra/newview/llviewerparcelaskplay.h +++ b/indra/newview/llviewerparcelaskplay.h @@ -34,8 +34,8 @@ class LLViewerParcelAskPlay : public LLSingleton<LLViewerParcelAskPlay>  {      LLSINGLETON(LLViewerParcelAskPlay);      ~LLViewerParcelAskPlay(); -    void initSingleton(); -    void cleanupSingleton(); +    void initSingleton() override; +    void cleanupSingleton() override;  public:      // functor expects functor(region_id, parcel_id, url, play/stop)      typedef boost::function<void(const LLUUID&, const S32&, const std::string&, const bool&)> ask_callback; diff --git a/indra/newview/llviewerparcelmedia.h b/indra/newview/llviewerparcelmedia.h index 779a65bdf8..790b2b71fc 100644 --- a/indra/newview/llviewerparcelmedia.h +++ b/indra/newview/llviewerparcelmedia.h @@ -74,7 +74,7 @@ public:  	void sendMediaNavigateMessage(const std::string& url);  	// inherited from LLViewerMediaObserver -	virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); +	virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) override;  private:  	void processParcelMediaCommandMessage(LLMessageSystem *msg); diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index d71fd4c075..e83085dee0 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -35,7 +35,7 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer, public LLSingleton<LLViewerPar  {  	LLSINGLETON(LLViewerParcelMediaAutoPlay);  public: -	virtual BOOL tick(); +	virtual BOOL tick() override;  	static void playStarted();   private: diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 0018e78d45..f159682b67 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -242,9 +242,9 @@ class LLUIImageList : public LLImageProviderInterface, public LLSingleton<LLUIIm  	LLSINGLETON_EMPTY_CTOR(LLUIImageList);  public:  	// LLImageProviderInterface -	/*virtual*/ LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority); -	/*virtual*/ LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority); -	void cleanUp(); +	/*virtual*/ LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority) override; +	/*virtual*/ LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority) override; +	void cleanUp() override;  	bool initFromFile(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e8fd74b37b..39b4075596 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1009,7 +1009,7 @@ public:  			const Line& line = *iter;  			LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,  											 LLFontGL::LEFT, LLFontGL::TOP, -											 LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +											 LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);  		}  	} diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 309c3eebdd..e68bfbe1ff 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -170,12 +170,12 @@ class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoice  	LLSINGLETON(LLVoiceChannelProximal);  public: -	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -	/*virtual*/ BOOL isActive(); -	/*virtual*/ void activate(); -	/*virtual*/ void deactivate(); +	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal) override; +	/*virtual*/ void handleStatusChange(EStatusType status) override; +	/*virtual*/ void handleError(EStatusType status) override; +	/*virtual*/ BOOL isActive() override; +	/*virtual*/ void activate() override; +	/*virtual*/ void deactivate() override;  }; @@ -184,15 +184,15 @@ class LLVoiceChannelP2P : public LLVoiceChannelGroup  public:  	LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id); -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -    /*virtual*/ void activate(); -	/*virtual*/ void getChannelInfo(); +	/*virtual*/ void handleStatusChange(EStatusType status) override; +	/*virtual*/ void handleError(EStatusType status) override; +    /*virtual*/ void activate() override; +	/*virtual*/ void getChannelInfo() override;  	void setSessionHandle(const std::string& handle, const std::string &inURI);  protected: -	virtual void setState(EState state); +	virtual void setState(EState state) override;  private: diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index e3ab99c675..ae2aec0e9c 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -64,26 +64,26 @@ public:  	/// @name LLVoiceModuleInterface virtual implementations  	///  @see LLVoiceModuleInterface  	//@{ -	virtual void init(LLPumpIO *pump);	// Call this once at application startup (creates connector) -	virtual void terminate();	// Call this to clean up during shutdown +	virtual void init(LLPumpIO *pump) override;	// Call this once at application startup (creates connector) +	virtual void terminate() override;	// Call this to clean up during shutdown -	virtual const LLVoiceVersionInfo& getVersion(); +	virtual const LLVoiceVersionInfo& getVersion() override; -	virtual void updateSettings(); // call after loading settings and whenever they change +	virtual void updateSettings() override; // call after loading settings and whenever they change  	// Returns true if vivox has successfully logged in and is not in error state	 -	virtual bool isVoiceWorking() const; +	virtual bool isVoiceWorking() const override;  	/////////////////////  	/// @name Tuning  	//@{ -	virtual void tuningStart(); -	virtual void tuningStop(); -	virtual bool inTuningMode(); +	virtual void tuningStart() override; +	virtual void tuningStop() override; +	virtual bool inTuningMode() override; -	virtual void tuningSetMicVolume(float volume); -	virtual void tuningSetSpeakerVolume(float volume); -	virtual float tuningGetEnergy(void); +	virtual void tuningSetMicVolume(float volume) override; +	virtual void tuningSetSpeakerVolume(float volume) override; +	virtual float tuningGetEnergy(void) override;  	//@}  	///////////////////// @@ -91,40 +91,40 @@ public:  	//@{  	// This returns true when it's safe to bring up the "device settings" dialog in the prefs.  	// i.e. when the daemon is running and connected, and the device lists are populated. -	virtual bool deviceSettingsAvailable(); -	virtual bool deviceSettingsUpdated();  //return if the list has been updated and never fetched,  only to be called from the voicepanel. +	virtual bool deviceSettingsAvailable() override; +	virtual bool deviceSettingsUpdated() override;  //return if the list has been updated and never fetched,  only to be called from the voicepanel.  	// Requery the vivox daemon for the current list of input/output devices.  	// If you pass true for clearCurrentList, deviceSettingsAvailable() will be false until the query has completed  	// (use this if you want to know when it's done).  	// If you pass false, you'll have no way to know when the query finishes, but the device lists will not appear empty in the interim. -	virtual void refreshDeviceLists(bool clearCurrentList = true); +	virtual void refreshDeviceLists(bool clearCurrentList = true) override; -	virtual void setCaptureDevice(const std::string& name); -	virtual void setRenderDevice(const std::string& name); +	virtual void setCaptureDevice(const std::string& name) override; +	virtual void setRenderDevice(const std::string& name) override; -	virtual LLVoiceDeviceList& getCaptureDevices(); -	virtual LLVoiceDeviceList& getRenderDevices(); +	virtual LLVoiceDeviceList& getCaptureDevices() override; +	virtual LLVoiceDeviceList& getRenderDevices() override;  	//@}	 -	virtual void getParticipantList(std::set<LLUUID> &participants); -	virtual bool isParticipant(const LLUUID& speaker_id); +	virtual void getParticipantList(std::set<LLUUID> &participants) override; +	virtual bool isParticipant(const LLUUID& speaker_id) override;  	// Send a text message to the specified user, initiating the session if necessary.  	// virtual BOOL sendTextMessage(const LLUUID& participant_id, const std::string& message) const {return false;};  	// close any existing text IM session with the specified user -	virtual void endUserIMSession(const LLUUID &uuid); +	virtual void endUserIMSession(const LLUUID &uuid) override;  	// Returns true if calling back the session URI after the session has closed is possible.  	// Currently this will be false only for PSTN P2P calls.		  	// NOTE: this will return true if the session can't be found.  -	virtual BOOL isSessionCallBackPossible(const LLUUID &session_id); +	virtual BOOL isSessionCallBackPossible(const LLUUID &session_id) override;  	// Returns true if the session can accepte text IM's.  	// Currently this will be false only for PSTN P2P calls.  	// NOTE: this will return true if the session can't be found.  -	virtual BOOL isSessionTextIMPossible(const LLUUID &session_id); +	virtual BOOL isSessionTextIMPossible(const LLUUID &session_id) override;  	//////////////////////////// @@ -132,21 +132,21 @@ public:  	//@{  	// returns true iff the user is currently in a proximal (local spatial) channel.  	// Note that gestures should only fire if this returns true. -	virtual bool inProximalChannel(); +	virtual bool inProximalChannel() override;  	virtual void setNonSpatialChannel(const std::string &uri, -									  const std::string &credentials); +									  const std::string &credentials) override;  	virtual bool setSpatialChannel(const std::string &uri, -								   const std::string &credentials); +								   const std::string &credentials) override; -	virtual void leaveNonSpatialChannel(); +	virtual void leaveNonSpatialChannel() override; -	virtual void leaveChannel(void);	 +	virtual void leaveChannel(void) override;  	// Returns the URI of the current channel, or an empty string if not currently in a channel.  	// NOTE that it will return an empty string if it's in the process of joining a channel. -	virtual std::string getCurrentChannel(); +	virtual std::string getCurrentChannel() override;  	//@} @@ -154,59 +154,59 @@ public:  	/// @name invitations  	//@{  	// start a voice channel with the specified user -	virtual void callUser(const LLUUID &uuid);	 -	virtual bool isValidChannel(std::string &channelHandle); -	virtual bool answerInvite(std::string &channelHandle); -	virtual void declineInvite(std::string &channelHandle); +	virtual void callUser(const LLUUID &uuid) override; +	virtual bool isValidChannel(std::string &channelHandle) override; +	virtual bool answerInvite(std::string &channelHandle) override; +	virtual void declineInvite(std::string &channelHandle) override;  	//@}  	/////////////////////////  	/// @name Volume/gain  	//@{ -	virtual void setVoiceVolume(F32 volume); -	virtual void setMicGain(F32 volume); +	virtual void setVoiceVolume(F32 volume) override; +	virtual void setMicGain(F32 volume) override;  	//@}  	/////////////////////////  	/// @name enable disable voice and features  	//@{ -	virtual bool voiceEnabled(); -	virtual void setVoiceEnabled(bool enabled); -	virtual BOOL lipSyncEnabled();	 -	virtual void setLipSyncEnabled(BOOL enabled); -	virtual void setMuteMic(bool muted);		// Set the mute state of the local mic. +	virtual bool voiceEnabled() override; +	virtual void setVoiceEnabled(bool enabled) override; +	virtual BOOL lipSyncEnabled() override; +	virtual void setLipSyncEnabled(BOOL enabled) override; +	virtual void setMuteMic(bool muted) override;		// Set the mute state of the local mic.  	//@}  	//////////////////////////  	/// @name nearby speaker accessors  	//@{ -	virtual BOOL getVoiceEnabled(const LLUUID& id);		// true if we've received data for this avatar -	virtual std::string getDisplayName(const LLUUID& id); -	virtual BOOL isParticipantAvatar(const LLUUID &id); -	virtual BOOL getIsSpeaking(const LLUUID& id); -	virtual BOOL getIsModeratorMuted(const LLUUID& id); -	virtual F32 getCurrentPower(const LLUUID& id);		// "power" is related to "amplitude" in a defined way.  I'm just not sure what the formula is... -	virtual BOOL getOnMuteList(const LLUUID& id); -	virtual F32 getUserVolume(const LLUUID& id); -	virtual void setUserVolume(const LLUUID& id, F32 volume); // set's volume for specified agent, from 0-1 (where .5 is nominal)	 +	virtual BOOL getVoiceEnabled(const LLUUID& id) override;		// true if we've received data for this avatar +	virtual std::string getDisplayName(const LLUUID& id) override; +	virtual BOOL isParticipantAvatar(const LLUUID &id) override; +	virtual BOOL getIsSpeaking(const LLUUID& id) override; +	virtual BOOL getIsModeratorMuted(const LLUUID& id) override; +	virtual F32 getCurrentPower(const LLUUID& id) override;		// "power" is related to "amplitude" in a defined way.  I'm just not sure what the formula is... +	virtual BOOL getOnMuteList(const LLUUID& id) override; +	virtual F32 getUserVolume(const LLUUID& id) override; +	virtual void setUserVolume(const LLUUID& id, F32 volume) override; // set's volume for specified agent, from 0-1 (where .5 is nominal)  	//@}  	// authorize the user  	virtual void userAuthorized(const std::string& user_id, -								const LLUUID &agentID); +								const LLUUID &agentID) override;  	//////////////////////////////  	/// @name Status notification  	//@{ -	virtual void addObserver(LLVoiceClientStatusObserver* observer); -	virtual void removeObserver(LLVoiceClientStatusObserver* observer); -	virtual void addObserver(LLFriendObserver* observer); -	virtual void removeObserver(LLFriendObserver* observer);		 -	virtual void addObserver(LLVoiceClientParticipantObserver* observer); -	virtual void removeObserver(LLVoiceClientParticipantObserver* observer); +	virtual void addObserver(LLVoiceClientStatusObserver* observer) override; +	virtual void removeObserver(LLVoiceClientStatusObserver* observer) override; +	virtual void addObserver(LLFriendObserver* observer) override; +	virtual void removeObserver(LLFriendObserver* observer) override; +	virtual void addObserver(LLVoiceClientParticipantObserver* observer) override; +	virtual void removeObserver(LLVoiceClientParticipantObserver* observer) override;  	//@} -	virtual std::string sipURIFromID(const LLUUID &id); +	virtual std::string sipURIFromID(const LLUUID &id) override;  	//@}  	/// @name LLVoiceEffectInterface virtual implementations @@ -216,32 +216,32 @@ public:  	//////////////////////////  	/// @name Accessors  	//@{ -	virtual bool setVoiceEffect(const LLUUID& id); -	virtual const LLUUID getVoiceEffect(); -	virtual LLSD getVoiceEffectProperties(const LLUUID& id); +	virtual bool setVoiceEffect(const LLUUID& id) override; +	virtual const LLUUID getVoiceEffect() override; +	virtual LLSD getVoiceEffectProperties(const LLUUID& id) override; -	virtual void refreshVoiceEffectLists(bool clear_lists); -	virtual const voice_effect_list_t& getVoiceEffectList() const; -	virtual const voice_effect_list_t& getVoiceEffectTemplateList() const; +	virtual void refreshVoiceEffectLists(bool clear_lists) override; +	virtual const voice_effect_list_t& getVoiceEffectList() const override; +	virtual const voice_effect_list_t& getVoiceEffectTemplateList() const override;  	//@}  	//////////////////////////////  	/// @name Status notification  	//@{ -	virtual void addObserver(LLVoiceEffectObserver* observer); -	virtual void removeObserver(LLVoiceEffectObserver* observer); +	virtual void addObserver(LLVoiceEffectObserver* observer) override; +	virtual void removeObserver(LLVoiceEffectObserver* observer) override;  	//@}  	//////////////////////////////  	/// @name Effect preview buffer  	//@{ -	virtual void enablePreviewBuffer(bool enable); -	virtual void recordPreviewBuffer(); -	virtual void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null); -	virtual void stopPreviewBuffer(); +	virtual void enablePreviewBuffer(bool enable) override; +	virtual void recordPreviewBuffer() override; +	virtual void playPreviewBuffer(const LLUUID& effect_id = LLUUID::null) override; +	virtual void stopPreviewBuffer() override; -	virtual bool isPreviewRecording(); -	virtual bool isPreviewPlaying(); +	virtual bool isPreviewRecording() override; +	virtual bool isPreviewPlaying() override;  	//@}  	//@} @@ -750,7 +750,7 @@ private:  	std::string getAudioSessionURI();  	std::string getAudioSessionHandle(); -    void setHidden(bool hidden); //virtual +    void setHidden(bool hidden) override; //virtual  	void sendPositionAndVolumeUpdate(void);      void sendCaptureAndRenderDevices(); diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index b0af565867..5cb7e7478b 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -408,7 +408,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,  										LLStrider<U16> &indicesp,  										U32 &index_offset)  { -	S32 vertex_count = 0;  	S32 i, x, y;  	S32 num_vertices; @@ -443,7 +442,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,  			normalsp++;  			texCoords0p++;  			texCoords1p++; -			vertex_count++;  		}  		// North patch @@ -456,7 +454,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,  			normalsp++;  			texCoords0p++;  			texCoords1p++; -			vertex_count++;  		} @@ -493,7 +490,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,  			normalsp++;  			texCoords0p++;  			texCoords1p++; -			vertex_count++;  		}  		// Iterate through the north patch's points @@ -507,7 +503,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,  			normalsp++;  			texCoords0p++;  			texCoords1p++; -			vertex_count++;  		} @@ -551,7 +546,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,  			normalsp++;  			texCoords0p++;  			texCoords1p++; -			vertex_count++;  		}  		// Iterate through the north patch's points @@ -565,7 +559,6 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,  			normalsp++;  			texCoords0p++;  			texCoords1p++; -			vertex_count++;  		}  		for (i = 0; i < length; i++) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index bf9a4dfa12..9a490bb0a6 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -6306,7 +6306,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace  	LLSpatialGroup::buffer_map_t buffer_map;  	LLViewerTexture* last_tex = NULL; -	S32 buffer_index = 0;  	S32 texture_index_channels = 1; @@ -6320,11 +6319,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace  		texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels;  	} -    if (distance_sort) -    { -        buffer_index = -1; -    } -  	static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16);  	texture_index_channels = llmin(texture_index_channels, (S32) max_texture_index); @@ -6347,14 +6341,9 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace  			tex = NULL;  		} -		if (last_tex == tex) -		{ -			buffer_index++; -		} -		else +		if (last_tex != tex)  		{  			last_tex = tex; -			buffer_index = 0;  		}  		bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic();  diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index f7774a7086..0dbe50d5e4 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -428,7 +428,7 @@ public:  	{  		LLSINGLETON(ContextMenu);  	public: -		/*virtual*/ void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y); +		/*virtual*/ void show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y) override;  		void show(LLView* spawning_view, LLWearableType::EType w_type, S32 x, S32 y); @@ -441,7 +441,7 @@ public:  			MASK_UNKNOWN		= 0x10,  		}; -		/* virtual */ LLContextMenu* createMenu(); +		/* virtual */ LLContextMenu* createMenu() override;  		void updateItemsVisibility(LLContextMenu* menu);  		void updateItemsLabels(LLContextMenu* menu);  		static void setMenuItemVisible(LLContextMenu* menu, const std::string& name, bool val); @@ -472,7 +472,7 @@ public:  	virtual ~LLWearableItemsList(); -	/*virtual*/ LLPanel* createNewItem(LLViewerInventoryItem* item); +	/*virtual*/ LLPanel* createNewItem(LLViewerInventoryItem* item) override;  	void updateList(const LLUUID& category_id); diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index 524adba652..31dbfb8ffd 100644 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -40,9 +40,9 @@ class LLWinDebug:  {  	LLSINGLETON_EMPTY_CTOR(LLWinDebug);  public: -	void initSingleton(); +	void initSingleton() override;  	static void generateMinidump(struct _EXCEPTION_POINTERS *pExceptionInfo = NULL); -	void cleanupSingleton(); +	void cleanupSingleton() override;  private:  	static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename);  }; diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 8f46e66551..386b56f9f7 100755 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -551,7 +551,8 @@ void LLWorldMapView::draw()  					S32_MAX, //max_chars  					mMapScale, //max_pixels  					NULL, -					TRUE); //use ellipses +					/*use_ellipses*/TRUE, +					/*use_color*/FALSE);  			}  		}  	} diff --git a/indra/newview/skins/default/textures/icons/emoji_picker_icon.png b/indra/newview/skins/default/textures/icons/emoji_picker_icon.pngBinary files differ new file mode 100644 index 0000000000..668dcaf193 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/emoji_picker_icon.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 7d999a2ffa..d8c873e791 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -206,6 +206,7 @@ with the same filename but different name    <texture name="DropTarget" file_name="widgets/DropTarget.png" preload="false" /> +  <texture name="Emoji_Picker_Icon" file_name="icons/emoji_picker_icon.png" preload="true" />    <texture name="ExternalBrowser_Off" file_name="icons/ExternalBrowser_Off.png" preload="false" />    <texture name="Edit_Wrench" file_name="icons/Edit_Wrench.png" preload="false" /> @@ -213,7 +214,7 @@ with the same filename but different name    <texture name="Presets_Icon" file_name="icons/Presets_Icon.png" preload="true" />    <texture name="Presets_Icon_Graphic" file_name="icons/Presets_Icon_Graphic.png" preload="true" /> - <texture name="Favorite_Star_Active" file_name="navbar/Favorite_Star_Active.png" preload="false" /> +  <texture name="Favorite_Star_Active" file_name="navbar/Favorite_Star_Active.png" preload="false" />    <texture name="Favorite_Star_Off" file_name="navbar/Favorite_Star_Off.png" preload="false" />    <texture name="Favorite_Star_Press" file_name="navbar/Favorite_Star_Press.png" preload="false" />    <texture name="Favorite_Star_Over" file_name="navbar/Favorite_Star_Over.png" preload="false" /> @@ -329,7 +330,7 @@ with the same filename but different name    <texture name="Inv_Underpants" file_name="icons/Inv_Underpants.png" preload="false" />    <texture name="Inv_Undershirt" file_name="icons/Inv_Undershirt.png" preload="false" />    <texture name="Inv_Link" file_name="icons/Inv_Link.png" preload="false" /> -    <texture name="Inv_Settings" file_name="icons/Inv_Settings.png" preload="false" /> +  <texture name="Inv_Settings" file_name="icons/Inv_Settings.png" preload="false" />    <texture name="Inv_SettingsSky" file_name="icons/Inv_SettingsSky.png" preload="false" />    <texture name="Inv_SettingsWater" file_name="icons/Inv_SettingsWater.png" preload="false" />    <texture name="Inv_SettingsDay" file_name="icons/Inv_SettingsDay.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/da/emoji_categories.xml b/indra/newview/skins/default/xui/da/emoji_categories.xml new file mode 100644 index 0000000000..456b18e4e2 --- /dev/null +++ b/indra/newview/skins/default/xui/da/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>smileys and følelser</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>mennesker and krop</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>komponenter</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>dyr and natur</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>mad and drikke</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>rejser and steder</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>oplevelser</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>objekter</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>symboler</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/de/emoji_categories.xml b/indra/newview/skins/default/xui/de/emoji_categories.xml new file mode 100644 index 0000000000..ed63d0bac9 --- /dev/null +++ b/indra/newview/skins/default/xui/de/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>Smileys and Emotionen</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>Menschen and Körper</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>Komponenten</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>Tiere and Natur</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>Essen and Trinken</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>Reisen and Orte</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>Aktivitäten</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>Gegenstände</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>Symbole</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/en/emoji_categories.xml b/indra/newview/skins/default/xui/en/emoji_categories.xml new file mode 100644 index 0000000000..0315d0c43a --- /dev/null +++ b/indra/newview/skins/default/xui/en/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>smileys and emotion</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>people and body</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>components</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>animals and nature</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>food and drink</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>travel and places</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>activities</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>objects</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>symbols</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/en/floater_activeim.xml b/indra/newview/skins/default/xui/en/floater_activeim.xml index b79c5d9a19..42c3e7e935 100644 --- a/indra/newview/skins/default/xui/en/floater_activeim.xml +++ b/indra/newview/skins/default/xui/en/floater_activeim.xml @@ -23,7 +23,7 @@  		<scrolling_panel_list  			follows="left|right"  			layout="topleft" -      left="1"       +			left="1"  			name="chiclet_row_panel_list"  			width="318"/>  	</scroll_container> diff --git a/indra/newview/skins/default/xui/en/floater_emoji_complete.xml b/indra/newview/skins/default/xui/en/floater_emoji_complete.xml new file mode 100644 index 0000000000..e9ea8f4de7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_emoji_complete.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + can_close="false" + can_dock="false" + can_drag_on_left="false" + can_minimize="false" + can_resize="false" + can_tear_off="false" + header_height="0" + layout="topleft" + legacy_header_height="0" + height="40" + single_instance="true" + width="240" + > +	<emoji_complete +	 autosize="true" +	 height="30" +	 follows="top|left" +	 layout="topleft" +	 left="5" +	 max_emoji="7" +	 name="emoji_complete_ctrl" +	 top="5" +	 width="230" +	 > +	</emoji_complete> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_emoji_picker.xml b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml new file mode 100644 index 0000000000..a2a290c306 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_emoji_picker.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater +    name="emojipicker" +    title="CHOOSE EMOJI" +    help_topic="emojipicker" +    positioning="cascading" +    legacy_header_height="0" +    can_resize="true" +    layout="topleft" +    min_width="250" +    height="400" +    width="250"> +  <floater.string name="title_for_recently_used" value="Recently used"/> +  <floater.string name="title_for_frequently_used" value="Frequently used"/> +  <line_editor +      name="Filter" +      label="Start typing to filter" +      layout="bottomleft" +      follows="bottom|left|right" +      text_tentative_color="TextFgTentativeColor" +      show_label_focused="true" +      max_length_bytes="63" +      text_pad_right="5" +      text_pad_left="5" +      bottom="14" +      left="10" +      height="29" +      width="230" /> +  <scroll_container +      name="EmojiGridContainer" +      layout="topleft" +      follows="all" +      top="25" +      left="0" +      height="325" +      width="250"> +    <scrolling_panel_list +        name="EmojiGrid" +        layout="topleft" +        follows="top|left|right" +        padding="4" +        spacing="0" +        top="0" +        left="0" +        width="250"/> +  </scroll_container> +  <panel +      name="Groups" +      layout="topleft" +      follows="top|left|right" +      top="0" +      left="0" +      height="25" +      width="250"> +    <panel +      name="Badge" +      layout="bottomleft" +      follows="bottom|left" +      background_visible="true" +      background_opaque="true" +      bg_opaque_color="FrogGreen" +      bottom="0" +      height="2" +      width="20" +      /> +  </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index da84fbeea6..1592352d1b 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -297,8 +297,20 @@                           tab_group="3"                           bottom="-8"                           left_pad="5" -                         right="-5" +                         right="-30"                           wrap="true" /> +                        <button +                         follows="right|bottom" +                         bottom="-7" +                         height="25" +                         image_hover_unselected="Toolbar_Middle_Over" +                         image_overlay="Emoji_Picker_Icon" +                         image_selected="Toolbar_Middle_Selected" +                         image_unselected="Toolbar_Middle_Off" +                         right="-1" +                         name="emoji_panel_btn" +                         tool_tip="Shows/hides emoji panel" +                         width="25"/>                      </layout_panel>                      <layout_panel                       auto_resize="false" diff --git a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml index dcbdfa8794..ac5467c036 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml @@ -73,6 +73,8 @@       spellcheck="true"       tab_group="1"       top="46" +     use_color="true" +     show_emoji_helper="true"       width="392"       word_wrap="true">          Loading... diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml index d88c267a95..40045625fd 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">TwemojiSVG.ttf</file>      <os name="Windows">        <file>meiryo.TTC</file>        <file>MSGOTHIC.TTC</file> @@ -69,6 +70,11 @@      <file>DejaVuSans-BoldOblique.ttf</file>    </font> +  <font name="Emoji" +	comment="Name of emoji font"> +    <file>TwemojiSVG.ttf</file> +  </font> +    <font name="Monospace"  	comment="Name of monospace font">      <file>DejaVuSansMono.ttf</file> diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml index 96fac1c6e8..40399b33ef 100644 --- a/indra/newview/skins/default/xui/en/menu_login.xml +++ b/indra/newview/skins/default/xui/en/menu_login.xml @@ -161,6 +161,32 @@        <menu_item_separator />        <menu         create_jump_keys="true" +       label="Fonts" +       name="Fonts" +       tear_off="true"> +        <menu_item_call +         label="Show Font Test" +         name="Show Font Test"> +          <menu_item_call.on_click +           function="Floater.Show" +           parameter="font_test" /> +        </menu_item_call> +        <menu_item_separator /> +        <menu_item_call +         label="Dump Fonts" +         name="Dump Fonts"> +          <menu_item_call.on_click +           function="Develop.Fonts.Dump" /> +        </menu_item_call> +        <menu_item_call +         label="Dump Font Textures" +         name="Dump Font Textures"> +          <menu_item_call.on_click +           function="Develop.Fonts.DumpTextures" /> +        </menu_item_call> +      </menu> +      <menu +       create_jump_keys="true"         label="UI Tests"         name="UI Tests"         tear_off="true"> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index f72d1f0bf9..bb9d4ea1f2 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3493,6 +3493,18 @@ function="World.EnvPreset"               parameter="https://cryptic-ridge-1632.herokuapp.com/"/>            </menu_item_call>            <menu_item_call +           label="Dump Fonts" +           name="Dump Fonts"> +            <menu_item_call.on_click +             function="Develop.Fonts.Dump" /> +          </menu_item_call> +          <menu_item_call +           label="Dump Font Textures" +           name="Dump Font Textures"> +            <menu_item_call.on_click +             function="Develop.Fonts.DumpTextures" /> +          </menu_item_call> +          <menu_item_call               label="Dump SelectMgr"               name="Dump SelectMgr">                  <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 01f5b513c7..b2c161455b 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -485,9 +485,9 @@ http://secondlife.com/support for help fixing this problem.  	<!-- build floater -->  	<string name="multiple_textures">Multiple</string> -<string name="use_texture">Use texture</string> -    <string name="manip_hint1">Move mouse cursor over ruler</string> -    <string name="manip_hint2">to snap to grid</string> +	<string name="use_texture">Use texture</string> +	<string name="manip_hint1">Move mouse cursor over ruler</string> +	<string name="manip_hint2">to snap to grid</string>  	<!-- world map -->  	<string name="texture_loading">Loading...</string> @@ -502,14 +502,14 @@ http://secondlife.com/support for help fixing this problem.  	<!-- Chat -->  	<string name="NearbyChatTitle">Nearby chat</string> -  <string name="NearbyChatLabel">(Nearby chat)</string> +	<string name="NearbyChatLabel">(Nearby chat)</string>  	<string name="whisper">whispers:</string>  	<string name="shout">shouts:</string>  	<string name="ringing">Connecting to in-world Voice Chat...</string>  	<string name="connected">Connected</string>  	<string name="unavailable">Voice not available at your current location</string>  	<string name="hang_up">Disconnected from in-world Voice Chat</string> -  <string name="reconnect_nearby">You will now be reconnected to Nearby Voice Chat</string> +	<string name="reconnect_nearby">You will now be reconnected to Nearby Voice Chat</string>  	<string name="ScriptQuestionCautionChatGranted">'[OBJECTNAME]', an object owned by '[OWNERNAME]', located in [REGIONNAME] at [REGIONPOS], has been granted permission to: [PERMISSIONS].</string>  	<string name="ScriptQuestionCautionChatDenied">'[OBJECTNAME]', an object owned by '[OWNERNAME]', located in [REGIONNAME] at [REGIONPOS], has been denied permission to: [PERMISSIONS].</string>  	<string name="AdditionalPermissionsRequestHeader">If you allow access to your account, you will also be allowing the object to:</string> diff --git a/indra/newview/skins/default/xui/en/widgets/chat_editor.xml b/indra/newview/skins/default/xui/en/widgets/chat_editor.xml index f9facb593a..c550f634e5 100644 --- a/indra/newview/skins/default/xui/en/widgets/chat_editor.xml +++ b/indra/newview/skins/default/xui/en/widgets/chat_editor.xml @@ -1,4 +1,7 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <chat_editor    name="chat_editor" -  show_context_menu="true"/> +  show_context_menu="true" +  show_emoji_helper="true" +  use_color="true" +  /> diff --git a/indra/newview/skins/default/xui/en/widgets/chat_history.xml b/indra/newview/skins/default/xui/en/widgets/chat_history.xml index c0a948931c..c4300c9350 100644 --- a/indra/newview/skins/default/xui/en/widgets/chat_history.xml +++ b/indra/newview/skins/default/xui/en/widgets/chat_history.xml @@ -10,11 +10,11 @@    bottom_separator_pad="1"    top_header_pad="12"    bottom_header_pad="5" -	max_length="2147483647" -	track_bottom="true" -	name="chat_history" -	type="string" -	word_wrap="true" +  max_length="2147483647" +  track_bottom="true" +  name="chat_history" +  type="string" +  word_wrap="true"    line_spacing.multiple="1.0"     font="SansSerif">    <more_chat_text diff --git a/indra/newview/skins/default/xui/en/widgets/emoji_complete.xml b/indra/newview/skins/default/xui/en/widgets/emoji_complete.xml new file mode 100644 index 0000000000..370f1d174e --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/emoji_complete.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<emoji_complete +  autosize="false" +  font="EmojiHuge" +  hover_image="ListItem_Over" +  max_emoji="7" +  padding="8" +  selected_image="ListItem_Select" +  > +</emoji_complete> diff --git a/indra/newview/skins/default/xui/es/emoji_categories.xml b/indra/newview/skins/default/xui/es/emoji_categories.xml new file mode 100644 index 0000000000..b1b73eba5e --- /dev/null +++ b/indra/newview/skins/default/xui/es/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>emoticonos y emoción</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>personas y cuerpo</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>componentes</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>animales y la naturaleza</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>comida y bebida</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>viajes y lugares</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>actividades</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>objetos</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>símbolos</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/fr/emoji_categories.xml b/indra/newview/skins/default/xui/fr/emoji_categories.xml new file mode 100644 index 0000000000..38dc9cb8f8 --- /dev/null +++ b/indra/newview/skins/default/xui/fr/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>smileys et émotion</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>les gens et le corps</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>composants</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>animaux et la nature</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>nourriture et boissons</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>voyages et lieux</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>activités</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>objets</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>symboles</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/it/emoji_categories.xml b/indra/newview/skins/default/xui/it/emoji_categories.xml new file mode 100644 index 0000000000..a4782e60a6 --- /dev/null +++ b/indra/newview/skins/default/xui/it/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>smileys and emozione</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>persone e corpo</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>componenti</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>animali and natura</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>cibo e bevande</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>viaggi and luoghi</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>attività</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>oggetti</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>simboli</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/ja/emoji_categories.xml b/indra/newview/skins/default/xui/ja/emoji_categories.xml new file mode 100644 index 0000000000..7750f4ad2e --- /dev/null +++ b/indra/newview/skins/default/xui/ja/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>スマイリーと感情</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>人体</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>コンポーネント</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>動物自然</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>飲み物・食べ物</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>旅行・場所</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>有効化</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>オブジェクト</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>シンボル</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/pl/emoji_categories.xml b/indra/newview/skins/default/xui/pl/emoji_categories.xml new file mode 100644 index 0000000000..9aad7af794 --- /dev/null +++ b/indra/newview/skins/default/xui/pl/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>buźki and emocje</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>ludzie and ciało</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>składniki</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>zwierzęta and przyroda</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>jedzenie i picie</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>podróże and miejsca</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>aktywność</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>objekt</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>symbole</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/pt/emoji_categories.xml b/indra/newview/skins/default/xui/pt/emoji_categories.xml new file mode 100644 index 0000000000..887444b957 --- /dev/null +++ b/indra/newview/skins/default/xui/pt/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>sorrisos e emoção</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>pessoas e corpo</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>componentes</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>animais e natureza</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>comida e bebida</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>viagens e lugares</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>atividades</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>objetos</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>símbolos</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/ru/emoji_categories.xml b/indra/newview/skins/default/xui/ru/emoji_categories.xml new file mode 100644 index 0000000000..b08f0d8117 --- /dev/null +++ b/indra/newview/skins/default/xui/ru/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>смайлики и люди</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>тело людей</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>компонент</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>животные и природа</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>еда и напитки</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>путешествия и местности</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>варианты досуга</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>предметы</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>символы</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/skins/default/xui/zh/emoji_categories.xml b/indra/newview/skins/default/xui/zh/emoji_categories.xml new file mode 100644 index 0000000000..fbe6165eeb --- /dev/null +++ b/indra/newview/skins/default/xui/zh/emoji_categories.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" ?> +<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="llsd.xsd"> +  <array> +    <map> +      <key>Name</key> +      <string>smileys and emotion</string> +      <key>Category</key> +      <string>笑脸</string> +    </map> +    <map> +      <key>Name</key> +      <string>people and body</string> +      <key>Category</key> +      <string>人体</string> +    </map> +    <map> +      <key>Name</key> +      <string>components</string> +      <key>Category</key> +      <string>组件</string> +    </map> +    <map> +      <key>Name</key> +      <string>animals and nature</string> +      <key>Category</key> +      <string>野生动物</string> +    </map> +    <map> +      <key>Name</key> +      <string>food and drink</string> +      <key>Category</key> +      <string>食物飲料</string> +    </map> +    <map> +      <key>Name</key> +      <string>travel and places</string> +      <key>Category</key> +      <string>旅遊地點</string> +    </map> +    <map> +      <key>Name</key> +      <string>activities</string> +      <key>Category</key> +      <string>个人活动</string> +    </map> +    <map> +      <key>Name</key> +      <string>objects</string> +      <key>Category</key> +      <string>物件</string> +    </map> +    <map> +      <key>Name</key> +      <string>symbols</string> +      <key>Category</key> +      <string>人的符号</string> +    </map> +  </array> +</llsd> diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 89481add29..de050d7c62 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -141,7 +141,7 @@ class ViewerManifest(LLManifest):                  self.path("*.tga")              # Include our fonts -            with self.prefix(src_dst="fonts"): +            with self.prefix(src="../packages/fonts",src_dst="fonts"):                  self.path("*.ttf")                  self.path("*.txt") @@ -517,6 +517,10 @@ class WindowsManifest(ViewerManifest):                  self.path("OpenAL32.dll")                  self.path("alut.dll") +            # For ICU4C +            self.path("icudt48.dll") +            self.path("icuuc48.dll") +              # For textures              self.path("openjp2.dll") | 
