diff options
109 files changed, 1751 insertions, 533 deletions
diff --git a/autobuild.xml b/autobuild.xml index 2470b2e5aa..eb057ec8e0 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -2187,18 +2187,18 @@ <key>archive</key> <map> <key>hash</key> - <string>40a87f5d505a141b2ec79513a6197c35</string> + <string>0a6349b11c8e9d34f0c80b8081736e75</string> <key>hash_algorithm</key> <string>md5</string> <key>url</key> - <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76516/728250/llca-202102021657.555615-common-555615.tar.bz2</string> + <string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/79438/751815/llca-202104010215.557744-common-557744.tar.bz2</string> </map> <key>name</key> <string>common</string> </map> </map> <key>version</key> - <string>202102021657.555615</string> + <string>202104010215.557744</string> </map> <key>llphysicsextensions_source</key> <map> diff --git a/doc/contributions.txt b/doc/contributions.txt index 9340d69b97..fc76f36b88 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -226,6 +226,7 @@ Ansariel Hiller SL-13364 SL-13858 SL-13697 + SL-13395 SL-3136 Aralara Rajal Arare Chantilly @@ -267,6 +268,7 @@ Beq Janus SL-10288 SL-13583 SL-14766 + SL-14927 Beth Walcher Bezilon Kasei Biancaluce Robbiani diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index 245c73e3a2..5fa91b8bf5 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -259,6 +259,10 @@ public: */ LLRunner& getRunner() { return mRunner; } +#ifdef LL_WINDOWS + virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { } +#endif + public: typedef std::map<std::string, std::string> string_map; string_map mOptionMap; // Contains all command-line options and arguments in a map diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 23419a52a7..111c50af93 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -56,6 +56,10 @@ #include "stringize.h" #include "llexception.h" +#if LL_WINDOWS +#include <excpt.h> +#endif + // static LLCoros::CoroData& LLCoros::get_CoroData(const std::string& caller) { @@ -249,29 +253,58 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl #if LL_WINDOWS -void LLCoros::winlevel(const callable_t& callable) +static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific + +U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, const std::string& name) +{ + // 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 + return EXCEPTION_CONTINUE_SEARCH; + } + else + { + // handle it + return EXCEPTION_EXECUTE_HANDLER; + } +} + +void LLCoros::winlevel(const std::string& name, const callable_t& callable) { __try { - callable(); + toplevelTryWrapper(name, callable); } - __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation())) + __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name)) { - // convert to C++ styled exception + // convert to C++ styled exception for handlers other than bugsplat // Note: it might be better to use _se_set_translator // if you want exception to inherit full callstack - char integer_string[32]; - sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); + // + // 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()); throw std::exception(integer_string); } } #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) +void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable) { // keep the CoroData on this top-level function's stack frame CoroData corodata(name); @@ -281,16 +314,12 @@ void LLCoros::toplevel(std::string name, callable_t callable) // run the code the caller actually wants in the coroutine try { -#if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD - winlevel(callable); -#else callable(); -#endif } catch (const Stop& exc) { LL_INFOS("LLCoros") << "coroutine " << name << " terminating because " - << exc.what() << LL_ENDL; + << exc.what() << LL_ENDL; } catch (const LLContinueError&) { @@ -303,10 +332,25 @@ void LLCoros::toplevel(std::string name, callable_t callable) { // Any OTHER kind of uncaught exception will cause the viewer to // crash, hopefully informatively. - CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); + // to not modify callstack + throw; } } +// 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 + // Can not use __try in functions that require unwinding, so use one more wrapper + winlevel(name, callable); +#else + toplevelTryWrapper(name, callable); +#endif +} + //static void LLCoros::checkStop() { diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 38c2356c99..6c0bec3ef9 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -290,11 +290,12 @@ public: private: std::string generateDistinctName(const std::string& prefix) const; - void toplevel(std::string name, callable_t callable); - struct CoroData; #if LL_WINDOWS - static void winlevel(const callable_t& callable); + void winlevel(const std::string& name, const callable_t& callable); #endif + void toplevelTryWrapper(const std::string& name, const callable_t& callable); + void toplevel(std::string name, callable_t callable); + struct CoroData; static CoroData& get_CoroData(const std::string& caller); S32 mStackSize; diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index 9942bc0cf8..22711a83d2 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -276,7 +276,7 @@ std::string LLURI::escapePathAndData(const std::string &str) std::string fragment; size_t fragment_pos = str.find('#'); - if (fragment_pos != std::string::npos) + if ((fragment_pos != std::string::npos) && (fragment_pos > delim_pos)) { query = str.substr(path_size, fragment_pos - path_size); fragment = str.substr(fragment_pos); diff --git a/indra/llcorehttp/httpoptions.cpp b/indra/llcorehttp/httpoptions.cpp index df5aa52fa9..c6365e5091 100644 --- a/indra/llcorehttp/httpoptions.cpp +++ b/indra/llcorehttp/httpoptions.cpp @@ -32,6 +32,7 @@ namespace LLCore { + bool HttpOptions::sDefaultVerifyPeer = false; HttpOptions::HttpOptions() : mWantHeaders(false), @@ -43,7 +44,7 @@ HttpOptions::HttpOptions() : mMaxRetryBackoff(HTTP_RETRY_BACKOFF_MAX_DEFAULT), mUseRetryAfter(HTTP_USE_RETRY_AFTER_DEFAULT), mFollowRedirects(true), - mVerifyPeer(false), + mVerifyPeer(sDefaultVerifyPeer), mVerifyHost(false), mDNSCacheTimeout(-1L), mNoBody(false) @@ -122,7 +123,15 @@ void HttpOptions::setHeadersOnly(bool nobody) { mNoBody = nobody; if (mNoBody) + { setWantHeaders(true); + setSSLVerifyPeer(false); + } +} + +void HttpOptions::setDefaultSSLVerifyPeer(bool verify) +{ + sDefaultVerifyPeer = verify; } } // end namespace LLCore diff --git a/indra/llcorehttp/httpoptions.h b/indra/llcorehttp/httpoptions.h index 8a6de61b04..41f71896b0 100644 --- a/indra/llcorehttp/httpoptions.h +++ b/indra/llcorehttp/httpoptions.h @@ -143,7 +143,7 @@ public: /// Instructs the LLCore::HTTPRequest to verify that the exchanged security /// certificate is authentic. - /// Default: false + /// Default: sDefaultVerifyPeer void setSSLVerifyPeer(bool verify); bool getSSLVerifyPeer() const { @@ -177,6 +177,13 @@ public: { return mNoBody; } + + /// Sets default behavior for verifying that the name in the + /// security certificate matches the name of the host contacted. + /// Defaults false if not set, but should be set according to + /// viewer's initialization options and command argunments, see + /// NoVerifySSLCert + static void setDefaultSSLVerifyPeer(bool verify); protected: bool mWantHeaders; @@ -192,6 +199,8 @@ protected: bool mVerifyHost; int mDNSCacheTimeout; bool mNoBody; + + static bool sDefaultVerifyPeer; }; // end class HttpOptions diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index 62fcdaf545..e02f3a6306 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -411,6 +411,7 @@ bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); httpOpts->setTimeout(timeout); + httpOpts->setSSLVerifyPeer(false); for(int i = 0; i < retries; ++i) { diff --git a/indra/llinventory/lllandmark.cpp b/indra/llinventory/lllandmark.cpp index 4c6075d6b5..bd7ab3c2c8 100644 --- a/indra/llinventory/lllandmark.cpp +++ b/indra/llinventory/lllandmark.cpp @@ -103,60 +103,104 @@ LLVector3 LLLandmark::getRegionPos() const // static -LLLandmark* LLLandmark::constructFromString(const char *buffer) +LLLandmark* LLLandmark::constructFromString(const char *buffer, const S32 buffer_size) { - const char* cur = buffer; S32 chars_read = 0; + S32 chars_read_total = 0; S32 count = 0; U32 version = 0; + bool bad_block = false; + LLLandmark* result = NULL; + // read version - count = sscanf( cur, "Landmark version %u\n%n", &version, &chars_read ); - if(count != 1) - { - goto error; - } + count = sscanf( buffer, "Landmark version %u\n%n", &version, &chars_read ); + chars_read_total += chars_read; - if(version == 1) - { - LLVector3d pos; - cur += chars_read; - // read position - count = sscanf( cur, "position %lf %lf %lf\n%n", pos.mdV+VX, pos.mdV+VY, pos.mdV+VZ, &chars_read ); - if( count != 3 ) - { - goto error; - } - cur += chars_read; - // LL_INFOS() << "Landmark read: " << pos << LL_ENDL; - - return new LLLandmark(pos); - } - else if(version == 2) - { - // *NOTE: Changing the buffer size will require changing the - // scanf call below. - char region_id_str[MAX_STRING]; /* Flawfinder: ignore */ - LLVector3 pos; - cur += chars_read; - count = sscanf( /* Flawfinder: ignore */ - cur, - "region_id %254s\n%n", - region_id_str, &chars_read); - if(count != 1) goto error; - cur += chars_read; - count = sscanf(cur, "local_pos %f %f %f\n%n", pos.mV+VX, pos.mV+VY, pos.mV+VZ, &chars_read); - if(count != 3) goto error; - cur += chars_read; - LLLandmark* lm = new LLLandmark; - lm->mRegionID.set(region_id_str); - lm->mRegionPos = pos; - return lm; - } + if (count != 1 + || chars_read_total >= buffer_size) + { + bad_block = true; + } + + if (!bad_block) + { + switch (version) + { + case 1: + { + LLVector3d pos; + // read position + count = sscanf(buffer + chars_read_total, "position %lf %lf %lf\n%n", pos.mdV + VX, pos.mdV + VY, pos.mdV + VZ, &chars_read); + if (count != 3) + { + bad_block = true; + } + else + { + LL_DEBUGS("Landmark") << "Landmark read: " << pos << LL_ENDL; + result = new LLLandmark(pos); + } + break; + } + case 2: + { + // *NOTE: Changing the buffer size will require changing the + // scanf call below. + char region_id_str[MAX_STRING]; + LLVector3 pos; + LLUUID region_id; + count = sscanf( buffer + chars_read_total, + "region_id %254s\n%n", + region_id_str, + &chars_read); + chars_read_total += chars_read; + + if (count != 1 + || chars_read_total >= buffer_size + || !LLUUID::validate(region_id_str)) + { + bad_block = true; + } + + if (!bad_block) + { + region_id.set(region_id_str); + if (region_id.isNull()) + { + bad_block = true; + } + } + + if (!bad_block) + { + count = sscanf(buffer + chars_read_total, "local_pos %f %f %f\n%n", pos.mV + VX, pos.mV + VY, pos.mV + VZ, &chars_read); + if (count != 3) + { + bad_block = true; + } + else + { + result = new LLLandmark; + result->mRegionID = region_id; + result->mRegionPos = pos; + } + } + break; + } + default: + { + LL_INFOS("Landmark") << "Encountered Unknown landmark version " << version << LL_ENDL; + break; + } + } + } - error: - LL_INFOS() << "Bad Landmark Asset: bad _DATA_ block." << LL_ENDL; - return NULL; + if (bad_block) + { + LL_INFOS("Landmark") << "Bad Landmark Asset: bad _DATA_ block." << LL_ENDL; + } + return result; } @@ -176,7 +220,7 @@ void LLLandmark::requestRegionHandle( if(region_id.isNull()) { // don't bother with checking - it's 0. - LL_DEBUGS() << "requestRegionHandle: null" << LL_ENDL; + LL_DEBUGS("Landmark") << "requestRegionHandle: null" << LL_ENDL; if(callback) { const U64 U64_ZERO = 0; @@ -187,7 +231,7 @@ void LLLandmark::requestRegionHandle( { if(region_id == mLocalRegion.first) { - LL_DEBUGS() << "requestRegionHandle: local" << LL_ENDL; + LL_DEBUGS("Landmark") << "requestRegionHandle: local" << LL_ENDL; if(callback) { callback(region_id, mLocalRegion.second); @@ -198,13 +242,13 @@ void LLLandmark::requestRegionHandle( region_map_t::iterator it = mRegions.find(region_id); if(it == mRegions.end()) { - LL_DEBUGS() << "requestRegionHandle: upstream" << LL_ENDL; + LL_DEBUGS("Landmark") << "requestRegionHandle: upstream" << LL_ENDL; if(callback) { region_callback_map_t::value_type vt(region_id, callback); sRegionCallbackMap.insert(vt); } - LL_DEBUGS() << "Landmark requesting information about: " + LL_DEBUGS("Landmark") << "Landmark requesting information about: " << region_id << LL_ENDL; msg->newMessage("RegionHandleRequest"); msg->nextBlock("RequestBlock"); @@ -214,7 +258,7 @@ void LLLandmark::requestRegionHandle( else if(callback) { // we have the answer locally - just call the callack. - LL_DEBUGS() << "requestRegionHandle: ready" << LL_ENDL; + LL_DEBUGS("Landmark") << "requestRegionHandle: ready" << LL_ENDL; callback(region_id, (*it).second.mRegionHandle); } } diff --git a/indra/llinventory/lllandmark.h b/indra/llinventory/lllandmark.h index 92923ea6fb..be34113a90 100644 --- a/indra/llinventory/lllandmark.h +++ b/indra/llinventory/lllandmark.h @@ -60,7 +60,7 @@ public: // constructs a new LLLandmark from a string // return NULL if there's an error - static LLLandmark* constructFromString(const char *buffer); + static LLLandmark* constructFromString(const char *buffer, const S32 buffer_size); // register callbacks that this class handles static void registerCallbacks(LLMessageSystem* msg); diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index 4d76dacdf7..be014e7b1e 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -138,13 +138,24 @@ LLCoprocedureManager::~LLCoprocedureManager() close(); } -LLCoprocedureManager::poolPtr_t LLCoprocedureManager::initializePool(const std::string &poolName) +void LLCoprocedureManager::initializePool(const std::string &poolName) { + poolMap_t::iterator it = mPoolMap.find(poolName); + + if (it != mPoolMap.end()) + { + // Pools are not supposed to be initialized twice + // Todo: ideally restrict init to STATE_FIRST + LL_ERRS() << "Pool is already present " << poolName << LL_ENDL; + return; + } + // Attempt to look up a pool size in the configuration. If found use that std::string keyName = "PoolSize" + poolName; int size = 0; LL_ERRS_IF(poolName.empty(), "CoprocedureManager") << "Poolname must not be empty" << LL_ENDL; + LL_INFOS("CoprocedureManager") << "Initializing pool " << poolName << LL_ENDL; if (mPropertyQueryFn) { @@ -171,8 +182,6 @@ LLCoprocedureManager::poolPtr_t LLCoprocedureManager::initializePool(const std:: bool inserted = mPoolMap.emplace(poolName, pool).second; LL_ERRS_IF(!inserted, "CoprocedureManager") << "Unable to add pool named \"" << poolName << "\" to map. FATAL!" << LL_ENDL; - - return pool; } //------------------------------------------------------------------------- @@ -182,20 +191,28 @@ LLUUID LLCoprocedureManager::enqueueCoprocedure(const std::string &pool, const s // not exist, create it. poolMap_t::iterator it = mPoolMap.find(pool); - poolPtr_t targetPool = (it != mPoolMap.end()) ? it->second : initializePool(pool); + if (it == mPoolMap.end()) + { + // initializing pools in enqueueCoprocedure is not thread safe, + // at the moment pools need to be initialized manually + LL_ERRS() << "Uninitialized pool " << pool << LL_ENDL; + } + poolPtr_t targetPool = it->second; return targetPool->enqueueCoprocedure(name, proc); } void LLCoprocedureManager::setPropertyMethods(SettingQuery_t queryfn, SettingUpdate_t updatefn) { // functions to discover and store the pool sizes + // Might be a better idea to make an initializePool(name, size) to init everything externally mPropertyQueryFn = queryfn; mPropertyDefineFn = updatefn; - // workaround until we get mutex into initializePool - initializePool("AssetStorage"); initializePool("Upload"); + initializePool("AIS"); // it might be better to have some kind of on-demand initialization for AIS + // "ExpCache" pool gets initialized in LLExperienceCache + // asset storage pool gets initialized in LLViewerAssetStorage } //------------------------------------------------------------------------- diff --git a/indra/llmessage/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h index d5557c129f..2d460826ff 100644 --- a/indra/llmessage/llcoproceduremanager.h +++ b/indra/llmessage/llcoproceduremanager.h @@ -79,6 +79,8 @@ public: void close(); void close(const std::string &pool); + + void initializePool(const std::string &poolName); private: @@ -87,8 +89,6 @@ private: poolMap_t mPoolMap; - poolPtr_t initializePool(const std::string &poolName); - SettingQuery_t mPropertyQueryFn; SettingUpdate_t mPropertyDefineFn; diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 64c01bd9eb..db22ad2ea3 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -108,6 +108,8 @@ void LLExperienceCache::initSingleton() cache_stream >> (*this); } + LLCoprocedureManager::instance().initializePool("ExpCache"); + LLCoros::instance().launch("LLExperienceCache::idleCoro", boost::bind(&LLExperienceCache::idleCoro, this)); diff --git a/indra/llmessage/tests/llcoproceduremanager_test.cpp b/indra/llmessage/tests/llcoproceduremanager_test.cpp index 9db13a37b5..6424117ef3 100644 --- a/indra/llmessage/tests/llcoproceduremanager_test.cpp +++ b/indra/llmessage/tests/llcoproceduremanager_test.cpp @@ -91,6 +91,7 @@ namespace tut { Sync sync; int foo = 0; + LLCoprocedureManager::instance().initializePool("PoolName"); LLUUID queueId = LLCoprocedureManager::instance().enqueueCoprocedure("PoolName", "ProcName", [&foo, &sync] (LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t & ptr, const LLUUID & id) { sync.bump(); diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 7d18bae947..e5b4dec1bd 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -154,9 +154,9 @@ void LLPluginProcessParent::shutdown() { EState state = (*it).second->mState; if (state != STATE_CLEANUP - || state != STATE_EXITING - || state != STATE_DONE - || state != STATE_ERROR) + && state != STATE_EXITING + && state != STATE_DONE + && state != STATE_ERROR) { (*it).second->setState(STATE_GOODBYE); } diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 11d9ef3f57..c908fac4ad 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -50,6 +50,7 @@ U32 LLRender::sUIVerts = 0; U32 LLTexUnit::sWhiteTexture = 0; bool LLRender::sGLCoreProfile = false; bool LLRender::sNsightDebugSupport = false; +LLVector2 LLRender::sUIGLScaleFactor = LLVector2(1.f, 1.f); static const U32 LL_NUM_TEXTURE_LAYERS = 32; static const U32 LL_NUM_LIGHT_UNITS = 8; diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 41f4fe4017..af8568f8a3 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -463,6 +463,7 @@ public: static U32 sUIVerts; static bool sGLCoreProfile; static bool sNsightDebugSupport; + static LLVector2 sUIGLScaleFactor; private: friend class LLLightState; diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp index 801b945806..dd34f3e383 100644 --- a/indra/llrender/llrender2dutils.cpp +++ b/indra/llrender/llrender2dutils.cpp @@ -106,11 +106,10 @@ void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixe top += LLFontGL::sCurOrigin.mY; gGL.loadUIIdentity(); - LLRender2D *r2d_inst = LLRender2D::getInstance(); - gl_rect_2d(llfloor((F32)left * r2d_inst->mGLScaleFactor.mV[VX]) - pixel_offset, - llfloor((F32)top * r2d_inst->mGLScaleFactor.mV[VY]) + pixel_offset, - llfloor((F32)right * r2d_inst->mGLScaleFactor.mV[VX]) + pixel_offset, - llfloor((F32)bottom * r2d_inst->mGLScaleFactor.mV[VY]) - pixel_offset, + gl_rect_2d(llfloor((F32)left * LLRender::sUIGLScaleFactor.mV[VX]) - pixel_offset, + llfloor((F32)top * LLRender::sUIGLScaleFactor.mV[VY]) + pixel_offset, + llfloor((F32)right * LLRender::sUIGLScaleFactor.mV[VX]) + pixel_offset, + llfloor((F32)bottom * LLRender::sUIGLScaleFactor.mV[VY]) - pixel_offset, filled); gGL.popUIMatrix(); } @@ -1568,7 +1567,6 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv LLRender2D::LLRender2D(LLImageProviderInterface* image_provider) { - mGLScaleFactor = LLVector2(1.f, 1.f); mImageProvider = image_provider; if(mImageProvider) { @@ -1585,7 +1583,7 @@ LLRender2D::~LLRender2D() } } - +// static void LLRender2D::translate(F32 x, F32 y, F32 z) { gGL.translateUI(x,y,z); @@ -1594,12 +1592,14 @@ void LLRender2D::translate(F32 x, F32 y, F32 z) LLFontGL::sCurDepth += z; } +// static void LLRender2D::pushMatrix() { gGL.pushUIMatrix(); LLFontGL::sOriginStack.push_back(std::make_pair(LLFontGL::sCurOrigin, LLFontGL::sCurDepth)); } +// static void LLRender2D::popMatrix() { gGL.popUIMatrix(); @@ -1608,6 +1608,7 @@ void LLRender2D::popMatrix() LLFontGL::sOriginStack.pop_back(); } +// static void LLRender2D::loadIdentity() { gGL.loadUIIdentity(); @@ -1616,15 +1617,11 @@ void LLRender2D::loadIdentity() LLFontGL::sCurDepth = 0.f; } -void LLRender2D::setScaleFactor(const LLVector2 &scale_factor) -{ - mGLScaleFactor = scale_factor; -} - +// static void LLRender2D::setLineWidth(F32 width) { gGL.flush(); - glLineWidth(width * lerp(mGLScaleFactor.mV[VX], mGLScaleFactor.mV[VY], 0.5f)); + glLineWidth(width * lerp(LLRender::sUIGLScaleFactor.mV[VX], LLRender::sUIGLScaleFactor.mV[VY], 0.5f)); } LLPointer<LLUIImage> LLRender2D::getUIImageByID(const LLUUID& image_id, S32 priority) diff --git a/indra/llrender/llrender2dutils.h b/indra/llrender/llrender2dutils.h index 8c01784071..206e68f084 100644 --- a/indra/llrender/llrender2dutils.h +++ b/indra/llrender/llrender2dutils.h @@ -128,19 +128,16 @@ class LLRender2D : public LLParamSingleton<LLRender2D> LOG_CLASS(LLRender2D); ~LLRender2D(); public: - void pushMatrix(); - void popMatrix(); - void loadIdentity(); - void translate(F32 x, F32 y, F32 z = 0.0f); + static void pushMatrix(); + static void popMatrix(); + static void loadIdentity(); + static void translate(F32 x, F32 y, F32 z = 0.0f); - void setLineWidth(F32 width); - void setScaleFactor(const LLVector2& scale_factor); + static void setLineWidth(F32 width); LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0); LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0); - LLVector2 mGLScaleFactor; - protected: // since LLRender2D has no control of image provider's lifecycle // we need a way to tell LLRender2D that provider died and diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp index 098621b543..04485c6262 100644 --- a/indra/llui/llaccordionctrltab.cpp +++ b/indra/llui/llaccordionctrltab.cpp @@ -1006,7 +1006,7 @@ void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child) LLRect screen_rect; localRectToScreen(child->getRect(),&screen_rect); - if ( root_rect.overlaps(screen_rect) && LLUI::getInstance()->mDirtyRect.overlaps(screen_rect)) + if ( root_rect.overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) { gGL.matrixMode(LLRender::MM_MODELVIEW); LLUI::pushMatrix(); diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp index 7817d99aef..8fc2978bdd 100644 --- a/indra/llui/llconsole.cpp +++ b/indra/llui/llconsole.cpp @@ -180,7 +180,9 @@ void LLConsole::draw() LLUIImagePtr imagep = LLUI::getUIImage("transparent"); - F32 console_opacity = llclamp(LLUI::getInstance()->mSettingGroups["config"]->getF32("ConsoleBackgroundOpacity"), 0.f, 1.f); + static LLCachedControl<F32> console_bg_opacity(*LLUI::getInstance()->mSettingGroups["config"], "ConsoleBackgroundOpacity", 0.7f); + F32 console_opacity = llclamp(console_bg_opacity(), 0.f, 1.f); + LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground"); color.mV[VALPHA] *= console_opacity; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index e9c980ad9a..cebb521189 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -376,13 +376,15 @@ void LLFloater::layoutDragHandle() // static void LLFloater::updateActiveFloaterTransparency() { - sActiveControlTransparency = LLUI::getInstance()->mSettingGroups["config"]->getF32("ActiveFloaterTransparency"); + static LLCachedControl<F32> active_transparency(*LLUI::getInstance()->mSettingGroups["config"], "ActiveFloaterTransparency", 1.f); + sActiveControlTransparency = active_transparency; } // static void LLFloater::updateInactiveFloaterTransparency() { - sInactiveControlTransparency = LLUI::getInstance()->mSettingGroups["config"]->getF32("InactiveFloaterTransparency"); + static LLCachedControl<F32> inactive_transparency(*LLUI::getInstance()->mSettingGroups["config"], "InactiveFloaterTransparency", 0.95f); + sInactiveControlTransparency = inactive_transparency; } void LLFloater::addResizeCtrls() diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 0c1dcc301b..622c9edba7 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -342,9 +342,9 @@ static LLTrace::BlockTimerStatHandle FTM_FILTER("Filter Folder View"); void LLFolderView::filter( LLFolderViewFilter& filter ) { LL_RECORD_BLOCK_TIME(FTM_FILTER); - static LLCachedControl<S32> filter_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); - static LLCachedControl<S32> filter_hidden(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1); - filter.resetTime(llclamp(mParentPanel.get()->getVisible() ? filter_visible() : filter_hidden(), 1, 100)); + static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); + static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1); + filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100)); // Note: we filter the model, not the view getViewModelItem()->filter(filter); @@ -663,7 +663,8 @@ void LLFolderView::draw() closeAutoOpenedFolders(); } - if (mSearchTimer.getElapsedTimeF32() > LLUI::getInstance()->mSettingGroups["config"]->getF32("TypeAheadTimeout") || !mSearchString.size()) + static LLCachedControl<F32> type_ahead_timeout(*LLUI::getInstance()->mSettingGroups["config"], "TypeAheadTimeout", 1.5f); + if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout || !mSearchString.size()) { mSearchString.clear(); } diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 1c6c7b1b35..285bf9f484 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -962,9 +962,10 @@ void LLFolderViewItem::draw() // if (filter_string_length > 0) { - F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, mViewModelItem->getFilterStringOffset()); + S32 filter_offset = mViewModelItem->getFilterStringOffset(); + F32 match_string_left = text_left + font->getWidthF32(combined_string, 0, filter_offset + filter_string_length) - font->getWidthF32(combined_string, filter_offset, filter_string_length); F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD; - font->renderUTF8( combined_string, mViewModelItem->getFilterStringOffset(), match_string_left, yy, + font->renderUTF8( combined_string, filter_offset, match_string_left, yy, sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, filter_string_length, S32_MAX, &right_x, FALSE ); } @@ -1607,7 +1608,7 @@ void LLFolderViewFolder::destroyView() // extractItem() removes the specified item from the folder, but // doesn't delete it. -void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) +void LLFolderViewFolder::extractItem( LLFolderViewItem* item, bool deparent_model ) { if (item->isSelected()) getRoot()->clearSelection(); @@ -1630,7 +1631,11 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) mItems.erase(it); } //item has been removed, need to update filter - getViewModelItem()->removeChild(item->getViewModelItem()); + if (deparent_model) + { + // in some cases model does not belong to parent view, is shared between views + getViewModelItem()->removeChild(item->getViewModelItem()); + } //because an item is going away regardless of filter status, force rearrange requestArrange(); removeChild(item); diff --git a/indra/llui/llfolderviewitem.h b/indra/llui/llfolderviewitem.h index da09d139e9..616d2e7d86 100644 --- a/indra/llui/llfolderviewitem.h +++ b/indra/llui/llfolderviewitem.h @@ -387,7 +387,7 @@ public: // extractItem() removes the specified item from the folder, but // doesn't delete it. - virtual void extractItem( LLFolderViewItem* item ); + virtual void extractItem( LLFolderViewItem* item, bool deparent_model = true); // This function is called by a child that needs to be resorted. void resort(LLFolderViewItem* item); diff --git a/indra/llui/llfolderviewmodel.cpp b/indra/llui/llfolderviewmodel.cpp index ea106b5fae..93122503d1 100644 --- a/indra/llui/llfolderviewmodel.cpp +++ b/indra/llui/llfolderviewmodel.cpp @@ -48,9 +48,9 @@ std::string LLFolderViewModelCommon::getStatusText() void LLFolderViewModelCommon::filter() { - static LLCachedControl<S32> filter_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); - getFilter().resetTime(llclamp(filter_visible(), 1, 100)); - mFolderView->getViewModelItem()->filter(getFilter()); + static LLCachedControl<S32> max_time(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); + getFilter().resetTime(llclamp(max_time(), 1, 100)); + mFolderView->getViewModelItem()->filter(getFilter()); } bool LLFolderViewModelItemCommon::hasFilterStringMatch() diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp index acfe4a0cba..f89064d59a 100644 --- a/indra/llui/llmultislider.cpp +++ b/indra/llui/llmultislider.cpp @@ -136,6 +136,7 @@ LLMultiSlider::LLMultiSlider(const LLMultiSlider::Params& p) } } + mRoundedSquareImgp = LLUI::getUIImage("Rounded_Square"); if (p.thumb_image.isProvided()) { mThumbImagep = LLUI::getUIImage(p.thumb_image()); @@ -666,8 +667,6 @@ void LLMultiSlider::draw() F32 opacity = getEnabled() ? 1.f : 0.3f; // Track - LLUIImagePtr thumb_imagep = LLUI::getUIImage("Rounded_Square"); - static LLUICachedControl<S32> multi_track_height_width ("UIMultiTrackHeight", 0); S32 height_offset = 0; S32 width_offset = 0; @@ -685,7 +684,7 @@ void LLMultiSlider::draw() if(mDrawTrack) { track_rect.stretch(-1); - thumb_imagep->draw(track_rect, mTrackColor.get() % opacity); + mRoundedSquareImgp->draw(track_rect, mTrackColor.get() % opacity); } // if we're supposed to use a drawn triangle @@ -704,7 +703,7 @@ void LLMultiSlider::draw() mTriangleColor.get() % opacity, TRUE); } } - else if (!thumb_imagep && !mThumbImagep) + else if (!mRoundedSquareImgp && !mThumbImagep) { // draw all the thumbs curSldrIt = mThumbRects.end(); @@ -757,7 +756,7 @@ void LLMultiSlider::draw() } else { - thumb_imagep->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); + mRoundedSquareImgp->drawSolid(mDragStartThumbRect, mThumbCenterColor.get() % 0.3f); } } @@ -772,7 +771,7 @@ void LLMultiSlider::draw() } else { - thumb_imagep->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); + mRoundedSquareImgp->drawBorder(mThumbRects[mCurSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); } } } @@ -784,7 +783,7 @@ void LLMultiSlider::draw() } else { - thumb_imagep->drawBorder(mThumbRects[mHoverSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); + mRoundedSquareImgp->drawBorder(mThumbRects[mHoverSlider], gFocusMgr.getFocusColor(), gFocusMgr.getFocusFlashWidth()); } } @@ -822,11 +821,11 @@ void LLMultiSlider::draw() } else if (capture == this) { - thumb_imagep->drawSolid(mIt->second, curThumbColor); + mRoundedSquareImgp->drawSolid(mIt->second, curThumbColor); } else { - thumb_imagep->drawSolid(mIt->second, curThumbColor % opacity); + mRoundedSquareImgp->drawSolid(mIt->second, curThumbColor % opacity); } } @@ -846,11 +845,11 @@ void LLMultiSlider::draw() } else if (capture == this) { - thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get()); + mRoundedSquareImgp->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get()); } else { - thumb_imagep->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity); + mRoundedSquareImgp->drawSolid(curSldrIt->second, mThumbCenterSelectedColor.get() % opacity); } } if(hoverSldrIt != mThumbRects.end()) @@ -861,7 +860,7 @@ void LLMultiSlider::draw() } else { - thumb_imagep->drawSolid(hoverSldrIt->second, mThumbCenterSelectedColor.get()); + mRoundedSquareImgp->drawSolid(hoverSldrIt->second, mThumbCenterSelectedColor.get()); } } } diff --git a/indra/llui/llmultislider.h b/indra/llui/llmultislider.h index 99a78d6e09..3cb4b760b0 100644 --- a/indra/llui/llmultislider.h +++ b/indra/llui/llmultislider.h @@ -150,6 +150,7 @@ protected: LLUIColor mDisabledThumbColor; LLUIColor mTriangleColor; LLUIImagePtr mThumbImagep; //blimps on the slider, for now no 'disabled' support + LLUIImagePtr mRoundedSquareImgp; //blimps on the slider, for now no 'disabled' support const EOrientation mOrientation; diff --git a/indra/llui/llnotificationptr.h b/indra/llui/llnotificationptr.h index acc047527f..580f353c7d 100644 --- a/indra/llui/llnotificationptr.h +++ b/indra/llui/llnotificationptr.h @@ -27,9 +27,8 @@ // Many classes just store a single LLNotificationPtr // and llnotifications.h is very large, so define this ligher header. -#include <boost/shared_ptr.hpp> class LLNotification; -typedef boost::shared_ptr<LLNotification> LLNotificationPtr; +typedef std::shared_ptr<LLNotification> LLNotificationPtr; #endif diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index 2f4578da17..39576ad86d 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -85,7 +85,6 @@ #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> -#include <boost/enable_shared_from_this.hpp> #include <boost/type_traits.hpp> #include <boost/signals2.hpp> #include <boost/range.hpp> @@ -304,7 +303,7 @@ typedef boost::shared_ptr<LLNotificationVisibilityRule> LLNotificationVisibility */ class LLNotification : boost::noncopyable, - public boost::enable_shared_from_this<LLNotification> + public std::enable_shared_from_this<LLNotification> { LOG_CLASS(LLNotification); friend class LLNotifications; @@ -743,7 +742,10 @@ public: : mFilter(filter), mItems() {} - virtual ~LLNotificationChannelBase() {} + virtual ~LLNotificationChannelBase() + { + mItems.clear(); + } // you can also connect to a Channel, so you can be notified of // changes to this channel LLBoundListener connectChanged(const LLEventListener& slot) @@ -873,6 +875,7 @@ class LLNotifications : { LLSINGLETON(LLNotifications); LOG_CLASS(LLNotifications); + virtual ~LLNotifications() {} public: @@ -1070,7 +1073,11 @@ public: LLPersistentNotificationChannel() : LLNotificationChannel("Persistent", "Visible", ¬ificationFilter) {} - virtual ~LLPersistentNotificationChannel() {} + + virtual ~LLPersistentNotificationChannel() + { + mHistory.clear(); + } typedef std::vector<LLNotificationPtr> history_list_t; history_list_t::iterator beginHistory() { sortHistory(); return mHistory.begin(); } diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp index cc9ff7a487..82b0415624 100644 --- a/indra/llui/llscrolllistcolumn.cpp +++ b/indra/llui/llscrolllistcolumn.cpp @@ -257,7 +257,7 @@ void LLScrollColumnHeader::updateResizeBars() for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) { LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (columnp->mHeader && columnp->mHeader->canResize()) + if (columnp && columnp->mHeader && columnp->mHeader->canResize()) { num_resizable_columns++; } @@ -269,7 +269,7 @@ void LLScrollColumnHeader::updateResizeBars() for (col = 0; col < mColumn->mParentCtrl->getNumColumns(); col++) { LLScrollListColumn* columnp = mColumn->mParentCtrl->getColumn(col); - if (!columnp->mHeader) continue; + if (!columnp || !columnp->mHeader) continue; BOOL enable = num_resizable_columns >= 2 && num_resizers_enabled < (num_resizable_columns - 1) && columnp->mHeader->canResize(); columnp->mHeader->enableResizeBar(enable); if (enable) diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index be85f1cb6a..de644185fd 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -743,12 +743,12 @@ void LLScrollListCtrl::updateColumns(bool force_update) LLScrollColumnHeader* last_header = NULL; for (column_ordered_it = mColumnsIndexed.begin(); column_ordered_it != mColumnsIndexed.end(); ++column_ordered_it) { - if ((*column_ordered_it)->getWidth() < 0) + LLScrollListColumn* column = *column_ordered_it; + if (!column || column->getWidth() < 0) { // skip hidden columns continue; } - LLScrollListColumn* column = *column_ordered_it; if (column->mHeader) { diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index e6f466ec78..0961db37ba 100644 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -1125,7 +1125,7 @@ BOOL LLToolBarButton::handleHover(S32 x, S32 y, MASK mask) BOOL handled = FALSE; S32 mouse_distance_squared = (x - mMouseDownX) * (x - mMouseDownX) + (y - mMouseDownY) * (y - mMouseDownY); - S32 drag_threshold = LLUI::getInstance()->mSettingGroups["config"]->getS32("DragAndDropDistanceThreshold"); + static LLCachedControl<S32> drag_threshold(*LLUI::getInstance()->mSettingGroups["config"], "DragAndDropDistanceThreshold", 3); if (mouse_distance_squared > drag_threshold * drag_threshold && hasMouseCapture() && mStartDragItemCallback && mHandleDragItemCallback) diff --git a/indra/llui/lltooltip.cpp b/indra/llui/lltooltip.cpp index 422534b781..2f56a8b1d0 100644 --- a/indra/llui/lltooltip.cpp +++ b/indra/llui/lltooltip.cpp @@ -358,8 +358,8 @@ void LLToolTip::draw() if (mFadeTimer.getStarted()) { - F32 tool_tip_fade_time = LLUI::getInstance()->mSettingGroups["config"]->getF32("ToolTipFadeTime"); - alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time, 1.f, 0.f); + static LLCachedControl<F32> tool_tip_fade_time(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFadeTime", 0.2f); + alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time(), 1.f, 0.f); if (alpha == 0.f) { // finished fading out, so hide ourselves diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 656b69d3ed..6f16745bd3 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -154,7 +154,6 @@ mAudioCallback(audio_callback), mDeferredAudioCallback(deferred_audio_callback), mWindow(NULL), // set later in startup mRootView(NULL), -mDirty(FALSE), mHelpImpl(NULL) { LLRender2D::initParamSingleton(image_provider); @@ -203,19 +202,6 @@ void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& rem mClearPopupsFunc = clear_popups; } -void LLUI::dirtyRect(LLRect rect) -{ - if (!mDirty) - { - mDirtyRect = rect; - mDirty = TRUE; - } - else - { - mDirtyRect.unionWith(rect); - } -} - void LLUI::setMousePositionScreen(S32 x, S32 y) { #if defined(LL_DARWIN) @@ -510,6 +496,18 @@ const LLView* LLUI::resolvePath(const LLView* context, const std::string& path) return context; } +//static +LLVector2& LLUI::getScaleFactor() +{ + return LLRender::sUIGLScaleFactor; +} + +//static +void LLUI::setScaleFactor(const LLVector2& scale_factor) +{ + LLRender::sUIGLScaleFactor = scale_factor; +} + // LLLocalClipRect and LLScreenClipRect moved to lllocalcliprect.h/cpp diff --git a/indra/llui/llui.h b/indra/llui/llui.h index 9856e551cc..30dbd7248f 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -245,10 +245,6 @@ public: void setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t&, const clear_popups_t& ); - LLRect mDirtyRect; - BOOL mDirty; - void dirtyRect(LLRect rect); - // Return the ISO639 language name ("en", "ko", etc.) for the viewer UI. // http://www.loc.gov/standards/iso639-2/php/code_list.php std::string getUILanguage(); @@ -313,14 +309,14 @@ public: void positionViewNearMouse(LLView* view, S32 spawn_x = S32_MAX, S32 spawn_y = S32_MAX); // LLRender2D wrappers - static void pushMatrix() { LLRender2D::getInstance()->pushMatrix(); } - static void popMatrix() { LLRender2D::getInstance()->popMatrix(); } - static void loadIdentity() { LLRender2D::getInstance()->loadIdentity(); } - static void translate(F32 x, F32 y, F32 z = 0.0f) { LLRender2D::getInstance()->translate(x, y, z); } - - static LLVector2& getScaleFactor() { return LLRender2D::getInstance()->mGLScaleFactor; } - static void setScaleFactor(const LLVector2& scale_factor) { LLRender2D::getInstance()->setScaleFactor(scale_factor); } - static void setLineWidth(F32 width) { LLRender2D::getInstance()->setLineWidth(width); } + static void pushMatrix() { LLRender2D::pushMatrix(); } + static void popMatrix() { LLRender2D::popMatrix(); } + static void loadIdentity() { LLRender2D::loadIdentity(); } + static void translate(F32 x, F32 y, F32 z = 0.0f) { LLRender2D::translate(x, y, z); } + + static LLVector2& getScaleFactor(); + static void setScaleFactor(const LLVector2& scale_factor); + static void setLineWidth(F32 width) { LLRender2D::setLineWidth(width); } static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0) { return LLRender2D::getInstance()->getUIImageByID(image_id, priority); } static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0) diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 20dda54771..e43c52c0c2 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -176,7 +176,7 @@ void LLUrlEntryBase::callObservers(const std::string &id, bool LLUrlEntryBase::isLinkDisabled() const { // this allows us to have a global setting to turn off text hyperlink highlighting/action - bool globally_disabled = LLUI::getInstance()->mSettingGroups["config"]->getBOOL("DisableTextHyperlinkActions"); + static LLCachedControl<bool> globally_disabled(*LLUI::getInstance()->mSettingGroups["config"], "DisableTextHyperlinkActions", false); return globally_disabled; } @@ -464,7 +464,9 @@ LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL() "|" "(https://([-\\w\\.]*\\.)?(secondlife|lindenlab|tilia-inc)\\.com(:\\d{1,5})?)" "|" - "(https://([-\\w\\.]*\\.)?secondlifegrid\\.net(:\\d{1,5})?))" + "(https://([-\\w\\.]*\\.)?secondlifegrid\\.net(:\\d{1,5})?)" + "|" + "(https?://([-\\w\\.]*\\.)?secondlife\\.io(:\\d{1,5})?))" "\\/\\S*", boost::regex::perl|boost::regex::icase); @@ -1127,7 +1129,7 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const // LLUrlEntryRegion::LLUrlEntryRegion() { - mPattern = boost::regex("secondlife:///app/region/[^/\\s]+(/\\d+)?(/\\d+)?(/\\d+)?/?", + mPattern = boost::regex("secondlife:///app/region/[A-Za-z0-9()_%]+(/\\d+)?(/\\d+)?(/\\d+)?/?", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index cd47e2ecea..b942be2a4a 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -60,6 +60,8 @@ static const S32 LINE_HEIGHT = 15; S32 LLView::sDepth = 0; bool LLView::sDebugRects = false; +bool LLView::sIsRectDirty = false; +LLRect LLView::sDirtyRect; bool LLView::sDebugRectsShowNames = true; bool LLView::sDebugKeys = false; bool LLView::sDebugMouseHandling = false; @@ -885,14 +887,16 @@ BOOL LLView::handleToolTip(S32 x, S32 y, MASK mask) std::string tooltip = getToolTip(); if (!tooltip.empty()) { + static LLCachedControl<F32> tooltip_fast_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipFastDelay", 0.1f); + static LLCachedControl<F32> tooltip_delay(*LLUI::getInstance()->mSettingGroups["config"], "ToolTipDelay", 0.7f); + static LLCachedControl<bool> allow_ui_tooltips(*LLUI::getInstance()->mSettingGroups["config"], "BasicUITooltips", true); // allow "scrubbing" over ui by showing next tooltip immediately // if previous one was still visible F32 timeout = LLToolTipMgr::instance().toolTipVisible() - ? LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipFastDelay" ) - : LLUI::getInstance()->mSettingGroups["config"]->getF32( "ToolTipDelay" ); + ? tooltip_fast_delay + : tooltip_delay; // Even if we don't show tooltips, consume the event, nothing below should show tooltip - bool allow_ui_tooltips = LLUI::getInstance()->mSettingGroups["config"]->getBOOL("BasicUITooltips"); if (allow_ui_tooltips) { LLToolTipMgr::instance().show(LLToolTip::Params() @@ -1189,7 +1193,7 @@ void LLView::drawChildren() if (viewp->getVisible() && viewp->getRect().isValid()) { LLRect screen_rect = viewp->calcScreenRect(); - if ( rootp->getLocalRect().overlaps(screen_rect) && LLUI::getInstance()->mDirtyRect.overlaps(screen_rect)) + if ( rootp->getLocalRect().overlaps(screen_rect) && sDirtyRect.overlaps(screen_rect)) { LLUI::pushMatrix(); { @@ -1231,7 +1235,15 @@ void LLView::dirtyRect() parent = parent->getParent(); } - LLUI::getInstance()->dirtyRect(cur->calcScreenRect()); + if (!sIsRectDirty) + { + sDirtyRect = cur->calcScreenRect(); + sIsRectDirty = true; + } + else + { + sDirtyRect.unionWith(cur->calcScreenRect()); + } } //Draw a box for debugging. diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 5c91c37d3c..c60dcf3344 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -657,6 +657,9 @@ public: // Draw debug rectangles around widgets to help with alignment and spacing static bool sDebugRects; + static bool sIsRectDirty; + static LLRect sDirtyRect; + // Draw widget names and sizes when drawing debug rectangles, turning this // off is useful to make the rectangles themselves easier to see. static bool sDebugRectsShowNames; diff --git a/indra/llui/tests/llurlentry_test.cpp b/indra/llui/tests/llurlentry_test.cpp index 4a4fdb72e3..1a474cca90 100644 --- a/indra/llui/tests/llurlentry_test.cpp +++ b/indra/llui/tests/llurlentry_test.cpp @@ -739,11 +739,6 @@ namespace tut "XXX secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30 XXX", "secondlife:///app/region/Burning%20Life%20(Hyper)/27/210/30"); - // DEV-35459: SLURLs and teleport Links not parsed properly - testRegex("Region with quote", url, - "XXX secondlife:///app/region/A'ksha%20Oasis/41/166/701 XXX", - "secondlife:///app/region/A%27ksha%20Oasis/41/166/701"); - // Rendering tests. testLabel("Render /app/region/Ahern/50/50/50/", url, "secondlife:///app/region/Ahern/50/50/50/", diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 397691d7cf..5ea2d0f7a5 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2528,6 +2528,10 @@ if (LL_TESTS) ${BOOST_CONTEXT_LIBRARY} ) + LL_ADD_INTEGRATION_TEST(cppfeatures + "" + "${test_libs}" + ) LL_ADD_INTEGRATION_TEST(llsechandler_basic llsechandler_basic.cpp "${test_libs}" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 77f0fd99bc..87bf9e5083 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -14324,19 +14324,6 @@ <key>Value</key> <integer>1</integer> </map> - <!-- SL-12594 removes fixed function rendering - <key>VertexShaderEnable</key> - <map> - <key>Comment</key> - <string>Enable/disable all GLSL shaders (debug)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <--> <key>VivoxAutoPostCrashDumps</key> <map> <key>Comment</key> diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index e6ee458719..f1bf8d76c2 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -56,7 +56,6 @@ RenderVBOMappingDisable 1 1 RenderVolumeLODFactor 1 2.0 UseStartScreen 1 1 UseOcclusion 1 1 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 Disregard128DefaultDrawDistance 1 1 @@ -95,7 +94,6 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 0 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -127,7 +125,6 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -158,7 +155,6 @@ RenderTerrainLODFactor 1 1.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -189,7 +185,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -220,7 +215,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 0 @@ -251,7 +245,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 @@ -282,7 +275,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 @@ -312,7 +304,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 2.0 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 RenderDeferred 1 1 @@ -380,7 +371,6 @@ list NoPixelShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 @@ -394,7 +384,6 @@ list NoVertexShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index bc836a99ca..5542eee6ca 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -56,7 +56,6 @@ RenderVBOMappingDisable 1 1 RenderVolumeLODFactor 1 2.0 UseStartScreen 1 1 UseOcclusion 1 1 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 Disregard128DefaultDrawDistance 1 1 @@ -94,7 +93,6 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -126,7 +124,6 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 0 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -157,7 +154,6 @@ RenderTerrainLODFactor 1 1.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -188,7 +184,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -219,7 +214,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderUseAdvancedAtmospherics 1 0 @@ -250,7 +244,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 @@ -281,7 +274,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 @@ -311,7 +303,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 2.0 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 RenderDeferred 1 1 @@ -379,7 +370,6 @@ list NoPixelShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 @@ -393,7 +383,6 @@ list NoVertexShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index 68202a571f..bac6fd5708 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -56,7 +56,6 @@ RenderVBOMappingDisable 1 1 RenderVolumeLODFactor 1 2.0 UseStartScreen 1 1 UseOcclusion 1 1 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 Disregard128DefaultDrawDistance 1 1 @@ -95,7 +94,6 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 0.5 -VertexShaderEnable 1 0 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -127,7 +125,6 @@ RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 RenderVolumeLODFactor 1 0.5 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -158,7 +155,6 @@ RenderTerrainLODFactor 1 1.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -189,7 +185,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 0 RenderDeferredSSAO 1 0 @@ -220,7 +215,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 0 @@ -251,7 +245,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 @@ -282,7 +275,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 0.5 RenderVolumeLODFactor 1 1.125 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 RenderDeferred 1 1 RenderDeferredSSAO 1 1 @@ -312,7 +304,6 @@ RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 RenderTreeLODFactor 1 1.0 RenderVolumeLODFactor 1 2.0 -VertexShaderEnable 1 1 WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 RenderDeferred 1 1 @@ -374,7 +365,6 @@ list NoPixelShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 @@ -388,7 +378,6 @@ list NoVertexShaders RenderAvatarVP 0 0 RenderAvatarCloth 0 0 RenderReflectionDetail 0 0 -VertexShaderEnable 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index c65bc0fa50..baf0acc94b 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -108,7 +108,8 @@ const U8 AGENT_STATE_EDITING = 0x10; // Autopilot constants const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f; // meters const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f; // meters -const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f; // seconds +const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS_WALK = 1.5f; // seconds +const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS_FLY = 2.5f; // seconds. Flying is less presize, needs a bit more time const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f; const F64 CHAT_AGE_FAST_RATE = 3.0; @@ -878,13 +879,12 @@ boost::signals2::connection LLAgent::addParcelChangedCallback(parcel_changed_cal } // static -void LLAgent::capabilityReceivedCallback(const LLUUID ®ion_id) +void LLAgent::capabilityReceivedCallback(const LLUUID ®ion_id, LLViewerRegion *regionp) { - LLViewerRegion* region = gAgent.getRegion(); - if (region && region->getRegionID() == region_id) + if (regionp && regionp->getRegionID() == region_id) { - region->requestSimulatorFeatures(); - LLAppViewer::instance()->updateNameLookupUrl(); + regionp->requestSimulatorFeatures(); + LLAppViewer::instance()->updateNameLookupUrl(regionp); } } @@ -935,7 +935,7 @@ void LLAgent::setRegion(LLViewerRegion *regionp) if (regionp->capabilitiesReceived()) { regionp->requestSimulatorFeatures(); - LLAppViewer::instance()->updateNameLookupUrl(); + LLAppViewer::instance()->updateNameLookupUrl(regionp); } else { @@ -961,11 +961,11 @@ void LLAgent::setRegion(LLViewerRegion *regionp) if (regionp->capabilitiesReceived()) { - LLAppViewer::instance()->updateNameLookupUrl(); + LLAppViewer::instance()->updateNameLookupUrl(regionp); } else { - regionp->setCapabilitiesReceivedCallback([](const LLUUID ®ion_id) {LLAppViewer::instance()->updateNameLookupUrl(); }); + regionp->setCapabilitiesReceivedCallback([](const LLUUID ®ion_id, LLViewerRegion* regionp) {LLAppViewer::instance()->updateNameLookupUrl(regionp); }); } } @@ -1562,6 +1562,12 @@ void LLAgent::startAutoPilotGlobal( { return; } + + if (target_global.isExactlyZero()) + { + LL_WARNS() << "Canceling attempt to start autopilot towards invalid position" << LL_ENDL; + return; + } // Are there any pending callbacks from previous auto pilot requests? if (mAutoPilotFinishedCallback) @@ -1777,7 +1783,16 @@ void LLAgent::autoPilot(F32 *delta_yaw) if (target_dist >= mAutoPilotTargetDist) { mAutoPilotNoProgressFrameCount++; - if (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped) + bool out_of_time = false; + if (getFlying()) + { + out_of_time = mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS_FLY * gFPSClamped; + } + else + { + out_of_time = mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS_WALK * gFPSClamped; + } + if (out_of_time) { stopAutoPilot(); return; @@ -1826,7 +1841,7 @@ void LLAgent::autoPilot(F32 *delta_yaw) F32 slow_distance; if (getFlying()) { - slow_distance = llmax(6.f, mAutoPilotStopDistance + 5.f); + slow_distance = llmax(8.f, mAutoPilotStopDistance + 5.f); } else { @@ -1870,14 +1885,41 @@ void LLAgent::autoPilot(F32 *delta_yaw) } else if (mAutoPilotTargetDist > mAutoPilotStopDistance) { - // walking/flying slow + // walking/flying slow + U32 movement_flag = 0; + if (at * direction > 0.9f) { - setControlFlags(AGENT_CONTROL_AT_POS); - } - else if (at * direction < -0.9f) - { - setControlFlags(AGENT_CONTROL_AT_NEG); + movement_flag = AGENT_CONTROL_AT_POS; + } + else if (at * direction < -0.9f) + { + movement_flag = AGENT_CONTROL_AT_NEG; + } + + if (getFlying()) + { + // flying is too fast and has high inertia, artificially slow it down + // Don't update flags too often, server might not react + static U64 last_time_microsec = 0; + U64 time_microsec = LLTimer::getTotalTime(); + U64 delta = time_microsec - last_time_microsec; + // fly during ~0-40 ms, stop during ~40-250 ms + if (delta > 250000) // 250ms + { + // reset even if !movement_flag + last_time_microsec = time_microsec; + } + else if (delta > 40000) // 40 ms + { + clearControlFlags(AGENT_CONTROL_AT_POS | AGENT_CONTROL_AT_POS); + movement_flag = 0; + } + } + + if (movement_flag) + { + setControlFlags(movement_flag); } } diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index d46c99db8c..f5ca42af5b 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -254,7 +254,7 @@ public: boost::signals2::connection addParcelChangedCallback(parcel_changed_callback_t); private: - static void capabilityReceivedCallback(const LLUUID ®ion_id); + static void capabilityReceivedCallback(const LLUUID ®ion_id, LLViewerRegion *regionp); typedef boost::signals2::signal<void()> parcel_changed_signal_t; parcel_changed_signal_t mParcelChangedSignal; diff --git a/indra/newview/llappcorehttp.cpp b/indra/newview/llappcorehttp.cpp index 134a34137b..3da87e657c 100644 --- a/indra/newview/llappcorehttp.cpp +++ b/indra/newview/llappcorehttp.cpp @@ -116,6 +116,7 @@ static const struct }; static void setting_changed(); +static void ssl_verification_changed(); LLAppCoreHttp::HttpClass::HttpClass() @@ -195,6 +196,23 @@ void LLAppCoreHttp::init() LL_WARNS("Init") << "Failed to set SSL Verification. Reason: " << status.toString() << LL_ENDL; } + // Set up Default SSL Verification option. + const std::string no_verify_ssl("NoVerifySSLCert"); + if (gSavedSettings.controlExists(no_verify_ssl)) + { + LLPointer<LLControlVariable> cntrl_ptr = gSavedSettings.getControl(no_verify_ssl); + if (cntrl_ptr.isNull()) + { + LL_WARNS("Init") << "Unable to set signal on global setting '" << no_verify_ssl + << "'" << LL_ENDL; + } + else + { + mSSLNoVerifySignal = cntrl_ptr->getCommitSignal()->connect(boost::bind(&ssl_verification_changed)); + LLCore::HttpOptions::setDefaultSSLVerifyPeer(!cntrl_ptr->getValue().asBoolean()); + } + } + // Tracing levels for library & libcurl (note that 2 & 3 are beyond spammy): // 0 - None // 1 - Basic start, stop simple transitions @@ -296,6 +314,11 @@ void setting_changed() LLAppViewer::instance()->getAppCoreHttp().refreshSettings(false); } +void ssl_verification_changed() +{ + LLCore::HttpOptions::setDefaultSSLVerifyPeer(!gSavedSettings.getBOOL("NoVerifySSLCert")); +} + namespace { // The NoOpDeletor is used when wrapping LLAppCoreHttp in a smart pointer below for @@ -355,6 +378,7 @@ void LLAppCoreHttp::cleanup() { mHttpClasses[i].mSettingsSignal.disconnect(); } + mSSLNoVerifySignal.disconnect(); mPipelinedSignal.disconnect(); delete mRequest; diff --git a/indra/newview/llappcorehttp.h b/indra/newview/llappcorehttp.h index 95c138d598..751c498ab0 100644 --- a/indra/newview/llappcorehttp.h +++ b/indra/newview/llappcorehttp.h @@ -256,6 +256,7 @@ private: HttpClass mHttpClasses[AP_COUNT]; bool mPipelined; // Global setting boost::signals2::connection mPipelinedSignal; // Signal for 'HttpPipelining' setting + boost::signals2::connection mSSLNoVerifySignal; // Signal for 'NoVerifySSLCert' setting static LLCore::HttpStatus sslVerify(const std::string &uri, const LLCore::HttpHandler::ptr_t &handler, void *appdata); }; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0b2cdff36c..a13ba97987 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -5362,10 +5362,9 @@ void LLAppViewer::sendLogoutRequest() } } -void LLAppViewer::updateNameLookupUrl() +void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) { - LLViewerRegion* region = gAgent.getRegion(); - if (!region || !region->capabilitiesReceived()) + if (!regionp || !regionp->capabilitiesReceived()) { return; } @@ -5374,7 +5373,7 @@ void LLAppViewer::updateNameLookupUrl() bool had_capability = LLAvatarNameCache::getInstance()->hasNameLookupURL(); std::string name_lookup_url; name_lookup_url.reserve(128); // avoid a memory allocation below - name_lookup_url = region->getCapability("GetDisplayNames"); + name_lookup_url = regionp->getCapability("GetDisplayNames"); bool have_capability = !name_lookup_url.empty(); if (have_capability) { @@ -5685,6 +5684,33 @@ void LLAppViewer::forceErrorDriverCrash() glDeleteTextures(1, NULL); } +void LLAppViewer::forceErrorCoroutineCrash() +{ + LL_WARNS() << "Forcing a crash in LLCoros" << LL_ENDL; + LLCoros::instance().launch("LLAppViewer::crashyCoro", [] {throw LLException("A deliberate crash from LLCoros"); }); +} + +void LLAppViewer::forceErrorThreadCrash() +{ + class LLCrashTestThread : public LLThread + { + public: + + LLCrashTestThread() : LLThread("Crash logging test thread") + { + } + + void run() + { + LL_ERRS() << "This is a deliberate llerror in thread" << LL_ENDL; + } + }; + + LL_WARNS() << "This is a deliberate crash in a thread" << LL_ENDL; + LLCrashTestThread *thread = new LLCrashTestThread(); + thread->start(); +} + void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) { if(!mMainloopTimeout) diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index d24cdcedc7..a5b58d3a81 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -57,6 +57,7 @@ class LLImageDecodeThread; class LLTextureFetch; class LLWatchdogTimeout; class LLViewerJoystick; +class LLViewerRegion; extern LLTrace::BlockTimerStatHandle FTM_FRAME; @@ -150,6 +151,8 @@ public: virtual void forceErrorInfiniteLoop(); virtual void forceErrorSoftwareException(); virtual void forceErrorDriverCrash(); + virtual void forceErrorCoroutineCrash(); + virtual void forceErrorThreadCrash(); // The list is found in app_settings/settings_files.xml // but since they are used explicitly in code, @@ -209,7 +212,7 @@ public: // llcorehttp init/shutdown/config information. LLAppCoreHttp & getAppCoreHttp() { return mAppCoreHttp; } - void updateNameLookupUrl(); + void updateNameLookupUrl(const LLViewerRegion* regionp); protected: virtual bool initWindow(); // Initialize the viewer's window. diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 9b1c0d1f8b..ce36d3458e 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -609,6 +609,13 @@ bool LLAppViewerWin32::init() #else // LL_BUGSPLAT #pragma message("Building with BugSplat") + if (!isSecondInstance()) + { + // Cleanup previous session + std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "bugsplat.log"); + LLFile::remove(log_file, ENOENT); + } + std::string build_data_fname( gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); // Use llifstream instead of std::ifstream because LL_PATH_EXECUTABLE @@ -616,7 +623,7 @@ bool LLAppViewerWin32::init() llifstream inf(build_data_fname.c_str()); if (! inf.is_open()) { - LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't read '" << build_data_fname << "'" << LL_ENDL; } else @@ -626,7 +633,7 @@ bool LLAppViewerWin32::init() if (! reader.parse(inf, build_data, false)) // don't collect comments { // gah, the typo is baked into Json::Reader API - LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, can't parse '" << build_data_fname << "': " << reader.getFormatedErrorMessages() << LL_ENDL; } else @@ -634,7 +641,7 @@ bool LLAppViewerWin32::init() Json::Value BugSplat_DB = build_data["BugSplat DB"]; if (! BugSplat_DB) { - LL_WARNS() << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" + LL_WARNS("BUGSPLAT") << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" << build_data_fname << "'" << LL_ENDL; } else @@ -645,18 +652,35 @@ bool LLAppViewerWin32::init() LL_VIEWER_VERSION_PATCH << '.' << LL_VIEWER_VERSION_BUILD)); + DWORD dwFlags = MDSF_NONINTERACTIVE | // automatically submit report without prompting + MDSF_PREVENTHIJACKING; // disallow swiping Exception filter + + bool needs_log_file = !isSecondInstance() && debugLoggingEnabled("BUGSPLAT"); + if (needs_log_file) + { + // Startup only! + LL_INFOS("BUGSPLAT") << "Engaged BugSplat logging to bugsplat.log" << LL_ENDL; + dwFlags |= MDSF_LOGFILE | MDSF_LOG_VERBOSE; + } + // have to convert normal wide strings to strings of __wchar_t sBugSplatSender = new MiniDmpSender( WCSTR(BugSplat_DB.asString()), WCSTR(LL_TO_WSTRING(LL_VIEWER_CHANNEL)), WCSTR(version_string), nullptr, // szAppIdentifier -- set later - MDSF_NONINTERACTIVE | // automatically submit report without prompting - MDSF_PREVENTHIJACKING); // disallow swiping Exception filter + dwFlags); sBugSplatSender->setCallback(bugsplatSendLog); + if (needs_log_file) + { + // Log file will be created in %TEMP%, but it will be moved into logs folder in case of crash + std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "bugsplat.log"); + sBugSplatSender->setLogFilePath(WCSTR(log_file)); + } + // engage stringize() overload that converts from wstring - LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) + LL_INFOS("BUGSPLAT") << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) << ' ' << stringize(version_string) << ')' << LL_ENDL; } // got BugSplat_DB } // parsed build_data.json @@ -685,6 +709,16 @@ bool LLAppViewerWin32::cleanup() return result; } +void LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo) +{ +#if defined(LL_BUGSPLAT) + if (sBugSplatSender) + { + sBugSplatSender->createReport((EXCEPTION_POINTERS*)pExcepInfo); + } +#endif // LL_BUGSPLAT +} + void LLAppViewerWin32::initLoggingAndGetLastDuration() { LLAppViewer::initLoggingAndGetLastDuration(); diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index c5fae6a3a3..83ae875a15 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -40,20 +40,22 @@ public: // // Main application logic // - virtual bool init(); // Override to do application initialization - virtual bool cleanup(); + bool init() override; // Override to do application initialization + bool cleanup() override; + + void reportCrashToBugsplat(void* pExcepInfo) override; protected: - virtual void initLoggingAndGetLastDuration(); // Override to clean stack_trace info. - virtual void initConsole(); // Initialize OS level debugging console. - virtual bool initHardwareTest(); // Win32 uses DX9 to test hardware. - virtual bool initParseCommandLine(LLCommandLineParser& clp); + void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info. + void initConsole() override; // Initialize OS level debugging console. + bool initHardwareTest() override; // Win32 uses DX9 to test hardware. + bool initParseCommandLine(LLCommandLineParser& clp) override; - virtual bool beingDebugged(); - virtual bool restoreErrorTrap(); - virtual void initCrashReporting(bool reportFreeze); + bool beingDebugged() override; + bool restoreErrorTrap() override; + void initCrashReporting(bool reportFreeze) override; - virtual bool sendURLToOtherInstance(const std::string& url); + bool sendURLToOtherInstance(const std::string& url) override; std::string generateSerialNumber(); diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 4cfde21e32..a685639427 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -380,7 +380,7 @@ LLConversationItemParticipant* LLConversationItemSession::findParticipant(const for (iter = mChildren.begin(); iter != mChildren.end(); iter++) { participant = dynamic_cast<LLConversationItemParticipant*>(*iter); - if (participant->hasSameValue(participant_id)) + if (participant && participant->hasSameValue(participant_id)) { break; } @@ -491,7 +491,7 @@ const bool LLConversationItemSession::getTime(F64& time) const { participant = dynamic_cast<LLConversationItemParticipant*>(*iter); F64 participant_time; - if (participant->getTime(participant_time)) + if (participant && participant->getTime(participant_time)) { has_time = true; most_recent_time = llmax(most_recent_time,participant_time); diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index df16868132..65cec68884 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -696,10 +696,13 @@ void LLConversationViewParticipant::refresh() { // Refresh the participant view from its model data LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(getViewModelItem()); - participant_model->resetRefresh(); - - // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat - mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted()); + if (participant_model) + { + participant_model->resetRefresh(); + + // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat + mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted()); + } // Do the regular upstream refresh LLFolderViewItem::refresh(); diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 74c1b99e4d..79f72220ed 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -1029,7 +1029,7 @@ void LLEnvironment::onRegionChange() } if (!cur_region->capabilitiesReceived()) { - cur_region->setCapabilitiesReceivedCallback([](const LLUUID ®ion_id) { LLEnvironment::instance().requestRegion(); }); + cur_region->setCapabilitiesReceivedCallback([](const LLUUID ®ion_id, LLViewerRegion* regionp) { LLEnvironment::instance().requestRegion(); }); return; } requestRegion(); @@ -1154,9 +1154,38 @@ void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironm } else if (!environment->getSky()) { - LL_DEBUGS("ENVIRONMENT") << "Blank sky for " << env_selection_to_string(env) << ". Reusing environment for sky." << LL_ENDL; - environment->setSky(mCurrentEnvironment->getSky()); - environment->setFlags(DayInstance::NO_ANIMATE_SKY); + if (mCurrentEnvironment->getEnvironmentSelection() != ENV_NONE) + { + // Note: This looks suspicious. Shouldn't we assign whole day if mCurrentEnvironment has whole day? + // and then add water/sky on top + // This looks like it will result in sky using single keyframe instead of whole day if day is present + // when setting static water without static sky + environment->setSky(mCurrentEnvironment->getSky()); + environment->setFlags(DayInstance::NO_ANIMATE_SKY); + } + else + { + // Environment is not properly initialized yet, but we should have environment by this point + DayInstance::ptr_t substitute = getEnvironmentInstance(ENV_PARCEL, true); + if (!substitute || !substitute->getSky()) + { + substitute = getEnvironmentInstance(ENV_REGION, true); + } + if (!substitute || !substitute->getSky()) + { + substitute = getEnvironmentInstance(ENV_DEFAULT, true); + } + + if (substitute && substitute->getSky()) + { + environment->setSky(substitute->getSky()); + environment->setFlags(DayInstance::NO_ANIMATE_SKY); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to assign substitute water/sky, environment is not properly initialized" << LL_ENDL; + } + } } if (fixed.second) @@ -1167,9 +1196,38 @@ void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironm } else if (!environment->getWater()) { - LL_DEBUGS("ENVIRONMENT") << "Blank water for " << env_selection_to_string(env) << ". Reusing environment for water." << LL_ENDL; - environment->setWater(mCurrentEnvironment->getWater()); - environment->setFlags(DayInstance::NO_ANIMATE_WATER); + if (mCurrentEnvironment->getEnvironmentSelection() != ENV_NONE) + { + // Note: This looks suspicious. Shouldn't we assign whole day if mCurrentEnvironment has whole day? + // and then add water/sky on top + // This looks like it will result in water using single keyframe instead of whole day if day is present + // when setting static sky without static water + environment->setWater(mCurrentEnvironment->getWater()); + environment->setFlags(DayInstance::NO_ANIMATE_WATER); + } + else + { + // Environment is not properly initialized yet, but we should have environment by this point + DayInstance::ptr_t substitute = getEnvironmentInstance(ENV_PARCEL, true); + if (!substitute || !substitute->getWater()) + { + substitute = getEnvironmentInstance(ENV_REGION, true); + } + if (!substitute || !substitute->getWater()) + { + substitute = getEnvironmentInstance(ENV_DEFAULT, true); + } + + if (substitute && substitute->getWater()) + { + environment->setWater(substitute->getWater()); + environment->setFlags(DayInstance::NO_ANIMATE_WATER); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to assign substitute water/sky, environment is not properly initialized" << LL_ENDL; + } + } } if (!mSignalEnvChanged.empty()) @@ -1698,8 +1756,11 @@ void LLEnvironment::recordEnvironment(S32 parcel_id, LLEnvironment::EnvironmentI } else { - setEnvironment(ENV_REGION, envinfo->mDayCycle, envinfo->mDayLength, envinfo->mDayOffset, envinfo->mEnvVersion); mTrackAltitudes = envinfo->mAltitudes; + // update track selection based on new altitudes + mCurrentTrack = calculateSkyTrackForAltitude(gAgent.getPositionAgent().mV[VZ]); + + setEnvironment(ENV_REGION, envinfo->mDayCycle, envinfo->mDayLength, envinfo->mDayOffset, envinfo->mEnvVersion); } LL_DEBUGS("ENVIRONMENT") << "Altitudes set to {" << mTrackAltitudes[0] << ", "<< mTrackAltitudes[1] << ", " << mTrackAltitudes[2] << ", " << mTrackAltitudes[3] << LL_ENDL; @@ -1931,6 +1992,10 @@ void LLEnvironment::coroRequestEnvironment(S32 parcel_id, LLEnvironment::environ { LL_WARNS("ENVIRONMENT") << "Couldn't retrieve environment settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; } + else if (LLApp::isExiting()) + { + return; + } else { LLSD environment = result[KEY_ENVIRONMENT]; @@ -2020,6 +2085,10 @@ void LLEnvironment::coroUpdateEnvironment(S32 parcel_id, S32 track_no, UpdateInf notify = LLSD::emptyMap(); notify["FAIL_REASON"] = result["message"].asString(); } + else if (LLApp::isExiting()) + { + return; + } else { LLSD environment = result[KEY_ENVIRONMENT]; @@ -2082,6 +2151,10 @@ void LLEnvironment::coroResetEnvironment(S32 parcel_id, S32 track_no, environmen notify = LLSD::emptyMap(); notify["FAIL_REASON"] = result["message"].asString(); } + else if (LLApp::isExiting()) + { + return; + } else { LLSD environment = result[KEY_ENVIRONMENT]; @@ -2319,6 +2392,15 @@ void LLEnvironment::onAgentPositionHasChanged(const LLVector3 &localpos) return; mCurrentTrack = trackno; + + LLViewerRegion* cur_region = gAgent.getRegion(); + if (!cur_region || !cur_region->capabilitiesReceived()) + { + // Environment not ready, environment will be updated later, don't cause 'blend' yet. + // But keep mCurrentTrack updated in case we won't get new altitudes for some reason + return; + } + for (S32 env = ENV_LOCAL; env < ENV_DEFAULT; ++env) { if (mEnvironments[env]) diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 171858e472..1fbd198019 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -236,6 +236,7 @@ void LLFloaterAbout::fetchServerReleaseNotesCoro(const std::string& cap_url) httpOpts->setWantHeaders(true); httpOpts->setFollowRedirects(false); + httpOpts->setSSLVerifyPeer(false); // We want this data even if SSL verification fails LLSD result = httpAdapter->getAndSuspend(httpRequest, cap_url, httpOpts); diff --git a/indra/newview/llfloaterexperienceprofile.cpp b/indra/newview/llfloaterexperienceprofile.cpp index 2c9a8e64b7..a99a096ea7 100644 --- a/indra/newview/llfloaterexperienceprofile.cpp +++ b/indra/newview/llfloaterexperienceprofile.cpp @@ -211,6 +211,20 @@ bool LLFloaterExperienceProfile::experiencePermission( LLHandle<LLFloaterExperie return false; } +bool LLFloaterExperienceProfile::matchesKey(const LLSD& key) +{ + if (key.has("experience_id")) + { + return mExperienceId == key["experience_id"].asUUID(); + } + else if (key.isUUID()) + { + return mExperienceId == key.asUUID(); + } + // Assume NULL uuid + return mExperienceId.isNull(); +} + void LLFloaterExperienceProfile::onClickEdit() { diff --git a/indra/newview/llfloaterexperienceprofile.h b/indra/newview/llfloaterexperienceprofile.h index 1394418d91..f9b6e2e2eb 100644 --- a/indra/newview/llfloaterexperienceprofile.h +++ b/indra/newview/llfloaterexperienceprofile.h @@ -51,6 +51,8 @@ public: LLFloaterExperienceProfile(const LLSD& data); virtual ~LLFloaterExperienceProfile(); + + /* virtual */ bool matchesKey(const LLSD& key); LLUUID getExperienceId() const { return mExperienceId; } void setPreferences( const LLSD& content ); diff --git a/indra/newview/llfloatergridstatus.cpp b/indra/newview/llfloatergridstatus.cpp index faa7e9f3db..9745e17bbb 100644 --- a/indra/newview/llfloatergridstatus.cpp +++ b/indra/newview/llfloatergridstatus.cpp @@ -95,6 +95,7 @@ void LLFloaterGridStatus::getGridStatusRSSCoro() LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + httpOpts->setSSLVerifyPeer(false); // We want this data even if SSL fails httpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML); std::string url = gSavedSettings.getString("GridStatusRSS"); diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 8d38a5743b..9c84fa1991 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -59,7 +59,9 @@ #include "boost/foreach.hpp" -const S32 EVENTS_PER_IDLE_LOOP = 100; +const S32 EVENTS_PER_IDLE_LOOP_CURRENT_SESSION = 80; +const S32 EVENTS_PER_IDLE_LOOP_BACKGROUND = 40; +const F32 EVENTS_PER_IDLE_LOOP_MIN_PERCENTAGE = 0.01f; // process a minimum of 1% of total events per frame // // LLFloaterIMContainer @@ -426,8 +428,11 @@ void LLFloaterIMContainer::processParticipantsStyleUpdate() while (current_participant_model != end_participant_model) { LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model); - // Get the avatar name for this participant id from the cache and update the model - participant_model->updateName(); + if (participant_model) + { + // Get the avatar name for this participant id from the cache and update the model + participant_model->updateName(); + } // Next participant current_participant_model++; } @@ -474,8 +479,11 @@ void LLFloaterIMContainer::idleUpdate() while (current_participant_model != end_participant_model) { LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model); - participant_model->setModeratorOptionsVisible(is_moderator); - participant_model->setGroupBanVisible(can_ban && participant_model->getUUID() != gAgentID); + if (participant_model) + { + participant_model->setModeratorOptionsVisible(is_moderator); + participant_model->setGroupBanVisible(can_ban && participant_model->getUUID() != gAgentID); + } current_participant_model++; } @@ -508,20 +516,49 @@ void LLFloaterIMContainer::idleUpdate() void LLFloaterIMContainer::idleProcessEvents() { - if (!mConversationEventQueue.empty()) - { - S32 events_to_handle = llmin((S32)mConversationEventQueue.size(), EVENTS_PER_IDLE_LOOP); - for (S32 i = 0; i < events_to_handle; i++) - { - handleConversationModelEvent(mConversationEventQueue.back()); - mConversationEventQueue.pop_back(); - } - } + LLUUID current_session_id = getSelectedSession(); + conversations_items_deque::iterator iter = mConversationEventQueue.begin(); + conversations_items_deque::iterator end = mConversationEventQueue.end(); + while (iter != end) + { + std::deque<LLSD> &events = iter->second; + if (!events.empty()) + { + S32 events_to_handle; + S32 query_size = (S32)events.size(); + if (current_session_id == iter->first) + { + events_to_handle = EVENTS_PER_IDLE_LOOP_CURRENT_SESSION; + } + else + { + events_to_handle = EVENTS_PER_IDLE_LOOP_BACKGROUND; + } + + if (events_to_handle <= query_size) + { + // Some groups can be very large and can generate huge amount of updates, scale processing up to keep up + events_to_handle = llmax(events_to_handle, (S32)(query_size * EVENTS_PER_IDLE_LOOP_MIN_PERCENTAGE)); + } + else + { + events_to_handle = query_size; + } + + for (S32 i = 0; i < events_to_handle; i++) + { + handleConversationModelEvent(events.back()); + events.pop_back(); + } + } + iter++; + } } bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event) { - mConversationEventQueue.push_front(event); + LLUUID id = event.get("session_uuid").asUUID(); + mConversationEventQueue[id].push_front(event); return true; } @@ -1834,6 +1871,8 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c // Suppress the conversation items and widgets from their respective maps mConversationsItems.erase(uuid); mConversationsWidgets.erase(uuid); + // Clear event query (otherwise reopening session in some way can bombard session with stale data) + mConversationEventQueue.erase(uuid); // Don't let the focus fall IW, select and refocus on the first conversation in the list if (change_focus) diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index 468b47f1f1..b4a9d377ab 100644 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -229,9 +229,10 @@ private: conversations_widgets_map mConversationsWidgets; LLConversationViewModel mConversationViewModel; LLFolderView* mConversationsRoot; - LLEventStream mConversationsEventStream; + LLEventStream mConversationsEventStream; - std::deque<LLSD> mConversationEventQueue; + typedef std::map<LLUUID, std::deque<LLSD> > conversations_items_deque; + conversations_items_deque mConversationEventQueue; LLTimer mParticipantRefreshTimer; }; diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index e7f428c06a..7541bb5efe 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -497,7 +497,10 @@ void LLFloaterIMSessionTab::buildConversationViewParticipant() while (current_participant_model != end_participant_model) { LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model); - addConversationViewParticipant(participant_model); + if (participant_model) + { + addConversationViewParticipant(participant_model); + } current_participant_model++; } } diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index f2efef0c33..63bce3d2eb 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -122,8 +122,7 @@ void LLFloaterURLEntry::headerFetchComplete(S32 status, const std::string& mime_ } } - // Decrement the cursor - getWindow()->decBusyCount(); + getChildView("loading_label")->setVisible( false); closeFloater(); } @@ -302,3 +301,9 @@ bool LLFloaterURLEntry::callback_clear_url_list(const LLSD& notification, const } return false; } + +void LLFloaterURLEntry::onClose( bool app_quitting ) +{ + // Decrement the cursor + getWindow()->decBusyCount(); +} diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index 20f4604907..04a8eca069 100644 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -42,6 +42,7 @@ public: // that panel via the handle. static LLHandle<LLFloater> show(LLHandle<LLPanel> panel_land_media_handle, const std::string media_url); /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose( bool app_quitting ); void headerFetchComplete(S32 status, const std::string& mime_type); bool addURLToCombobox(const std::string& media_url); diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index 4ed802138d..9d49c30a49 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -105,6 +105,9 @@ LLHUDNameTag::LLHUDNameTag(const U8 type) { LLPointer<LLHUDNameTag> ptr(this); sTextObjects.insert(ptr); + + mRoundedRectImgp = LLUI::getUIImage("Rounded_Rect"); + mRoundedRectTopImgp = LLUI::getUIImage("Rounded_Rect_Top"); } LLHUDNameTag::~LLHUDNameTag() @@ -274,9 +277,6 @@ void LLHUDNameTag::renderText(BOOL for_select) mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); - // *TODO: cache this image - LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Rect"); - // *TODO: make this a per-text setting LLColor4 bg_color = LLUIColorTable::instance().getColor("NameTagBackground"); bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor); @@ -306,17 +306,16 @@ void LLHUDNameTag::renderText(BOOL for_select) LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); LLRect screen_rect; screen_rect.setCenterAndSize(0, static_cast<S32>(lltrunc(-mHeight / 2 + mOffsetY)), static_cast<S32>(lltrunc(mWidth)), static_cast<S32>(lltrunc(mHeight))); - imagep->draw3D(render_position, x_pixel_vec, y_pixel_vec, screen_rect, bg_color); + mRoundedRectImgp->draw3D(render_position, x_pixel_vec, y_pixel_vec, screen_rect, bg_color); if (mLabelSegments.size()) { - LLUIImagePtr rect_top_image = LLUI::getUIImage("Rounded_Rect_Top"); LLRect label_top_rect = screen_rect; const S32 label_height = ll_round((mFontp->getLineHeight() * (F32)mLabelSegments.size() + (VERTICAL_PADDING / 3.f))); label_top_rect.mBottom = label_top_rect.mTop - label_height; LLColor4 label_top_color = text_color; label_top_color.mV[VALPHA] = gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor; - rect_top_image->draw3D(render_position, x_pixel_vec, y_pixel_vec, label_top_rect, label_top_color); + mRoundedRectTopImgp->draw3D(render_position, x_pixel_vec, y_pixel_vec, label_top_rect, label_top_color); } F32 y_offset = (F32)mOffsetY; diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h index 20272a8232..7577dd5de6 100644 --- a/indra/newview/llhudnametag.h +++ b/indra/newview/llhudnametag.h @@ -40,8 +40,8 @@ #include <set> #include <vector> -class LLDrawable; class LLHUDNameTag; +class LLUIImage; struct llhudnametag_further_away { @@ -171,6 +171,8 @@ private: EVertAlignment mVertAlignment; S32 mLOD; BOOL mHidden; + LLPointer<LLUIImage> mRoundedRectImgp; + LLPointer<LLUIImage> mRoundedRectTopImgp; static BOOL sDisplayText ; static std::set<LLPointer<LLHUDNameTag> > sTextObjects; diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 72d28a3d44..7c957ac712 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -138,9 +138,6 @@ void LLHUDText::renderText() mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); - // *TODO: cache this image - LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square"); - // *TODO: make this a per-text setting LLColor4 bg_color = LLUIColorTable::instance().getColor("ObjectBubbleColor"); bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index d35d8456be..a729b276d5 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -3987,6 +3987,12 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items const LLUUID &lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); const LLUUID &favorites = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE); const LLUUID &marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &outfits_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + + if (outfits_id == mUUID) + { + items.push_back(std::string("New Outfit")); + } if (lost_and_found_id == mUUID) { @@ -4085,7 +4091,8 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items // Not sure what the right thing is to do here. if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) { - if (!isInboxFolder()) // don't allow creation in inbox + if (!isInboxFolder() // don't allow creation in inbox + && outfits_id != mUUID) { // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) diff --git a/indra/newview/lllandmarklist.cpp b/indra/newview/lllandmarklist.cpp index 543d2a087f..921b80a667 100644 --- a/indra/newview/lllandmarklist.cpp +++ b/indra/newview/lllandmarklist.cpp @@ -132,36 +132,49 @@ void LLLandmarkList::processGetAssetReply( LLVFile file(vfs, uuid, type); S32 file_length = file.getSize(); - std::vector<char> buffer(file_length + 1); - file.read( (U8*)&buffer[0], file_length); - buffer[ file_length ] = 0; + if (file_length > 0) + { + std::vector<char> buffer(file_length + 1); + file.read((U8*)&buffer[0], file_length); + buffer[file_length] = 0; - LLLandmark* landmark = LLLandmark::constructFromString(&buffer[0]); - if (landmark) - { - gLandmarkList.mList[ uuid ] = landmark; - gLandmarkList.mRequestedList.erase(uuid); - - LLVector3d pos; - if(!landmark->getGlobalPos(pos)) - { - LLUUID region_id; - if(landmark->getRegionID(region_id)) - { - LLLandmark::requestRegionHandle( - gMessageSystem, - gAgent.getRegionHost(), - region_id, - boost::bind(&LLLandmarkList::onRegionHandle, &gLandmarkList, uuid)); - } - - // the callback will be called when we get the region handle. - } - else - { - gLandmarkList.makeCallbacks(uuid); - } - } + LLLandmark* landmark = LLLandmark::constructFromString(&buffer[0], buffer.size()); + if (landmark) + { + gLandmarkList.mList[uuid] = landmark; + gLandmarkList.mRequestedList.erase(uuid); + + LLVector3d pos; + if (!landmark->getGlobalPos(pos)) + { + LLUUID region_id; + if (landmark->getRegionID(region_id)) + { + LLLandmark::requestRegionHandle( + gMessageSystem, + gAgent.getRegionHost(), + region_id, + boost::bind(&LLLandmarkList::onRegionHandle, &gLandmarkList, uuid)); + } + + // the callback will be called when we get the region handle. + } + else + { + gLandmarkList.makeCallbacks(uuid); + } + } + else + { + // failed to parse, shouldn't happen + gLandmarkList.eraseCallbacks(uuid); + } + } + else + { + // got a good status, but no file, shouldn't happen + gLandmarkList.eraseCallbacks(uuid); + } } else { @@ -179,7 +192,7 @@ void LLLandmarkList::processGetAssetReply( gLandmarkList.mBadList.insert(uuid); gLandmarkList.mRequestedList.erase(uuid); //mBadList effectively blocks any load, so no point keeping id in requests - // todo: this should clean mLoadedCallbackMap! + gLandmarkList.eraseCallbacks(uuid); } // getAssetData can fire callback immediately, causing @@ -223,32 +236,39 @@ BOOL LLLandmarkList::assetExists(const LLUUID& asset_uuid) void LLLandmarkList::onRegionHandle(const LLUUID& landmark_id) { LLLandmark* landmark = getAsset(landmark_id); - - if (!landmark) - { - LL_WARNS() << "Got region handle but the landmark not found." << LL_ENDL; - return; - } + if (!landmark) + { + LL_WARNS() << "Got region handle but the landmark " << landmark_id << " not found." << LL_ENDL; + eraseCallbacks(landmark_id); + return; + } // Calculate landmark global position. // This should succeed since the region handle is available. LLVector3d pos; if (!landmark->getGlobalPos(pos)) { - LL_WARNS() << "Got region handle but the landmark global position is still unknown." << LL_ENDL; - return; + LL_WARNS() << "Got region handle but the landmark " << landmark_id << " global position is still unknown." << LL_ENDL; + eraseCallbacks(landmark_id); + return; } + // Call this even if no landmark exists to clean mLoadedCallbackMap makeCallbacks(landmark_id); } +void LLLandmarkList::eraseCallbacks(const LLUUID& landmark_id) +{ + mLoadedCallbackMap.erase(landmark_id); +} + void LLLandmarkList::makeCallbacks(const LLUUID& landmark_id) { LLLandmark* landmark = getAsset(landmark_id); if (!landmark) { - LL_WARNS() << "Landmark to make callbacks for not found." << LL_ENDL; + LL_WARNS() << "Landmark " << landmark_id << " to make callbacks for not found." << LL_ENDL; } // make all the callbacks here. diff --git a/indra/newview/lllandmarklist.h b/indra/newview/lllandmarklist.h index 2e7bd25610..4f3b11660d 100644 --- a/indra/newview/lllandmarklist.h +++ b/indra/newview/lllandmarklist.h @@ -65,6 +65,7 @@ public: protected: void onRegionHandle(const LLUUID& landmark_id); + void eraseCallbacks(const LLUUID& landmark_id); void makeCallbacks(const LLUUID& landmark_id); typedef std::map<LLUUID, LLLandmark*> landmark_list_t; diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 958c76f261..bd24c47a4f 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -31,6 +31,7 @@ #include "lluictrl.h" #include "llframetimer.h" +#include "llnotificationptr.h" class LLViewBorder; class LLUICtrlFactory; @@ -145,7 +146,7 @@ public: void setTextureSize(S32 width, S32 height); - void showNotification(boost::shared_ptr<class LLNotification> notify); + void showNotification(LLNotificationPtr notify); void hideNotification(); void setTrustedContent(bool trusted); diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 272e7ae351..1bc08bd0d7 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -67,6 +67,7 @@ LLOutfitGallery::LLOutfitGallery(const LLOutfitGallery::Params& p) mOutfitsObserver(NULL), mScrollPanel(NULL), mGalleryPanel(NULL), + mLastRowPanel(NULL), mGalleryCreated(false), mRowCount(0), mItemsAddedCount(0), @@ -166,9 +167,7 @@ bool compareGalleryItem(LLOutfitGalleryItem* item1, LLOutfitGalleryItem* item2) std::string name1 = item1->getItemName(); std::string name2 = item2->getItemName(); - LLStringUtil::toUpper(name1); - LLStringUtil::toUpper(name2); - return name1 < name2; + return (LLStringUtil::compareDict(name1, name2) < 0); } else { @@ -241,7 +240,15 @@ void LLOutfitGallery::removeLastRow() mGalleryPanel->removeChild(mLastRowPanel); mUnusedRowPanels.push_back(mLastRowPanel); mRowPanels.pop_back(); - mLastRowPanel = mRowPanels.back(); + if (mRowPanels.size() > 0) + { + // Just removed last row + mLastRowPanel = mRowPanels.back(); + } + else + { + mLastRowPanel = NULL; + } } LLPanel* LLOutfitGallery::addToRow(LLPanel* row_stack, LLOutfitGalleryItem* item, int pos, int hgap) diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 71ab826e1c..423e57978a 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -59,10 +59,7 @@ bool LLOutfitTabNameComparator::compare(const LLAccordionCtrlTab* tab1, const LL std::string name1 = tab1->getTitle(); std::string name2 = tab2->getTitle(); - LLStringUtil::toUpper(name1); - LLStringUtil::toUpper(name2); - - return name1 < name2; + return (LLStringUtil::compareDict(name1, name2) < 0); } struct outfit_accordion_tab_params : public LLInitParam::Block<outfit_accordion_tab_params, LLAccordionCtrlTab::Params> diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 3964dc075c..381b80fb66 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -254,7 +254,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLLineEditor* password_edit(getChild<LLLineEditor>("password_edit")); password_edit->setKeystrokeCallback(onPassKey, this); // STEAM-14: When user presses Enter with this field in focus, initiate login - password_edit->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + password_edit->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, false)); // change z sort of clickable text to be behind buttons sendChildToBack(getChildView("forgot_password_text")); @@ -265,7 +265,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, { LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); updateLocationSelectorsVisibility(); // separate so that it can be called from preferences - favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, false)); favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo"); @@ -458,6 +458,9 @@ void LLPanelLogin::addFavoritesToStartLocation() if (combo->getValue().asString().empty()) { combo->selectFirstItem(); + // Value 'home' or 'last' should have been taken from NextLoginLocation + // but NextLoginLocation was not set, so init it from combo explicitly + onLocationSLURL(); } } @@ -1004,12 +1007,15 @@ void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev // Protected methods //--------------------------------------------------------------------------- // static -void LLPanelLogin::onClickConnect(void *) +void LLPanelLogin::onClickConnect(bool commit_fields) { if (sInstance && sInstance->mCallback) { - // JC - Make sure the fields all get committed. - sInstance->setFocus(FALSE); + if (commit_fields) + { + // JC - Make sure the fields all get committed. + sInstance->setFocus(FALSE); + } LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo"); LLSD combo_val = combo->getSelectedValue(); @@ -1132,7 +1138,7 @@ void LLPanelLogin::onUserListCommit(void*) } else { - onClickConnect(NULL); + onClickConnect(); } } } @@ -1364,6 +1370,7 @@ void LLPanelLogin::onSelectServer() { // the grid specified by the location is not this one, so clear the combo location_combo->setCurrentByIndex(0); // last location on the new grid + onLocationSLURL(); } } break; diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 788c269ffd..c5e6b41def 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -99,7 +99,7 @@ private: static void setFields(LLPointer<LLCredential> credential); - static void onClickConnect(void*); + static void onClickConnect(bool commit_fields = true); static void onClickNewAccount(void*); static void onClickVersion(void*); static void onClickForgotPassword(void*); diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp index 4762e15d8f..8294977f99 100644 --- a/indra/newview/llpanelpicks.cpp +++ b/indra/newview/llpanelpicks.cpp @@ -483,19 +483,7 @@ void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) mNoClassifieds = !mClassifiedsList->size(); } - bool no_data = mNoPicks && mNoClassifieds; - mNoItemsLabel->setVisible(no_data); - if (no_data) - { - if(getAvatarId() == gAgentID) - { - mNoItemsLabel->setValue(LLTrans::getString("NoPicksClassifiedsText")); - } - else - { - mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksClassifiedsText")); - } - } + updateNoItemsLabel(); } LLPickItem* LLPanelPicks::getSelectedPickItem() @@ -724,6 +712,13 @@ bool LLPanelPicks::callbackDeletePick(const LLSD& notification, const LLSD& resp { LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_value[PICK_ID]); mPicksList->removeItemByValue(pick_value); + + mNoPicks = !mPicksList->size(); + if (mNoPicks) + { + showAccordion("tab_picks", false); + } + updateNoItemsLabel(); } updateButtons(); return false; @@ -738,6 +733,13 @@ bool LLPanelPicks::callbackDeleteClassified(const LLSD& notification, const LLSD { LLAvatarPropertiesProcessor::instance().sendClassifiedDelete(value[CLASSIFIED_ID]); mClassifiedsList->removeItemByValue(value); + + mNoClassifieds = !mClassifiedsList->size(); + if (mNoClassifieds) + { + showAccordion("tab_classifieds", false); + } + updateNoItemsLabel(); } updateButtons(); return false; @@ -851,6 +853,23 @@ void LLPanelPicks::updateButtons() } } +void LLPanelPicks::updateNoItemsLabel() +{ + bool no_data = mNoPicks && mNoClassifieds; + mNoItemsLabel->setVisible(no_data); + if (no_data) + { + if (getAvatarId() == gAgentID) + { + mNoItemsLabel->setValue(LLTrans::getString("NoPicksClassifiedsText")); + } + else + { + mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksClassifiedsText")); + } + } +} + void LLPanelPicks::setProfilePanel(LLPanelProfile* profile_panel) { mProfilePanel = profile_panel; diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h index 3bb7413ac3..fd7688b99d 100644 --- a/indra/newview/llpanelpicks.h +++ b/indra/newview/llpanelpicks.h @@ -87,6 +87,7 @@ public: protected: /*virtual*/void updateButtons(); + void updateNoItemsLabel(); private: void onClickDelete(); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 4c539ded38..f13910cde5 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -636,14 +636,17 @@ bool LLScriptEdCore::writeToFile(const std::string& filename) void LLScriptEdCore::sync() { - // Sync with external editor. - std::string tmp_file = mContainer->getTmpFileName(); - llstat s; - if (LLFile::stat(tmp_file, &s) == 0) // file exists - { - if (mLiveFile) mLiveFile->ignoreNextUpdate(); - writeToFile(tmp_file); - } + // Sync with external editor. + if (mLiveFile) + { + std::string tmp_file = mLiveFile->filename(); + llstat s; + if (LLFile::stat(tmp_file, &s) == 0) // file exists + { + mLiveFile->ignoreNextUpdate(); + writeToFile(tmp_file); + } + } } bool LLScriptEdCore::hasChanged() @@ -1027,9 +1030,25 @@ void LLScriptEdCore::openInExternalEditor() { delete mLiveFile; // deletes file - // Save the script to a temporary file. - std::string filename = mContainer->getTmpFileName(); - writeToFile(filename); + // Generate a suitable filename + std::string script_name = mScriptName; + std::string forbidden_chars = "<>:\"\\/|?*"; + for (std::string::iterator c = forbidden_chars.begin(); c != forbidden_chars.end(); c++) + { + script_name.erase(std::remove(script_name.begin(), script_name.end(), *c), script_name.end()); + } + std::string filename = mContainer->getTmpFileName(script_name); + + // Save the script to a temporary file. + if (!writeToFile(filename)) + { + // In case some characters from script name are forbidden + // and not accounted for, name is too long or some other issue, + // try file that doesn't include script name + script_name.clear(); + filename = mContainer->getTmpFileName(script_name); + writeToFile(filename); + } // Start watching file changes. mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdContainer::onExternalChange, mContainer, _1)); @@ -1419,7 +1438,7 @@ LLScriptEdContainer::LLScriptEdContainer(const LLSD& key) : { } -std::string LLScriptEdContainer::getTmpFileName() +std::string LLScriptEdContainer::getTmpFileName(const std::string& script_name) { // Take script inventory item id (within the object inventory) // to consideration so that it's possible to edit multiple scripts @@ -1431,7 +1450,14 @@ std::string LLScriptEdContainer::getTmpFileName() LLMD5 script_id_hash((const U8 *)script_id.c_str()); script_id_hash.hex_digest(script_id_hash_str); - return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl"; + if (script_name.empty()) + { + return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl"; + } + else + { + return std::string(LLFile::tmpdir()) + "sl_script_" + script_name + "_" + script_id_hash_str + ".lsl"; + } } bool LLScriptEdContainer::onExternalChange(const std::string& filename) diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index 3cf22a0e6e..c1fea31063 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -205,7 +205,7 @@ public: LLScriptEdContainer(const LLSD& key, const bool live); protected: - std::string getTmpFileName(); + std::string getTmpFileName(const std::string& script_name); bool onExternalChange(const std::string& filename); virtual void saveIfNeeded(bool sync = true) = 0; diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index f325315933..e02b21f036 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -131,7 +131,12 @@ void LLSkinningUtil::initSkinningMatrixPalette( initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar); for (U32 j = 0; j < count; ++j) { - LLJoint *joint = avatar->getJoint(skin->mJointNums[j]); + S32 joint_num = skin->mJointNums[j]; + LLJoint *joint = NULL; + if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS) + { + joint = avatar->getJoint(joint_num); + } llassert(joint); if (joint) { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index af0421b4c5..83974b5ae4 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1821,9 +1821,6 @@ bool idle_startup() display_startup(); - //all categories loaded. lets create "My Favorites" category - gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); - // set up callbacks LL_INFOS() << "Registering Callbacks" << LL_ENDL; LLMessageSystem* msg = gMessageSystem; diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp index 8a5704939a..658ab453d2 100644 --- a/indra/newview/llteleporthistorystorage.cpp +++ b/indra/newview/llteleporthistorystorage.cpp @@ -201,6 +201,12 @@ void LLTeleportHistoryStorage::load() std::string line; while (std::getline(file, line)) { + if (line.empty()) + { + LL_WARNS() << "Teleport history contains empty line."<< LL_ENDL; + continue; + } + LLSD s_item; std::istringstream iss(line); if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 322d0bc727..75a5fabdc2 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -1234,7 +1234,8 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l BOOL LLToolPie::handleToolTip(S32 local_x, S32 local_y, MASK mask) { - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("ShowHoverTips")) return TRUE; + static LLCachedControl<bool> show_hover_tips(*LLUI::getInstance()->mSettingGroups["config"], "ShowHoverTips", true); + if (!show_hover_tips) return TRUE; if (!mHoverPick.isValid()) return TRUE; LLViewerObject* hover_object = mHoverPick.getObject(); diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index fa3b44f702..553a3cd086 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -144,6 +144,7 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std:: httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); httpOpts->setFollowRedirects(true); + httpOpts->setSSLVerifyPeer(false); std::string url = this->getKeyVerificationURL(key); if (url.empty()) @@ -185,6 +186,7 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); + httpOpts->setSSLVerifyPeer(false); std::string url = this->getTranslateURL(fromTo.first, fromTo.second, msg); if (url.empty()) diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index 7842d24279..acb9e27c55 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -115,6 +115,7 @@ LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager * mCountSucceeded(0), mTotalBytesFetched(0) { + LLCoprocedureManager::instance().initializePool(VIEWER_ASSET_STORAGE_CORO_POOL); } @@ -128,6 +129,7 @@ LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager * mCountSucceeded(0), mTotalBytesFetched(0) { + LLCoprocedureManager::instance().initializePool(VIEWER_ASSET_STORAGE_CORO_POOL); } LLViewerAssetStorage::~LLViewerAssetStorage() diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index d314b1477a..575410eb32 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1501,10 +1501,9 @@ void render_ui_2d() if (gSavedSettings.getBOOL("RenderUIBuffer")) { - LLUI* ui_inst = LLUI::getInstance(); - if (ui_inst->mDirty) + if (LLView::sIsRectDirty) { - ui_inst->mDirty = FALSE; + LLView::sIsRectDirty = false; LLRect t_rect; gPipeline.mUIScreen.bindTarget(); @@ -1512,25 +1511,25 @@ void render_ui_2d() { static const S32 pad = 8; - ui_inst->mDirtyRect.mLeft -= pad; - ui_inst->mDirtyRect.mRight += pad; - ui_inst->mDirtyRect.mBottom -= pad; - ui_inst->mDirtyRect.mTop += pad; + LLView::sDirtyRect.mLeft -= pad; + LLView::sDirtyRect.mRight += pad; + LLView::sDirtyRect.mBottom -= pad; + LLView::sDirtyRect.mTop += pad; LLGLEnable scissor(GL_SCISSOR_TEST); - static LLRect last_rect = ui_inst->mDirtyRect; + static LLRect last_rect = LLView::sDirtyRect; //union with last rect to avoid mouse poop - last_rect.unionWith(ui_inst->mDirtyRect); + last_rect.unionWith(LLView::sDirtyRect); - t_rect = ui_inst->mDirtyRect; - ui_inst->mDirtyRect = last_rect; + t_rect = LLView::sDirtyRect; + LLView::sDirtyRect = last_rect; last_rect = t_rect; - - last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / ui_inst->getScaleFactor().mV[0]); - last_rect.mRight = LLRect::tCoordType(last_rect.mRight / ui_inst->getScaleFactor().mV[0]); - last_rect.mTop = LLRect::tCoordType(last_rect.mTop / ui_inst->getScaleFactor().mV[1]); - last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / ui_inst->getScaleFactor().mV[1]); + + last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::getScaleFactor().mV[0]); + last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::getScaleFactor().mV[0]); + last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::getScaleFactor().mV[1]); + last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::getScaleFactor().mV[1]); LLRect clip_rect(last_rect); @@ -1542,7 +1541,7 @@ void render_ui_2d() gPipeline.mUIScreen.flush(); gGL.setColorMask(true, false); - ui_inst->mDirtyRect = t_rect; + LLView::sDirtyRect = t_rect; } LLGLDisable cull(GL_CULL_FACE); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 9ed2df2759..73d0a83a0d 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1237,6 +1237,7 @@ void LLViewerMedia::getOpenIDCookieCoro(std::string url) httpOpts->setFollowRedirects(true); httpOpts->setWantHeaders(true); + httpOpts->setSSLVerifyPeer(false); // viewer's cert bundle doesn't appear to agree with web certs from "https://my.secondlife.com/" LLURL hostUrl(url.c_str()); std::string hostAuth = hostUrl.getAuthority(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 9d05f59b09..c9cca411f3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -286,6 +286,8 @@ void force_error_bad_memory_access(void *); void force_error_infinite_loop(void *); void force_error_software_exception(void *); void force_error_driver_crash(void *); +void force_error_coroutine_crash(void *); +void force_error_thread_crash(void *); void handle_force_delete(void*); void print_object_info(void*); @@ -2363,6 +2365,24 @@ class LLAdvancedForceErrorDriverCrash : public view_listener_t } }; +class LLAdvancedForceErrorCoroutineCrash : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_coroutine_crash(NULL); + return true; + } +}; + +class LLAdvancedForceErrorThreadCrash : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_thread_crash(NULL); + return true; + } +}; + class LLAdvancedForceErrorDisconnectViewer : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -4108,25 +4128,31 @@ void near_sit_down_point(BOOL success, void *) class LLLandSit : public view_listener_t { - bool handleEvent(const LLSD& userdata) - { - gAgent.standUp(); - LLViewerParcelMgr::getInstance()->deselectLand(); + bool handleEvent(const LLSD& userdata) + { + LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal; - LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal; - - LLQuaternion target_rot; - if (isAgentAvatarValid()) - { - target_rot = gAgentAvatarp->getRotation(); - } - else - { - target_rot = gAgent.getFrameAgent().getQuaternion(); - } - gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f); - return true; - } + LLQuaternion target_rot; + if (isAgentAvatarValid()) + { + target_rot = gAgentAvatarp->getRotation(); + } + else + { + target_rot = gAgent.getFrameAgent().getQuaternion(); + } + gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f); + return true; + } +}; + +class LLLandCanSit : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal; + return !posGlobal.isExactlyZero(); // valid position, not beyond draw distance + } }; //------------------------------------------------------------------- @@ -8041,6 +8067,16 @@ void force_error_driver_crash(void *) LLAppViewer::instance()->forceErrorDriverCrash(); } +void force_error_coroutine_crash(void *) +{ + LLAppViewer::instance()->forceErrorCoroutineCrash(); +} + +void force_error_thread_crash(void *) +{ + LLAppViewer::instance()->forceErrorThreadCrash(); +} + class LLToolsUseSelectionForGrid : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -9207,6 +9243,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); // Advanced (toplevel) @@ -9341,6 +9379,7 @@ void initialize_menus() // Land pie menu view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); + view_listener_t::addMenu(new LLLandCanSit(), "Land.CanSit"); view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 2fde4fe49c..7628a6c7ef 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -82,6 +82,8 @@ #include "llcallstack.h" #include "llsettingsdaycycle.h" +#include <boost/regex.hpp> + #ifdef LL_WINDOWS #pragma warning(disable:4355) #endif @@ -143,15 +145,22 @@ public: // build a secondlife://{PLACE} SLurl from this SLapp std::string url = "secondlife://"; + boost::regex name_rx("[A-Za-z0-9()_%]+"); + boost::regex coord_rx("[0-9]+"); for (int i = 0; i < num_params; i++) { if (i > 0) { url += "/"; } + if (!boost::regex_match(params[i].asString(), i > 0 ? coord_rx : name_rx)) + { + return false; + } + url += params[i].asString(); } - + // Process the SLapp as if it was a secondlife://{PLACE} SLurl LLURLDispatcher::dispatch(url, "clicked", web, true); return true; @@ -2241,7 +2250,7 @@ void LLViewerRegion::setSimulatorFeaturesReceived(bool received) mSimulatorFeaturesReceived = received; if (received) { - mSimulatorFeaturesReceivedSignal(getRegionID()); + mSimulatorFeaturesReceivedSignal(getRegionID(), this); mSimulatorFeaturesReceivedSignal.disconnect_all_slots(); } } @@ -3183,7 +3192,7 @@ void LLViewerRegion::setCapabilitiesReceived(bool received) // so that they can safely use getCapability(). if (received) { - mCapabilitiesReceivedSignal(getRegionID()); + mCapabilitiesReceivedSignal(getRegionID(), this); LLFloaterPermsDefault::sendInitialPerms(); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index dfd8c64f76..fcbf56c81f 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -94,7 +94,7 @@ public: NUM_PARTITIONS } eObjectPartitions; - typedef boost::signals2::signal<void(const LLUUID& region_id)> caps_received_signal_t; + typedef boost::signals2::signal<void(const LLUUID& region_id, LLViewerRegion* regionp)> caps_received_signal_t; LLViewerRegion(const U64 &handle, const LLHost &host, diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 0f96a0b06c..43e77e0b08 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2584,7 +2584,7 @@ void LLViewerWindow::draw() if (!gSavedSettings.getBOOL("RenderUIBuffer")) { - LLUI::getInstance()->mDirtyRect = getWindowRectScaled(); + LLView::sDirtyRect = getWindowRectScaled(); } // HACK for timecode debugging diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index f69b9b3861..e085a945a8 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -10584,7 +10584,8 @@ void LLVOAvatar::accountRenderComplexityForObject( LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID() << " total: " << attachment_total_cost << ", volume: " << attachment_volume_cost - << ", textures: " << attachment_texture_cost + << ", " << textures.size() + << " textures: " << attachment_texture_cost << ", " << volume->numChildren() << " children: " << attachment_children_cost << LL_ENDL; @@ -10684,10 +10685,23 @@ void LLVOAvatar::calculateUpdateRenderComplexity() ETextureIndex tex_index = baked_dict->mTextureIndex; if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT))) { - if (isTextureVisible(tex_index)) - { - cost +=COMPLEXITY_BODY_PART_COST; - } + // Same as isTextureVisible(), but doesn't account for isSelf to ensure identical numbers for all avatars + if (isIndexLocalTexture(tex_index)) + { + if (isTextureDefined(tex_index, 0)) + { + cost += COMPLEXITY_BODY_PART_COST; + } + } + else + { + // baked textures can use TE images directly + if (isTextureDefined(tex_index) + && (getTEImage(tex_index)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha)) + { + cost += COMPLEXITY_BODY_PART_COST; + } + } } } LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL; @@ -10728,8 +10742,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() // Diagnostic output to identify all avatar-related textures. // Does not affect rendering cost calculation. - // Could be wrapped in a debug option if output becomes problematic. - if (isSelf()) + if (isSelf() && debugLoggingEnabled("ARCdetail")) { // print any attachment textures we didn't already know about. for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 689eeee0e3..5ebc65405f 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -44,6 +44,9 @@ F32 LLVOCacheEntry::sFrontPixelThreshold = 1.0f; F32 LLVOCacheEntry::sRearPixelThreshold = 1.0f; BOOL LLVOCachePartition::sNeedsOcclusionCheck = FALSE; +const S32 ENTRY_HEADER_SIZE = 6 * sizeof(S32); +const S32 MAX_ENTRY_BODY_SIZE = 10000; + BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) { return apr_file->read(src, n_bytes) == n_bytes ; @@ -111,32 +114,22 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) { S32 size = -1; BOOL success; + static U8 data_buffer[ENTRY_HEADER_SIZE]; mDP.assignBuffer(mBuffer, 0); - - success = check_read(apr_file, &mLocalID, sizeof(U32)); - if(success) - { - success = check_read(apr_file, &mCRC, sizeof(U32)); - } - if(success) - { - success = check_read(apr_file, &mHitCount, sizeof(S32)); - } - if(success) - { - success = check_read(apr_file, &mDupeCount, sizeof(S32)); - } - if(success) - { - success = check_read(apr_file, &mCRCChangeCount, sizeof(S32)); - } - if(success) - { - success = check_read(apr_file, &size, sizeof(S32)); + + success = check_read(apr_file, (void *)data_buffer, ENTRY_HEADER_SIZE); + if (success) + { + memcpy(&mLocalID, data_buffer, sizeof(U32)); + memcpy(&mCRC, data_buffer + sizeof(U32), sizeof(U32)); + memcpy(&mHitCount, data_buffer + (2 * sizeof(U32)), sizeof(S32)); + memcpy(&mDupeCount, data_buffer + (3 * sizeof(U32)), sizeof(S32)); + memcpy(&mCRCChangeCount, data_buffer + (4 * sizeof(U32)), sizeof(S32)); + memcpy(&size, data_buffer + (5 * sizeof(U32)), sizeof(S32)); // Corruption in the cache entries - if ((size > 10000) || (size < 1)) + if ((size > MAX_ENTRY_BODY_SIZE) || (size < 1)) { // We've got a bogus size, skip reading it. // We won't bother seeking, because the rest of this file @@ -345,26 +338,25 @@ void LLVOCacheEntry::dump() const << LL_ENDL; } -BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const +S32 LLVOCacheEntry::writeToBuffer(U8 *data_buffer) const { - static const S32 data_buffer_size = 6 * sizeof(S32); - static U8 data_buffer[data_buffer_size]; S32 size = mDP.getBufferSize(); + if (size > MAX_ENTRY_BODY_SIZE) + { + LL_WARNS() << "Failed to write entry with size above allowed limit: " << size << LL_ENDL; + return 0; + } + memcpy(data_buffer, &mLocalID, sizeof(U32)); memcpy(data_buffer + sizeof(U32), &mCRC, sizeof(U32)); memcpy(data_buffer + (2 * sizeof(U32)), &mHitCount, sizeof(S32)); memcpy(data_buffer + (3 * sizeof(U32)), &mDupeCount, sizeof(S32)); memcpy(data_buffer + (4 * sizeof(U32)), &mCRCChangeCount, sizeof(S32)); memcpy(data_buffer + (5 * sizeof(U32)), &size, sizeof(S32)); + memcpy(data_buffer + ENTRY_HEADER_SIZE, (void*)mBuffer, size); - BOOL success = check_write(apr_file, (void*)data_buffer, data_buffer_size); - if (success) - { - success = check_write(apr_file, (void*)mBuffer, size); - } - - return success; + return ENTRY_HEADER_SIZE + size; } //static @@ -1393,11 +1385,11 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca bool success = true ; { std::string filename; + LLUUID cache_id; getObjectCacheFilename(handle, filename); LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); - LLUUID cache_id ; - success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ; + success = check_read(&apr_file, cache_id.mData, UUID_BYTES); if(success) { @@ -1409,7 +1401,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca if(success) { - S32 num_entries; + S32 num_entries; // if removal was enabled during write num_entries might be wrong success = check_read(&apr_file, &num_entries, sizeof(S32)) ; if(success) @@ -1516,28 +1508,57 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { std::string filename; getObjectCacheFilename(handle, filename); - LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY|APR_TRUNCATE, mLocalAPRFilePoolp); - success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ; - + success = check_write(&apr_file, (void*)id.mData, UUID_BYTES); if(success) { - S32 num_entries = cache_entry_map.size() ; + S32 num_entries = cache_entry_map.size(); // if removal is enabled num_entries might be wrong success = check_write(&apr_file, &num_entries, sizeof(S32)); - - // This can have a lot of entries, so might be better to dump them into buffer first and write in one go. - for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter) - { - if(!removal_enabled || iter->second->isValid()) - { - success = iter->second->writeToFile(&apr_file) ; - if(!success) - { - break; - } - } - } + if (success) + { + const S32 buffer_size = 32768; //should be large enough for couple MAX_ENTRY_BODY_SIZE + U8 data_buffer[buffer_size]; // generaly entries are fairly small, so collect them and drop onto disk in one go + S32 size_in_buffer = 0; + + // This can have a lot of entries, so might be better to dump them into buffer first and write in one go. + for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter) + { + if (!removal_enabled || iter->second->isValid()) + { + S32 size = iter->second->writeToBuffer(data_buffer + size_in_buffer); + + if (size > ENTRY_HEADER_SIZE) // body is minimum of 1 + { + size_in_buffer += size; + } + else + { + success = false; + break; + } + + // Make sure we have space in buffer for next element + if (buffer_size - size_in_buffer < MAX_ENTRY_BODY_SIZE + ENTRY_HEADER_SIZE) + { + success = check_write(&apr_file, (void*)data_buffer, size_in_buffer); + size_in_buffer = 0; + if (!success) + { + break; + } + } + } + } + + if (success && size_in_buffer > 0) + { + // final write + success = check_write(&apr_file, (void*)data_buffer, size_in_buffer); + size_in_buffer = 0; + } + } } } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 6c95541c11..dd6afd6b85 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -106,7 +106,7 @@ public: F32 getSceneContribution() const { return mSceneContrib;} void dump() const; - BOOL writeToFile(LLAPRFile* apr_file) const; + S32 writeToBuffer(U8 *data_buffer) const; LLDataPackerBinaryBuffer *getDP(); void recordHit(); void recordDupe() { mDupeCount++; } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 2d1a882a7e..aa03b6f44f 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3755,7 +3755,25 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const { if (textures.find(img->getID()) == textures.end()) { - S32 texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (img->getFullHeight() / 128.f + img->getFullWidth() / 128.f)); + S32 texture_cost = 0; + S8 type = img->getType(); + if (type == LLViewerTexture::FETCHED_TEXTURE || type == LLViewerTexture::LOD_TEXTURE) + { + const LLViewerFetchedTexture* fetched_texturep = static_cast<const LLViewerFetchedTexture*>(img); + if (fetched_texturep + && fetched_texturep->getFTType() == FTT_LOCAL_FILE + && (img->getID() == IMG_ALPHA_GRAD_2D || img->getID() == IMG_ALPHA_GRAD) + ) + { + // These two textures appear to switch between each other, but are of different sizes (4x256 and 256x256). + // Hardcode cost from larger one to not cause random complexity changes + texture_cost = 320; + } + } + if (texture_cost == 0) + { + texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (img->getFullHeight() / 128.f + img->getFullWidth() / 128.f)); + } textures.insert(texture_cost_t::value_type(img->getID(), texture_cost)); } } @@ -5218,8 +5236,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) U32 useage = group->getSpatialPartition()->mBufferUsage; - LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); - LLCachedControl<S32> max_node_size(gSavedSettings, "RenderMaxNodeSize", 65536); + static LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); + static LLCachedControl<S32> max_node_size(gSavedSettings, "RenderMaxNodeSize", 65536); U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); U32 max_total = (max_node_size * 1024) / LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); @@ -5985,7 +6003,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace #endif //calculate maximum number of vertices to store in a single buffer - LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); + static LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 63257d6543..d019b400e8 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -237,7 +237,7 @@ bool LLWeb::useExternalBrowser(const std::string &url) up.extractParts(); std::string uri_string = up.host(); - boost::regex pattern = boost::regex("\\b(lindenlab.com|secondlife.com)$", boost::regex::perl|boost::regex::icase); + boost::regex pattern = boost::regex("\\b(lindenlab.com|secondlife.com|secondlife.io)$", boost::regex::perl|boost::regex::icase); boost::match_results<std::string::const_iterator> matches; return !(boost::regex_search(uri_string, matches, pattern)); } diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 569f479a16..ff899fe895 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -113,6 +113,7 @@ void LLWebProfile::uploadImageCoro(LLPointer<LLImageFormatted> image, std::strin httpOpts->setWantHeaders(true); httpOpts->setFollowRedirects(false); + httpOpts->setSSLVerifyPeer(false); ; // viewer's cert bundle doesn't appear to agree with web certs from "https://my.secondlife.com/" // Get upload configuration data. std::string configUrl(getProfileURL(std::string()) + "snapshots/s3_upload_config"); diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index 730aa3774f..d55e1b7cd3 100644 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -51,7 +51,7 @@ bool LLEnvironmentRequest::initiate(LLEnvironment::environment_apply_fn cb) if (!cur_region->capabilitiesReceived()) { LL_INFOS("WindlightCaps") << "Deferring windlight settings request until we've got region caps" << LL_ENDL; - cur_region->setCapabilitiesReceivedCallback([cb](const LLUUID ®ion_id) { LLEnvironmentRequest::onRegionCapsReceived(region_id, cb); }); + cur_region->setCapabilitiesReceivedCallback([cb](const LLUUID ®ion_id, LLViewerRegion* regionp) { LLEnvironmentRequest::onRegionCapsReceived(region_id, cb); }); return false; } diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index e282f1b179..306a0876fc 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -626,23 +626,6 @@ top_delta="16" width="300" /> - <!-- SL-12594, basic shaders always enabled, no fixed-function GL - <check_box - control_name="VertexShaderEnable" - height="16" - initial_value="true" - label="Basic shaders" - layout="topleft" - left="420" - name="BasicShaders" - tool_tip="Disabling this option may prevent some graphics card drivers from crashing" - top_delta="16" - width="300"> - <check_box.commit_callback - function="Pref.VertexShaderEnable" /> - </check_box> - --> - <slider control_name="RenderTerrainDetail" follows="left|top" diff --git a/indra/newview/skins/default/xui/en/floater_url_entry.xml b/indra/newview/skins/default/xui/en/floater_url_entry.xml index 29fb29fabf..2dfc0fd125 100644 --- a/indra/newview/skins/default/xui/en/floater_url_entry.xml +++ b/indra/newview/skins/default/xui/en/floater_url_entry.xml @@ -66,7 +66,7 @@ layout="topleft" left="152" name="loading_label" - visible="true"> + visible="false"> Loading... </text> </floater> diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index eda9739976..5a35bbf121 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -152,6 +152,14 @@ parameter="category" /> </menu_item_call> <menu_item_call + label="New Outfit" + layout="topleft" + name="New Outfit"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="outfit" /> + </menu_item_call> + <menu_item_call label="New Script" layout="topleft" name="New Script"> diff --git a/indra/newview/skins/default/xui/en/menu_land.xml b/indra/newview/skins/default/xui/en/menu_land.xml index 2ad5cbbe95..1ce0d65b3e 100644 --- a/indra/newview/skins/default/xui/en/menu_land.xml +++ b/indra/newview/skins/default/xui/en/menu_land.xml @@ -18,6 +18,8 @@ <menu_item_call label="Sit Here" name="Sit Here"> + <menu_item_call.on_enable + function="Land.CanSit" /> <menu_item_call.on_click function="Land.Sit" /> </menu_item_call> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 0a50ff089f..ceea960e7c 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2442,6 +2442,18 @@ function="World.EnvPreset" function="Advanced.ForceErrorSoftwareException" /> </menu_item_call> <menu_item_call + label="Force a Crash in a Coroutine" + name="Force a Crash in a Coroutine"> + <menu_item_call.on_click + function="Advanced.ForceErrorCoroutineCrash" /> + </menu_item_call> + <menu_item_call + label="Force a Crash in a Thread" + name="Force a Crash in a Thread"> + <menu_item_call.on_click + function="Advanced.ForceErrorThreadCrash" /> + </menu_item_call> + <menu_item_call label="Force Disconnect Viewer" name="Force Disconnect Viewer"> <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index a1c73d12d0..be217aff51 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -10013,6 +10013,15 @@ Removal of the object <nolink>'[OBJ_NAME]'</nolink> from the simulat Cannot save your selection because you do not have permission to modify the object <nolink>'[OBJ_NAME]'</nolink>. </notification> + + <notification + icon="alertmodal.tga" + name="NoTransNoSaveToContents" + type="notify"> + <tag>fail</tag> + Cannot save <nolink>'[OBJ_NAME]'</nolink> to object contents because you do not have permission to transfer the object's ownership. + </notification> + <notification icon="alertmodal.tga" name="NoCopyNoSaveSelection" diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml index ada980cda1..9023d68ea9 100644 --- a/indra/newview/skins/default/xui/en/panel_status_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml @@ -35,7 +35,7 @@ </panel.string> <panel height="18" - left="-458" + left="-398" top="0" width="120" follows="right|top" @@ -75,7 +75,7 @@ </panel> <panel height="18" - left="-458" + left="-398" width="185" top="1" follows="right|top" @@ -142,7 +142,7 @@ left_pad="0" name="TimeText" tool_tip="Current time (Pacific)" - width="145"> + width="85"> 24:00 AM PST </text> <icon diff --git a/indra/newview/tests/cppfeatures_test.cpp b/indra/newview/tests/cppfeatures_test.cpp new file mode 100644 index 0000000000..923bb1e1b2 --- /dev/null +++ b/indra/newview/tests/cppfeatures_test.cpp @@ -0,0 +1,386 @@ +/** + * @file cppfeatures_test + * @author Vir + * @date 2021-03 + * @brief cpp features + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, 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$ + */ + +// Tests related to newer C++ features, for verifying support across compilers and platforms + +#include "linden_common.h" +#include "../test/lltut.h" + +namespace tut +{ + +struct cpp_features_test {}; +typedef test_group<cpp_features_test> cpp_features_test_t; +typedef cpp_features_test_t::object cpp_features_test_object_t; +tut::cpp_features_test_t tut_cpp_features_test("LLCPPFeatures"); + +// bracket initializers +// Can initialize containers or values using curly brackets +template<> template<> +void cpp_features_test_object_t::test<1>() +{ + S32 explicit_val{3}; + ensure(explicit_val==3); + + S32 default_val{}; + ensure(default_val==0); + + std::vector<S32> fibs{1,1,2,3,5}; + ensure(fibs[4]==5); +} + +// auto +// +// https://en.cppreference.com/w/cpp/language/auto +// +// Can use auto in place of a more complex type specification, if the compiler can infer the type +template<> template<> +void cpp_features_test_object_t::test<2>() +{ + std::vector<S32> numbers{3,6,9}; + + // auto element + auto& aval = numbers[1]; + ensure("auto element", aval==6); + + // auto iterator (non-const) + auto it = numbers.rbegin(); + *it += 1; + S32 val = *it; + ensure("auto iterator", val==10); +} + +// range for +// +// https://en.cppreference.com/w/cpp/language/range-for +// +// Can iterate over containers without explicit iterator +template<> template<> +void cpp_features_test_object_t::test<3>() +{ + + // Traditional iterator for with container + // + // Problems: + // * Have to create a new variable for the iterator, which is unrelated to the problem you're trying to solve. + // * Redundant and somewhat fragile. Have to make sure begin() and end() are both from the right container. + std::vector<S32> numbers{3,6,9}; + for (auto it = numbers.begin(); it != numbers.end(); ++it) + { + auto& n = *it; + n *= 2; + } + ensure("iterator for vector", numbers[2]==18); + + // Range for with container + // + // Under the hood, this is doing the same thing as the traditional + // for loop above. Still uses begin() and end() but you don't have + // to access them directly. + std::vector<S32> numbersb{3,6,9}; + for (auto& n: numbersb) + { + n *= 2; + } + ensure("range for vector", numbersb[2]==18); + + // Range for over a C-style array. + // + // This is handy because the language determines the range automatically. + // Getting this right manually is a little trickier. + S32 pows[] = {1,2,4,8,16}; + S32 sum{}; + for (const auto& v: pows) + { + sum += v; + } + ensure("for C-array", sum==31); +} + +// override specifier +// +// https://en.cppreference.com/w/cpp/language/override +// +// Specify that a particular class function is an override of a virtual function. +// Benefits: +// * Makes code somewhat easier to read by showing intent. +// * Prevents mistakes where you think something is an override but it doesn't actually match the declaration in the parent class. +// Drawbacks: +// * Some compilers require that any class using override must use it consistently for all functions. +// This makes switching a class to use override a lot more work. + +class Foo +{ +public: + virtual bool is_happy() const = 0; +}; + +class Bar: public Foo +{ +public: + bool is_happy() const override { return true; } + // Override would fail: non-const declaration doesn't match parent + // bool is_happy() override { return true; } + // Override would fail: wrong name + // bool is_happx() override { return true; } +}; + +template<> template<> +void cpp_features_test_object_t::test<4>() +{ + Bar b; + ensure("override", b.is_happy()); +} + +// final +// +// https://en.cppreference.com/w/cpp/language/final: "Specifies that a +// virtual function cannot be overridden in a derived class or that a +// class cannot be inherited from." + +class Vehicle +{ +public: + virtual bool has_wheels() const = 0; +}; + +class WheeledVehicle: public Vehicle +{ +public: + virtual bool has_wheels() const final override { return true; } +}; + +class Bicycle: public WheeledVehicle +{ +public: + // Error: can't override final version in WheeledVehicle + // virtual bool has_wheels() override const { return true; } +}; + +template<> template<> +void cpp_features_test_object_t::test<5>() +{ + Bicycle bi; + ensure("final", bi.has_wheels()); +} + +// deleted function declaration +// +// https://en.cppreference.com/w/cpp/language/function#Deleted_functions +// +// Typical case: copy constructor doesn't make sense for a particular class, so you want to make +// sure the no one tries to copy-construct an instance of the class, and that the +// compiler won't generate a copy constructor for you automatically. +// Traditional fix is to declare a +// copy constructor but never implement it, giving you a link-time error if anyone tries to use it. +// Now you can explicitly declare a function to be deleted, which has at least two advantages over +// the old way: +// * Makes the intention clear +// * Creates an error sooner, at compile time + +class DoNotCopy +{ +public: + DoNotCopy() {} + DoNotCopy(const DoNotCopy& ref) = delete; +}; + +template<> template<> +void cpp_features_test_object_t::test<6>() +{ + DoNotCopy nc; // OK, default constructor + //DoNotCopy nc2(nc); // No, can't copy + //DoNotCopy nc3 = nc; // No, this also calls copy constructor (even though it looks like an assignment) +} + +// defaulted function declaration +// +// https://en.cppreference.com/w/cpp/language/function#Function_definition +// +// What about the complementary case to the deleted function declaration, where you want a copy constructor +// and are happy with the default implementation the compiler will make (memberwise copy). +// Now you can explicitly declare that too. +// Usage: I guess it makes the intent clearer, but otherwise not obviously useful. +class DefaultCopyOK +{ +public: + DefaultCopyOK(): mVal(123) {} + DefaultCopyOK(const DefaultCopyOK&) = default; + S32 val() const { return mVal; } +private: + S32 mVal; +}; + +template<> template<> +void cpp_features_test_object_t::test<7>() +{ + DefaultCopyOK d; // OK + DefaultCopyOK d2(d); // OK + DefaultCopyOK d3 = d; // OK + ensure("default copy d", d.val()==123); + ensure("default copy d2", d.val()==d2.val()); + ensure("default copy d3", d.val()==d3.val()); +} + +// initialize class members inline +// +// https://en.cppreference.com/w/cpp/language/data_members#Member_initialization +// +// Default class member values can be set where they are declared, using either brackets or = + +// It is preferred to skip creating a constructor if all the work can be done by inline initialization: +// http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html#c45-dont-define-a-default-constructor-that-only-initializes-data-members-use-in-class-member-initializers-instead +// +class InitInline +{ +public: + S32 mFoo{10}; +}; + +class InitInlineWithConstructor +{ +public: + // Here mFoo is not specified, so you will get the default value of 10. + // mBar is specified, so 25 will override the default value. + InitInlineWithConstructor(): + mBar(25) + {} + + // Default values set using two different styles, same effect. + S32 mFoo{10}; + S32 mBar = 20; +}; + +template<> template<> +void cpp_features_test_object_t::test<8>() +{ + InitInline ii; + ensure("init member inline 1", ii.mFoo==10); + + InitInlineWithConstructor iici; + ensure("init member inline 2", iici.mFoo=10); + ensure("init member inline 3", iici.mBar==25); +} + +// constexpr +// +// https://en.cppreference.com/w/cpp/language/constexpr +// +// Various things can be computed at compile time, and flagged as constexpr. +constexpr S32 compute2() { return 2; } + +constexpr S32 ce_factorial(S32 n) +{ + if (n<=0) + { + return 1; + } + else + { + return n*ce_factorial(n-1); + } +} + +template<> template<> +void cpp_features_test_object_t::test<9>() +{ + S32 val = compute2(); + ensure("constexpr 1", val==2); + + // Compile-time factorial. You used to need complex templates to do something this useless. + S32 fac5 = ce_factorial(5); + ensure("constexpr 2", fac5==120); +} + +// static assert +// +// https://en.cppreference.com/w/cpp/language/static_assert +// +// You can add asserts to be checked at compile time. The thing to be checked must be a constexpr. +// There are two forms: +// * static_assert(expr); +// * static_assert(expr, message); +// +// Currently only the 2-parameter form works on windows. The 1-parameter form needs a flag we don't set. + +template<> template<> +void cpp_features_test_object_t::test<10>() +{ + // static_assert(ce_factorial(6)==720); No, needs a flag we don't currently set. + static_assert(ce_factorial(6)==720, "bad factorial"); // OK +} + +// type aliases +// +// https://en.cppreference.com/w/cpp/language/type_alias +// +// You can use the "using" statement to create simpler templates that +// are aliases for more complex ones. "Template typedef" + +// This makes stringmap<T> an alias for std::map<std::string, T> +template<typename T> +using stringmap = std::map<std::string, T>; + +template<> template<> +void cpp_features_test_object_t::test<11>() +{ + stringmap<S32> name_counts{ {"alice", 3}, {"bob", 2} }; + ensure("type alias", name_counts["bob"]==2); +} + +// Other possibilities: + +// nullptr + +// class enums + +// std::unique_ptr and make_unique + +// std::shared_ptr and make_shared + +// lambdas + +// perfect forwarding + +// variadic templates + +// std::thread + +// std::mutex + +// thread_local + +// rvalue reference && + +// move semantics + +// std::move + +// string_view + +} // namespace tut diff --git a/scripts/metrics/viewerstats.py b/scripts/metrics/viewerstats.py new file mode 100755 index 0000000000..f7be3d967e --- /dev/null +++ b/scripts/metrics/viewerstats.py @@ -0,0 +1,226 @@ +#!runpy.sh + +"""\ + +This module contains code for analyzing ViewerStats data as uploaded by the viewer. + +$LicenseInfo:firstyear=2021&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2021, 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$ +""" + +import argparse +import numpy as np +import pandas as pd +import json +from collections import Counter, defaultdict +from llbase import llsd +import io +import re +import os +import sys + +def show_stats_by_key(recs,indices,settings_sd = None): + result = () + cnt = Counter() + per_key_cnt = defaultdict(Counter) + for r in recs: + try: + d = r + for idx in indices: + d = d[idx] + for k,v in d.items(): + if isinstance(v,dict): + continue + cnt[k] += 1 + if isinstance(v,list): + v = tuple(v) + per_key_cnt[k][v] += 1 + except Exception as e: + print "err", e + print "d", d, "k", k, "v", v + raise + mc = cnt.most_common() + print "=========================" + keyprefix = "" + if len(indices)>0: + keyprefix = ".".join(indices) + "." + for i,m in enumerate(mc): + k = m[0] + bigc = m[1] + unset_cnt = len(recs) - bigc + kmc = per_key_cnt[k].most_common(5) + print i, keyprefix+str(k), bigc + if settings_sd is not None and k in settings_sd and "Value" in settings_sd[k]: + print " ", "default",settings_sd[k]["Value"],"count",unset_cnt + for v in kmc: + print " ", "value",v[0],"count",v[1] + if settings_sd is not None: + print "Total keys in settings", len(settings_sd.keys()) + unused_keys = list(set(settings_sd.keys()) - set(cnt.keys())) + unused_keys_non_str = [k for k in unused_keys if settings_sd[k]["Type"] != "String"] + unused_keys_str = [k for k in unused_keys if settings_sd[k]["Type"] == "String"] + + # Things that no one in the sample has set to a non-default value. Possible candidates for removal. + print "\nUnused_keys_non_str", len(unused_keys_non_str) + print "======================" + print "\n".join(sorted(unused_keys_non_str)) + + # Strings are not currently logged, so we have no info on usage. + print "\nString keys (usage unknown)", len(unused_keys_str) + print "======================" + print "\n".join(sorted(unused_keys_str)) + + # Things that someone has set but that aren't recognized settings. + unrec_keys = list(set(cnt.keys()) - set(settings_sd.keys())) + print "\nUnrecognized keys", len(unrec_keys) + print "======================" + print "\n".join(sorted(unrec_keys)) + + result = (settings_sd.keys(), unused_keys_str, unused_keys_non_str, unrec_keys) + return result + +def parse_settings_xml(fname): + # assume we're in scripts/metrics + fname = "../../indra/newview/app_settings/" + fname + with open(fname,"r") as f: + contents = f.read() + return llsd.parse_xml(contents) + +def read_raw_settings_xml(fname): + # assume we're in scripts/metrics + fname = "../../indra/newview/app_settings/" + fname + contents = None + with open(fname,"r") as f: + contents = f.read() + return contents + +def write_settings_xml(fname, contents): + # assume we're in scripts/metrics + fname = "../../indra/newview/app_settings/" + fname + with open(fname,"w") as f: + f.write(llsd.format_pretty_xml(contents)) + f.close() + +def write_raw_settings_xml(fname, string): + # assume we're in scripts/metrics + fname = "../../indra/newview/app_settings/" + fname + with io.open(fname,"w", newline='\n') as f: + f.write(string.decode('latin1')) + f.close() + +def remove_settings(string, to_remove): + for r in to_remove: + subs_str = r"<key>" + r + r"<.*?</map>\n" + string = re.sub(subs_str,"",string,flags=re.S|re.DOTALL) + return string + +def get_used_strings(root_dir): + used_str = set() + skipped_ext = set() + for dir_name, sub_dir_list, file_list in os.walk(root_dir): + for fname in file_list: + if fname in ["settings.xml", "settings.xml.edit", "settings_per_account.xml"]: + print "skip", fname + continue + (base,ext) = os.path.splitext(fname) + #if ext not in [".cpp", ".hpp", ".h", ".xml"]: + # skipped_ext.add(ext) + # continue + + full_name = os.path.join(dir_name,fname) + + with open(full_name,"r") as f: + #print full_name + lines = f.readlines() + for l in lines: + ms = re.findall(r'[>\"]([A-Za-z0-9_]+)[\"<]',l) + for m in ms: + #print "used_str",m + used_str.add(m) + print "skipped extensions", skipped_ext + print "got used_str", len(used_str) + return used_str + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description="process tab-separated table containing viewerstats logs") + parser.add_argument("--verbose", action="store_true",help="verbose flag") + parser.add_argument("--preferences", action="store_true", help="analyze preference info") + parser.add_argument("--remove_unused", action="store_true", help="remove unused preferences") + parser.add_argument("--column", help="name of column containing viewerstats info") + parser.add_argument("infiles", nargs="+", help="name of .tsv files to process") + args = parser.parse_args() + + for fname in args.infiles: + print "process", fname + df = pd.read_csv(fname,sep='\t') + #print "DF", df.describe() + jstrs = df['RAW_LOG:BODY'] + #print "JSTRS", jstrs.describe() + recs = [] + for i,jstr in enumerate(jstrs): + recs.append(json.loads(jstr)) + show_stats_by_key(recs,[]) + show_stats_by_key(recs,["agent"]) + if args.preferences: + print "\nSETTINGS.XML" + settings_sd = parse_settings_xml("settings.xml") + #for skey,svals in settings_sd.items(): + # print skey, "=>", svals + (all_str,_,_,_) = show_stats_by_key(recs,["preferences","settings"],settings_sd) + print + + #print "\nSETTINGS_PER_ACCOUNT.XML" + #settings_pa_sd = parse_settings_xml("settings_per_account.xml") + #show_stats_by_key(recs,["preferences","settings_per_account"],settings_pa_sd) + + if args.remove_unused: + # walk codebase looking for strings + all_str_set = set(all_str) + used_strings = get_used_strings("../../indra") + used_strings_set = set(used_strings) + unref_strings = all_str_set-used_strings_set + # Some settings names are generated by appending to a prefix. Need to look for this case. + prefix_used = set() + print "checking unref_strings", len(unref_strings) + for u in unref_strings: + for k in range(6,len(u)): + prefix = u[0:k] + if prefix in all_str_set and prefix in used_strings_set: + prefix_used.add(u) + #print "PREFIX_USED",u,prefix + print "PREFIX_USED", len(prefix_used), ",".join(list(prefix_used)) + print + unref_strings = unref_strings - prefix_used + + print "\nUNREF_IN_CODE " + str(len(unref_strings)) + "\n" + print "\n".join(list(unref_strings)) + settings_str = read_raw_settings_xml("settings.xml") + # Do this via direct string munging to generate minimal changeset + settings_edited = remove_settings(settings_str,unref_strings) + write_raw_settings_xml("settings.xml.edit",settings_edited) + + + + + + |