diff options
Diffstat (limited to 'indra')
91 files changed, 2127 insertions, 1421 deletions
| diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index ff705101de..04b4202ca3 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -52,7 +52,7 @@ if(WINDOWS)      set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}")      set(release_files -        openjpeg.dll +        openjp2.dll          libapr-1.dll          libaprutil-1.dll          libapriconv-1.dll @@ -220,7 +220,7 @@ elseif(LINUX)          libgobject-2.0.so          libhunspell-1.3.so.0.0.0          libopenal.so -        libopenjpeg.so +        libopenjp2.so          libuuid.so.16          libuuid.so.16.0.22          libfontconfig.so.1.8.0 diff --git a/indra/cmake/FindOpenJPEG.cmake b/indra/cmake/FindOpenJPEG.cmake index 949384eec4..2d4353b54f 100644 --- a/indra/cmake/FindOpenJPEG.cmake +++ b/indra/cmake/FindOpenJPEG.cmake @@ -14,9 +14,10 @@ FIND_PATH(OPENJPEG_INCLUDE_DIR openjpeg.h  /usr/local/include  /usr/include/openjpeg  /usr/include +include/openjpeg  ) -SET(OPENJPEG_NAMES ${OPENJPEG_NAMES} openjpeg) +SET(OPENJPEG_NAMES ${OPENJPEG_NAMES} openjp2)  FIND_LIBRARY(OPENJPEG_LIBRARY    NAMES ${OPENJPEG_NAMES}    PATHS /usr/lib /usr/local/lib diff --git a/indra/cmake/OpenJPEG.cmake b/indra/cmake/OpenJPEG.cmake index bf0bde2ba7..a078c97cb8 100644 --- a/indra/cmake/OpenJPEG.cmake +++ b/indra/cmake/OpenJPEG.cmake @@ -8,15 +8,7 @@ if (USESYSTEMLIBS)    include(FindOpenJPEG)  else (USESYSTEMLIBS)    use_prebuilt_binary(openjpeg) -   -  if(WINDOWS) -    # Windows has differently named release and debug openjpeg(d) libs. -    set(OPENJPEG_LIBRARIES  -        debug openjpegd -        optimized openjpeg) -  else(WINDOWS) -    set(OPENJPEG_LIBRARIES openjpeg) -  endif(WINDOWS) -   -    set(OPENJPEG_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/openjpeg) + +  set(OPENJPEG_LIBRARIES openjp2) +  set(OPENJPEG_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/openjpeg)  endif (USESYSTEMLIBS) diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index d7706e73b2..3957ede77f 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -99,14 +99,14 @@ if (WINDOWS)      # Copy over OpenJPEG.dll      # *NOTE: On Windows with VS2005, only the first comment prints      set(OPENJPEG_RELEASE -        "${ARCH_PREBUILT_DIRS_RELEASE}/openjpeg.dll") +        "${ARCH_PREBUILT_DIRS_RELEASE}/openjp2.dll")      add_custom_command( TARGET llui_libtest POST_BUILD          COMMAND ${CMAKE_COMMAND} -E copy_if_different               ${OPENJPEG_RELEASE} ${CMAKE_CURRENT_BINARY_DIR}          COMMENT "Copying OpenJPEG DLLs to binary directory"          )      set(OPENJPEG_DEBUG -        "${ARCH_PREBUILT_DIRS_DEBUG}/openjpegd.dll") +        "${ARCH_PREBUILT_DIRS_DEBUG}/openjp2.dll")      add_custom_command( TARGET llui_libtest POST_BUILD          COMMAND ${CMAKE_COMMAND} -E copy_if_different               ${OPENJPEG_DEBUG} ${CMAKE_CURRENT_BINARY_DIR} diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index f0df3e1474..c1336fd612 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -305,7 +305,12 @@ LLAvatarAppearance::~LLAvatarAppearance()  		}  	} -	if (mRoot) mRoot->removeAllChildren(); +	if (mRoot)  +	{ +		mRoot->removeAllChildren(); +		delete mRoot; +		mRoot = nullptr; +	}  	mJointMap.clear();  	clearSkeleton(); diff --git a/indra/llappearance/lllocaltextureobject.cpp b/indra/llappearance/lllocaltextureobject.cpp index 3f564ec3de..0481326e9e 100644 --- a/indra/llappearance/lllocaltextureobject.cpp +++ b/indra/llappearance/lllocaltextureobject.cpp @@ -76,6 +76,7 @@ LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) :  LLLocalTextureObject::~LLLocalTextureObject()  { +	delete_and_clear(mTexLayers);  }  LLGLTexture* LLLocalTextureObject::getImage() const diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 14bfb98629..70d8dfc8b9 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -288,25 +288,15 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl      return name;  } +namespace +{ +  #if LL_WINDOWS  static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific -U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, const std::string& name) +U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)  { -    // C++ exceptions were logged in toplevelTryWrapper, but not SEH -    // log SEH exceptions here, to make sure it gets into bugsplat's  -    // report and because __try won't allow std::string operations -    if (code != STATUS_MSC_EXCEPTION) -    { -        LL_WARNS() << "SEH crash in " << name << ", code: " << code << LL_ENDL; -    } -    // Handle bugsplat here, since GetExceptionInformation() can only be -    // called from within filter for __except(filter), not from __except's {} -    // Bugsplat should get all exceptions, C++ and SEH -    LLApp::instance()->reportCrashToBugsplat(exception_infop); - -    // Only convert non C++ exceptions.      if (code == STATUS_MSC_EXCEPTION)      {          // C++ exception, go on @@ -319,28 +309,38 @@ U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop,      }  } -void LLCoros::sehHandle(const std::string& name, const LLCoros::callable_t& callable) +void sehandle(const LLCoros::callable_t& callable)  {      __try      { -        LLCoros::toplevelTryWrapper(name, callable); +        callable();      } -    __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name)) +    __except (exception_filter(GetExceptionCode(), GetExceptionInformation()))      { -        // convert to C++ styled exception for handlers other than bugsplat +        // convert to C++ styled exception          // Note: it might be better to use _se_set_translator          // if you want exception to inherit full callstack -        // -        // in case of bugsplat this will get to exceptionTerminateHandler and -        // looks like fiber will terminate application after that          char integer_string[512]; -        sprintf(integer_string, "SEH crash in %s, code: %lu\n", name.c_str(), GetExceptionCode()); +        sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode());          throw std::exception(integer_string);      }  } -#endif -void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable) +#else  // ! LL_WINDOWS + +inline void sehandle(const LLCoros::callable_t& callable) +{ +    callable(); +} + +#endif // ! LL_WINDOWS + +} // anonymous namespace + +// Top-level wrapper around caller's coroutine callable. +// Normally we like to pass strings and such by const reference -- but in this +// case, we WANT to copy both the name and the callable to our local stack! +void LLCoros::toplevel(std::string name, callable_t callable)  {      // keep the CoroData on this top-level function's stack frame      CoroData corodata(name); @@ -350,12 +350,12 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call      // run the code the caller actually wants in the coroutine      try      { -        callable(); +        sehandle(callable);      }      catch (const Stop& exc)      {          LL_INFOS("LLCoros") << "coroutine " << name << " terminating because " -            << exc.what() << LL_ENDL; +                            << exc.what() << LL_ENDL;      }      catch (const LLContinueError&)      { @@ -366,36 +366,14 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call      }      catch (...)      { -#if LL_WINDOWS -        // Any OTHER kind of uncaught exception will cause the viewer to -        // crash, SEH handling should catch it and report to bugsplat. -        LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); -        // to not modify callstack -        throw; -#else          // Stash any OTHER kind of uncaught exception in the rethrow() queue          // to be rethrown by the main fiber.          LL_WARNS("LLCoros") << "Capturing uncaught exception in coroutine "                              << name << LL_ENDL;          LLCoros::instance().saveException(name, std::current_exception()); -#endif      }  } -// Top-level wrapper around caller's coroutine callable. -// Normally we like to pass strings and such by const reference -- but in this -// case, we WANT to copy both the name and the callable to our local stack! -void LLCoros::toplevel(std::string name, callable_t callable) -{ -#if LL_WINDOWS -    // Because SEH can's have unwinding, need to call a wrapper -    // 'try' is inside SEH handling to not catch LLContinue -    sehHandle(name, callable); -#else -    toplevelTryWrapper(name, callable); -#endif -} -  //static  void LLCoros::checkStop()  { diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index dbff921f16..966ce03296 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -307,11 +307,7 @@ public:  private:      std::string generateDistinctName(const std::string& prefix) const; -    void toplevelTryWrapper(const std::string& name, const callable_t& callable); -#if LL_WINDOWS -    void sehHandle(const std::string& name, const callable_t& callable); // calls toplevelTryWrapper -#endif -    void toplevel(std::string name, callable_t callable); // calls sehHandle or toplevelTryWrapper +    void toplevel(std::string name, callable_t callable);      struct CoroData;      static CoroData& get_CoroData(const std::string& caller);      void saveException(const std::string& name, std::exception_ptr exc); diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 8b4a0ee6d8..a510b73096 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -34,6 +34,9 @@  #include <iostream>  #include "apr_base64.h" +#include <boost/iostreams/device/array.hpp> +#include <boost/iostreams/stream.hpp> +  #ifdef LL_USESYSTEMLIBS  # include <zlib.h>  #else @@ -2128,7 +2131,9 @@ std::string zip_llsd(LLSD& data)  		{ //copy result into output  			if (strm.avail_out >= CHUNK)  			{ -				free(output); +				deflateEnd(&strm); +				if(output) +					free(output);  				LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;  				return std::string();  			} @@ -2151,7 +2156,9 @@ std::string zip_llsd(LLSD& data)  		}  		else   		{ -			free(output); +			deflateEnd(&strm); +			if(output) +				free(output);  			LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL;  			return std::string();  		} @@ -2162,7 +2169,8 @@ std::string zip_llsd(LLSD& data)  	std::string result((char*) output, size);  	deflateEnd(&strm); -	free(output); +	if(output) +		free(output);  	return result;  } @@ -2172,53 +2180,66 @@ std::string zip_llsd(LLSD& data)  // and deserializes from that copy using LLSDSerialize  LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, S32 size)  { +	std::unique_ptr<U8[]> in = std::unique_ptr<U8[]>(new(std::nothrow) U8[size]); +	if (!in) +	{ +		return ZR_MEM_ERROR; +	} +	is.read((char*) in.get(), size);  + +	return unzip_llsd(data, in.get(), size); +} + +LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32 size) +{  	U8* result = NULL;  	U32 cur_size = 0;  	z_stream strm; -	const U32 CHUNK = 65536; +	constexpr U32 CHUNK = 1024 * 512; -	U8 *in = new(std::nothrow) U8[size]; -	if (!in) +	static thread_local std::unique_ptr<U8[]> out; +	if (!out)  	{ -		return ZR_MEM_ERROR; +		out = std::unique_ptr<U8[]>(new(std::nothrow) U8[CHUNK]);  	} -	is.read((char*) in, size);  - -	U8 out[CHUNK];  	strm.zalloc = Z_NULL;  	strm.zfree = Z_NULL;  	strm.opaque = Z_NULL;  	strm.avail_in = size; -	strm.next_in = in; +	strm.next_in = const_cast<U8*>(in);  	S32 ret = inflateInit(&strm);  	do  	{  		strm.avail_out = CHUNK; -		strm.next_out = out; +		strm.next_out = out.get();  		ret = inflate(&strm, Z_NO_FLUSH); -		if (ret == Z_STREAM_ERROR) +		switch (ret) +		{ +		case Z_NEED_DICT: +		case Z_DATA_ERROR:  		{  			inflateEnd(&strm);  			free(result); -			delete [] in;  			return ZR_DATA_ERROR;  		} -		 -		switch (ret) +		case Z_STREAM_ERROR: +		case Z_BUF_ERROR:  		{ -		case Z_NEED_DICT: -			ret = Z_DATA_ERROR; -		case Z_DATA_ERROR: +			inflateEnd(&strm); +			free(result); +			return ZR_BUFFER_ERROR; +		} +  		case Z_MEM_ERROR: +		{  			inflateEnd(&strm);  			free(result); -			delete [] in;  			return ZR_MEM_ERROR; -			break; +		}  		}  		U32 have = CHUNK-strm.avail_out; @@ -2231,17 +2252,15 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,  			{  				free(result);  			} -			delete[] in;  			return ZR_MEM_ERROR;  		}  		result = new_result; -		memcpy(result+cur_size, out, have); +		memcpy(result+cur_size, out.get(), have);  		cur_size += have; -	} while (ret == Z_OK); +	} while (ret == Z_OK && ret != Z_STREAM_END);  	inflateEnd(&strm); -	delete [] in;  	if (ret != Z_STREAM_END)  	{ @@ -2251,37 +2270,11 @@ LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is,  	//result now points to the decompressed LLSD block  	{ -		std::istringstream istr; -		// Since we are using this for meshes, data we are dealing with tend to be large. -		// So string can potentially fail to allocate, make sure this won't cause problems -		try -		{ -			std::string res_str((char*)result, cur_size); - -			std::string deprecated_header("<? LLSD/Binary ?>"); - -			if (res_str.substr(0, deprecated_header.size()) == deprecated_header) -			{ -				res_str = res_str.substr(deprecated_header.size() + 1, cur_size); -			} -			cur_size = res_str.size(); - -			istr.str(res_str); -		} -#ifdef LL_WINDOWS -		catch (std::length_error) -		{ -			free(result); -			return ZR_SIZE_ERROR; -		} -#endif -		catch (std::bad_alloc&) -		{ -			free(result); -			return ZR_MEM_ERROR; -		} +		char* result_ptr = strip_deprecated_header((char*)result, cur_size); -		if (!LLSDSerialize::fromBinary(data, istr, cur_size, UNZIP_LLSD_MAX_DEPTH)) +		boost::iostreams::stream<boost::iostreams::array_source> istrm(result_ptr, cur_size); +		 +		if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH))  		{  			free(result);  			return ZR_PARSE_ERROR; @@ -2395,4 +2388,22 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32  	return result;  } +char* strip_deprecated_header(char* in, U32& cur_size, U32* header_size) +{ +	const char* deprecated_header = "<? LLSD/Binary ?>"; +	constexpr size_t deprecated_header_size = 17; + +	if (cur_size > deprecated_header_size +		&& memcmp(in, deprecated_header, deprecated_header_size) == 0) +	{ +		in = in + deprecated_header_size; +		cur_size = cur_size - deprecated_header_size; +		if (header_size) +		{ +			*header_size = deprecated_header_size + 1; +		} +	} + +	return in; +} diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index d6079fd9fa..d33d2b6f34 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -858,9 +858,12 @@ public:          ZR_SIZE_ERROR,          ZR_DATA_ERROR,          ZR_PARSE_ERROR, +		ZR_BUFFER_ERROR, +		ZR_VERSION_ERROR      } EZipRresult;      // return OK or reason for failure      static EZipRresult unzip_llsd(LLSD& data, std::istream& is, S32 size); +	static EZipRresult unzip_llsd(LLSD& data, const U8* in, S32 size);  };  //dirty little zip functions -- yell at davep @@ -868,4 +871,7 @@ LL_COMMON_API std::string zip_llsd(LLSD& data);  LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, unsigned int& 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);  #endif // LL_LLSDSERIALIZE_H diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 925da5674b..12985c3c7f 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -29,40 +29,41 @@  // this is defined so that we get static linking.  #include "openjpeg.h" +#include "event.h" +#include "cio.h" -#include "lltimer.h" -//#include "llmemory.h" +#define MAX_ENCODED_DISCARD_LEVELS 5  // Factory function: see declaration in llimagej2c.cpp  LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl()  { -	return new LLImageJ2COJ(); +    return new LLImageJ2COJ();  }  std::string LLImageJ2COJ::getEngineInfo() const  {  #ifdef OPENJPEG_VERSION -	return std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ") -		+ opj_version(); +    return std::string("OpenJPEG: " OPENJPEG_VERSION ", Runtime: ") +        + opj_version();  #else -	return std::string("OpenJPEG runtime: ") + opj_version(); +    return std::string("OpenJPEG runtime: ") + opj_version();  #endif  }  // Return string from message, eliminating final \n if present  static std::string chomp(const char* msg)  { -	// stomp trailing \n -	std::string message = msg; -	if (!message.empty()) -	{ -		size_t last = message.size() - 1; -		if (message[last] == '\n') -		{ -			message.resize( last ); -		} -	} -	return message; +    // stomp trailing \n +    std::string message = msg; +    if (!message.empty()) +    { +        size_t last = message.size() - 1; +        if (message[last] == '\n') +        { +            message.resize(last); +        } +} +    return message;  }  /** @@ -70,419 +71,770 @@ sample error callback expecting a LLFILE* client object  */  void error_callback(const char* msg, void*)  { -	LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; +    LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;  }  /**  sample warning callback expecting a LLFILE* client object  */  void warning_callback(const char* msg, void*)  { -	LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; +    LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;  }  /**  sample debug callback expecting no client object  */  void info_callback(const char* msg, void*)  { -	LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; +    LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL;  }  // Divide a by 2 to the power of b and round upwards  int ceildivpow2(int a, int b)  { -	return (a + (1 << b) - 1) >> b; +    return (a + (1 << b) - 1) >> b;  } - -LLImageJ2COJ::LLImageJ2COJ() -	: LLImageJ2CImpl() +class JPEG2KBase  { -} +public: +    JPEG2KBase() {} +    U8*        buffer = nullptr; +    OPJ_SIZE_T size = 0; +    OPJ_OFF_T  offset = 0; +}; -LLImageJ2COJ::~LLImageJ2COJ() +#define WANT_VERBOSE_OPJ_SPAM LL_DEBUG + +static void opj_info(const char* msg, void* user_data)  { +    llassert(user_data); +#if WANT_VERBOSE_OPJ_SPAM +    LL_INFOS("OpenJPEG") << msg << LL_ENDL; +#endif  } -bool LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region) +static void opj_warn(const char* msg, void* user_data)  { -	// No specific implementation for this method in the OpenJpeg case -	return false; +    llassert(user_data); +#if WANT_VERBOSE_OPJ_SPAM +    LL_WARNS("OpenJPEG") << msg << LL_ENDL; +#endif  } -bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels) +static void opj_error(const char* msg, void* user_data)  { -	// No specific implementation for this method in the OpenJpeg case -	return false; +    llassert(user_data); +#if WANT_VERBOSE_OPJ_SPAM +    LL_WARNS("OpenJPEG") << msg << LL_ENDL; +#endif  } -bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) +static OPJ_SIZE_T opj_read(void * buffer, OPJ_SIZE_T bytes, void* user_data)  { -	// -	// FIXME: Get the comment field out of the texture -	// - -	LLTimer decode_timer; - -	opj_dparameters_t parameters;	/* decompression parameters */ -	opj_event_mgr_t event_mgr;		/* event manager */ -	opj_image_t *image = NULL; - -	opj_dinfo_t* dinfo = NULL;	/* handle to a decompressor */ -	opj_cio_t *cio = NULL; - - -	/* configure the event callbacks (not required) */ -	memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); -	event_mgr.error_handler = error_callback; -	event_mgr.warning_handler = warning_callback; -	event_mgr.info_handler = info_callback; - -	/* set decoding parameters to default values */ -	opj_set_default_decoder_parameters(¶meters); - -	parameters.cp_reduce = base.getRawDiscardLevel(); - -	/* decode the code-stream */ -	/* ---------------------- */ - -	/* JPEG-2000 codestream */ - -	/* get a decoder handle */ -	dinfo = opj_create_decompress(CODEC_J2K); - -	/* catch events using our callbacks and give a local context */ -	opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);			 - -	/* setup the decoder decoding parameters using user parameters */ -	opj_setup_decoder(dinfo, ¶meters); - -	/* open a byte stream */ -	cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); - -	/* decode the stream and fill the image structure */ -	image = opj_decode(dinfo, cio); - -	/* close the byte stream */ -	opj_cio_close(cio); - -	/* free remaining structures */ -	if(dinfo) -	{ -		opj_destroy_decompress(dinfo); -	} - -	// The image decode failed if the return was NULL or the component -	// count was zero.  The latter is just a sanity check before we -	// dereference the array. -	if(!image || !image->numcomps) -	{ -		LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL; -		if (image) -		{ -			opj_image_destroy(image); -		} - -		return true; // done -	} - -	// sometimes we get bad data out of the cache - check to see if the decode succeeded -	for (S32 i = 0; i < image->numcomps; i++) -	{ -		if (image->comps[i].factor != base.getRawDiscardLevel()) -		{ -			// if we didn't get the discard level we're expecting, fail -			opj_image_destroy(image); -			base.mDecoding = false; -			return true; -		} -	} -	 -	if(image->numcomps <= first_channel) -	{ -		LL_WARNS() << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << LL_ENDL; -		if (image) -		{ -			opj_image_destroy(image); -		} -			 -		return true; -	} - -	// Copy image data into our raw image format (instead of the separate channel format - -	S32 img_components = image->numcomps; -	S32 channels = img_components - first_channel; -	if( channels > max_channel_count ) -		channels = max_channel_count; - -	// Component buffers are allocated in an image width by height buffer. -	// The image placed in that buffer is ceil(width/2^factor) by -	// ceil(height/2^factor) and if the factor isn't zero it will be at the -	// top left of the buffer with black filled in the rest of the pixels. -	// It is integer math so the formula is written in ceildivpo2. -	// (Assuming all the components have the same width, height and -	// factor.) -	S32 comp_width = image->comps[0].w; -	S32 f=image->comps[0].factor; -	S32 width = ceildivpow2(image->x1 - image->x0, f); -	S32 height = ceildivpow2(image->y1 - image->y0, f); -	raw_image.resize(width, height, channels); -	U8 *rawp = raw_image.getData(); - -	// first_channel is what channel to start copying from -	// dest is what channel to copy to.  first_channel comes from the -	// argument, dest always starts writing at channel zero. -	for (S32 comp = first_channel, dest=0; comp < first_channel + channels; -		comp++, dest++) -	{ -		if (image->comps[comp].data) -		{ -			S32 offset = dest; -			for (S32 y = (height - 1); y >= 0; y--) -			{ -				for (S32 x = 0; x < width; x++) -				{ -					rawp[offset] = image->comps[comp].data[y*comp_width + x]; -					offset += channels; -				} -			} -		} -		else // Some rare OpenJPEG versions have this bug. -		{ -			LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << LL_ENDL; -			opj_image_destroy(image); - -			return true; // done -		} -	} - -	/* free image data structure */ -	opj_image_destroy(image); - -	return true; // done +    llassert(user_data); +    JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data); +    OPJ_SIZE_T remainder = (jpeg_codec->size - jpeg_codec->offset); +    if (remainder <= 0) +    { +        jpeg_codec->offset = jpeg_codec->size; +        // Indicate end of stream (hacky?) +        return (OPJ_OFF_T)-1; +    } +    OPJ_SIZE_T to_read = llclamp(U32(bytes), U32(0), U32(remainder)); +    memcpy(buffer, jpeg_codec->buffer + jpeg_codec->offset, to_read); +    jpeg_codec->offset += to_read; +    return to_read;  } - -bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible) +static OPJ_SIZE_T opj_write(void * buffer, OPJ_SIZE_T bytes, void* user_data)  { -	const S32 MAX_COMPS = 5; -	opj_cparameters_t parameters;	/* compression parameters */ -	opj_event_mgr_t event_mgr;		/* event manager */ - - -	/*  -	configure the event callbacks (not required) -	setting of each callback is optional  -	*/ -	memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); -	event_mgr.error_handler = error_callback; -	event_mgr.warning_handler = warning_callback; -	event_mgr.info_handler = info_callback; - -	/* set encoding parameters to default values */ -	opj_set_default_encoder_parameters(¶meters); -	parameters.cod_format = 0; -	parameters.cp_disto_alloc = 1; - -	if (reversible) -	{ -		parameters.tcp_numlayers = 1; -		parameters.tcp_rates[0] = 0.0f; -	} -	else -	{ -		parameters.tcp_numlayers = 5; -                parameters.tcp_rates[0] = 1920.0f; -                parameters.tcp_rates[1] = 480.0f; -                parameters.tcp_rates[2] = 120.0f; -                parameters.tcp_rates[3] = 30.0f; -		parameters.tcp_rates[4] = 10.0f; -		parameters.irreversible = 1; -		if (raw_image.getComponents() >= 3) -		{ -			parameters.tcp_mct = 1; -		} -	} - -	if (!comment_text) -	{ -		parameters.cp_comment = (char *) ""; -	} -	else -	{ -		// Awful hacky cast, too lazy to copy right now. -		parameters.cp_comment = (char *) comment_text; -	} - -	// -	// Fill in the source image from our raw image -	// -	OPJ_COLOR_SPACE color_space = CLRSPC_SRGB; -	opj_image_cmptparm_t cmptparm[MAX_COMPS]; -	opj_image_t * image = NULL; -	S32 numcomps = raw_image.getComponents(); -	S32 width = raw_image.getWidth(); -	S32 height = raw_image.getHeight(); - -	memset(&cmptparm[0], 0, MAX_COMPS * sizeof(opj_image_cmptparm_t)); -	for(S32 c = 0; c < numcomps; c++) { -		cmptparm[c].prec = 8; -		cmptparm[c].bpp = 8; -		cmptparm[c].sgnd = 0; -		cmptparm[c].dx = parameters.subsampling_dx; -		cmptparm[c].dy = parameters.subsampling_dy; -		cmptparm[c].w = width; -		cmptparm[c].h = height; -	} - -	/* create the image */ -	image = opj_image_create(numcomps, &cmptparm[0], color_space); - -	image->x1 = width; -	image->y1 = height; - -	S32 i = 0; -	const U8 *src_datap = raw_image.getData(); -	for (S32 y = height - 1; y >= 0; y--) -	{ -		for (S32 x = 0; x < width; x++) -		{ -			const U8 *pixel = src_datap + (y*width + x) * numcomps; -			for (S32 c = 0; c < numcomps; c++) -			{ -				image->comps[c].data[i] = *pixel; -				pixel++; -			} -			i++; -		} -	} - - - -	/* encode the destination image */ -	/* ---------------------------- */ - -	int codestream_length; -	opj_cio_t *cio = NULL; - -	/* get a J2K compressor handle */ -	opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); - -	/* catch events using our callbacks and give a local context */ -	opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);			 - -	/* setup the encoder parameters using the current image and using user parameters */ -	opj_setup_encoder(cinfo, ¶meters, image); - -	/* open a byte stream for writing */ -	/* allocate memory for all tiles */ -	cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); - -	/* encode the image */ -	bool bSuccess = opj_encode(cinfo, cio, image, NULL); -	if (!bSuccess) -	{ -		opj_cio_close(cio); -		LL_DEBUGS("Texture") << "Failed to encode image." << LL_ENDL; -		return false; -	} -	codestream_length = cio_tell(cio); - -	base.copyData(cio->buffer, codestream_length); -	base.updateData(); // set width, height - -	/* close and free the byte stream */ -	opj_cio_close(cio); - -	/* free remaining compression structures */ -	opj_destroy_compress(cinfo); - - -	/* free user parameters structure */ -	if(parameters.cp_matrice) free(parameters.cp_matrice); - -	/* free image data */ -	opj_image_destroy(image); -	return true; +    llassert(user_data); +    JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data); +    OPJ_SIZE_T remainder = jpeg_codec->size - jpeg_codec->offset; +    if (remainder < bytes) +    { +        OPJ_SIZE_T new_size = jpeg_codec->size + (bytes - remainder); +        U8* new_buffer = (U8*)ll_aligned_malloc_16(new_size); +        memcpy(new_buffer, jpeg_codec->buffer, jpeg_codec->offset); +        U8* old_buffer = jpeg_codec->buffer; +        jpeg_codec->buffer = new_buffer; +        ll_aligned_free_16(old_buffer); +        jpeg_codec->size = new_size; +    } +    memcpy(jpeg_codec->buffer + jpeg_codec->offset, buffer, bytes); +    jpeg_codec->offset += bytes; +    return bytes;  } -bool LLImageJ2COJ::getMetadata(LLImageJ2C &base) +static OPJ_OFF_T opj_skip(OPJ_OFF_T bytes, void* user_data)  { -	// -	// FIXME: We get metadata by decoding the ENTIRE image. -	// - -	// Update the raw discard level -	base.updateRawDiscardLevel(); - -	opj_dparameters_t parameters;	/* decompression parameters */ -	opj_event_mgr_t event_mgr;		/* event manager */ -	opj_image_t *image = NULL; - -	opj_dinfo_t* dinfo = NULL;	/* handle to a decompressor */ -	opj_cio_t *cio = NULL; - - -	/* configure the event callbacks (not required) */ -	memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); -	event_mgr.error_handler = error_callback; -	event_mgr.warning_handler = warning_callback; -	event_mgr.info_handler = info_callback; - -	/* set decoding parameters to default values */ -	opj_set_default_decoder_parameters(¶meters); - -	// Only decode what's required to get the size data. -	parameters.cp_limit_decoding=LIMIT_TO_MAIN_HEADER; +    JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data); +    jpeg_codec->offset += bytes; + +    if (jpeg_codec->offset > jpeg_codec->size) +    { +        jpeg_codec->offset = jpeg_codec->size; +        // Indicate end of stream +        return (OPJ_OFF_T)-1; +    } + +    if (jpeg_codec->offset < 0) +    { +        // Shouldn't be possible? +        jpeg_codec->offset = 0; +        return (OPJ_OFF_T)-1; +    } + +    return bytes; +} -	//parameters.cp_reduce = mRawDiscardLevel; +static OPJ_BOOL opj_seek(OPJ_OFF_T bytes, void * user_data) +{ +    JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data); +    jpeg_codec->offset = bytes; +    jpeg_codec->offset = llclamp(U32(jpeg_codec->offset), U32(0), U32(jpeg_codec->size)); +    return OPJ_TRUE; +} -	/* decode the code-stream */ -	/* ---------------------- */ +static void opj_free_user_data(void * user_data) +{ +    JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data); +    // Don't free, data is managed externally +    jpeg_codec->buffer = nullptr; +    jpeg_codec->size = 0; +    jpeg_codec->offset = 0; +} -	/* JPEG-2000 codestream */ +static void opj_free_user_data_write(void * user_data) +{ +    JPEG2KBase* jpeg_codec = static_cast<JPEG2KBase*>(user_data); +    // Free, data was allocated here +    ll_aligned_free_16(jpeg_codec->buffer); +    jpeg_codec->buffer = nullptr; +    jpeg_codec->size = 0; +    jpeg_codec->offset = 0; +} -	/* get a decoder handle */ -	dinfo = opj_create_decompress(CODEC_J2K); +class JPEG2KDecode : public JPEG2KBase +{ +public: + +    JPEG2KDecode(S8 discardLevel) +    { +        memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); +        memset(¶meters, 0, sizeof(opj_dparameters_t)); +        event_mgr.error_handler = error_callback; +        event_mgr.warning_handler = warning_callback; +        event_mgr.info_handler = info_callback; +        opj_set_default_decoder_parameters(¶meters); +        parameters.cp_reduce = discardLevel; +    } + +    ~JPEG2KDecode() +    { +        if (decoder) +        { +            opj_destroy_codec(decoder); +        } +        decoder = nullptr; + +        if (image) +        { +            opj_image_destroy(image); +        } +        image = nullptr; + +        if (stream) +        { +            opj_stream_destroy(stream); +        } +        stream = nullptr; + +        if (codestream_info) +        { +            opj_destroy_cstr_info(&codestream_info); +        } +        codestream_info = nullptr; +    } + +    bool readHeader( +        U8* data, +        U32 dataSize, +        S32& widthOut, +        S32& heightOut, +        S32& components, +        S32& discard_level) +    { +        parameters.flags |= OPJ_DPARAMETERS_DUMP_FLAG; + +        decoder = opj_create_decompress(OPJ_CODEC_J2K); + +        if (!opj_setup_decoder(decoder, ¶meters)) +        { +            return false; +        } + +        if (stream) +        { +            opj_stream_destroy(stream); +        } + +        stream = opj_stream_create(dataSize, true); +        if (!stream) +        { +            return false; +        } + +        opj_stream_set_user_data(stream, this, opj_free_user_data); +        opj_stream_set_user_data_length(stream, dataSize); +        opj_stream_set_read_function(stream, opj_read); +        opj_stream_set_write_function(stream, opj_write); +        opj_stream_set_skip_function(stream, opj_skip); +        opj_stream_set_seek_function(stream, opj_seek); + +        buffer = data; +        size = dataSize; +        offset = 0; + +        // enable decoding partially loaded images +        opj_decoder_set_strict_mode(decoder, OPJ_FALSE); + +        /* Read the main header of the codestream and if necessary the JP2 boxes*/ +        if (!opj_read_header((opj_stream_t*)stream, decoder, &image)) +        { +            return false; +        } + +        codestream_info = opj_get_cstr_info(decoder); + +        if (!codestream_info) +        { +            return false; +        } + +        U32 tileDimX = codestream_info->tdx; +        U32 tileDimY = codestream_info->tdy; +        U32 tilesW = codestream_info->tw; +        U32 tilesH = codestream_info->th; + +        widthOut = S32(tilesW * tileDimX); +        heightOut = S32(tilesH * tileDimY); +        components = codestream_info->nbcomps; + +        discard_level = 0; +        while (tilesW > 1 && tilesH > 1 && discard_level < MAX_DISCARD_LEVEL) +        { +            discard_level++; +            tilesW >>= 1; +            tilesH >>= 1; +        } + +        return true; +    } + +    bool decode(U8* data, U32 dataSize, U32* channels, U8 discard_level) +    { +        parameters.flags &= ~OPJ_DPARAMETERS_DUMP_FLAG; + +        decoder = opj_create_decompress(OPJ_CODEC_J2K); +        opj_setup_decoder(decoder, ¶meters); + +        opj_set_info_handler(decoder, opj_info, this); +        opj_set_warning_handler(decoder, opj_warn, this); +        opj_set_error_handler(decoder, opj_error, this); + +        if (stream) +        { +            opj_stream_destroy(stream); +        } + +        stream = opj_stream_create(dataSize, true); +        if (!stream) +        { +            return false; +        } + +        opj_stream_set_user_data(stream, this, opj_free_user_data); +        opj_stream_set_user_data_length(stream, dataSize); +        opj_stream_set_read_function(stream, opj_read); +        opj_stream_set_write_function(stream, opj_write); +        opj_stream_set_skip_function(stream, opj_skip); +        opj_stream_set_seek_function(stream, opj_seek); + +        buffer = data; +        size = dataSize; +        offset = 0; + +        if (image) +        { +            opj_image_destroy(image); +            image = nullptr; +        } + +        // needs to happen before opj_read_header and opj_decode... +        opj_set_decoded_resolution_factor(decoder, discard_level); + +        // enable decoding partially loaded images +        opj_decoder_set_strict_mode(decoder, OPJ_FALSE); + +        if (!opj_read_header(stream, decoder, &image)) +        { +            return false; +        } + +        // needs to happen before decode which may fail +        if (channels) +        { +            *channels = image->numcomps; +        } + +        OPJ_BOOL decoded = opj_decode(decoder, stream, image); + +        // count was zero.  The latter is just a sanity check before we +        // dereference the array. +        if (!decoded || !image || !image->numcomps) +        { +            opj_end_decompress(decoder, stream); +            return false; +        } + +        opj_end_decompress(decoder, stream); + +        return true; +    } + +    opj_image_t* getImage() { return image; } + +private: +    opj_dparameters_t         parameters; +    opj_event_mgr_t           event_mgr; +    opj_image_t*              image = nullptr; +    opj_codec_t*              decoder = nullptr; +    opj_stream_t*             stream = nullptr; +    opj_codestream_info_v2_t* codestream_info = nullptr; +}; + +class JPEG2KEncode : public JPEG2KBase +{ +public: +    const OPJ_UINT32 TILE_SIZE = 64 * 64 * 3; + +    JPEG2KEncode(const char* comment_text_in, bool reversible) +    { +        memset(¶meters, 0, sizeof(opj_cparameters_t)); +        memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); +        event_mgr.error_handler = error_callback; +        event_mgr.warning_handler = warning_callback; +        event_mgr.info_handler = info_callback; + +        opj_set_default_encoder_parameters(¶meters); +        parameters.cod_format = OPJ_CODEC_J2K; +        parameters.cp_disto_alloc = 1; +        parameters.max_cs_size = (1 << 15); + +        if (reversible) +        { +            parameters.tcp_numlayers = 1; +            parameters.tcp_rates[0] = 1.0f; +        } +        else +        { +            parameters.tcp_numlayers = 5; +            parameters.tcp_rates[0] = 1920.0f; +            parameters.tcp_rates[1] = 960.0f; +            parameters.tcp_rates[2] = 480.0f; +            parameters.tcp_rates[3] = 120.0f; +            parameters.tcp_rates[4] = 30.0f; +            parameters.irreversible = 1; +            parameters.tcp_mct = 1; +        } + +        if (comment_text) +        { +            free(comment_text); +        } +        comment_text = comment_text_in ? strdup(comment_text_in) : nullptr; + +        parameters.cp_comment = comment_text ? comment_text : (char*)"no comment"; +        llassert(parameters.cp_comment); +    } + +    ~JPEG2KEncode() +    { +        if (encoder) +        { +            opj_destroy_codec(encoder); +        } +        encoder = nullptr; + +        if (image) +        { +            opj_image_destroy(image); +        } +        image = nullptr; + +        if (stream) +        { +            opj_stream_destroy(stream); +        } +        stream = nullptr; + +        if (comment_text) +        { +            free(comment_text); +        } +        comment_text = nullptr; +    } + +    bool encode(const LLImageRaw& rawImageIn, LLImageJ2C &compressedImageOut) +    { +        setImage(rawImageIn); + +        encoder = opj_create_compress(OPJ_CODEC_J2K); + +        parameters.tcp_mct = (image->numcomps >= 3) ? 1 : 0; +        parameters.cod_format = OPJ_CODEC_J2K; +        parameters.prog_order = OPJ_RLCP; +        parameters.cp_disto_alloc = 1; + +        if (!opj_setup_encoder(encoder, ¶meters, image)) +        { +            return false; +        } + +        opj_set_info_handler(encoder, opj_info, this); +        opj_set_warning_handler(encoder, opj_warn, this); +        opj_set_error_handler(encoder, opj_error, this); + +        U32 tile_count = (rawImageIn.getWidth() >> 6) * (rawImageIn.getHeight() >> 6); +        U32 data_size_guess = tile_count * TILE_SIZE; + +        // will be freed in opj_free_user_data_write +        buffer = (U8*)ll_aligned_malloc_16(data_size_guess); +        size = data_size_guess; +        offset = 0; + +        memset(buffer, 0, data_size_guess); + +        if (stream) +        { +            opj_stream_destroy(stream); +        } + +        stream = opj_stream_create(data_size_guess, false); +        if (!stream) +        { +            return false; +        } + +        opj_stream_set_user_data(stream, this, opj_free_user_data_write); +        opj_stream_set_user_data_length(stream, data_size_guess); +        opj_stream_set_read_function(stream, opj_read); +        opj_stream_set_write_function(stream, opj_write); +        opj_stream_set_skip_function(stream, opj_skip); +        opj_stream_set_seek_function(stream, opj_seek); + +        OPJ_BOOL started = opj_start_compress(encoder, image, stream); + +        if (!started) +        { +            return false; +        } + +        if (!opj_encode(encoder, stream)) +        { +            return false; +        } + +        OPJ_BOOL encoded = opj_end_compress(encoder, stream); + +        // if we successfully encoded, then stream out the compressed data... +        if (encoded) +        { +            // "append" (set) the data we "streamed" (memcopied) for writing to the formatted image +            // with side-effect of setting the actually encoded size  to same +            compressedImageOut.allocateData(offset); +            memcpy(compressedImageOut.getData(), buffer, offset); +            compressedImageOut.updateData(); // update width, height etc from header +        } +        return encoded; +    } + +    void setImage(const LLImageRaw& raw) +    { +        opj_image_cmptparm_t cmptparm[MAX_ENCODED_DISCARD_LEVELS]; +        memset(&cmptparm[0], 0, MAX_ENCODED_DISCARD_LEVELS * sizeof(opj_image_cmptparm_t)); + +        S32 numcomps = raw.getComponents(); +        S32 width = raw.getWidth(); +        S32 height = raw.getHeight(); + +        for (S32 c = 0; c < numcomps; c++) +        { +            cmptparm[c].prec = 8; +            cmptparm[c].bpp = 8; +            cmptparm[c].sgnd = 0; +            cmptparm[c].dx = parameters.subsampling_dx; +            cmptparm[c].dy = parameters.subsampling_dy; +            cmptparm[c].w = width; +            cmptparm[c].h = height; +        } + +        image = opj_image_create(numcomps, &cmptparm[0], OPJ_CLRSPC_SRGB); + +        image->x1 = width; +        image->y1 = height; + +        const U8 *src_datap = raw.getData(); + +        S32 i = 0; +        for (S32 y = height - 1; y >= 0; y--) +        { +            for (S32 x = 0; x < width; x++) +            { +                const U8 *pixel = src_datap + (y*width + x) * numcomps; +                for (S32 c = 0; c < numcomps; c++) +                { +                    image->comps[c].data[i] = *pixel; +                    pixel++; +                } +                i++; +            } +        } + +        // This likely works, but there seems to be an issue openjpeg side +        // check over after gixing that. + +        // De-interleave to component plane data +        /* +        switch (numcomps) +        { +        case 0: +        default: +            break; + +        case 1: +        { +            U32 rBitDepth = image->comps[0].bpp; +            U32 bytesPerPixel = rBitDepth >> 3; +            memcpy(image->comps[0].data, src, width * height * bytesPerPixel); +        } +        break; + +        case 2: +        { +            U32 rBitDepth = image->comps[0].bpp; +            U32 gBitDepth = image->comps[1].bpp; +            U32 totalBitDepth = rBitDepth + gBitDepth; +            U32 bytesPerPixel = totalBitDepth >> 3; +            U32 stride = width * bytesPerPixel; +            U32 offset = 0; +            for (S32 y = height - 1; y >= 0; y--) +            { +                const U8* component = src + (y * stride); +                for (S32 x = 0; x < width; x++) +                { +                    image->comps[0].data[offset] = *component++; +                    image->comps[1].data[offset] = *component++; +                    offset++; +                } +            } +        } +        break; + +        case 3: +        { +            U32 rBitDepth = image->comps[0].bpp; +            U32 gBitDepth = image->comps[1].bpp; +            U32 bBitDepth = image->comps[2].bpp; +            U32 totalBitDepth = rBitDepth + gBitDepth + bBitDepth; +            U32 bytesPerPixel = totalBitDepth >> 3; +            U32 stride = width * bytesPerPixel; +            U32 offset = 0; +            for (S32 y = height - 1; y >= 0; y--) +            { +                const U8* component = src + (y * stride); +                for (S32 x = 0; x < width; x++) +                { +                    image->comps[0].data[offset] = *component++; +                    image->comps[1].data[offset] = *component++; +                    image->comps[2].data[offset] = *component++; +                    offset++; +                } +            } +        } +        break; + + +        case 4: +        { +            U32 rBitDepth = image->comps[0].bpp; +            U32 gBitDepth = image->comps[1].bpp; +            U32 bBitDepth = image->comps[2].bpp; +            U32 aBitDepth = image->comps[3].bpp; + +            U32 totalBitDepth = rBitDepth + gBitDepth + bBitDepth + aBitDepth; +            U32 bytesPerPixel = totalBitDepth >> 3; + +            U32 stride = width * bytesPerPixel; +            U32 offset = 0; +            for (S32 y = height - 1; y >= 0; y--) +            { +                const U8* component = src + (y * stride); +                for (S32 x = 0; x < width; x++) +                { +                    image->comps[0].data[offset] = *component++; +                    image->comps[1].data[offset] = *component++; +                    image->comps[2].data[offset] = *component++; +                    image->comps[3].data[offset] = *component++; +                    offset++; +                } +            } +        } +        break; +        }*/ +    } + +    opj_image_t* getImage() { return image; } + +private: +    opj_cparameters_t   parameters; +    opj_event_mgr_t     event_mgr; +    opj_image_t*        image = nullptr; +    opj_codec_t*        encoder = nullptr; +    opj_stream_t*       stream = nullptr; +    char*               comment_text = nullptr; +}; -	/* catch events using our callbacks and give a local context */ -	opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, stderr);			 -	/* setup the decoder decoding parameters using user parameters */ -	opj_setup_decoder(dinfo, ¶meters); +LLImageJ2COJ::LLImageJ2COJ() +	: LLImageJ2CImpl() +{ +} -	/* open a byte stream */ -	cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); -	/* decode the stream and fill the image structure */ -	image = opj_decode(dinfo, cio); +LLImageJ2COJ::~LLImageJ2COJ() +{ +} -	/* close the byte stream */ -	opj_cio_close(cio); +bool LLImageJ2COJ::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level, int* region) +{ +    base.mDiscardLevel = discard_level; +	return false; +} -	/* free remaining structures */ -	if(dinfo) -	{ -		opj_destroy_decompress(dinfo); -	} +bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size, int precincts_size, int levels) +{ +	// No specific implementation for this method in the OpenJpeg case +	return false; +} -	if(!image) -	{ -		LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL; -		return false; -	} +bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) +{ +    JPEG2KDecode decoder(0); + +    U32 image_channels = 0; +    S32 data_size = base.getDataSize(); +    S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size); +    bool decoded = decoder.decode(base.getData(), max_bytes, &image_channels, base.mDiscardLevel); + +    // set correct channel count early so failed decodes don't miss it... +    S32 channels = (S32)image_channels - first_channel; +    channels = llmin(channels, max_channel_count); + +    if (!decoded) +    { +        // reset the channel count if necessary +        if (raw_image.getComponents() != channels) +        { +            raw_image.resize(raw_image.getWidth(), raw_image.getHeight(), S8(channels)); +        } + +        LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL; +        return true; // done +    } + +    opj_image_t *image = decoder.getImage(); + +    // Component buffers are allocated in an image width by height buffer. +    // The image placed in that buffer is ceil(width/2^factor) by +    // ceil(height/2^factor) and if the factor isn't zero it will be at the +    // top left of the buffer with black filled in the rest of the pixels. +    // It is integer math so the formula is written in ceildivpo2. +    // (Assuming all the components have the same width, height and +    // factor.) +    U32 comp_width = image->comps[0].w; // leave this unshifted by 'f' discard factor, the strides are always for the full buffer width +    U32 f = image->comps[0].factor; + +    // do size the texture to the mem we'll acrually use... +    U32 width = image->comps[0].w; +    U32 height = image->comps[0].h; + +    raw_image.resize(U16(width), U16(height), S8(channels)); + +    U8 *rawp = raw_image.getData(); + +    // first_channel is what channel to start copying from +    // dest is what channel to copy to.  first_channel comes from the +    // argument, dest always starts writing at channel zero. +    for (S32 comp = first_channel, dest = 0; comp < first_channel + channels; comp++, dest++) +    { +        llassert(image->comps[comp].data); +        if (image->comps[comp].data) +        { +            S32 offset = dest; +            for (S32 y = (height - 1); y >= 0; y--) +            { +                for (S32 x = 0; x < width; x++) +                { +                    rawp[offset] = image->comps[comp].data[y*comp_width + x]; +                    offset += channels; +                } +            } +        } +        else // Some rare OpenJPEG versions have this bug. +        { +            LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed! (OpenJPEG bug)" << LL_ENDL; +        } +    } + +    base.setDiscardLevel(f); + +    return true; // done +} -	// Copy image data into our raw image format (instead of the separate channel format -	S32 width = 0; -	S32 height = 0; -	S32 img_components = image->numcomps; -	width = image->x1 - image->x0; -	height = image->y1 - image->y0; -	base.setSize(width, height, img_components); +bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time, bool reversible) +{ +    JPEG2KEncode encode(comment_text, reversible); +    bool encoded = encode.encode(raw_image, base); +    if (encoded) +    { +        LL_WARNS() << "Openjpeg encoding implementation isn't complete, returning false" << LL_ENDL; +    } +    return encoded; +    //return false; +} -	/* free image data structure */ -	opj_image_destroy(image); -	return true; +bool LLImageJ2COJ::getMetadata(LLImageJ2C &base) +{ +    JPEG2KDecode decode(0); + +    S32 width = 0; +    S32 height = 0; +    S32 components = 0; +    S32 discard_level = 0; + +    U32 dataSize = base.getDataSize(); +    U8* data = base.getData(); +    bool header_read = decode.readHeader(data, dataSize, width, height, components, discard_level); +    if (!header_read) +    { +        return false; +    } + +    base.mDiscardLevel = discard_level; +    base.setSize(width, height, components); +    return true;  } diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index f43d07ce5e..b0f28fd2be 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2386,7 +2386,25 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)  		LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL;  		return false;  	} -	 +	return unpackVolumeFacesInternal(mdl); +} + +bool LLVolume::unpackVolumeFaces(U8* in_data, S32 size) +{ +	//input data is now pointing at a zlib compressed block of LLSD +	//decompress block +	LLSD mdl; +	U32 uzip_result = LLUZipHelper::unzip_llsd(mdl, in_data, size); +	if (uzip_result != LLUZipHelper::ZR_OK) +	{ +		LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD with code " << uzip_result << " , will probably fetch from sim again." << LL_ENDL; +		return false; +	} +	return unpackVolumeFacesInternal(mdl); +} + +bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) +{  	{  		U32 face_count = mdl.size(); diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 3ccaed47f1..1509241623 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -1101,8 +1101,12 @@ protected:  	BOOL generate();  	void createVolumeFaces();  public: -	virtual bool unpackVolumeFaces(std::istream& is, S32 size); +	bool unpackVolumeFaces(std::istream& is, S32 size); +	bool unpackVolumeFaces(U8* in_data, S32 size); +private: +	bool unpackVolumeFacesInternal(const LLSD& mdl); +public:  	virtual void setMeshAssetLoaded(BOOL loaded);  	virtual BOOL isMeshAssetLoaded(); diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 805af55299..765a8cda22 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -1386,6 +1386,16 @@ LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin):  	fromLLSD(skin);  } +LLMeshSkinInfo::LLMeshSkinInfo(const LLUUID& mesh_id, LLSD& skin) : +	mMeshID(mesh_id), +	mPelvisOffset(0.0), +	mLockScaleIfJointPosition(false), +	mInvalidJointsScrubbed(false), +	mJointNumsInitialized(false) +{ +	fromLLSD(skin); +} +  void LLMeshSkinInfo::fromLLSD(LLSD& skin)  {  	if (skin.has("joint_names")) diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index a6ab96ab18..9c99bb75a0 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -41,12 +41,13 @@ class domMesh;  #define MAX_MODEL_FACES 8  LL_ALIGN_PREFIX(16) -class LLMeshSkinInfo  +class LLMeshSkinInfo : public LLRefCount  {      LL_ALIGN_NEW  public:  	LLMeshSkinInfo();  	LLMeshSkinInfo(LLSD& data); +	LLMeshSkinInfo(const LLUUID& mesh_id, LLSD& data);  	void fromLLSD(LLSD& data);  	LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const;      void updateHash(); diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 5e00bf7f45..b13e7389cc 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -505,6 +505,17 @@ LLFlatListView::LLFlatListView(const LLFlatListView::Params& p)  	}  }; +LLFlatListView::~LLFlatListView() +{ +	for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) +	{ +		mItemsPanel->removeChild((*it)->first); +		(*it)->first->die(); +		delete *it; +	} +	mItemPairs.clear(); +} +  // virtual  void LLFlatListView::draw()  { diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h index 230ea200d8..d47c1cf333 100644 --- a/indra/llui/llflatlistview.h +++ b/indra/llui/llflatlistview.h @@ -299,6 +299,7 @@ public:  	virtual S32	notify(const LLSD& info) ; +	virtual ~LLFlatListView();  protected:  	/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */ diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index ea2ca68e47..e1869e8125 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -163,6 +163,7 @@ LLFolderView::LLFolderView(const Params& p)  :	LLFolderViewFolder(p),  	mScrollContainer( NULL ),  	mPopupMenuHandle(), +	mMenuFileName(p.options_menu),  	mAllowMultiSelect(p.allow_multiselect),  	mAllowDrag(p.allow_drag),  	mShowEmptyMessage(p.show_empty_message), @@ -182,6 +183,7 @@ LLFolderView::LLFolderView(const Params& p)  	mMinWidth(0),  	mDragAndDropThisFrame(FALSE),  	mCallbackRegistrar(NULL), +	mEnableRegistrar(NULL),  	mUseEllipses(p.use_ellipses),  	mDraggingOverItem(NULL),  	mStatusTextBox(NULL), @@ -244,17 +246,6 @@ LLFolderView::LLFolderView(const Params& p)  	mStatusTextBox->setFollowsTop();  	addChild(mStatusTextBox); - -	// make the popup menu available -	llassert(LLMenuGL::sMenuContainer != NULL); -	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(p.options_menu, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); -	if (!menu) -	{ -		menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu"); -	} -	menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); -	mPopupMenuHandle = menu->getHandle(); -  	mViewModelItem->openItem();  	mAreChildrenInited = true; // root folder is a special case due to not being loaded normally, assume that it's inited. @@ -276,6 +267,7 @@ LLFolderView::~LLFolderView( void )  	mStatusTextBox = NULL;  	if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); +	mPopupMenuHandle.markDead();  	mAutoOpenItems.removeAllNodes();  	clearSelection(); @@ -1438,22 +1430,56 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )  	BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL;  	S32 count = mSelectedItems.size(); -	LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); +	LLMenuGL* menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); +	if (!menu) +	{ +		if (mCallbackRegistrar) +		{ +			mCallbackRegistrar->pushScope(); +		} +		if (mEnableRegistrar) +		{ +			mEnableRegistrar->pushScope(); +		} +		llassert(LLMenuGL::sMenuContainer != NULL); +		menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(mMenuFileName, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); +		if (!menu) +		{ +			menu = LLUICtrlFactory::getDefaultWidget<LLMenuGL>("inventory_menu"); +		} +		menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); +		mPopupMenuHandle = menu->getHandle(); +		if (mEnableRegistrar) +		{ +			mEnableRegistrar->popScope(); +		} +		if (mCallbackRegistrar) +		{ +			mCallbackRegistrar->popScope(); +		} +	}  	bool hide_folder_menu = mSuppressFolderMenu && isFolderSelected(); -	if ((handled -		&& ( count > 0 && (hasVisibleChildren()) ) // show menu only if selected items are visible -		&& menu ) && +	if (menu && (handled +		&& ( count > 0 && (hasVisibleChildren()) )) && // show menu only if selected items are visible  		!hide_folder_menu)  	{  		if (mCallbackRegistrar)          {  			mCallbackRegistrar->pushScope();          } +		if (mEnableRegistrar) +		{ +			mEnableRegistrar->pushScope(); +		}  		updateMenuOptions(menu);  		menu->updateParent(LLMenuGL::sMenuContainer);  		LLMenuGL::showPopup(this, menu, x, y); +		if (mEnableRegistrar) +		{ +			mEnableRegistrar->popScope(); +		}  		if (mCallbackRegistrar)          {  			mCallbackRegistrar->popScope(); @@ -1531,7 +1557,7 @@ void LLFolderView::deleteAllChildren()  {  	closeRenamer();  	if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); -	mPopupMenuHandle = LLHandle<LLView>(); +	mPopupMenuHandle.markDead();  	mScrollContainer = NULL;  	mRenameItem = NULL;  	mRenamer = NULL; diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 6bb5e6c02e..7dfa04828a 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -235,6 +235,7 @@ public:  	bool showItemLinkOverlays() { return mShowItemLinkOverlays; }  	void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; } +	void setEnableRegistrar(LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* registrar) { mEnableRegistrar = registrar; }  	LLPanel* getParentPanel() { return mParentPanel.get(); }  	// DEBUG only @@ -272,6 +273,7 @@ protected:  protected:  	LLHandle<LLView>					mPopupMenuHandle; +	std::string						mMenuFileName;  	selected_items_t				mSelectedItems;  	bool							mKeyboardSelection, @@ -327,6 +329,7 @@ protected:  	LLFolderViewItem*				mDraggingOverItem; // See EXT-719  	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar; +	LLUICtrl::EnableCallbackRegistry::ScopedRegistrar* mEnableRegistrar;  public:  	static F32 sAutoOpenTime; diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index 093e213be3..dd5eb47a63 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -419,21 +419,15 @@ public:  		mFilter(filter)  	{} -	virtual ~LLFolderViewModel()  -	{ -		delete mSorter; -		mSorter = NULL; -		delete mFilter; -		mFilter = NULL; -	} +	virtual ~LLFolderViewModel() {}  	virtual SortType& getSorter()					 { return *mSorter; }  	virtual const SortType& getSorter() const 		 { return *mSorter; } -	virtual void setSorter(const SortType& sorter) 	 { mSorter = new SortType(sorter); requestSortAll(); } +	virtual void setSorter(const SortType& sorter) 	 { mSorter.reset(new SortType(sorter)); requestSortAll(); }  	virtual FilterType& getFilter() 				 { return *mFilter; }  	virtual const FilterType& getFilter() const		 { return *mFilter; } -	virtual void setFilter(const FilterType& filter) { mFilter = new FilterType(filter); } +	virtual void setFilter(const FilterType& filter) { mFilter.reset(new FilterType(filter)); }  	// By default, we assume the content is available. If a network fetch mechanism is implemented for the model,  	// this method needs to be overloaded and return the relevant fetch status. @@ -471,8 +465,8 @@ public:  	}  protected: -	SortType*		mSorter; -	FilterType*		mFilter; +	std::unique_ptr<SortType>		mSorter; +	std::unique_ptr<FilterType>		mFilter;  };  #endif // LLFOLDERVIEWMODEL_H diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 33037b5001..f16f8c3e8d 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -209,13 +209,6 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)  	setPrevalidateInput(p.prevalidate_input_callback());  	setPrevalidate(p.prevalidate_callback()); - -	llassert(LLMenuGL::sMenuContainer != NULL); -	LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu> -		("menu_text_editor.xml", -		 LLMenuGL::sMenuContainer, -		 LLMenuHolderGL::child_registry_t::instance()); -	setContextMenu(menu);  }  LLLineEditor::~LLLineEditor() @@ -2637,6 +2630,15 @@ LLWString LLLineEditor::getConvertedText() const  void LLLineEditor::showContextMenu(S32 x, S32 y)  {  	LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); +	if (!menu) +	{ +		llassert(LLMenuGL::sMenuContainer != NULL); +		menu = LLUICtrlFactory::createFromFile<LLContextMenu> +			("menu_text_editor.xml", +				LLMenuGL::sMenuContainer, +				LLMenuHolderGL::child_registry_t::instance()); +		setContextMenu(menu); +	}  	if (menu)  	{ diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 4264028338..5cb840fd61 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -4087,25 +4087,39 @@ void LLTearOffMenu::closeTearOff()  }  LLContextMenuBranch::LLContextMenuBranch(const LLContextMenuBranch::Params& p)  -:	LLMenuItemGL(p), -	mBranch( p.branch()->getHandle() ) +:	LLMenuItemGL(p)  { -	mBranch.get()->hide(); -	mBranch.get()->setParentMenuItem(this); +	LLContextMenu* branch = static_cast<LLContextMenu*>(p.branch); +	if (branch) +	{ +		mBranch = branch->getHandle(); +		branch->hide(); +		branch->setParentMenuItem(this); +	} +} + +LLContextMenuBranch::~LLContextMenuBranch() +{ +	if (mBranch.get()) +	{ +		mBranch.get()->die(); +	}  }  // called to rebuild the draw label  void LLContextMenuBranch::buildDrawLabel( void )  { +	auto menu = getBranch(); +	if (menu)  	{  		// default enablement is this -- if any of the subitems are  		// enabled, this item is enabled. JC -		U32 sub_count = mBranch.get()->getItemCount(); +		U32 sub_count = menu->getItemCount();  		U32 i;  		BOOL any_enabled = FALSE;  		for (i = 0; i < sub_count; i++)  		{ -			LLMenuItemGL* item = mBranch.get()->getItem(i); +			LLMenuItemGL* item = menu->getItem(i);  			item->buildDrawLabel();  			if (item->getEnabled() && !item->getDrawTextDisabled() )  			{ @@ -4127,13 +4141,17 @@ void LLContextMenuBranch::buildDrawLabel( void )  void	LLContextMenuBranch::showSubMenu()  { -	LLMenuItemGL* menu_item = mBranch.get()->getParentMenuItem(); -	if (menu_item != NULL && menu_item->getVisible()) +	auto menu = getBranch(); +	if(menu)  	{ -		S32 center_x; -		S32 center_y; -		localPointToScreen(getRect().getWidth(), getRect().getHeight() , ¢er_x, ¢er_y); -		mBranch.get()->show(center_x, center_y); +		LLMenuItemGL* menu_item = menu->getParentMenuItem(); +		if (menu_item != NULL && menu_item->getVisible()) +		{ +			S32 center_x; +			S32 center_y; +			localPointToScreen(getRect().getWidth(), getRect().getHeight(), ¢er_x, ¢er_y); +			menu->show(center_x, center_y); +		}  	}  } @@ -4147,13 +4165,17 @@ void LLContextMenuBranch::setHighlight( BOOL highlight )  {  	if (highlight == getHighlight()) return;  	LLMenuItemGL::setHighlight(highlight); -	if( highlight ) -	{ -		showSubMenu(); -	} -	else +	auto menu = getBranch(); +	if (menu)  	{ -		mBranch.get()->hide(); +		if (highlight) +		{ +			showSubMenu(); +		} +		else +		{ +			menu->hide(); +		}  	}  } diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index abbfd9a24a..f84c4d41eb 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -745,8 +745,7 @@ public:  	LLContextMenuBranch(const Params&); -	virtual ~LLContextMenuBranch() -	{} +	virtual ~LLContextMenuBranch();  	// called to rebuild the draw label  	virtual void	buildDrawLabel( void ); diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 65c7b420ce..167593bd52 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -196,7 +196,6 @@ LLScrollListCtrl::LLScrollListCtrl(const LLScrollListCtrl::Params& p)  	mHighlightedItem(-1),  	mBorder(NULL),  	mSortCallback(NULL), -	mPopupMenu(NULL),  	mCommentTextView(NULL),  	mNumDynamicWidthColumns(0),  	mTotalStaticColumnWidth(0), @@ -348,6 +347,13 @@ LLScrollListCtrl::~LLScrollListCtrl()  	mItemList.clear();      clearColumns(); //clears columns and deletes headers  	delete mIsFriendSignal; + +	auto menu = mPopupMenuHandle.get(); +	if (menu) +	{ +		menu->die(); +		mPopupMenuHandle.markDead(); +	}  } @@ -1997,17 +2003,23 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)  			// create the context menu from the XUI file and display it  			std::string menu_name = is_group ? "menu_url_group.xml" : "menu_url_agent.xml"; -			delete mPopupMenu; +			auto menu = mPopupMenuHandle.get(); +			if (menu) +			{ +				menu->die(); +				mPopupMenuHandle.markDead(); +			}  			llassert(LLMenuGL::sMenuContainer != NULL); -			mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( +			menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(  				menu_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance()); -			if (mPopupMenu) +			if (menu)  			{ +				mPopupMenuHandle = menu->getHandle();  				if (mIsFriendSignal)  				{  					bool isFriend = *(*mIsFriendSignal)(uuid); -					LLView* addFriendButton = mPopupMenu->getChild<LLView>("add_friend"); -					LLView* removeFriendButton = mPopupMenu->getChild<LLView>("remove_friend"); +					LLView* addFriendButton = menu->getChild<LLView>("add_friend"); +					LLView* removeFriendButton = menu->getChild<LLView>("remove_friend");  					if (addFriendButton && removeFriendButton)  					{ @@ -2016,8 +2028,8 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)  					}  				} -				mPopupMenu->show(x, y); -				LLMenuGL::showPopup(this, mPopupMenu, x, y); +				menu->show(x, y); +				LLMenuGL::showPopup(this, menu, x, y);  				return TRUE;  			}  		} diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 77d10fdec7..6f7d4768e1 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -526,7 +526,7 @@ private:  	S32				mHighlightedItem;  	class LLViewBorder*	mBorder; -	LLContextMenu	*mPopupMenu; +	LLHandle<LLContextMenu>	mPopupMenuHandle;  	LLView			*mCommentTextView; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 7e4aaa53bf..fcfdd64e6a 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -273,6 +273,12 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)  LLTextBase::~LLTextBase()  {  	mSegments.clear(); +	LLContextMenu* menu = static_cast<LLContextMenu*>(mPopupMenuHandle.get()); +	if (menu) +	{ +		menu->die(); +		mPopupMenuHandle.markDead(); +	}  	delete mURLClickSignal;  	delete mIsFriendSignal;  	delete mIsObjectBlockedSignal; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index b1f8b00cab..3d2a426913 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -257,7 +257,6 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :  	mMouseDownY(0),  	mTabsToNextField(p.ignore_tab),  	mPrevalidateFunc(p.prevalidate_callback()), -	mContextMenu(NULL),  	mShowContextMenu(p.show_context_menu),  	mEnableTooltipPaste(p.enable_tooltip_paste),  	mPassDelete(FALSE), @@ -301,8 +300,13 @@ LLTextEditor::~LLTextEditor()  	// Scrollbar is deleted by LLView  	std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer());  	mUndoStack.clear(); -	// context menu is owned by menu holder, not us -	//delete mContextMenu; +	// Mark the menu as dead or its retained in memory till shutdown. +	LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); +	if(menu) +	{ +		menu->die(); +		mContextMenuHandle.markDead(); +	}  }  //////////////////////////////////////////////////////////// @@ -2051,12 +2055,19 @@ void LLTextEditor::setEnabled(BOOL enabled)  void LLTextEditor::showContextMenu(S32 x, S32 y)  { -	if (!mContextMenu) +	LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); +	if (!menu)  	{  		llassert(LLMenuGL::sMenuContainer != NULL); -		mContextMenu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_text_editor.xml",  +		menu = LLUICtrlFactory::createFromFile<LLContextMenu>("menu_text_editor.xml",   																				LLMenuGL::sMenuContainer,   																				LLMenuHolderGL::child_registry_t::instance()); +        if(!menu) +        { +            LL_WARNS() << "Failed to create menu for LLTextEditor: " << getName() << LL_ENDL; +            return; +        } +		mContextMenuHandle = menu->getHandle();  	}  	// Route menu to this class @@ -2102,11 +2113,11 @@ void LLTextEditor::showContextMenu(S32 x, S32 y)  		}  	} -	mContextMenu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); -	mContextMenu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); -	mContextMenu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); -	mContextMenu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); -	mContextMenu->show(screen_x, screen_y, this); +	menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); +	menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); +	menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); +	menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); +	menu->show(screen_x, screen_y, this);  } diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 1a10d2fd1e..f3939248c2 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -329,7 +329,7 @@ private:  	keystroke_signal_t mKeystrokeSignal;  	LLTextValidate::validate_func_t mPrevalidateFunc; -	LLContextMenu* mContextMenu; +	LLHandle<LLContextMenu> mContextMenuHandle;  }; // end class LLTextEditor  // Build time optimization, generate once in .cpp file diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index 5150df25f2..2707f7a15c 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -127,7 +127,12 @@ LLToolBar::LLToolBar(const LLToolBar::Params& p)  LLToolBar::~LLToolBar()  { -	delete mPopupMenuHandle.get(); +	auto menu = mPopupMenuHandle.get(); +	if (menu) +	{ +		menu->die(); +		mPopupMenuHandle.markDead(); +	}  	delete mButtonAddSignal;  	delete mButtonEnterSignal;  	delete mButtonLeaveSignal; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7d78ec9e3c..4fe83f0c45 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1825,9 +1825,9 @@ if (WINDOWS)        ${SHARED_LIB_STAGING_DIR}/Release/libcollada14dom22.dll        ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libcollada14dom22.dll        ${SHARED_LIB_STAGING_DIR}/Debug/libcollada14dom22-d.dll -      ${SHARED_LIB_STAGING_DIR}/Release/openjpeg.dll -      ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjpeg.dll -      ${SHARED_LIB_STAGING_DIR}/Debug/openjpegd.dll +      ${SHARED_LIB_STAGING_DIR}/Release/openjp2.dll +      ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjp2.dll +      ${SHARED_LIB_STAGING_DIR}/Debug/openjp2.dll        ${SHARED_LIB_STAGING_DIR}/Release/libhunspell.dll        ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libhunspell.dll        ${SHARED_LIB_STAGING_DIR}/Debug/libhunspell.dll diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl index 331249dc33..de22312d3c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl @@ -25,6 +25,17 @@  /*[EXTRA_CODE_HERE]*/ +// Inputs +VARYING vec4 vary_HazeColor; +VARYING float vary_LightNormPosDot; + +uniform sampler2D rainbow_map; +uniform sampler2D halo_map; + +uniform float moisture_level; +uniform float droplet_radius; +uniform float ice_level; +  #ifdef DEFINE_GL_FRAGCOLOR  out vec4 frag_data[3];  #else @@ -35,11 +46,34 @@ out vec4 frag_data[3];  // The fragment shader for the sky  ///////////////////////////////////////////////////////////////////////// -VARYING vec4 vary_HazeColor; +vec3 rainbow(float d) +{ +    // 'Interesting' values of d are -0.75 .. -0.825, i.e. when view vec nearly opposite of sun vec +    // Rainbox tex is mapped with REPEAT, so -.75 as tex coord is same as 0.25.  -0.825 -> 0.175. etc. +    // SL-13629 +    // Unfortunately the texture is inverted, so we need to invert the y coord, but keep the 'interesting' +    // part within the same 0.175..0.250 range, i.e. d = (1 - d) - 1.575 +    d         = clamp(-0.575 - d, 0.0, 1.0); + +    // With the colors in the lower 1/4 of the texture, inverting the coords leaves most of it inaccessible. +    // So, we can stretch the texcoord above the colors (ie > 0.25) to fill the entire remaining coordinate +    // space. This improves gradation, reduces banding within the rainbow interior. (1-0.25) / (0.425/0.25) = 4.2857 +    float interior_coord = max(0.0, d - 0.25) * 4.2857; +    d = clamp(d, 0.0, 0.25) + interior_coord; + +    float rad = (droplet_radius - 5.0f) / 1024.0f; +    return pow(texture2D(rainbow_map, vec2(rad+0.5, d)).rgb, vec3(1.8)) * moisture_level; +} + +vec3 halo22(float d) +{ +    d       = clamp(d, 0.1, 1.0); +    float v = sqrt(clamp(1 - (d * d), 0, 1)); +    return texture2D(halo_map, vec2(0, v)).rgb * ice_level; +}  /// Soft clips the light with a gamma correction  vec3 scaleSoftClip(vec3 light); -vec3 srgb_to_linear(vec3 c);  void main()  { @@ -48,14 +82,18 @@ void main()      // the fragment) if the sky wouldn't show up because the clouds       // are fully opaque. -    vec4 color; -    color = vary_HazeColor; +    vec4 color = vary_HazeColor; +    float  rel_pos_lightnorm = vary_LightNormPosDot; +    float optic_d = rel_pos_lightnorm; +    vec3  halo_22 = halo22(optic_d); +    color.rgb += rainbow(optic_d); +    color.rgb += halo_22;      color.rgb *= 2.;      color.rgb = scaleSoftClip(color.rgb); -    /// Gamma correct for WL (soft clip effect). -    frag_data[0] = vec4(color.rgb, 0.0); +    // Gamma correct for WL (soft clip effect). +    frag_data[0] = vec4(color.rgb, 1.0);      frag_data[1] = vec4(0.0,0.0,0.0,0.0);      frag_data[2] = vec4(0.0,0.0,0.0,1.0); //1.0 in norm.w masks off fog diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl index 28a1faf24f..6db4690bff 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl @@ -33,6 +33,7 @@ ATTRIBUTE vec3 position;  // Output parameters  VARYING vec4 vary_HazeColor; +VARYING float vary_LightNormPosDot;  // Inputs  uniform vec3 camPosLocal; @@ -72,27 +73,29 @@ void main()      vec3 rel_pos = position.xyz - camPosLocal.xyz + vec3(0, 50, 0);      // Adj position vector to clamp altitude -    if (rel_pos.y > 0) +    if (rel_pos.y > 0.)      {          rel_pos *= (max_y / rel_pos.y);      } -    if (rel_pos.y < 0) +    if (rel_pos.y < 0.)      {          rel_pos *= (-32000. / rel_pos.y);      } -    // Can normalize then -    vec3 rel_pos_norm = normalize(rel_pos); +    // Normalized +    vec3  rel_pos_norm = normalize(rel_pos); +    float rel_pos_len  = length(rel_pos); -    float rel_pos_len = length(rel_pos); +    // Grab this value and pass to frag shader for rainbows +    float rel_pos_lightnorm_dot = dot(rel_pos_norm, lightnorm.xyz); +    vary_LightNormPosDot = rel_pos_lightnorm_dot;      // Initialize temp variables      vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_color; -    vec4 light_atten;      // Sunlight attenuation effect (hue and brightness) due to atmosphere      // this is used later for sunlight modulation at various altitudes -    light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y); +    vec4 light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y);      // Calculate relative weights      vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density)); @@ -112,7 +115,7 @@ void main()      combined_haze = exp(-combined_haze * density_dist);      // Compute haze glow -    float haze_glow = 1.0 - dot(rel_pos_norm, lightnorm.xyz); +    float haze_glow = 1.0 - rel_pos_lightnorm_dot;      // haze_glow is 0 at the sun and increases away from sun      haze_glow = max(haze_glow, .001);      // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) @@ -123,30 +126,30 @@ void main()      // Add "minimum anti-solar illumination"      // For sun, add to glow.  For moon, remove glow entirely. SL-13768 -    haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (haze_glow + 0.25); +    haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (sun_moon_glow_factor * (haze_glow + 0.25)); -    vec4 color = -        (blue_horizon * blue_weight * (sunlight + ambient_color) + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient_color)); +    // Haze color above cloud +    vec4 color = (blue_horizon * blue_weight * (sunlight + ambient_color) +               + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient_color));      // Final atmosphere additive      color *= (1. - combined_haze);      // Increase ambient when there are more clouds -    vec4 tmpAmbient = ambient_color; -    tmpAmbient += max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5; +    vec4 ambient = ambient_color + max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5;      // Dim sunlight by cloud shadow percentage      sunlight *= max(0.0, (1. - cloud_shadow));      // Haze color below cloud -    vec4 additiveColorBelowCloud = -        (blue_horizon * blue_weight * (sunlight + tmpAmbient) + (haze_horizon * haze_weight) * (sunlight * haze_glow + tmpAmbient)); +    vec4 add_below_cloud = (blue_horizon * blue_weight * (sunlight + ambient)  +                         + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient));      // Attenuate cloud color by atmosphere      combined_haze = sqrt(combined_haze);  // less atmos opacity (more transparency) below clouds      // At horizon, blend high altitude sky color towards the darker color below the clouds -    color += (additiveColorBelowCloud - color) * (1. - sqrt(combined_haze)); +    color += (add_below_cloud - color) * (1. - sqrt(combined_haze));      // Haze color above cloud      vary_HazeColor = color; diff --git a/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl deleted file mode 100644 index 6841a8194f..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl +++ /dev/null @@ -1,199 +0,0 @@ -/** - * @file class2/deferred/skyF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -uniform mat4 modelview_projection_matrix; - -// SKY //////////////////////////////////////////////////////////////////////// -// The vertex shader for creating the atmospheric sky -/////////////////////////////////////////////////////////////////////////////// - -// Inputs -uniform vec3 camPosLocal; - -uniform vec4  lightnorm; -uniform vec4  sunlight_color; -uniform vec4  moonlight_color; -uniform int   sun_up_factor; -uniform vec4  ambient_color; -uniform vec4  blue_horizon; -uniform vec4  blue_density; -uniform float haze_horizon; -uniform float haze_density; - -uniform float cloud_shadow; -uniform float density_multiplier; -uniform float distance_multiplier; -uniform float max_y; - -uniform vec4  glow; -uniform float sun_moon_glow_factor; - -uniform vec4 cloud_color; - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_data[3]; -#else -#define frag_data gl_FragData -#endif - -VARYING vec3 pos; - -///////////////////////////////////////////////////////////////////////// -// The fragment shader for the sky -///////////////////////////////////////////////////////////////////////// - -uniform sampler2D rainbow_map; -uniform sampler2D halo_map; - -uniform float moisture_level; -uniform float droplet_radius; -uniform float ice_level; - -vec3 rainbow(float d) -{ -    // d is the dot product of view and sun directions, so ranging -1.0..1.0 -    // 'interesting' values of d are the range -0.75..-0.825, when view is nearly opposite of sun vec -    // Rainbox texture mode is GL_REPEAT, so tc of -.75 is equiv to 0.25, -0.825 equiv to 0.175. - -    // SL-13629 Rainbow texture has colors within the correct .175...250 range, but order is inverted. -    // Rather than replace the texture, we mirror and translate the y tc to keep the colors within the -    // interesting range, but in reversed order:  i.e. d = (1 - d) - 1.575 -    d = clamp(-0.575 - d, 0.0, 1.0); - -    // With the colors in the lower 1/4 of the texture, inverting the coords leaves most of it inaccessible. -    // So, we can stretch the texcoord above the colors (ie > 0.25) to fill the entire remaining coordinate -    // space. This improves gradation, reduces banding within the rainbow interior. (1-0.25) / (0.425/0.25) = 4.2857 -    float interior_coord = max(0.0, d - 0.25) * 4.2857; -    d = clamp(d, 0.0, 0.25) + interior_coord; - -    float rad = (droplet_radius - 5.0f) / 1024.0f; -    return pow(texture2D(rainbow_map, vec2(rad, d)).rgb, vec3(1.8)) * moisture_level; -} - -vec3 halo22(float d) -{ -    d       = clamp(d, 0.1, 1.0); -    float v = sqrt(clamp(1 - (d * d), 0, 1)); -    return texture2D(halo_map, vec2(0, v)).rgb * ice_level; -} - -/// Soft clips the light with a gamma correction -vec3 scaleSoftClip(vec3 light); - -void main() -{ -    // World / view / projection -    // Get relative position (offset why?) -    vec3 rel_pos = pos.xyz - camPosLocal.xyz + vec3(0, 50, 0); - -    // Adj position vector to clamp altitude -    if (rel_pos.y > 0.) -    { -        rel_pos *= (max_y / rel_pos.y); -    } -    if (rel_pos.y < 0.) -    { -        rel_pos *= (-32000. / rel_pos.y); -    } - -    // Normalized -    vec3  rel_pos_norm = normalize(rel_pos); -    float rel_pos_len  = length(rel_pos); - -    // Initialize temp variables -    vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_color; - -    // Sunlight attenuation effect (hue and brightness) due to atmosphere -    // this is used later for sunlight modulation at various altitudes -    vec4 light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y); - -    // Calculate relative weights -    vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density)); -    vec4 blue_weight   = blue_density / combined_haze; -    vec4 haze_weight   = haze_density / combined_haze; - -    // Compute sunlight from rel_pos & lightnorm (for long rays like sky) -    float off_axis = 1.0 / max(1e-6, max(0, rel_pos_norm.y) + lightnorm.y); -    sunlight *= exp(-light_atten * off_axis); - -    // Distance -    float density_dist = rel_pos_len * density_multiplier; - -    // Transparency (-> combined_haze) -    // ATI Bugfix -- can't store combined_haze*density_dist in a variable because the ati -    // compiler gets confused. -    combined_haze = exp(-combined_haze * density_dist); - -    // Compute haze glow -    float haze_glow = dot(rel_pos_norm, lightnorm.xyz); -    haze_glow       = 1. - haze_glow; -    // haze_glow is 0 at the sun and increases away from sun -    haze_glow = max(haze_glow, .001); -    // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) -    haze_glow *= glow.x; -    // Higher glow.x gives dimmer glow (because next step is 1 / "angle") -    haze_glow = pow(haze_glow, glow.z); -    // glow.z should be negative, so we're doing a sort of (1 / "angle") function - -    // Add "minimum anti-solar illumination" -    // For sun, add to glow.  For moon, remove glow entirely. SL-13768 -    haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (sun_moon_glow_factor * (haze_glow + 0.25)); - -    // Haze color above cloud -    vec4 color = blue_horizon * blue_weight * (sunlight + ambient_color)  -               + haze_horizon * haze_weight * (sunlight * haze_glow + ambient_color); - -    // Final atmosphere additive -    color *= (1. - combined_haze); - -    // Increase ambient when there are more clouds -    // TODO 9/20: DJH what does this do?  max(0,(1-ambient)) will change the color -    vec4 ambient = ambient_color + max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5; - -    // Dim sunlight by cloud shadow percentage -    sunlight *= max(0.0, (1. - cloud_shadow)); - -    // Haze color below cloud -    vec4 add_below_cloud = blue_horizon * blue_weight * (sunlight + ambient)  -                         + haze_horizon * haze_weight * (sunlight * haze_glow + ambient); - -    // Attenuate cloud color by atmosphere -    combined_haze = sqrt(combined_haze);  // less atmos opacity (more transparency) below clouds - -    // At horizon, blend high altitude sky color towards the darker color below the clouds -    color += (add_below_cloud - color) * (1. - sqrt(combined_haze)); - -    float optic_d = dot(rel_pos_norm, lightnorm.xyz); -    vec3  halo_22 = halo22(optic_d); -    color.rgb += rainbow(optic_d); -    color.rgb += halo_22; -    color.rgb *= 2.; -    color.rgb = scaleSoftClip(color.rgb); - -    // Gamma correct for WL (soft clip effect). -    frag_data[0] = vec4(color.rgb, 1.0); -    frag_data[1] = vec4(0.0, 0.0, 0.0, 0.0); -    frag_data[2] = vec4(0.0, 0.0, 0.0, 1.0);  // 1.0 in norm.w masks off fog -} diff --git a/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl deleted file mode 100644 index bcf775577a..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl +++ /dev/null @@ -1,42 +0,0 @@ -/**  - * @file WLSkyV.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; - -// SKY //////////////////////////////////////////////////////////////////////// -// The vertex shader for creating the atmospheric sky -/////////////////////////////////////////////////////////////////////////////// - -VARYING vec3 pos; - -void main() -{ - -	// World / view / projection -    pos = position.xyz; -	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); -} diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp index 1c69dadb12..7ad06f8eaa 100644 --- a/indra/newview/llbuycurrencyhtml.cpp +++ b/indra/newview/llbuycurrencyhtml.cpp @@ -41,7 +41,7 @@ class LLBuyCurrencyHTMLHandler :  {  public:  	// requests will be throttled from a non-trusted browser -	LLBuyCurrencyHTMLHandler() : LLCommandHandler( "buycurrencyhtml", UNTRUSTED_ALLOW ) {} +	LLBuyCurrencyHTMLHandler() : LLCommandHandler( "buycurrencyhtml", UNTRUSTED_THROTTLE) {}  	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)  	{ diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 7ff24f64ac..42283f0238 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -141,6 +141,18 @@ public:  		{  			mAvatarNameCacheConnection.disconnect();  		} +		auto menu = mPopupMenuHandleAvatar.get(); +		if (menu) +		{ +			menu->die(); +			mPopupMenuHandleAvatar.markDead(); +		} +		menu = mPopupMenuHandleObject.get(); +		if (menu) +		{ +			menu->die(); +			mPopupMenuHandleObject.markDead(); +		}  	}  	BOOL handleMouseUp(S32 x, S32 y, MASK mask) @@ -567,36 +579,6 @@ public:  	BOOL postBuild()  	{ -		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; -		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable; - -		registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2)); -		registrar_enable.add("AvatarIcon.Check", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemChecked, this, _2)); -		registrar_enable.add("AvatarIcon.Enable", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2)); -		registrar_enable.add("AvatarIcon.Visible", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2)); -		registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2)); -		registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2)); - -		LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -		if (menu) -		{ -			mPopupMenuHandleAvatar = menu->getHandle(); -		} -		else -		{ -			LL_WARNS() << " Failed to create menu_avatar_icon.xml" << LL_ENDL; -		} - -		menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_object_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -		if (menu) -		{ -			mPopupMenuHandleObject = menu->getHandle(); -		} -		else -		{ -			LL_WARNS() << " Failed to create menu_object_icon.xml" << LL_ENDL; -		} -  		setDoubleClickCallback(boost::bind(&LLChatHistoryHeader::showInspector, this));  		setMouseEnterCallback(boost::bind(&LLChatHistoryHeader::showInfoCtrl, this)); @@ -883,13 +865,53 @@ protected:  	void showObjectContextMenu(S32 x,S32 y)  	{  		LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleObject.get(); -		if(menu) +		if (!menu) +		{ +			LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; +			LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable; +			registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2)); +			registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2)); + +			menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_object_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +			if (menu) +			{ +				mPopupMenuHandleObject = menu->getHandle(); +				menu->updateParent(LLMenuGL::sMenuContainer); +				LLMenuGL::showPopup(this, menu, x, y); +			} +			else +			{ +				LL_WARNS() << " Failed to create menu_object_icon.xml" << LL_ENDL; +			} +		} +		else +		{  			LLMenuGL::showPopup(this, menu, x, y); +		}  	}  	void showAvatarContextMenu(S32 x,S32 y)  	{  		LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleAvatar.get(); +		if (!menu) +		{ +			LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; +			LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable; +			registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2)); +			registrar_enable.add("AvatarIcon.Check", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemChecked, this, _2)); +			registrar_enable.add("AvatarIcon.Enable", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2)); +			registrar_enable.add("AvatarIcon.Visible", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2)); + +			menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +			if (menu) +			{ +				mPopupMenuHandleAvatar = menu->getHandle(); +			} +			else +			{ +				LL_WARNS() << " Failed to create menu_avatar_icon.xml" << LL_ENDL; +			} +		}  		if(menu)  		{ @@ -1081,10 +1103,7 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)  LLSD LLChatHistory::getValue() const  { -  LLSD* text=new LLSD();  -  text->assign(mEditor->getText()); -  return *text; -     +	return LLSD(mEditor->getText());  }  LLChatHistory::~LLChatHistory() diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 0f187b0ecf..cc4f4536a4 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -67,7 +67,6 @@ LLSysWellChiclet::LLSysWellChiclet(const Params& p)  	, mMaxDisplayedCount(p.max_displayed_count)  	, mIsNewMessagesState(false)  	, mFlashToLitTimer(NULL) -	, mContextMenu(NULL)  {  	LLButton::Params button_params = p.button;  	mButton = LLUICtrlFactory::create<LLButton>(button_params); @@ -79,6 +78,12 @@ LLSysWellChiclet::LLSysWellChiclet(const Params& p)  LLSysWellChiclet::~LLSysWellChiclet()  {  	mFlashToLitTimer->unset(); +	LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); +	if (menu) +	{ +		menu->die(); +		mContextMenuHandle.markDead(); +	}  }  void LLSysWellChiclet::setCounter(S32 counter) @@ -145,14 +150,16 @@ void LLSysWellChiclet::updateWidget(bool is_window_empty)  // virtual  BOOL LLSysWellChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)  { -	if(!mContextMenu) +	LLContextMenu* menu_avatar = mContextMenuHandle.get(); +	if(!menu_avatar)  	{  		createMenu(); +		menu_avatar = mContextMenuHandle.get();  	} -	if (mContextMenu) +	if (menu_avatar)  	{ -		mContextMenu->show(x, y); -		LLMenuGL::showPopup(this, mContextMenu, x, y); +		menu_avatar->show(x, y); +		LLMenuGL::showPopup(this, menu_avatar, x, y);  	}  	return TRUE;  } @@ -192,7 +199,7 @@ bool LLNotificationChiclet::enableMenuItem(const LLSD& user_data)  void LLNotificationChiclet::createMenu()  { -	if(mContextMenu) +	if(mContextMenuHandle.get())  	{  		LL_WARNS() << "Menu already exists" << LL_ENDL;  		return; @@ -207,10 +214,14 @@ void LLNotificationChiclet::createMenu()  		boost::bind(&LLNotificationChiclet::enableMenuItem, this, _2));  	llassert(LLMenuGL::sMenuContainer != NULL); -	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu> +	LLContextMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>  		("menu_notification_well_button.xml",  		 LLMenuGL::sMenuContainer,  		 LLViewerMenuHolderGL::child_registry_t::instance()); +	if (menu) +	{ +		mContextMenuHandle = menu->getHandle(); +	}  }  /*virtual*/ @@ -309,10 +320,19 @@ LLIMChiclet::LLIMChiclet(const LLIMChiclet::Params& p)  , mDefaultWidth(p.rect().getWidth())  , mNewMessagesIcon(NULL)  , mChicletButton(NULL) -, mPopupMenu(NULL)  {  } +LLIMChiclet::~LLIMChiclet() +{ +	auto menu = mPopupMenuHandle.get(); +	if (menu) +	{ +		menu->die(); +		mPopupMenuHandle.markDead(); +	} +} +  /* virtual*/  BOOL LLIMChiclet::postBuild()  { @@ -364,16 +384,18 @@ void LLIMChiclet::setToggleState(bool toggle)  BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)  { -	if(!mPopupMenu) +	auto menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); +	if(!menu)  	{  		createPopupMenu(); +		menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get());  	} -	if (mPopupMenu) +	if (menu)  	{  		updateMenuItems(); -		mPopupMenu->arrangeAndClear(); -		LLMenuGL::showPopup(this, mPopupMenu, x, y); +		menu->arrangeAndClear(); +		LLMenuGL::showPopup(this, menu, x, y);  	}  	return TRUE; @@ -381,15 +403,16 @@ BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)  void LLIMChiclet::hidePopupMenu()  { -	if (mPopupMenu) +	auto menu = mPopupMenuHandle.get(); +	if (menu)  	{ -		mPopupMenu->setVisible(FALSE); +		menu->setVisible(FALSE);  	}  }  bool LLIMChiclet::canCreateMenu()  { -	if(mPopupMenu) +	if(mPopupMenuHandle.get())  	{  		LL_WARNS() << "Menu already exists" << LL_ENDL;  		return false; @@ -1107,8 +1130,13 @@ void LLScriptChiclet::createPopupMenu()  	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;  	registrar.add("ScriptChiclet.Action", boost::bind(&LLScriptChiclet::onMenuItemClicked, this, _2)); -	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> +	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>  		("menu_script_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +	if (menu) +	{ +		mPopupMenuHandle = menu->getHandle(); +	} +  }  ////////////////////////////////////////////////////////////////////////// @@ -1185,8 +1213,12 @@ void LLInvOfferChiclet::createPopupMenu()  	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;  	registrar.add("InvOfferChiclet.Action", boost::bind(&LLInvOfferChiclet::onMenuItemClicked, this, _2)); -	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> +	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>  		("menu_inv_offer_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +	if (menu) +	{ +		mPopupMenuHandle = menu->getHandle(); +	}  }  // EOF diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index aceedda07e..58a797218f 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -252,7 +252,7 @@ public:  	{}; -	virtual ~LLIMChiclet() {}; +	virtual ~LLIMChiclet();  	/**  	 * It is used for default setting up of chicklet:click handler, etc.   @@ -325,7 +325,7 @@ protected:  	bool canCreateMenu(); -	LLMenuGL* mPopupMenu; +	LLHandle<LLUICtrl> mPopupMenuHandle;  	bool mShowSpeaker;  	bool mCounterEnabled; @@ -519,7 +519,7 @@ protected:  	bool mIsNewMessagesState;  	LLFlashTimer* mFlashToLitTimer; -	LLContextMenu* mContextMenu; +	LLHandle<LLContextMenu> mContextMenuHandle;  };  class LLNotificationChiclet : public LLSysWellChiclet diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp index 23e2271eae..74f37961c7 100644 --- a/indra/newview/llcommandhandler.cpp +++ b/indra/newview/llcommandhandler.cpp @@ -39,6 +39,7 @@  #define THROTTLE_PERIOD    5    // required seconds between throttled commands  static LLCommandDispatcherListener sCommandDispatcherListener; +const std::string LLCommandHandler::NAV_TYPE_CLICKED = "clicked";  //---------------------------------------------------------------------------  // Underlying registry for command handlers, not directly accessible. @@ -64,6 +65,9 @@ public:  				  bool trusted_browser);  private: +    void notifySlurlBlocked(); +    void notifySlurlThrottled(); +  	friend LLSD LLCommandDispatcher::enumerate();  	std::map<std::string, LLCommandHandlerInfo> mMap;  }; @@ -96,8 +100,6 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,  										const std::string& nav_type,  										bool trusted_browser)  { -	static bool slurl_blocked = false; -	static bool slurl_throttled = false;  	static F64 last_throttle_time = 0.0;  	F64 cur_time = 0.0;  	std::map<std::string, LLCommandHandlerInfo>::iterator it = mMap.find(cmd); @@ -115,44 +117,45 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,  			// block request from external browser, but report as  			// "handled" because it was well formatted.  			LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL; -			if (! slurl_blocked) -			{ -				if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) -				{ -					// Note: commands can arrive before we initialize everything we need for Notification. -					LLNotificationsUtil::add("BlockedSLURL"); -				} -				slurl_blocked = true; -			} +            notifySlurlBlocked();  			return true; +        case LLCommandHandler::UNTRUSTED_CLICK_ONLY: +            if (nav_type == LLCommandHandler::NAV_TYPE_CLICKED +                && info.mHandler->canHandleUntrusted(params, query_map, web, nav_type)) +            { +                break; +            } +            LL_WARNS_ONCE("SLURL") << "Blocked SLURL click-only command " << cmd << " from untrusted browser" << LL_ENDL; +            notifySlurlBlocked(); +            return true; +  		case LLCommandHandler::UNTRUSTED_THROTTLE: +			//skip initial request from external browser before STATE_BROWSER_INIT +			if (LLStartUp::getStartupState() == STATE_FIRST) +			{ +				return true; +			} +            if (!info.mHandler->canHandleUntrusted(params, query_map, web, nav_type)) +            { +                LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL; +                notifySlurlBlocked(); +                return true; +            }  			// if users actually click on a link, we don't need to throttle it  			// (throttling mechanism is used to prevent an avalanche of clicks via  			// javascript -			if ( nav_type == "clicked" ) +			if (nav_type == LLCommandHandler::NAV_TYPE_CLICKED)  			{  				break;  			} -			//skip initial request from external browser before STATE_BROWSER_INIT -			if (LLStartUp::getStartupState() == STATE_FIRST) -			{ -				return true; -			}  			cur_time = LLTimer::getElapsedSeconds();  			if (cur_time < last_throttle_time + THROTTLE_PERIOD)  			{  				// block request from external browser if it happened  				// within THROTTLE_PERIOD seconds of the last command  				LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL; -				if (! slurl_throttled) -				{ -					if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) -					{ -						LLNotificationsUtil::add("ThrottledSLURL"); -					} -					slurl_throttled = true; -				} +                notifySlurlThrottled();  				return true;  			}  			last_throttle_time = cur_time; @@ -163,6 +166,34 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,  	return info.mHandler->handle(params, query_map, web);  } +void LLCommandHandlerRegistry::notifySlurlBlocked() +{ +    static bool slurl_blocked = false; +    if (!slurl_blocked) +    { +        if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) +        { +            // Note: commands can arrive before we initialize everything we need for Notification. +            LLNotificationsUtil::add("BlockedSLURL"); +        } +        slurl_blocked = true; +    } +} + +void LLCommandHandlerRegistry::notifySlurlThrottled() +{ +    static bool slurl_throttled = false; +    if (!slurl_throttled) +    { +        if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) +        { +            // Note: commands can arrive before we initialize everything we need for Notification. +            LLNotificationsUtil::add("ThrottledSLURL"); +        } +        slurl_throttled = true; +    } +} +  //---------------------------------------------------------------------------  // Automatic registration of commands, runs before main()  //--------------------------------------------------------------------------- @@ -230,6 +261,7 @@ symbol_info symbols[] =  {  	ent(LLCommandHandler::UNTRUSTED_ALLOW),		  // allow commands from untrusted browsers  	ent(LLCommandHandler::UNTRUSTED_BLOCK),		  // ignore commands from untrusted browsers +    ent(LLCommandHandler::UNTRUSTED_CLICK_ONLY),  // allow untrusted, but only if clicked  	ent(LLCommandHandler::UNTRUSTED_THROTTLE)	  // allow untrusted, but only a few per min.  }; diff --git a/indra/newview/llcommandhandler.h b/indra/newview/llcommandhandler.h index 1e0895565a..763e3ee51f 100644 --- a/indra/newview/llcommandhandler.h +++ b/indra/newview/llcommandhandler.h @@ -65,9 +65,12 @@ public:  	{  		UNTRUSTED_ALLOW,       // allow commands from untrusted browsers  		UNTRUSTED_BLOCK,       // ignore commands from untrusted browsers +        UNTRUSTED_CLICK_ONLY,  // allow untrusted, but only if clicked  		UNTRUSTED_THROTTLE     // allow untrusted, but only a few per min.  	}; +    static const std::string NAV_TYPE_CLICKED; +  	LLCommandHandler(const char* command, EUntrustedAccess untrusted_access);  		// Automatically registers object to get called when   		// command is executed.  All commands can be processed @@ -76,6 +79,13 @@ public:  	virtual ~LLCommandHandler(); +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { return true; } +  	virtual bool handle(const LLSD& params,  						const LLSD& query_map,  						LLMediaCtrl* web) = 0; diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp index c075f7e8bd..8ad0bb3995 100644 --- a/indra/newview/llfloater360capture.cpp +++ b/indra/newview/llfloater360capture.cpp @@ -84,7 +84,7 @@ LLFloater360Capture::~LLFloater360Capture()      // Tell the Simulator not to send us everything anymore      // and revert to the regular "keyhole" frustum of interest      // list updates. -    if (gSavedSettings.getBOOL("360CaptureUseInterestListCap")) +    if (gSavedSettings.getBOOL("360CaptureUseInterestListCap") && !LLApp::isExiting())      {          const bool send_everything = false;          changeInterestListMode(send_everything); @@ -537,7 +537,8 @@ void LLFloater360Capture::capture360Images()      // We need to convert from the angle getYaw() gives us into something      // the XMP data field wants (N=0, E=90, S=180, W= 270 etc.)      mInitialHeadingDeg  = (360 + 90 - (int)(camera->getYaw() * RAD_TO_DEG)) % 360; -    LL_INFOS("360Capture") << "Recording a heading of " << (int)(mInitialHeadingDeg) << LL_ENDL; +    LL_INFOS("360Capture") << "Recording a heading of " << (int)(mInitialHeadingDeg) +        << " Image size: " << (S32)mSourceImageSize << LL_ENDL;      // camera constants for the square, cube map capture image      camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV @@ -587,6 +588,9 @@ void LLFloater360Capture::capture360Images()      // for each of the 6 directions we shoot...      for (int i = 0; i < 6; i++)      { +        LLAppViewer::instance()->pauseMainloopTimeout(); +        LLViewerStats::instance().getRecording().stop(); +          // these buffers are where the raw, captured pixels are stored and          // the first time we use them, we have to make a new one          if (mRawImages[i] == nullptr) @@ -624,8 +628,10 @@ void LLFloater360Capture::capture360Images()          auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(t_end - t_start);          encode_time_total += duration.count(); -        // ping the main loop in case the snapshot process takes a really long -        // time and we get disconnected +        LLViewerStats::instance().getRecording().resume(); +        LLAppViewer::instance()->resumeMainloopTimeout(); +         +        // update main loop timeout state          LLAppViewer::instance()->pingMainloopTimeout("LLFloater360Capture::capture360Images");      } diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp index 33e4c7cd5f..307ab8c4d1 100644 --- a/indra/newview/llfloaterbump.cpp +++ b/indra/newview/llfloaterbump.cpp @@ -69,6 +69,12 @@ LLFloaterBump::LLFloaterBump(const LLSD& key)  // Destroys the object  LLFloaterBump::~LLFloaterBump()  { +	auto menu = mPopupMenuHandle.get(); +	if (menu) +	{ +		menu->die(); +		mPopupMenuHandle.markDead(); +	}  }  BOOL LLFloaterBump::postBuild() @@ -77,11 +83,15 @@ BOOL LLFloaterBump::postBuild()  	mList->setAllowMultipleSelection(false);  	mList->setRightMouseDownCallback(boost::bind(&LLFloaterBump::onScrollListRightClicked, this, _1, _2, _3)); -	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>("menu_avatar_other.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -	mPopupMenu->setItemVisible(std::string("Normal"), false); -	mPopupMenu->setItemVisible(std::string("Always use impostor"), false); -	mPopupMenu->setItemVisible(std::string("Never use impostor"), false); -	mPopupMenu->setItemVisible(std::string("Impostor seperator"), false); +	LLContextMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>("menu_avatar_other.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +	if (menu) +	{ +		mPopupMenuHandle = menu->getHandle(); +		menu->setItemVisible(std::string("Normal"), false); +		menu->setItemVisible(std::string("Always use impostor"), false); +		menu->setItemVisible(std::string("Never use impostor"), false); +		menu->setItemVisible(std::string("Impostor seperator"), false); +	}  	return TRUE;  } @@ -176,18 +186,19 @@ void LLFloaterBump::onScrollListRightClicked(LLUICtrl* ctrl, S32 x, S32 y)  	if (!gMeanCollisionList.empty())  	{  		LLScrollListItem* item = mList->hitItem(x, y); -		if (item && mPopupMenu) +		auto menu = mPopupMenuHandle.get(); +		if (item && menu)  		{  			mItemUUID = item->getUUID(); -			mPopupMenu->buildDrawLabels(); -			mPopupMenu->updateParent(LLMenuGL::sMenuContainer); +			menu->buildDrawLabels(); +			menu->updateParent(LLMenuGL::sMenuContainer);  			std::string mute_msg = (LLMuteList::getInstance()->isMuted(mItemUUID, mNames[mItemUUID])) ? "UnmuteAvatar" : "MuteAvatar"; -			mPopupMenu->getChild<LLUICtrl>("Avatar Mute")->setValue(LLTrans::getString(mute_msg)); -			mPopupMenu->setItemEnabled(std::string("Zoom In"), bool(gObjectList.findObject(mItemUUID))); +			menu->getChild<LLUICtrl>("Avatar Mute")->setValue(LLTrans::getString(mute_msg)); +			menu->setItemEnabled(std::string("Zoom In"), bool(gObjectList.findObject(mItemUUID))); -			((LLContextMenu*)mPopupMenu)->show(x, y); -			LLMenuGL::showPopup(ctrl, mPopupMenu, x, y); +			menu->show(x, y); +			LLMenuGL::showPopup(ctrl, menu, x, y);  		}  	}  } diff --git a/indra/newview/llfloaterbump.h b/indra/newview/llfloaterbump.h index ce52c75255..d2f9fabdd3 100644 --- a/indra/newview/llfloaterbump.h +++ b/indra/newview/llfloaterbump.h @@ -68,7 +68,7 @@ private:  	virtual ~LLFloaterBump();  	LLScrollListCtrl* mList; -	LLMenuGL* mPopupMenu; +	LLHandle<LLContextMenu> mPopupMenuHandle;  	LLUUID mItemUUID;  	typedef std::map<LLUUID, std::string> uuid_map_t; diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 703b5d0011..2720b7fcf7 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -211,6 +211,7 @@ BOOL LLFloaterIMContainer::postBuild()      p.options_menu = "menu_conversation.xml";  	mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);      mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); +	mConversationsRoot->setEnableRegistrar(&mEnableCallbackRegistrar);  	// Add listener to conversation model events  	mConversationsEventStream.listen("ConversationsRefresh", boost::bind(&LLFloaterIMContainer::onConversationModelEvent, this, _1)); diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 93a0b39e02..f973ae43cc 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -317,6 +317,7 @@ BOOL LLFloaterIMSessionTab::postBuild()      p.name = "root";  	mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);      mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); +	mConversationsRoot->setEnableRegistrar(&mEnableCallbackRegistrar);  	// Attach that root to the scroller  	mScroller->addChild(mConversationsRoot);  	mConversationsRoot->setScrollContainer(mScroller); diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 2a1749bd42..a682064dad 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -56,8 +56,6 @@ LLFloaterOpenObject::LLFloaterOpenObject(const LLSD& key)  	mDirty(TRUE)  {  	mCommitCallbackRegistrar.add("OpenObject.MoveToInventory",	boost::bind(&LLFloaterOpenObject::onClickMoveToInventory, this)); -	mCommitCallbackRegistrar.add("OpenObject.MoveAndWear",		boost::bind(&LLFloaterOpenObject::onClickMoveAndWear, this)); -	mCommitCallbackRegistrar.add("OpenObject.ReplaceOutfit",	boost::bind(&LLFloaterOpenObject::onClickReplace, this));  	mCommitCallbackRegistrar.add("OpenObject.Cancel",			boost::bind(&LLFloaterOpenObject::onClickCancel, this));  } @@ -243,18 +241,6 @@ void LLFloaterOpenObject::onClickMoveToInventory()  	closeFloater();  } -void LLFloaterOpenObject::onClickMoveAndWear() -{ -	moveToInventory(true, false); -	closeFloater(); -} - -void LLFloaterOpenObject::onClickReplace() -{ -	moveToInventory(true, true); -	closeFloater(); -} -  void LLFloaterOpenObject::onClickCancel()  {  	closeFloater(); diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index 2e761f99bf..745753316b 100644 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -63,8 +63,6 @@ protected:  	void moveToInventory(bool wear, bool replace = false);  	void onClickMoveToInventory(); -	void onClickMoveAndWear(); -	void onClickReplace();  	void onClickCancel();  	static void callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear, bool replace = false);  	static void callbackMoveInventory(S32 result, void* data); diff --git a/indra/newview/llfloaterpathfindinglinksets.cpp b/indra/newview/llfloaterpathfindinglinksets.cpp index 1e46d7a402..03aede94c6 100644 --- a/indra/newview/llfloaterpathfindinglinksets.cpp +++ b/indra/newview/llfloaterpathfindinglinksets.cpp @@ -44,6 +44,7 @@  #include "llpathfindinglinkset.h"  #include "llpathfindinglinksetlist.h"  #include "llpathfindingmanager.h" +#include "llsearcheditor.h"  #include "llscrolllistitem.h"  #include "llsd.h"  #include "lltextbase.h" @@ -114,17 +115,13 @@ BOOL LLFloaterPathfindingLinksets::postBuild()  {  	mBeaconColor = LLUIColorTable::getInstance()->getColor("PathfindingLinksetBeaconColor"); -	mFilterByName = findChild<LLLineEditor>("filter_by_name"); -	llassert(mFilterByName != NULL); -	mFilterByName->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); -	mFilterByName->setSelectAllonFocusReceived(true); -	mFilterByName->setCommitOnFocusLost(true); - -	mFilterByDescription = findChild<LLLineEditor>("filter_by_description"); -	llassert(mFilterByDescription != NULL); -	mFilterByDescription->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); -	mFilterByDescription->setSelectAllonFocusReceived(true); -	mFilterByDescription->setCommitOnFocusLost(true); +    mFilterByName = getChild<LLSearchEditor>("filter_by_name"); +    mFilterByName->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); +    mFilterByName->setCommitOnFocusLost(true); + +    mFilterByDescription = getChild<LLSearchEditor>("filter_by_description"); +    mFilterByDescription->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); +    mFilterByDescription->setCommitOnFocusLost(true);  	mFilterByLinksetUse = findChild<LLComboBox>("filter_by_linkset_use");  	llassert(mFilterByLinksetUse != NULL); diff --git a/indra/newview/llfloaterpathfindinglinksets.h b/indra/newview/llfloaterpathfindinglinksets.h index 7149da9215..a954d8a8ec 100644 --- a/indra/newview/llfloaterpathfindinglinksets.h +++ b/indra/newview/llfloaterpathfindinglinksets.h @@ -42,6 +42,7 @@ class LLSD;  class LLTextBase;  class LLUICtrl;  class LLVector3; +class LLSearchEditor;  class LLFloaterPathfindingLinksets : public LLFloaterPathfindingObjects  { @@ -105,8 +106,8 @@ private:  	LLPathfindingLinkset::ELinksetUse convertToLinksetUse(LLSD pXuiValue) const;  	LLSD                              convertToXuiValue(LLPathfindingLinkset::ELinksetUse pLinksetUse) const; -	LLLineEditor     *mFilterByName; -	LLLineEditor     *mFilterByDescription; +    LLSearchEditor   *mFilterByName; +    LLSearchEditor   *mFilterByDescription;  	LLComboBox       *mFilterByLinksetUse;  	LLComboBox       *mEditLinksetUse;  	LLScrollListItem *mEditLinksetUseUnset; diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index bb3ed77772..7e6af45515 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -45,7 +45,7 @@ class LLSearchHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_THROTTLE) { } +	LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { }  	bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)  	{  		if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableSearch")) diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 01bfae8934..704abd269f 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -122,7 +122,7 @@ class LLWorldMapHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_THROTTLE ) { } +	LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_CLICK_ONLY ) { }  	bool handle(const LLSD& params, const LLSD& query_map,  				LLMediaCtrl* web) @@ -159,7 +159,7 @@ class LLMapTrackAvatarHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_THROTTLE)  +	LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_CLICK_ONLY)   	{   	} diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 84a1278767..815840f990 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -52,7 +52,32 @@ class LLGroupHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLGroupHandler() : LLCommandHandler("group", UNTRUSTED_THROTTLE) { } +	LLGroupHandler() : LLCommandHandler("group", UNTRUSTED_CLICK_ONLY) { } + +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { +        if (params.size() < 1) +        { +            return true; // don't block, will fail later +        } + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            return true; +        } + +        const std::string verb = params[0].asString(); +        if (verb == "create") +        { +            return false; +        } +        return true; +    } +  	bool handle(const LLSD& tokens, const LLSD& query_map,  				LLMediaCtrl* web)  	{ diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index fab7ae8f1a..06351dc540 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1691,11 +1691,11 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo  	// Can't have links to links, so there's no need for this update  	// if the item removed is a link. Can also skip if source of the  	// update is getting broken link info separately. -	obj = NULL; // delete obj  	if (fix_broken_links && !is_link_type)  	{  		updateLinkedObjectsFromPurge(id);  	} +	obj = nullptr; // delete obj  	if (do_notify_observers)  	{  		notifyObservers(); diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 6b102c7500..c065c76dca 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -211,7 +211,11 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )      p.allow_drop = mParams.allow_drop_on_root;      p.options_menu = "menu_inventory.xml"; -    return LLUICtrlFactory::create<LLFolderView>(p); +	LLFolderView* fv = LLUICtrlFactory::create<LLFolderView>(p); +	fv->setCallbackRegistrar(&mCommitCallbackRegistrar); +	fv->setEnableRegistrar(&mEnableCallbackRegistrar); + +	return fv;  }  void LLInventoryPanel::clearFolderRoot() @@ -264,6 +268,7 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)  	}  	mCommitCallbackRegistrar.popScope();  	mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar); +	mFolderRoot.get()->setEnableRegistrar(&mEnableCallbackRegistrar);  	// Scroller  		LLRect scroller_view_rect = getRect(); diff --git a/indra/newview/lllistcontextmenu.cpp b/indra/newview/lllistcontextmenu.cpp index 6bda8b1d0d..77185411c5 100644 --- a/indra/newview/lllistcontextmenu.cpp +++ b/indra/newview/lllistcontextmenu.cpp @@ -51,6 +51,7 @@ LLListContextMenu::~LLListContextMenu()  	if (!mMenuHandle.isDead())  	{  		mMenuHandle.get()->die(); +		mMenuHandle.markDead();  	}  } @@ -59,13 +60,8 @@ void LLListContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32  	LLContextMenu* menup = mMenuHandle.get();  	if (menup)  	{ -		//preventing parent (menu holder) from deleting already "dead" context menus on exit -		LLView* parent = menup->getParent(); -		if (parent) -		{ -			parent->removeChild(menup); -		} -		delete menup; +		menup->die(); +		mMenuHandle.markDead();  		mUUIDs.clear();  	} diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index 11aa607393..a52f7244f3 100644 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -429,12 +429,10 @@ void LLMaterialMgr::onGetResponse(bool success, const LLSD& content, const LLUUI  	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));  	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary()); -	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary(); -	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size()); -	std::istringstream content_stream(content_string); +	const LLSD::Binary& content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();  	LLSD response_data; -	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size()); +	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_binary.data(), content_binary.size());  	if (uzip_result != LLUZipHelper::ZR_OK)  	{  		LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL; @@ -472,12 +470,10 @@ void LLMaterialMgr::onGetAllResponse(bool success, const LLSD& content, const LL  	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));  	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary()); -	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary(); -	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size()); -	std::istringstream content_stream(content_string); +	const LLSD::Binary& content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();  	LLSD response_data; -	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size()); +	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_binary.data(), content_binary.size());  	if (uzip_result != LLUZipHelper::ZR_OK)  	{  		LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL; @@ -541,12 +537,10 @@ void LLMaterialMgr::onPutResponse(bool success, const LLSD& content)  	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));  	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary()); -	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary(); -	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size()); -	std::istringstream content_stream(content_string); +	const LLSD::Binary& content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();  	LLSD response_data; -	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size()); +	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_binary.data(), content_binary.size());  	if (uzip_result != LLUZipHelper::ZR_OK)  	{  		LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL; @@ -666,8 +660,8 @@ void LLMaterialMgr::processGetQueue()  		{  			material_queue_t::iterator itMaterial = loopMaterial++;  			materialsData.append((*itMaterial).asLLSD()); -			materials.erase(itMaterial);  			markGetPending(region_id, *itMaterial); +			materials.erase(itMaterial);  		}  		if (materials.empty())  		{ diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 9142aadab9..36ac1bdf97 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -106,7 +106,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  	mTrusted(p.trusted_content),  	mWindowShade(NULL),  	mHoverTextChanged(false), -	mContextMenu(NULL),      mAllowFileDownload(false)  {  	{ @@ -151,6 +150,13 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  LLMediaCtrl::~LLMediaCtrl()  { +	auto menu = mContextMenuHandle.get(); +	if (menu) +	{ +		menu->die(); +		mContextMenuHandle.markDead(); +	} +  	if (mMediaSource)  	{  		mMediaSource->remObserver( this ); @@ -336,15 +342,33 @@ BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )  		setFocus( TRUE );  	} -	if (mContextMenu) +	auto menu = mContextMenuHandle.get(); +	if (!menu) +	{ +		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; +		registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); + +		// stinson 05/05/2014 : use this as the parent of the context menu if the static menu +		// container has yet to be created +		LLPanel* menuParent = (LLMenuGL::sMenuContainer != NULL) ? dynamic_cast<LLPanel*>(LLMenuGL::sMenuContainer) : dynamic_cast<LLPanel*>(this); +		llassert(menuParent != NULL); +		menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( +			"menu_media_ctrl.xml", menuParent, LLViewerMenuHolderGL::child_registry_t::instance()); +		if (menu) +		{ +			mContextMenuHandle = menu->getHandle(); +		} +	} + +	if (menu)  	{  		// hide/show debugging options  		bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); -		mContextMenu->setItemVisible("open_webinspector", media_plugin_debugging_enabled ); -		mContextMenu->setItemVisible("debug_separator", media_plugin_debugging_enabled ); +		menu->setItemVisible("open_webinspector", media_plugin_debugging_enabled ); +		menu->setItemVisible("debug_separator", media_plugin_debugging_enabled ); -		mContextMenu->show(x, y); -		LLMenuGL::showPopup(this, mContextMenu, x, y); +		menu->show(x, y); +		LLMenuGL::showPopup(this, menu, x, y);  	}  	return TRUE; @@ -409,15 +433,6 @@ void LLMediaCtrl::onFocusLost()  //  BOOL LLMediaCtrl::postBuild ()  { -	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; -	registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); - -	// stinson 05/05/2014 : use this as the parent of the context menu if the static menu -	// container has yet to be created -	LLPanel* menuParent = (LLMenuGL::sMenuContainer != NULL) ? dynamic_cast<LLPanel*>(LLMenuGL::sMenuContainer) : dynamic_cast<LLPanel*>(this); -	llassert(menuParent != NULL); -	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( -		"menu_media_ctrl.xml", menuParent, LLViewerMenuHolderGL::child_registry_t::instance());  	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChanged, this, _2));  	return TRUE; @@ -1230,11 +1245,6 @@ void LLMediaCtrl::setTrustedContent(bool trusted)  	}  } -void LLMediaCtrl::updateContextMenuParent(LLView* pNewParent) -{ -	mContextMenu->updateParent(pNewParent); -} -  bool LLMediaCtrl::wantsKeyUpKeyDown() const  {      return true; diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index bc4cbaae68..487c654adc 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -174,8 +174,6 @@ public:  		LLUUID getTextureID() {return mMediaTextureID;} -		void updateContextMenuParent(LLView* pNewParent); -          // The Browser windows want keyup and keydown events. Overridden from LLFocusableElement to return true.          virtual bool    wantsKeyUpKeyDown() const;          virtual bool    wantsReturnKey() const; @@ -220,7 +218,7 @@ public:  			mTextureHeight;  		class LLWindowShade* mWindowShade; -		LLContextMenu* mContextMenu; +		LLHandle<LLContextMenu> mContextMenuHandle;  };  #endif // LL_LLMediaCtrl_H diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a15a61429b..f937754368 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -77,6 +77,8 @@  #include "lluploaddialog.h"  #include "llfloaterreg.h" +#include "boost/iostreams/device/array.hpp" +#include "boost/iostreams/stream.hpp"  #include "boost/lexical_cast.hpp"  #ifndef LL_WINDOWS @@ -138,7 +140,7 @@  //                               data copied  //                               headerReceived() invoked  //                                 LLSD parsed -//                                 mMeshHeader, mMeshHeaderSize updated +//                                 mMeshHeader updated  //                                 scan mPendingLOD for LOD request  //                                 push LODRequest to mLODReqQ  //                             ... @@ -246,7 +248,6 @@  //     sActiveLODRequests       mMutex        rw.any.mMutex, ro.repo.none [1]  //     sMaxConcurrentRequests   mMutex        wo.main.none, ro.repo.none, ro.main.mMutex  //     mMeshHeader              mHeaderMutex  rw.repo.mHeaderMutex, ro.main.mHeaderMutex, ro.main.none [0] -//     mMeshHeaderSize          mHeaderMutex  rw.repo.mHeaderMutex  //     mSkinRequests            mMutex        rw.repo.mMutex, ro.repo.none [5]  //     mSkinInfoQ               mMutex        rw.repo.mMutex, rw.main.mMutex [5] (was:  [0])  //     mDecompositionRequests   mMutex        rw.repo.mMutex, ro.repo.none [5] @@ -858,6 +859,12 @@ LLMeshRepoThread::~LLMeshRepoThread()  	mHttpRequestSet.clear();      mHttpHeaders.reset(); +	while (!mSkinInfoQ.empty()) +    { +        delete mSkinInfoQ.front(); +        mSkinInfoQ.pop_front(); +    } +      while (!mDecompositionQ.empty())      {          delete mDecompositionQ.front(); @@ -947,7 +954,8 @@ void LLMeshRepoThread::run()                      else                      {                          // too many fails -                        mUnavailableQ.push(req); +						LLMutexLock lock(mMutex); +                        mUnavailableQ.push_back(req);                          LL_WARNS() << "Failed to load " << req.mMeshParams << " , skip" << LL_ENDL;                      }                  } @@ -1023,37 +1031,42 @@ void LLMeshRepoThread::run()              if (!mSkinRequests.empty())              { -                std::set<UUIDBasedRequest> incomplete; -                while (!mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater) -                { -                    mMutex->lock(); -                    std::set<UUIDBasedRequest>::iterator iter = mSkinRequests.begin(); -                    UUIDBasedRequest req = *iter; -                    mSkinRequests.erase(iter); -                    mMutex->unlock(); -                    if (req.isDelayed()) -                    { -                        incomplete.insert(req); -                    } -                    else if (!fetchMeshSkinInfo(req.mId)) -                    { -                        if (req.canRetry()) -                        { -                            req.updateTime(); -                            incomplete.insert(req); -                        } -                        else -                        { -                            LL_DEBUGS() << "mSkinRequests failed: " << req.mId << LL_ENDL; -                        } -                    } -                } +				std::list<UUIDBasedRequest> incomplete; +				while (!mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater) +				{ -                if (!incomplete.empty()) -                { -                    LLMutexLock locker(mMutex); -                    mSkinRequests.insert(incomplete.begin(), incomplete.end()); -                } +					mMutex->lock(); +					auto req = mSkinRequests.front(); +					mSkinRequests.pop_front(); +					mMutex->unlock(); +					if (req.isDelayed()) +					{ +						incomplete.emplace_back(req); +					} +					else if (!fetchMeshSkinInfo(req.mId, req.canRetry())) +					{ +						if (req.canRetry()) +						{ +							req.updateTime(); +							incomplete.emplace_back(req); +						} +						else +						{ +							LLMutexLock locker(mMutex); +							mSkinUnavailableQ.push_back(req); +							LL_DEBUGS() << "mSkinReqQ failed: " << req.mId << LL_ENDL; +						} +					} +				} + +				if (!incomplete.empty()) +				{ +					LLMutexLock locker(mMutex); +					for (const auto& req : incomplete) +					{ +						mSkinRequests.push_back(req); +					} +				}              }              // holding lock, try next list @@ -1152,7 +1165,7 @@ void LLMeshRepoThread::run()  // Mutex:  LLMeshRepoThread::mMutex must be held on entry  void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id)  { -	mSkinRequests.insert(UUIDBasedRequest(mesh_id)); +	mSkinRequests.push_back(UUIDBasedRequest(mesh_id));  }  // Mutex:  LLMeshRepoThread::mMutex must be held on entry @@ -1178,10 +1191,13 @@ void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32  void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  { //could be called from any thread +	const LLUUID& mesh_id = mesh_params.getSculptID();  	LLMutexLock lock(mMutex); -	mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID()); +	LLMutexLock header_lock(mHeaderMutex); +	mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);  	if (iter != mMeshHeader.end())  	{ //if we have the header, request LOD byte range +  		LODRequest req(mesh_params, lod);  		{  			mLODReqQ.push(req); @@ -1191,8 +1207,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  	else  	{   		HeaderRequest req(mesh_params); -		 -		pending_lod_map::iterator pending = mPendingLOD.find(mesh_params); +		pending_lod_map::iterator pending = mPendingLOD.find(mesh_id);  		if (pending != mPendingLOD.end())  		{ //append this lod request to existing header request @@ -1202,7 +1217,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  		else  		{ //if no header request is pending, fetch header  			mHeaderReqQ.push(req); -			mPendingLOD[mesh_params].push_back(lod); +			mPendingLOD[mesh_id].push_back(lod);  		}  	}  } @@ -1307,7 +1322,7 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url,  } -bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) +bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry)  {  	if (!mHeaderMutex) @@ -1317,7 +1332,8 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  	mHeaderMutex->lock(); -	if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) +	auto header_it = mMeshHeader.find(mesh_id); +	if (header_it == mMeshHeader.end())  	{ //we have no header info for this mesh, do nothing  		mHeaderMutex->unlock();  		return false; @@ -1325,13 +1341,14 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  	++LLMeshRepository::sMeshRequestCount;  	bool ret = true; -	U32 header_size = mMeshHeaderSize[mesh_id]; +	U32 header_size = header_it->second.first;  	if (header_size > 0)  	{ -		S32 version = mMeshHeader[mesh_id]["version"].asInteger(); -		S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger(); -		S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger(); +		const LLSD& header = header_it->second.second; +		S32 version = header["version"].asInteger(); +		S32 offset = header_size + header["skin"]["offset"].asInteger(); +		S32 size = header["skin"]["size"].asInteger();  		mHeaderMutex->unlock(); @@ -1387,12 +1404,27 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  									   << LL_ENDL;  					ret = false;  				} -				else +				else if(can_retry)  				{  					handler->mHttpHandle = handle;  					mHttpRequestSet.insert(handler);  				} +				else +				{ +					LLMutexLock locker(mMutex); +					mSkinUnavailableQ.emplace_back(mesh_id); +				}  			} +			else +			{ +				LLMutexLock locker(mMutex); +				mSkinUnavailableQ.emplace_back(mesh_id); +			} +		} +		else +		{ +			LLMutexLock locker(mMutex); +			mSkinUnavailableQ.emplace_back(mesh_id);  		}  	}  	else @@ -1413,21 +1445,23 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  	mHeaderMutex->lock(); -	if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) +	auto header_it = mMeshHeader.find(mesh_id); +	if (header_it == mMeshHeader.end())  	{ //we have no header info for this mesh, do nothing  		mHeaderMutex->unlock();  		return false;  	}  	++LLMeshRepository::sMeshRequestCount; -	U32 header_size = mMeshHeaderSize[mesh_id]; +	U32 header_size = header_it->second.first;  	bool ret = true;  	if (header_size > 0)  	{ -		S32 version = mMeshHeader[mesh_id]["version"].asInteger(); -		S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger(); -		S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger(); +		const auto& header = header_it->second.second; +		S32 version = header["version"].asInteger(); +		S32 offset = header_size + header["physics_convex"]["offset"].asInteger(); +		S32 size = header["physics_convex"]["size"].asInteger();  		mHeaderMutex->unlock(); @@ -1510,21 +1544,23 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  	mHeaderMutex->lock(); -	if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) +	auto header_it = mMeshHeader.find(mesh_id); +	if (header_it == mMeshHeader.end())  	{ //we have no header info for this mesh, do nothing  		mHeaderMutex->unlock();  		return false;  	}  	++LLMeshRepository::sMeshRequestCount; -	U32 header_size = mMeshHeaderSize[mesh_id]; +	U32 header_size = header_it->second.first;  	bool ret = true;  	if (header_size > 0)  	{ -		S32 version = mMeshHeader[mesh_id]["version"].asInteger(); -		S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger(); -		S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger(); +		const auto& header = header_it->second.second; +		S32 version = header["version"].asInteger(); +		S32 offset = header_size + header["physics_mesh"]["offset"].asInteger(); +		S32 size = header["physics_mesh"]["size"].asInteger();  		mHeaderMutex->unlock(); @@ -1704,20 +1740,25 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,  		return false;  	} -	mHeaderMutex->lock(); +	const LLUUID& mesh_id = mesh_params.getSculptID(); +	mHeaderMutex->lock(); +	auto header_it = mMeshHeader.find(mesh_id); +	if (header_it == mMeshHeader.end()) +	{ //we have no header info for this mesh, do nothing +		mHeaderMutex->unlock(); +		return false; +	}  	++LLMeshRepository::sMeshRequestCount;  	bool retval = true; - -	LLUUID mesh_id = mesh_params.getSculptID(); -	U32 header_size = mMeshHeaderSize[mesh_id]; - +	U32 header_size = header_it->second.first;  	if (header_size > 0)  	{ -		S32 version = mMeshHeader[mesh_id]["version"].asInteger(); -		S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger(); -		S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger(); +		const auto& header = header_it->second.second; +		S32 version = header["version"].asInteger(); +		S32 offset = header_size + header[header_lod[lod]]["offset"].asInteger(); +		S32 size = header[header_lod[lod]]["size"].asInteger();  		mHeaderMutex->unlock();  		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) @@ -1792,17 +1833,20 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,  				}  				else  				{ -					mUnavailableQ.push(LODRequest(mesh_params, lod)); +					LLMutexLock lock(mMutex); +					mUnavailableQ.push_back(LODRequest(mesh_params, lod));  				}  			}  			else  			{ -				mUnavailableQ.push(LODRequest(mesh_params, lod)); +				LLMutexLock lock(mMutex); +				mUnavailableQ.push_back(LODRequest(mesh_params, lod));  			}  		}  		else  		{ -			mUnavailableQ.push(LODRequest(mesh_params, lod)); +			LLMutexLock lock(mMutex); +			mUnavailableQ.push_back(LODRequest(mesh_params, lod));  		}  	}  	else @@ -1821,27 +1865,12 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes  	U32 header_size = 0;  	if (data_size > 0)  	{ -        std::istringstream stream; -        try -        { -            std::string res_str((char*)data, data_size); +		U32 dsize = data_size; +		char* result_ptr = strip_deprecated_header((char*)data, dsize, &header_size); -            std::string deprecated_header("<? LLSD/Binary ?>"); +		data_size = dsize; -            if (res_str.substr(0, deprecated_header.size()) == deprecated_header) -            { -                res_str = res_str.substr(deprecated_header.size() + 1, data_size); -                header_size = deprecated_header.size() + 1; -            } -            data_size = res_str.size(); - -            stream.str(res_str); -        } -        catch (std::bad_alloc&) -        { -            // out of memory, we won't be able to process this mesh -            return MESH_OUT_OF_MEMORY; -        } +		boost::iostreams::stream<boost::iostreams::array_source> stream(result_ptr, data_size);  		if (!LLSDSerialize::fromBinary(header, stream, data_size))  		{ @@ -1878,8 +1907,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes  		{  			LLMutexLock lock(mHeaderMutex); -			mMeshHeaderSize[mesh_id] = header_size; -			mMeshHeader[mesh_id] = header; +			mMeshHeader[mesh_id] = { header_size, header };              LLMeshRepository::sCacheBytesHeaders += header_size;  		} @@ -1887,7 +1915,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes  		LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time.  		//check for pending requests -		pending_lod_map::iterator iter = mPendingLOD.find(mesh_params); +		pending_lod_map::iterator iter = mPendingLOD.find(mesh_id);  		if (iter != mPendingLOD.end())  		{  			for (U32 i = 0; i < iter->second.size(); ++i) @@ -1911,26 +1939,14 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p  	}  	LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); -	std::istringstream stream; -	try -	{ -		std::string mesh_string((char*)data, data_size); -		stream.str(mesh_string); -	} -	catch (std::bad_alloc&) -	{ -		// out of memory, we won't be able to process this mesh -		return MESH_OUT_OF_MEMORY; -	} - -	if (volume->unpackVolumeFaces(stream, data_size)) +	if (volume->unpackVolumeFaces(data, data_size))  	{  		if (volume->getNumFaces() > 0)  		{  			LoadedMesh mesh(volume, mesh_params, lod);  			{  				LLMutexLock lock(mMutex); -				mLoadedQ.push(mesh); +				mLoadedQ.push_back(mesh);  				// LLPointer is not thread safe, since we added this pointer into  				// threaded list, make sure counter gets decreased inside mutex lock  				// and won't affect mLoadedQ processing @@ -1953,10 +1969,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat  	{          try          { -            std::string res_str((char*)data, data_size); -            std::istringstream stream(res_str); - -            U32 uzip_result = LLUZipHelper::unzip_llsd(skin, stream, data_size); +            U32 uzip_result = LLUZipHelper::unzip_llsd(skin, data, data_size);              if (uzip_result != LLUZipHelper::ZR_OK)              {                  LL_WARNS(LOG_MESH) << "Mesh skin info parse error.  Not a valid mesh asset!  ID:  " << mesh_id @@ -1973,8 +1986,16 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat  	}  	{ -		LLMeshSkinInfo info(skin); -		info.mMeshID = mesh_id; +		LLMeshSkinInfo* info = nullptr; +		try +		{ +			info = new LLMeshSkinInfo(mesh_id, skin); +		} +		catch (const std::bad_alloc& ex) +		{ +			LL_WARNS() << "Failed to allocate skin info with exception: " << ex.what()  << LL_ENDL; +			return false; +		}          // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;  		{ @@ -1994,10 +2015,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3      {          try          { -            std::string res_str((char*)data, data_size); -            std::istringstream stream(res_str); - -            U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, stream, data_size); +            U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, data, data_size);              if (uzip_result != LLUZipHelper::ZR_OK)              {                  LL_WARNS(LOG_MESH) << "Mesh decomposition parse error.  Not a valid mesh asset!  ID:  " << mesh_id @@ -2006,7 +2024,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3                  return false;              }          } -        catch (std::bad_alloc&) +        catch (const std::bad_alloc&)          {              LL_WARNS(LOG_MESH) << "Out of memory for mesh ID " << mesh_id << " of size: " << data_size << LL_ENDL;              return false; @@ -2043,20 +2061,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_  		volume_params.setSculptID(mesh_id, LL_SCULPT_TYPE_MESH);  		LLPointer<LLVolume> volume = new LLVolume(volume_params,0); -        std::istringstream stream; -        try -        { -            std::string mesh_string((char*)data, data_size); -            stream.str(mesh_string); -        } -        catch (std::bad_alloc&) -        { -            // out of memory, we won't be able to process this mesh -            delete d; -            return MESH_OUT_OF_MEMORY; -        } - -		if (volume->unpackVolumeFaces(stream, data_size)) +		if (volume->unpackVolumeFaces(data, data_size))  		{  			d->mPhysicsShapeMesh.clear(); @@ -2870,58 +2875,72 @@ void LLMeshRepoThread::notifyLoadedMeshes()  		return;  	} -	while (!mLoadedQ.empty()) +	if (!mLoadedQ.empty())  	{ +		std::deque<LoadedMesh> loaded_queue; +  		mMutex->lock(); -		if (mLoadedQ.empty()) +		if (!mLoadedQ.empty())  		{ +			loaded_queue.swap(mLoadedQ);  			mMutex->unlock(); -			break; -		} -		LoadedMesh mesh = mLoadedQ.front(); // make sure nothing else owns volume pointer by this point -		mLoadedQ.pop(); -		mMutex->unlock(); -		 -		update_metrics = true; -		if (mesh.mVolume->getNumVolumeFaces() > 0) -		{ -			gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume); -		} -		else -		{ -			gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams,  -				LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail())); + +			update_metrics = true; + +			// Process the elements free of the lock +			for (const auto& mesh : loaded_queue) +			{ +				if (mesh.mVolume->getNumVolumeFaces() > 0) +				{ +					gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume); +				} +				else +				{ +					gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams, +						LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail())); +				} +			}  		}  	} -	while (!mUnavailableQ.empty()) +	if (!mUnavailableQ.empty())  	{ +		std::deque<LODRequest> unavil_queue; +  		mMutex->lock(); -		if (mUnavailableQ.empty()) +		if (!mUnavailableQ.empty())  		{ +			unavil_queue.swap(mUnavailableQ);  			mMutex->unlock(); -			break; -		} -		 -		LODRequest req = mUnavailableQ.front(); -		mUnavailableQ.pop(); -		mMutex->unlock(); -		update_metrics = true; -		gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD); +			update_metrics = true; + +			// Process the elements free of the lock +			for (const auto& req : unavil_queue) +			{ +				gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD); +			} +		}  	} -	if (! mSkinInfoQ.empty() || ! mDecompositionQ.empty()) +	if (!mSkinInfoQ.empty() || !mSkinUnavailableQ.empty() || ! mDecompositionQ.empty())  	{  		if (mMutex->trylock())  		{ -			std::list<LLMeshSkinInfo> skin_info_q; +			std::deque<LLMeshSkinInfo*> skin_info_q; +			std::deque<UUIDBasedRequest> skin_info_unavail_q;  			std::list<LLModel::Decomposition*> decomp_q;  			if (! mSkinInfoQ.empty())  			{  				skin_info_q.swap(mSkinInfoQ);  			} + +			if (! mSkinUnavailableQ.empty()) +			{ +				skin_info_unavail_q.swap(mSkinUnavailableQ); +			} +  			if (! mDecompositionQ.empty())  			{  				decomp_q.swap(mDecompositionQ); @@ -2935,6 +2954,11 @@ void LLMeshRepoThread::notifyLoadedMeshes()  				gMeshRepo.notifySkinInfoReceived(skin_info_q.front());  				skin_info_q.pop_front();  			} +			while (! skin_info_unavail_q.empty()) +			{ +				gMeshRepo.notifySkinInfoUnavailable(skin_info_unavail_q.front().mId); +				skin_info_unavail_q.pop_front(); +			}  			while (! decomp_q.empty())  			{ @@ -2959,7 +2983,7 @@ S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo  	if (iter != mMeshHeader.end())  	{ -		LLSD& header = iter->second; +		LLSD& header = iter->second.second;  		return LLMeshRepository::getActualMeshLOD(header, lod);  	} @@ -3162,7 +3186,7 @@ void LLMeshHeaderHandler::processFailure(LLCore::HttpStatus status)  	LLMutexLock lock(gMeshRepo.mThread->mMutex);  	for (int i(0); i < 4; ++i)  	{ -		gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); +		gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));  	}  } @@ -3191,7 +3215,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  		LLMutexLock lock(gMeshRepo.mThread->mMutex);  		for (int i(0); i < 4; ++i)  		{ -			gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); +			gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));  		}  	}  	else if (data && data_size > 0) @@ -3204,8 +3228,8 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  		LLMeshRepoThread::mesh_header_map::iterator iter = gMeshRepo.mThread->mMeshHeader.find(mesh_id);  		if (iter != gMeshRepo.mThread->mMeshHeader.end())  		{ -			header_bytes = (S32)gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; -			header = iter->second; +			header_bytes = (S32)iter->second.first; +			header = iter->second.second;  		}  		if (header_bytes > 0 @@ -3273,7 +3297,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  			LLMutexLock lock(gMeshRepo.mThread->mMutex);  			for (int i(0); i < 4; ++i)  			{ -				gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); +				gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));  			}  		}  	} @@ -3300,7 +3324,7 @@ void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)  					   << LL_ENDL;  	LLMutexLock lock(gMeshRepo.mThread->mMutex); -	gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); +	gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));  }  void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, @@ -3337,7 +3361,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body  							   << " Not retrying."  							   << LL_ENDL;  			LLMutexLock lock(gMeshRepo.mThread->mMutex); -			gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); +			gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));  		}  	}  	else @@ -3348,7 +3372,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body  						   << " Data size: " << data_size  						   << LL_ENDL;  		LLMutexLock lock(gMeshRepo.mThread->mMutex); -		gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); +		gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));  	}  } @@ -3366,9 +3390,8 @@ void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status)  					   << ", Reason:  " << status.toString()  					   << " (" << status.toTerseString() << ").  Not retrying."  					   << LL_ENDL; - -	// *TODO:  Mark mesh unavailable on error.  For now, simply leave -	// request unfulfilled rather than retry forever. +		LLMutexLock lock(gMeshRepo.mThread->mMutex); +		gMeshRepo.mThread->mSkinUnavailableQ.emplace_back(mMeshID);  }  void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, @@ -3399,7 +3422,8 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /*  		LL_WARNS(LOG_MESH) << "Error during mesh skin info processing.  ID:  " << mMeshID  						   << ", Unknown reason.  Not retrying."  						   << LL_ENDL; -		// *TODO:  Mark mesh unavailable on error +		LLMutexLock lock(gMeshRepo.mThread->mMutex); +		gMeshRepo.mThread->mSkinUnavailableQ.emplace_back(mMeshID);  	}  } @@ -3508,7 +3532,7 @@ LLMeshRepository::LLMeshRepository()    mMeshThreadCount(0),    mThread(NULL)  { - +	mSkinInfoCullTimer.resetWithExpiry(10.f);  }  void LLMeshRepository::init() @@ -3609,6 +3633,22 @@ S32 LLMeshRepository::update()  	return size ;  } +void LLMeshRepository::unregisterMesh(LLVOVolume* vobj) +{ +	for (auto& lod : mLoadingMeshes) +	{ +		for (auto& param : lod) +		{ +			vector_replace_with_last(param.second, vobj); +		} +	} + +	for (auto& skin_pair : mLoadingSkins) +	{ +		vector_replace_with_last(skin_pair.second, vobj); +	} +} +  S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); @@ -3624,15 +3664,19 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para  	{  		LLMutexLock lock(mMeshMutex);  		//add volume to list of loading meshes -		mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_params); +		const auto& mesh_id = mesh_params.getSculptID(); +		mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_id);  		if (iter != mLoadingMeshes[detail].end())  		{ //request pending for this mesh, append volume id to list -			iter->second.insert(vobj->getID()); +			auto it = std::find(iter->second.begin(), iter->second.end(), vobj); +			if (it == iter->second.end()) { +				iter->second.push_back(vobj); +			}  		}  		else  		{  			//first request for this mesh -			mLoadingMeshes[detail][mesh_params].insert(vobj->getID()); +			mLoadingMeshes[detail][mesh_id].push_back(vobj);  			mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail));  			LLMeshRepository::sLODPending++;  		} @@ -3789,6 +3833,28 @@ void LLMeshRepository::notifyLoadedMeshes()  	//call completed callbacks on finished decompositions  	mDecompThread->notifyCompleted(); +	if (mSkinInfoCullTimer.checkExpirationAndReset(10.f))  +	{ +		//// Clean up dead skin info +		//U64Bytes skinbytes(0); +		for (auto iter = mSkinMap.begin(), ender = mSkinMap.end(); iter != ender;) +		{ +			auto copy_iter = iter++; + +			//skinbytes += U64Bytes(sizeof(LLMeshSkinInfo)); +			//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(std::string)); +			//skinbytes += U64Bytes(copy_iter->second->mJointNums.size() * sizeof(S32)); +			//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4a)); +			//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4)); + +			if (copy_iter->second->getNumRefs() == 1) +			{ +				mSkinMap.erase(copy_iter); +			} +		} +		//LL_INFOS() << "Skin info cache elements:" << mSkinMap.size() << " Memory: " << U64Kilobytes(skinbytes) << LL_ENDL; +	} +  	// For major operations, attempt to get the required locks  	// without blocking and punt if they're not available.  The  	// longest run of holdoffs is kept in sMaxLockHoldoffs just @@ -3859,10 +3925,9 @@ void LLMeshRepository::notifyLoadedMeshes()  					for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin();  iter != mLoadingMeshes[i].end(); ++iter)  					{  						F32 max_score = 0.f; -						for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter) +						for (auto obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)  						{ -							LLViewerObject* object = gObjectList.findObject(*obj_iter); -							 +							LLVOVolume* object = *obj_iter;						  							if (object)  							{  								LLDrawable* drawable = object->mDrawable; @@ -3874,7 +3939,7 @@ void LLMeshRepository::notifyLoadedMeshes()  							}  						} -						score_map[iter->first.getSculptID()] = max_score; +						score_map[iter->first] = max_score;  					}  				} @@ -3926,24 +3991,39 @@ void LLMeshRepository::notifyLoadedMeshes()  	mThread->mSignal->signal();  } -void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info) +void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info)  { -	mSkinMap[info.mMeshID] = info; +	mSkinMap[info->mMeshID] = info; // Cache into LLPointer      // Alternative: We can get skin size from header -    sCacheBytesSkins += info.sizeBytes(); +    sCacheBytesSkins += info->sizeBytes(); -	skin_load_map::iterator iter = mLoadingSkins.find(info.mMeshID); +	skin_load_map::iterator iter = mLoadingSkins.find(info->mMeshID);  	if (iter != mLoadingSkins.end())  	{ -		for (std::set<LLUUID>::iterator obj_id = iter->second.begin(); obj_id != iter->second.end(); ++obj_id) +		for (LLVOVolume* vobj : iter->second)  		{ -			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*obj_id);  			if (vobj)  			{ -				vobj->notifyMeshLoaded(); +				vobj->notifySkinInfoLoaded(info);  			}  		} -		mLoadingSkins.erase(info.mMeshID); +		mLoadingSkins.erase(iter); +	} +} + +void LLMeshRepository::notifySkinInfoUnavailable(const LLUUID& mesh_id) +{ +	skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); +	if (iter != mLoadingSkins.end()) +	{ +		for (LLVOVolume* vobj : iter->second) +		{ +			if (vobj) +			{ +				vobj->notifySkinInfoUnavailable(); +			} +		} +		mLoadingSkins.erase(iter);  	}  } @@ -3972,14 +4052,15 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol  	S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail());  	//get list of objects waiting to be notified this mesh is loaded -	mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_params); +	const auto& mesh_id = mesh_params.getSculptID(); +	mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_id);  	if (volume && obj_iter != mLoadingMeshes[detail].end())  	{  		//make sure target volume is still valid  		if (volume->getNumVolumeFaces() <= 0)  		{ -			LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume.  ID:  " << mesh_params.getSculptID() +			LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume.  ID:  " << mesh_id  							   << LL_ENDL;  		} @@ -3993,37 +4074,35 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol  			}  			else  			{ -				LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_params.getSculptID() +				LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_id  								   << LL_ENDL;  			}  		}  		//notify waiting LLVOVolume instances that their requested mesh is available -		for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) +		for (LLVOVolume* vobj : obj_iter->second)  		{ -			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);  			if (vobj)  			{  				vobj->notifyMeshLoaded();  			}  		} -		mLoadingMeshes[detail].erase(mesh_params); +		mLoadingMeshes[detail].erase(obj_iter);  	}  }  void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod)  { //called from main thread  	//get list of objects waiting to be notified this mesh is loaded -	mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_params); - -	F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod); - +	const auto& mesh_id = mesh_params.getSculptID(); +	mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_id);  	if (obj_iter != mLoadingMeshes[lod].end())  	{ -		for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) +		F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod); + +		for (LLVOVolume* vobj : obj_iter->second)  		{ -			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);  			if (vobj)  			{  				LLVolume* obj_volume = vobj->getVolume(); @@ -4037,7 +4116,7 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params,  			}  		} -		mLoadingMeshes[lod].erase(mesh_params); +		mLoadingMeshes[lod].erase(obj_iter);  	}  } @@ -4046,7 +4125,7 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo  	return mThread->getActualMeshLOD(mesh_params, lod);  } -const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj) +const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;      if (mesh_id.notNull()) @@ -4054,7 +4133,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const          skin_map::iterator iter = mSkinMap.find(mesh_id);          if (iter != mSkinMap.end())          { -            return &(iter->second); +            return iter->second;          }          //no skin info known about given mesh, try to fetch it @@ -4063,14 +4142,22 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const              LLMutexLock lock(mMeshMutex);              //add volume to list of loading meshes              skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); -            if (iter == mLoadingSkins.end()) -            { //no request pending for this skin info +			if (iter != mLoadingSkins.end()) +			{ //request pending for this mesh, append volume id to list +				auto it = std::find(iter->second.begin(), iter->second.end(), requesting_obj); +				if (it == iter->second.end()) { +					iter->second.push_back(requesting_obj); +				} +			} +			else +			{ +				//first request for this mesh +				mLoadingSkins[mesh_id].push_back(requesting_obj);                  mPendingSkinRequests.push(mesh_id);              } -            mLoadingSkins[mesh_id].insert(requesting_obj->getID());          }      } -	return NULL; +	return nullptr;  }  void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) @@ -4173,16 +4260,13 @@ bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)  bool LLMeshRepoThread::hasPhysicsShapeInHeader(const LLUUID& mesh_id)  {      LLMutexLock lock(mHeaderMutex); -    if (mMeshHeaderSize[mesh_id] > 0) +    mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); +    if (iter != mMeshHeader.end() && iter->second.first > 0)      { -        mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); -        if (iter != mMeshHeader.end()) +        LLSD &mesh = iter->second.second; +        if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0))          { -            LLSD &mesh = iter->second; -            if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0)) -            { -                return true; -            } +            return true;          }      } @@ -4207,9 +4291,9 @@ S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod)  	{  		LLMutexLock lock(mThread->mHeaderMutex);  		LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); -		if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) +		if (iter != mThread->mMeshHeader.end() && iter->second.first > 0)  		{ -			LLSD& header = iter->second; +			const LLSD& header = iter->second.second;  			if (header.has("404"))  			{ @@ -4313,9 +4397,9 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* by      {          LLMutexLock lock(mThread->mHeaderMutex);          LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); -        if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) +        if (iter != mThread->mMeshHeader.end() && iter->second.first > 0)          { -            result  = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); +            result  = getStreamingCostLegacy(iter->second.second, radius, bytes, bytes_visible, lod, unscaled_value);          }      }      if (result > 0.f) @@ -4628,9 +4712,9 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data)      {          LLMutexLock lock(mThread->mHeaderMutex);          LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); -        if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) +        if (iter != mThread->mMeshHeader.end() && iter->second.first > 0)          { -            LLSD& header = iter->second; +            LLSD& header = iter->second.second;              bool header_invalid = (header.has("404")                                     || !header.has("lowest_lod") diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index f61da3e571..e3688ff243 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -210,10 +210,8 @@ public:  	LLCondition* mSignal;  	//map of known mesh headers -	typedef std::map<LLUUID, LLSD> mesh_header_map; +	typedef boost::unordered_map<LLUUID, std::pair<U32, LLSD>> mesh_header_map; // pair is header_size and data  	mesh_header_map mMeshHeader; -	 -	std::map<LLUUID, U32> mMeshHeaderSize;  	class HeaderRequest : public RequestStats  	{  @@ -283,10 +281,13 @@ public:  	};  	//set of requested skin info -	std::set<UUIDBasedRequest> mSkinRequests; +	std::deque<UUIDBasedRequest> mSkinRequests;  	// list of completed skin info requests -	std::list<LLMeshSkinInfo> mSkinInfoQ; +	std::deque<LLMeshSkinInfo*> mSkinInfoQ; + +	// list of skin info requests that have failed or are unavailaibe +	std::deque<UUIDBasedRequest> mSkinUnavailableQ;  	//set of requested decompositions  	std::set<UUIDBasedRequest> mDecompositionRequests; @@ -304,13 +305,13 @@ public:  	std::queue<LODRequest> mLODReqQ;  	//queue of unavailable LODs (either asset doesn't exist or asset doesn't have desired LOD) -	std::queue<LODRequest> mUnavailableQ; +	std::deque<LODRequest> mUnavailableQ;  	//queue of successfully loaded meshes -	std::queue<LoadedMesh> mLoadedQ; +	std::deque<LoadedMesh> mLoadedQ;  	//map of pending header requests and currently desired LODs -	typedef std::map<LLVolumeParams, std::vector<S32> > pending_lod_map; +	typedef boost::unordered_map<LLUUID, std::vector<S32> > pending_lod_map;  	pending_lod_map mPendingLOD;  	// llcorehttp library interface objects. @@ -354,7 +355,7 @@ public:  	//send request for skin info, returns true if header info exists   	//  (should hold onto mesh_id and try again later if header info does not exist) -	bool fetchMeshSkinInfo(const LLUUID& mesh_id); +	bool fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry = true);  	//send request for decomposition, returns true if header info exists   	//  (should hold onto mesh_id and try again later if header info does not exist) @@ -577,18 +578,20 @@ public:  	void shutdown();  	S32 update(); +	void unregisterMesh(LLVOVolume* volume);  	//mesh management functions  	S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);  	void notifyLoadedMeshes();  	void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);  	void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod); -	void notifySkinInfoReceived(LLMeshSkinInfo& info); +	void notifySkinInfoReceived(LLMeshSkinInfo* info); +	void notifySkinInfoUnavailable(const LLUUID& info);  	void notifyDecompositionReceived(LLModel::Decomposition* info);  	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);  	static S32 getActualMeshLOD(LLSD& header, S32 lod); -	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj = nullptr); +	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj = nullptr);  	LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);  	void fetchPhysicsShape(const LLUUID& mesh_id);  	bool hasPhysicsShape(const LLUUID& mesh_id); @@ -613,10 +616,10 @@ public:  	static void metricsProgress(unsigned int count);  	static void metricsUpdate(); -	typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map; +	typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > mesh_load_map;  	mesh_load_map mLoadingMeshes[4]; -	typedef std::unordered_map<LLUUID, LLMeshSkinInfo> skin_map; +	typedef std::unordered_map<LLUUID, LLPointer<LLMeshSkinInfo>> skin_map;  	skin_map mSkinMap;  	typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map; @@ -627,7 +630,7 @@ public:  	std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;  	//list of mesh ids awaiting skin info -	typedef std::map<LLUUID, std::set<LLUUID> > skin_load_map; +	typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > skin_load_map;  	skin_load_map mLoadingSkins;  	//list of mesh ids that need to send skin info fetch requests @@ -652,6 +655,8 @@ public:  	std::vector<LLMeshUploadThread*> mUploadWaitList;  	LLPhysicsDecomp* mDecompThread; + +	LLFrameTimer     mSkinInfoCullTimer;  	class inventory_data  	{ diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 642df7f931..e1a5b22490 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1926,32 +1926,16 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d                      if (sloppy_ratio < 0)                      {                          // Sloppy method didn't work, try with smaller decimation values -                        S32 size_vertices = 0; - -                        for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) -                        { -                            const LLVolumeFace &face = base->getVolumeFace(face_idx); -                            size_vertices += face.mNumVertices; -                        } - -                        // Complex models aren't supposed to get here, they are supposed -                        // to work on a first try of sloppy due to having more viggle room. -                        // If they didn't, something is likely wrong, no point locking the -                        // thread in a long calculation that will fail. -                        const U32 too_many_vertices = 27000; -                        if (size_vertices > too_many_vertices) -                        { -                            LL_WARNS() << "Sloppy optimization method failed for a complex model " << target_model->getName() << LL_ENDL; -                        } -                        else                          {                              // Find a decimator that does work                              F32 sloppy_decimation_step = sqrt((F32)decimation); // example: 27->15->9->5->3                              F32 sloppy_decimator = indices_decimator / sloppy_decimation_step; +                            U64Microseconds end_time = LLTimer::getTotalTime() + U64Seconds(5);                              while (sloppy_ratio < 0                                  && sloppy_decimator > precise_ratio -                                && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case +                                && sloppy_decimator > 1 // precise_ratio isn't supposed to be below 1, but check just in case +                                && end_time > LLTimer::getTotalTime())                              {                                  sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);                                  sloppy_decimator = sloppy_decimator / sloppy_decimation_step; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index b34be80b07..1f84e14877 100755..100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -102,8 +102,7 @@ LLNetMap::LLNetMap (const Params & p)  	mObjectImagep(),  	mClosestAgentToCursor(),  	mClosestAgentAtLastRightClick(), -	mToolTipMsg(), -	mPopupMenu(NULL) +	mToolTipMsg()  {  	mScale = gSavedSettings.getF32("MiniMapScale");      if (gAgent.isFirstLogin()) @@ -119,6 +118,10 @@ LLNetMap::LLNetMap (const Params & p)  LLNetMap::~LLNetMap()  { +	if (mPopupMenu) +	{ +        mPopupMenu->die(); +	}  }  BOOL LLNetMap::postBuild() @@ -137,8 +140,7 @@ BOOL LLNetMap::postBuild()      mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder,                                                                            LLViewerMenuHolderGL::child_registry_t::instance());      mPopupMenu->setItemEnabled("Re-center map", false); - -    return true; +	return TRUE;  }  void LLNetMap::setScale( F32 scale ) @@ -1045,10 +1047,10 @@ BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)  {  	if (mPopupMenu)  	{ -        mPopupWorldPos = viewPosToGlobal(x, y); -		mPopupMenu->buildDrawLabels(); -		mPopupMenu->updateParent(LLMenuGL::sMenuContainer); -		mPopupMenu->setItemEnabled("Stop tracking", LLTracker::isTracking(0)); +		mPopupWorldPos = viewPosToGlobal(x, y); +        mPopupMenu->buildDrawLabels(); +        mPopupMenu->updateParent(LLMenuGL::sMenuContainer); +        mPopupMenu->setItemEnabled("Stop Tracking", LLTracker::isTracking(0));  		LLMenuGL::showPopup(this, mPopupMenu, x, y);  	}  	return TRUE; @@ -1184,7 +1186,7 @@ void LLNetMap::handleStopTracking (const LLSD& userdata)  {  	if (mPopupMenu)  	{ -		mPopupMenu->setItemEnabled ("Stop tracking", false); +        mPopupMenu->setItemEnabled ("Stop Tracking", false);  		LLTracker::stopTracking (LLTracker::isTracking(NULL));  	}  } diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h index fe1aca65a9..20d0828ab1 100644 --- a/indra/newview/llnetmap.h +++ b/indra/newview/llnetmap.h @@ -162,7 +162,7 @@ private:      void setMapOrientation(const LLSD& userdata);      void popupShowAboutLand(const LLSD& userdata); -	LLMenuGL*		mPopupMenu; +    LLMenuGL*       mPopupMenu;  	uuid_vec_t		gmSelected;  }; diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp index 6a79a0c68c..f86edfd0cf 100644 --- a/indra/newview/llnotificationlistitem.cpp +++ b/indra/newview/llnotificationlistitem.cpp @@ -521,8 +521,6 @@ void LLGroupNoticeNotificationListItem::close()  void LLGroupNoticeNotificationListItem::onClickAttachment()  {      if (mInventoryOffer != NULL) { -        mInventoryOffer->forceResponse(IOR_ACCEPT); -          static const LLUIColor textColor = LLUIColorTable::instance().getColor(              "GroupNotifyDimmedTextColor");          mAttachmentTextBox->setColor(textColor); @@ -532,7 +530,7 @@ void LLGroupNoticeNotificationListItem::onClickAttachment()          if (!isAttachmentOpenable(mInventoryOffer->mType)) {              LLNotifications::instance().add("AttachmentSaved", LLSD(), LLSD());          } - +        mInventoryOffer->forceResponse(IOR_ACCEPT);          mInventoryOffer = NULL;      }  } diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index ea10aa75ae..0103bf628a 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1663,7 +1663,7 @@ void LLPanelEditWearable::initPreviousAlphaTextureEntry(LLAvatarAppearanceDefine  class LLMetricSystemHandler : public LLCommandHandler  {  public: -        LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_THROTTLE) { } +        LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_CLICK_ONLY) { }          bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)          { diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 89256b40c4..81acb1c8b4 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -307,6 +307,13 @@ LLPanelMainInventory::~LLPanelMainInventory( void )  	gInventory.removeObserver(this);  	delete mSavedFolderState; + +	auto menu = mMenuAddHandle.get(); +	if(menu) +	{ +		menu->die(); +		mMenuAddHandle.markDead(); +	}  }  LLInventoryPanel* LLPanelMainInventory::getAllItemsPanel() @@ -1177,13 +1184,12 @@ void LLPanelMainInventory::initListCommandsHandlers()  	mEnableCallbackRegistrar.add("Inventory.GearDefault.Check", boost::bind(&LLPanelMainInventory::isActionChecked, this, _2));  	mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2));  	mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -	mGearMenuButton->setMenu(mMenuGearDefault); +	mGearMenuButton->setMenu(mMenuGearDefault, LLMenuButton::MP_TOP_LEFT, true);  	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory_add.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());  	mMenuAddHandle = menu->getHandle();  	mMenuVisibility = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_search_visibility.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -	mVisibilityMenuButton->setMenu(mMenuVisibility); -	mVisibilityMenuButton->setMenuPosition(LLMenuButton::MP_BOTTOM_LEFT); +	mVisibilityMenuButton->setMenu(mMenuVisibility, LLMenuButton::MP_BOTTOM_LEFT, true);  	// Update the trash button when selected item(s) get worn or taken off.  	LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLPanelMainInventory::updateListCommands, this)); diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index cfaa9456be..445bed673b 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1275,7 +1275,8 @@ LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Par  	mHaveInventory(FALSE),  	mIsInventoryEmpty(TRUE),  	mInventoryNeedsUpdate(FALSE), -	mInventoryViewModel(p.name) +	mInventoryViewModel(p.name), +    mShowRootFolder(p.show_root_folder)  {  	// Setup context menu callbacks  	mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelObjectInventory::doToSelected, this, _2)); @@ -1360,6 +1361,7 @@ void LLPanelObjectInventory::reset()  	mFolders = LLUICtrlFactory::create<LLFolderView>(p);  	mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); +	mFolders->setEnableRegistrar(&mEnableCallbackRegistrar);  	if (hasFocus())  	{ @@ -1526,15 +1528,23 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root  		p.font_highlight_color = item_color;  		LLFolderViewFolder* new_folder = LLUICtrlFactory::create<LLFolderViewFolder>(p); -		new_folder->addToFolder(mFolders); -		new_folder->toggleOpen(); + +        if (mShowRootFolder) +        { +            new_folder->addToFolder(mFolders); +            new_folder->toggleOpen(); +        }  		if (!contents.empty())  		{ -			createViewsForCategory(&contents, inventory_root, new_folder); +			createViewsForCategory(&contents, inventory_root, mShowRootFolder ? new_folder : mFolders);  		} -        // Refresh for label to add item count -        new_folder->refresh(); + +        if (mShowRootFolder) +        { +            // Refresh for label to add item count +            new_folder->refresh(); +        }  	}  } diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index 7b9ecfb8f3..0e450d8ce9 100644 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -48,8 +48,14 @@ class LLViewerObject;  class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener  {  public: -	// dummy param block for template registration purposes -	struct Params : public LLPanel::Params {}; +    struct Params : public LLInitParam::Block<Params, LLPanel::Params> +    { +        Optional<bool> show_root_folder; + +        Params() +            : show_root_folder("show_root_folder", true) +        {} +    };  	LLPanelObjectInventory(const Params&);  	virtual ~LLPanelObjectInventory(); @@ -110,6 +116,7 @@ private:  	BOOL mIsInventoryEmpty; // 'Empty' label  	BOOL mInventoryNeedsUpdate; // for idle, set on changed callback  	LLFolderViewModelInventory	mInventoryViewModel;	 +    bool mShowRootFolder;  };  #endif // LL_LLPANELOBJECTINVENTORY_H diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index f4eaa78f11..deebf0cd1b 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -484,6 +484,30 @@ public:  	// requires trusted browser to trigger  	LLAgentHandler() : LLCommandHandler("agent", UNTRUSTED_THROTTLE) { } +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { +        if (params.size() < 2) +        { +            return true; // don't block, will fail later +        } + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            return true; +        } + +        const std::string verb = params[1].asString(); +        if (verb == "about" || verb == "inspect" || verb == "reportAbuse") +        { +            return true; +        } +        return false; +    } +  	bool handle(const LLSD& params, const LLSD& query_map,  		LLMediaCtrl* web)  	{ @@ -1280,6 +1304,8 @@ void LLPanelProfileSecondLife::fillRightsData()  void LLPanelProfileSecondLife::fillAgeData(const LLDate &born_on)  { +    // Date from server comes already converted to stl timezone, +    // so display it as an UTC + 0      std::string name_and_date = getString("date_format");      LLSD args_name;      args_name["datetime"] = (S32)born_on.secondsSinceEpoch(); diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp index a3913ddc49..1ff12b4f37 100644 --- a/indra/newview/llpanelprofileclassifieds.cpp +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -81,6 +81,30 @@ public:  	std::set<LLUUID> mClassifiedIds;  	std::string mRequestVerb; + +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { +        if (params.size() < 1) +        { +            return true; // don't block, will fail later +        } + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            return true; +        } + +        const std::string verb = params[0].asString(); +        if (verb == "create") +        { +            return false; +        } +        return true; +    }  	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)      { diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 774119f169..45d0252e4f 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -63,6 +63,30 @@ public:      // requires trusted browser to trigger      LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { } +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { +        if (params.size() < 1) +        { +            return true; // don't block, will fail later +        } + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            return true; +        } + +        const std::string verb = params[0].asString(); +        if (verb == "create") +        { +            return false; +        } +        return true; +    } +      bool handle(const LLSD& params, const LLSD& query_map,          LLMediaCtrl* web)      { diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 3fd4f51559..33656566d1 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -255,7 +255,7 @@ void LLPreviewNotecard::loadAsset()  			else  			{  				LLHost source_sim = LLHost(); -				LLSD* user_data = new LLSD(); +				LLSD* user_data = nullptr;  				if (mObjectUUID.notNull())  				{  					LLViewerObject *objectp = gObjectList.findObject(mObjectUUID); @@ -274,6 +274,7 @@ void LLPreviewNotecard::loadAsset()  						mAssetStatus = PREVIEW_ASSET_LOADED;  						return;  					} +					user_data = new LLSD();  					user_data->with("taskid", mObjectUUID).with("itemid", mItemUUID);  				}  				else diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp index da912ef3d4..6a27ff3047 100644 --- a/indra/newview/llscriptfloater.cpp +++ b/indra/newview/llscriptfloater.cpp @@ -460,10 +460,11 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)  		if(it != mNotifications.end())  		{ +			LLUUID old_id = it->first; // copy LLUUID to prevent use after free when it is erased below  			LLChicletPanel * chiclet_panelp = LLChicletBar::getInstance()->getChicletPanel();  			if (NULL != chiclet_panelp)  			{ -				LLIMChiclet * chicletp = chiclet_panelp->findChiclet<LLIMChiclet>(it->first); +				LLIMChiclet * chicletp = chiclet_panelp->findChiclet<LLIMChiclet>(old_id);  				if (NULL != chicletp)  				{  					// Pass the new_message icon state further. @@ -472,14 +473,14 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)  				}  			} -			LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", it->first); +			LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", old_id);  			if (floater)  			{  				// Generate chiclet with a "new message" indicator if a docked window was opened but not in focus. See EXT-3142.  				set_new_message |= !floater->hasFocus();  			} -			removeNotification(it->first); +			removeNotification(old_id);  		}  	} diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 06a6c5e373..b4382a4646 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -173,11 +173,103 @@  class LLFloaterOpenHandler : public LLCommandHandler  {  public: -	// requires trusted browser to trigger +	// requires trusted browser to trigger or an explicit click  	LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { } -	bool handle(const LLSD& params, const LLSD& query_map, -				LLMediaCtrl* web) +    bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) override +    { +        if (params.size() != 1) +        { +            return true; // will fail silently +        } +         +        std::string fl_name = params[0].asString(); + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            const std::list<std::string> blacklist_clicked = { +                "camera_presets", +                "delete_pref_preset", +                "forget_username", +                "god_tools", +                "group_picker", +                "hud", +                "incoming_call", +                "linkreplace", +                "message_critical", // Modal!!! Login specific. +                "message_tos", // Modal!!! Login specific. +                "save_pref_preset", +                "save_camera_preset", +                "region_restarting", +                "outfit_snapshot", +                "upload_anim_bvh", +                "upload_anim_anim", +                "upload_image", +                "upload_model", +                "upload_script", +                "upload_sound" +            }; +            return std::find(blacklist_clicked.begin(), blacklist_clicked.end(), fl_name) == blacklist_clicked.end(); +        } +        else +        { +            const std::list<std::string> blacklist_untrusted = { +                "360capture", +                "block_timers", +                "add_payment_method", +                "appearance", +                "associate_listing", +                "avatar_picker", +                "camera", +                "camera_presets", +                "classified", +                "add_landmark", +                "delete_pref_preset", +                "env_fixed_environmentent_water", +                "env_fixed_environmentent_sky", +                "env_edit_extdaycycle", +                "font_test", +                "forget_username", +                "god_tools", +                "group_picker", +                "hud", +                "incoming_call", +                "linkreplace", +                "mem_leaking", +                "marketplace_validation", +                "message_critical", // Modal!!! Login specific. If this is in use elsewhere, better to create a non modal variant +                "message_tos", // Modal!!! Login specific. +                "mute_object_by_name", +                "publish_classified", +                "save_pref_preset", +                "save_camera_preset", +                "region_restarting", +                "script_debug", +                "script_debug_output", +                "sell_land", +                "outfit_snapshot", +                "upload_anim_bvh", +                "upload_anim_anim", +                "upload_image", +                "upload_model", +                "upload_script", +                "upload_sound" +            }; +            return std::find(blacklist_untrusted.begin(), blacklist_untrusted.end(), fl_name) == blacklist_untrusted.end(); +        } + + +        return true; +    } + +	bool handle( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web) override  	{  		if (params.size() != 1)  		{ diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 43b9cd90bd..6bab2c2100 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -1614,12 +1614,22 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask,              clicktype = CLICK_DOUBLELEFT;          } +        // If the first LMB click is handled by the menu, skip the following double click +        static bool skip_double_click = false; +        if (clicktype == CLICK_LEFT && down ) +        { +            skip_double_click = handled; +        }          if (double_click_sp && down)          {              // Consume click.              // Due to handling, double click that is not handled will be immediately followed by LMB click          } +        else if (clicktype == CLICK_DOUBLELEFT && skip_double_click) +        { +            handled = true; +        }          // If UI handled 'down', it should handle 'up' as well          // If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI          else if (handled) diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 55ac817479..50252556de 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -232,7 +232,7 @@ class LLInventoryHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_THROTTLE) { } +	LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_CLICK_ONLY) { }  	bool handle(const LLSD& params, const LLSD& query_map,  				LLMediaCtrl* web) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 3573af40cb..3bff01625b 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -5628,6 +5628,7 @@ class LLToolsSelectNextPartFace : public view_listener_t                      }                  }                  LLSelectMgr::getInstance()->selectObjectOnly(to_select, new_te); +                LLSelectMgr::getInstance()->addAsIndividual(to_select, new_te, false);              }              else              { diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index aad6c14b4d..b2e2f23ca7 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3233,36 +3233,39 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)          return;      } -    LLFilenameAndTask* ft = new LLFilenameAndTask; -    ft->mTaskID = task_id;      // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update -    msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); +    S16 serial = 0; +    msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, serial); -    if (ft->mSerial == object->mInventorySerialNum -        && ft->mSerial < object->mExpectedInventorySerialNum) +    if (serial == object->mInventorySerialNum +        && serial < object->mExpectedInventorySerialNum)      {          // Loop Protection.          // We received same serial twice.          // Viewer did some changes to inventory that couldn't be saved server side          // or something went wrong to cause serial to be out of sync.          // Drop xfer and restart after some time, assign server's value as expected -        LL_WARNS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client expected serial: " << object->mExpectedInventorySerialNum << LL_ENDL; -        object->mExpectedInventorySerialNum = ft->mSerial; +        LL_WARNS() << "Task inventory serial might be out of sync, server serial: " << serial << " client expected serial: " << object->mExpectedInventorySerialNum << LL_ENDL; +        object->mExpectedInventorySerialNum = serial;          object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_DESYNC);      } -    else if (ft->mSerial < object->mExpectedInventorySerialNum) +    else if (serial < object->mExpectedInventorySerialNum)      {          // Out of date message, record to current serial for loop protection, but do not load it          // Drop xfer and restart after some time -        if (ft->mSerial < object->mInventorySerialNum) +        if (serial < object->mInventorySerialNum)          {              LL_WARNS() << "Task serial decreased. Potentially out of order packet or desync." << LL_ENDL;          } -        object->mInventorySerialNum = ft->mSerial; +        object->mInventorySerialNum = serial;          object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_OUTDATED);      } -    else if (ft->mSerial >= object->mExpectedInventorySerialNum) +    else if (serial >= object->mExpectedInventorySerialNum)      { +        LLFilenameAndTask* ft = new LLFilenameAndTask; +        ft->mTaskID = task_id; +        ft->mSerial = serial; +                  // We received version we expected or newer. Load it.          object->mInventorySerialNum = ft->mSerial;          object->mExpectedInventorySerialNum = ft->mSerial; @@ -3297,7 +3300,7 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)              object->mRegionp->getHost(),              TRUE,              &LLViewerObject::processTaskInvFile, -            (void**)ft, +            (void**)ft, // This takes ownership of ft              LLXferManager::HIGH_PRIORITY);          if (object->mInvRequestState == INVENTORY_XFER)          { diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp index f042040e98..1751ee1ebb 100644 --- a/indra/newview/llviewerpartsource.cpp +++ b/indra/newview/llviewerpartsource.cpp @@ -793,7 +793,7 @@ void LLViewerPartSourceBeam::update(const F32 dt)  		}  		LLViewerPart* part = new LLViewerPart(); -		part->init(this, mImagep, NULL); +		part->init(this, mImagep, updatePart);  		part->mFlags = LLPartData::LL_PART_INTERP_COLOR_MASK |  						LLPartData::LL_PART_INTERP_SCALE_MASK | diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 8a7d5f12d0..588fb4eb1b 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -3421,6 +3421,59 @@ void LLViewerWindow::updateUI()  		root_view = mRootView;  	} +	static LLCachedControl<bool> dump_menu_holder(gSavedSettings, "DumpMenuHolderSize", false); +	if (dump_menu_holder) +	{ +		static bool init = false; +		static LLFrameTimer child_count_timer; +		static std::vector <std::string> child_vec; +		if (!init) +		{ +			child_count_timer.resetWithExpiry(5.f); +			init = true; +		} +		if (child_count_timer.hasExpired()) +		{ +			LL_INFOS() << "gMenuHolder child count: " << gMenuHolder->getChildCount() << LL_ENDL; +			std::vector<std::string> local_child_vec; +			LLView::child_list_t child_list = *gMenuHolder->getChildList(); +			for (auto child : child_list) +			{ +				local_child_vec.emplace_back(child->getName()); +			} +			if (!local_child_vec.empty() && local_child_vec != child_vec) +			{ +				std::vector<std::string> out_vec; +				std::sort(local_child_vec.begin(), local_child_vec.end()); +				std::sort(child_vec.begin(), child_vec.end()); +				std::set_difference(child_vec.begin(), child_vec.end(), local_child_vec.begin(), local_child_vec.end(), std::inserter(out_vec, out_vec.begin())); +				if (!out_vec.empty()) +				{ +					LL_INFOS() << "gMenuHolder removal diff size: '"<<out_vec.size() <<"' begin_child_diff"; +					for (auto str : out_vec) +					{ +						LL_CONT << " : " << str; +					} +					LL_CONT << " : end_child_diff" << LL_ENDL; +				} + +				out_vec.clear(); +				std::set_difference(local_child_vec.begin(), local_child_vec.end(), child_vec.begin(), child_vec.end(), std::inserter(out_vec, out_vec.begin())); +				if (!out_vec.empty()) +				{ +					LL_INFOS() << "gMenuHolder addition diff size: '" << out_vec.size() << "' begin_child_diff"; +					for (auto str : out_vec) +					{ +						LL_CONT << " : " << str; +					} +					LL_CONT << " : end_child_diff" << LL_ENDL; +				} +				child_vec.swap(local_child_vec); +			} +			child_count_timer.resetWithExpiry(5.f); +		} +	} +  	// only update mouse hover set when UI is visible (since we shouldn't send hover events to invisible UI  	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))  	{ diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index e923115c43..e24d131345 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -228,6 +228,9 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re      mColorChanged = FALSE;  	mSpotLightPriority = 0.f; +	mSkinInfoFailed = false; +	mSkinInfo = NULL; +  	mMediaImplList.resize(getNumTEs());  	mLastFetchedMediaVersion = -1;      mServerDrawableUpdateCount = 0; @@ -244,6 +247,8 @@ LLVOVolume::~LLVOVolume()  	delete mVolumeImpl;  	mVolumeImpl = NULL; +	gMeshRepo.unregisterMesh(this); +  	if(!mMediaImplList.empty())  	{  		for(U32 i = 0 ; i < mMediaImplList.size() ; i++) @@ -1095,6 +1100,12 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo  			// if it's a mesh  			if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)  			{ +				if (mSkinInfo && mSkinInfo->mMeshID != volume_params.getSculptID()) +				{ +					mSkinInfo = NULL; +					mSkinInfoFailed = false; +				} +  				if (!getVolume()->isMeshAssetLoaded())  				{   					//load request not yet issued, request pipeline load this mesh @@ -1106,6 +1117,14 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo  					}  				} +				if (!mSkinInfo && !mSkinInfoFailed) +				{ +					const LLMeshSkinInfo* skin_info = gMeshRepo.getSkinInfo(volume_params.getSculptID(), this); +					if (skin_info) +					{ +						notifySkinInfoLoaded(skin_info); +					} +				}  			}  			else // otherwise is sculptie  			{ @@ -1158,6 +1177,9 @@ void LLVOVolume::updateSculptTexture()  		{  			mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);  		} + +		mSkinInfoFailed = false; +		mSkinInfo = NULL;  	}  	else  	{ @@ -1212,6 +1234,20 @@ void LLVOVolume::notifyMeshLoaded()      updateVisualComplexity();  } +void LLVOVolume::notifySkinInfoLoaded(const LLMeshSkinInfo* skin) +{ +	mSkinInfoFailed = false; +	mSkinInfo = skin; + +	notifyMeshLoaded(); +} + +void LLVOVolume::notifySkinInfoUnavailable() +{ +	mSkinInfoFailed = true; +	mSkinInfo = nullptr; +} +  // sculpt replaces generate() for sculpted surfaces  void LLVOVolume::sculpt()  {	 @@ -3645,7 +3681,7 @@ const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const  {      if (getVolume())      { -        return gMeshRepo.getSkinInfo(getMeshID(), this); +         return mSkinInfo;      }      else      { diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 01ad40274b..59599ddc0c 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -353,6 +353,8 @@ public:      void updateVisualComplexity();  	void notifyMeshLoaded(); +	void notifySkinInfoLoaded(const LLMeshSkinInfo* skin); +	void notifySkinInfoUnavailable();  	// Returns 'true' iff the media data for this object is in flight  	bool isMediaDataBeingFetched() const; @@ -437,6 +439,8 @@ private:  	LLPointer<LLRiggedVolume> mRiggedVolume; +	bool mSkinInfoFailed; +	LLConstPointer<LLMeshSkinInfo> mSkinInfo;  	// statics  public:  	static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index aa32ef04b2..fb9f5f41e6 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -293,13 +293,13 @@ void LLWorld::removeRegion(const LLHost &host)  	mRegionRemovedSignal(regionp); -	delete regionp; -  	updateWaterObjects();  	//double check all objects of this region are removed.  	gObjectList.clearAllMapObjectsInRegion(regionp) ;  	//llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ; + +	delete regionp; // Delete last to prevent use after free  } diff --git a/indra/newview/skins/default/xui/en/floater_object_weights.xml b/indra/newview/skins/default/xui/en/floater_object_weights.xml index eb283a1043..889efa061c 100644 --- a/indra/newview/skins/default/xui/en/floater_object_weights.xml +++ b/indra/newview/skins/default/xui/en/floater_object_weights.xml @@ -2,7 +2,7 @@  <floater   can_close="true"   can_tear_off="false" - height="315" + height="289"   help_topic="object_weights"   layout="topleft"   name="object_weights" @@ -320,23 +320,4 @@       top_delta="0"       value="Total capacity"       width="130" /> -    <view_border -     bevel_style="none" -     follows="top|left" -     height="0" -     layout="topleft" -     left="10" -     name="land_impacts_text_border" -     top_pad="5" -     width="180"/> - -    <text -     follows="left|top" -     height="16" -     layout="topleft" -     left="10" -     name="help_SLURL" -     top_pad="10" -     value="[secondlife:///app/help/object_weights What is all this?...]" -     width="180" />  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_openobject.xml b/indra/newview/skins/default/xui/en/floater_openobject.xml index 912db80bcc..ec03d7d32c 100644 --- a/indra/newview/skins/default/xui/en/floater_openobject.xml +++ b/indra/newview/skins/default/xui/en/floater_openobject.xml @@ -3,7 +3,7 @@   legacy_header_height="18"   can_resize="true"   default_tab_group="1" - height="370" + height="350"   layout="topleft"   min_height="190"   min_width="285" @@ -31,62 +31,18 @@       background_visible="false"       draw_border="false"       follows="all" -     height="240" +     height="265"       layout="topleft" +     show_root_folder="false"       left="10"       name="object_contents"       top_pad="0"       width="284" /> -  	<view_border -     bevel_style="none" -     follows="bottom|left" -     height="50" -     highlight_light_color="0.6 0.6 0.6" -     layout="topleft" -     left="10" -     name="border" -     top_pad="5" -     width="270"/>  -  	<text -  	 follows="bottom|left" -  	 height="15" -  	 layout="topleft" -  	 left="15" -  	 name="border_note" -  	 text_color="White" -  	 top_delta="5"> -  	 	Copy to inventory and wear -    </text>   - 	<button -     follows="bottom|left" -     height="23" -     label="Add to outfit" -     label_selected="Add to outfit" -     layout="topleft" - 	 left="15"     -     name="copy_and_wear_button" 	 - 	 top_pad="3"	 -     width="135"> -        <button.commit_callback -         function="OpenObject.MoveAndWear" /> -    </button> -	<button -     follows="bottom|left" -     height="23" -     label="Replace outfit" -     label_selected="Replace outfit" -     layout="topleft" -     left_pad="5" -     name="copy_and_replace_button" -     width="120"> -        <button.commit_callback -         function="OpenObject.ReplaceOutfit" /> -    </button>        <button       follows="bottom|left"       height="23"       label="Only copy to inventory" -     label_selected="Only copy to inventory" +     label_selected="Copy to inventory"       layout="topleft"       left="15"       name="copy_to_inventory_button" diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml index 41384a77b8..59117c0178 100644 --- a/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml @@ -82,17 +82,20 @@          width="62">        Name      </text> -    <line_editor -        border_style="line" -        border_thickness="1" -        follows="left|top" -        height="20" -        layout="topleft" -        left_pad="0" -        top_pad="-18" -        max_length_chars="255" -        name="filter_by_name" -        width="161" /> + +    <search_editor +       follows="left|top" +       search_button_visible="false" +       height="20" +       text_readonly_color="DkGray" +       label="Objects by Name" +       layout="topleft" +       left_pad="0" +       top_pad="-18" +       name="filter_by_name" +       select_on_focus="true" +       width="161"> +    </search_editor>      <text          name="linksets_desc_label"          height="13" @@ -108,17 +111,19 @@          width="88">        Description      </text> -    <line_editor -        border_style="line" -        border_thickness="1" -        follows="left|top" -        height="20" -        layout="topleft" -        left_pad="0" -        top_pad="-17" -        max_length_chars="255" -        name="filter_by_description" -        width="162" /> +    <search_editor +       follows="left|top" +       search_button_visible="false" +       height="20" +       text_readonly_color="DkGray" +       label="Objects by Description" +       layout="topleft" +       left_pad="0" +       top_pad="-17" +       name="filter_by_description" +       select_on_focus="true" +       width="162"> +    </search_editor>      <combo_box          height="20"          layout="topleft" diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml index 551b477876..777b37d666 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml @@ -9,9 +9,13 @@   follows="all"   layout="topleft"  > +  <!-- +  Date from server comes already converted to stl timezone, +  so display it as an UTC+0 +  -->     <string       name="date_format" -    value="SL birthdate: [mth,datetime,slt] [day,datetime,slt], [year,datetime,slt]" /> +    value="SL birthdate: [mth,datetime,utc] [day,datetime,utc], [year,datetime,utc]" />     <string      name="age_format"      value="[AGE]" /> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 6f95e282ca..b88a01f035 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3983,7 +3983,7 @@ Please check http://status.secondlifegrid.net to see if there is a known problem    <string name="Premium_PlusMembership">Premium Plus</string>    <string name="InternalMembership">Internal</string> <!-- No need to translate --> -  <string name="MembershipUpgradeText">Upgrade to Premium</string> +  <string name="MembershipUpgradeText">Change membership plan...</string>    <string name="MembershipPremiumText">My Premium membership</string>    <!-- Question strings for delete items notifications --> diff --git a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml index 1c4822b8d5..9c80deeafc 100644 --- a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml +++ b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml @@ -6,7 +6,7 @@    text_pad_left="7"    select_on_focus="true"    text_tentative_color="TextFgTentativeColor" -  highlight_text_field="false" +  highlight_text_field="true"    background_image="TextField_Search_Off"    background_image_disabled="TextField_Search_Disabled"    background_image_focused="TextField_Search_Active" diff --git a/indra/newview/skins/default/xui/en/widgets/search_editor.xml b/indra/newview/skins/default/xui/en/widgets/search_editor.xml index dc5a07bf4f..18d99f1ed1 100644 --- a/indra/newview/skins/default/xui/en/widgets/search_editor.xml +++ b/indra/newview/skins/default/xui/en/widgets/search_editor.xml @@ -7,7 +7,7 @@    text_pad_right="6"     select_on_focus="true"    text_tentative_color="TextFgTentativeColor" -  highlight_text_field="false" +  highlight_text_field="true"    background_image="TextField_Search_Off"    background_image_disabled="TextField_Search_Disabled"    background_image_focused="TextField_Search_Active" diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 59eb18b734..6d68fd5453 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -518,7 +518,7 @@ class WindowsManifest(ViewerManifest):                  self.path("alut.dll")              # For textures -            self.path("openjpeg.dll") +            self.path("openjp2.dll")              # Uriparser              self.path("uriparser.dll") @@ -1501,7 +1501,7 @@ class Linux_i686_Manifest(LinuxManifest):              self.path("libdirectfb-1.*.so.*")              self.path("libfusion-1.*.so.*")              self.path("libdirect-1.*.so.*") -            self.path("libopenjpeg.so*") +            self.path("libopenjp2.so*")              self.path("libdirectfb-1.4.so.5")              self.path("libfusion-1.4.so.5")              self.path("libdirect-1.4.so.5*") | 
