diff options
Diffstat (limited to 'indra/newview')
69 files changed, 1186 insertions, 346 deletions
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/llfloatereditenvironmentbase.cpp b/indra/newview/llfloatereditenvironmentbase.cpp index e888144b6a..2850951668 100644 --- a/indra/newview/llfloatereditenvironmentbase.cpp +++ b/indra/newview/llfloatereditenvironmentbase.cpp @@ -262,7 +262,7 @@ void LLFloaterEditEnvironmentBase::onSaveAsCommit(const LLSD& notification, cons          {              const LLUUID &marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false);              LLUUID parent_id = mInventoryItem->getParentUUID(); -            if (marketplacelistings_id == parent_id) +            if (marketplacelistings_id == parent_id || gInventory.isObjectDescendentOf(mInventoryItem->getUUID(), gInventory.getLibraryRootFolderID()))              {                  parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS);              } 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/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index afa84a5afc..f770db31dd 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -130,7 +130,7 @@ LLViewerFolderDictionary::LLViewerFolderDictionary()  	addEntry(LLFolderType::FT_FAVORITE, 			new ViewerFolderEntry("Favorites",				"Inv_SysOpen",			"Inv_SysClosed",		FALSE,     true));  	addEntry(LLFolderType::FT_CURRENT_OUTFIT, 		new ViewerFolderEntry("Current Outfit",			"Inv_SysOpen",			"Inv_SysClosed",		TRUE,      false)); -	addEntry(LLFolderType::FT_OUTFIT, 				new ViewerFolderEntry("New Outfit",				"Inv_LookFolderOpen",	"Inv_LookFolderClosed",	TRUE,      true)); +	addEntry(LLFolderType::FT_OUTFIT, 				new ViewerFolderEntry("New Outfit",				"Inv_LookFolderOpen",	"Inv_LookFolderClosed",	TRUE,      false));  	addEntry(LLFolderType::FT_MY_OUTFITS, 			new ViewerFolderEntry("My Outfits",				"Inv_SysOpen",			"Inv_SysClosed",		TRUE,      true));  	addEntry(LLFolderType::FT_MESH, 				new ViewerFolderEntry("Meshes",					"Inv_SysOpen",			"Inv_SysClosed",		FALSE,     true));  	addEntry(LLFolderType::FT_SETTINGS, 		    new ViewerFolderEntry("Settings",			    "Inv_SysOpen",			"Inv_SysClosed",		FALSE,     true)); 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  | 
