diff --git a/.hgtags b/.hgtags
index 64e691f1aaf821541790d4b4b563d90c8e6bdcec..216066ea006f1b061079a6b35e715cf35f5233c4 100644
--- a/.hgtags
+++ b/.hgtags
@@ -184,3 +184,6 @@ f2412ecd6740803ea9452f1d17fd872e263a0df7 3.0.2-start
 e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e DRTVWR-86_3.0.2-beta2
 e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e 3.0.2-beta2
 b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start
+6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 DRTVWR-85_3.0.3-beta1
+586907287be581817b2422b5137971b22d54ea48 3.0.4-start
+6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 3.0.3-beta1
diff --git a/autobuild.xml b/autobuild.xml
index e5c6b83037782ddffd1ac14a2c1ec297b188d304..347ef419edd01e53e18d6af551e6705c66b7e5c2 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1206,9 +1206,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>a7c80fd8516df3b879b669b2b220067f</string>
+              <string>9cd66e879908f047d9af665b92946ecc</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/232420/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110608.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/239803/arch/Darwin/installer/llqtwebkit-4.7.1-darwin-20110830.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -1230,9 +1230,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>b9cc0333cc274c9cc40256ab7146b4fc</string>
+              <string>ab9393795515cbbe9526bde33b41bf2a</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/232420/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110608.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llqtwebkit/rev/239670/arch/CYGWIN/installer/llqtwebkit-4.7.1-windows-20110829.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 016aa0064a03977605b6de9494576803768972d1..5930bab04f7f325c816f468fd178bcedebe0a6c2 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -65,11 +65,15 @@ Aimee Trescothick
 Alejandro Rosenthal
 	VWR-1184
 Aleric Inglewood
+	SNOW-84
 	SNOW-240
+	SNOW-477
 	SNOW-522
 	SNOW-626
+	SNOW-744
 	SNOW-756
 	SNOW-764
+	SNOW-766
 	SNOW-800
 	VWR-10001
 	VWR-10579
@@ -95,11 +99,8 @@ Aleric Inglewood
 	VWR-24366
 	VWR-24519
 	VWR-24520
-	SNOW-84
-	SNOW-477
-	SNOW-744
-	SNOW-766
 	STORM-163
+	STORM-864
 	STORM-955
 	STORM-960
 Ales Beaumont
diff --git a/doc/translations.txt b/doc/translations.txt
index c9cfc1cdeb59b9145468f9f4821beff196fe82f2..9b7f2d62922c8e207027a5f3cbdeb788014298ba 100644
--- a/doc/translations.txt
+++ b/doc/translations.txt
@@ -1,7 +1,9 @@
-#List of translators who contribute to SL Viewer 2.0+ and SL web translation by language
+#List of translators who contribute to SL Viewer 2.0+ by language
 
 	Danish
 Flemming Congrejo
+	German
+Torben Trautman
 	French
 Valerie Linden
 	Polish
@@ -21,6 +23,7 @@ Lunita Savira
 Minerva Memel
 Polo Gufler
 Xiki Luik
-Perez Linden
+Shinya Tandino
+Catwise Yoshikawa
 	Traditional Chinese
 gefeit Dufaux
diff --git a/indra/llaudio/llaudioengine_fmod.cpp b/indra/llaudio/llaudioengine_fmod.cpp
index a40de9fa68b21afe656d862642d2b7992a33829f..88dfdb9c2449c5e3d2a88c38e731c3d1a0ffc88b 100644
--- a/indra/llaudio/llaudioengine_fmod.cpp
+++ b/indra/llaudio/llaudioengine_fmod.cpp
@@ -673,7 +673,7 @@ bool LLAudioBufferFMOD::loadWAV(const std::string& filename)
 		return false;
 	}
 
-	if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB))
+	if (!LLAPRFile::isExist(filename, LL_APR_RPB))
 	{
 		// File not found, abort.
 		return false;
diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp
index 0e0c80a45675b6aad361fb49fd563645cf3409d8..44eeea0ca4115730f614c873faefaa503c68dc9a 100644
--- a/indra/llaudio/llvorbisencode.cpp
+++ b/indra/llaudio/llvorbisencode.cpp
@@ -82,8 +82,7 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
 	error_msg.clear();
 
 	//********************************
-	LLAPRFile infile ;
-    infile.open(in_fname,LL_APR_RB);
+	LLAPRFile infile(in_fname, LL_APR_RB);
 	//********************************
 	if (!infile.getFileHandle())
 	{
@@ -233,8 +232,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
 
 	S32 data_left = 0;
 
-	LLAPRFile infile ;
-	infile.open(in_fname,LL_APR_RB);
+	LLAPRFile infile(in_fname,LL_APR_RB);
 	if (!infile.getFileHandle())
 	{
 		llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
@@ -242,8 +240,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
 		return(LLVORBISENC_SOURCE_OPEN_ERR);
 	}
 
-	LLAPRFile outfile ;
-	outfile.open(out_fname,LL_APR_WPB);
+	LLAPRFile outfile(out_fname, LL_APR_WPB);
 	if (!outfile.getFileHandle())
 	{
 		llwarns << "Couldn't open upload sound file for reading: " << in_fname
diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp
index f3cf950afae70deffcafc7a07adabcb4878f415e..c3c7f03247f4b412c9a6f3a8514bb917c2142aeb 100644
--- a/indra/llcharacter/llbvhloader.cpp
+++ b/indra/llcharacter/llbvhloader.cpp
@@ -219,8 +219,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
 	//--------------------------------------------------------------------
 	std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
 
-	LLAPRFile infile ;
-	infile.open(path, LL_APR_R);
+	LLAPRFile infile(path, LL_APR_R);
 	apr_file_t *fp = infile.getFileHandle();
 	if (!fp)
 		return E_ST_NO_XLT_FILE;
diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp
index 82fe8971f5a4183d6e7c2dfc917d74e9c91ffaf0..c3d5dec875414b3a27e2e91b665db28de8456500 100644
--- a/indra/llcharacter/llkeyframemotionparam.cpp
+++ b/indra/llcharacter/llkeyframemotionparam.cpp
@@ -351,8 +351,7 @@ BOOL LLKeyframeMotionParam::loadMotions()
 	// open the file
 	//-------------------------------------------------------------------------
 	S32 fileSize = 0;
-	LLAPRFile infile ;
-	infile.open(path, LL_APR_R, NULL, &fileSize);
+	LLAPRFile infile(path, LL_APR_R, &fileSize);
 	apr_file_t* fp = infile.getFileHandle() ;
 	if (!fp || fileSize == 0)
 	{
diff --git a/indra/llcharacter/llstatemachine.cpp b/indra/llcharacter/llstatemachine.cpp
index e0454131a52e393d6c006a5897815336a0fa20df..dcc4ff5f0e7c2b095984f170b036662cff37a5b8 100644
--- a/indra/llcharacter/llstatemachine.cpp
+++ b/indra/llcharacter/llstatemachine.cpp
@@ -204,8 +204,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
 
 BOOL LLStateDiagram::saveDotFile(const std::string& filename)
 {
-	LLAPRFile outfile ;
-	outfile.open(filename, LL_APR_W);
+	LLAPRFile outfile(filename, LL_APR_W);
 	apr_file_t* dot_file = outfile.getFileHandle() ;
 
 	if (!dot_file)
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 16e2a0e5c8b59f159f94dedb5a14071843a7aea1..60d4cfe6d30e1d0919df89d3b0900f6de4559128 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -31,6 +31,7 @@ set(llcommon_SOURCE_FILES
     llallocator_heap_profile.cpp
     llapp.cpp
     llapr.cpp
+    llaprpool.cpp
     llassettype.cpp
     llavatarname.cpp
     llbase32.cpp
@@ -80,6 +81,7 @@ set(llcommon_SOURCE_FILES
     llrand.cpp
     llrefcount.cpp
     llrun.cpp
+    llscopedvolatileaprpool.h
     llsd.cpp
     llsdserialize.cpp
     llsdserialize_xml.cpp
@@ -122,6 +124,7 @@ set(llcommon_HEADER_FILES
     llavatarname.h
     llapp.h
     llapr.h
+    llaprpool.h
     llassettype.h
     llassoclist.h
     llavatarconstants.h
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index ed192a9975125106a8ffafb4d1f72b84d59f0917..a8b7106078fb3fa32d9c839735464481ef890789 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -137,10 +137,6 @@ void LLApp::commonCtor()
 		mOptions.append(sd);
 	}
 
-	// Make sure we clean up APR when we exit
-	// Don't need to do this if we're cleaning up APR in the destructor
-	//atexit(ll_cleanup_apr);
-
 	// Set the application to this instance.
 	sApplication = this;
 	
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index d1c44c94032851a19a4ab42f20006ce04a1eb1f4..1e4a51102e782d282e49e63cdd51dc8fab697951 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -29,212 +29,8 @@
 #include "linden_common.h"
 #include "llapr.h"
 #include "apr_dso.h"
+#include "llscopedvolatileaprpool.h"
 
-apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
-LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
-apr_thread_mutex_t *gLogMutexp = NULL;
-apr_thread_mutex_t *gCallStacksLogMutexp = NULL;
-
-const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool
-
-void ll_init_apr()
-{
-	if (!gAPRPoolp)
-	{
-		// Initialize APR and create the global pool
-		apr_initialize();
-		apr_pool_create(&gAPRPoolp, NULL);
-		
-		// Initialize the logging mutex
-		apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
-		apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp);
-	}
-
-	if(!LLAPRFile::sAPRFilePoolp)
-	{
-		LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
-	}
-}
-
-
-void ll_cleanup_apr()
-{
-	LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
-
-	if (gLogMutexp)
-	{
-		// Clean up the logging mutex
-
-		// All other threads NEED to be done before we clean up APR, so this is okay.
-		apr_thread_mutex_destroy(gLogMutexp);
-		gLogMutexp = NULL;
-	}
-	if (gCallStacksLogMutexp)
-	{
-		// Clean up the logging mutex
-
-		// All other threads NEED to be done before we clean up APR, so this is okay.
-		apr_thread_mutex_destroy(gCallStacksLogMutexp);
-		gCallStacksLogMutexp = NULL;
-	}
-	if (gAPRPoolp)
-	{
-		apr_pool_destroy(gAPRPoolp);
-		gAPRPoolp = NULL;
-	}
-	if (LLAPRFile::sAPRFilePoolp)
-	{
-		delete LLAPRFile::sAPRFilePoolp ;
-		LLAPRFile::sAPRFilePoolp = NULL ;
-	}
-	apr_terminate();
-}
-
-//
-//
-//LLAPRPool
-//
-LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 	
-	: mParent(parent),
-	mReleasePoolFlag(releasePoolFlag),
-	mMaxSize(size),
-	mPool(NULL)
-{	
-	createAPRPool() ;
-}
-
-LLAPRPool::~LLAPRPool() 
-{
-	releaseAPRPool() ;
-}
-
-void LLAPRPool::createAPRPool()
-{
-	if(mPool)
-	{
-		return ;
-	}
-
-	mStatus = apr_pool_create(&mPool, mParent);
-	ll_apr_warn_status(mStatus) ;
-
-	if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes.
-	{
-		apr_allocator_t *allocator = apr_pool_allocator_get(mPool); 
-		if (allocator) 
-		{ 
-			apr_allocator_max_free_set(allocator, mMaxSize) ;
-		}
-	}
-}
-
-void LLAPRPool::releaseAPRPool()
-{
-	if(!mPool)
-	{
-		return ;
-	}
-
-	if(!mParent || mReleasePoolFlag)
-	{
-		apr_pool_destroy(mPool) ;
-		mPool = NULL ;
-	}
-}
-
-//virtual
-apr_pool_t* LLAPRPool::getAPRPool() 
-{	
-	return mPool ; 
-}
-
-LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 
-				  : LLAPRPool(parent, size, releasePoolFlag),
-				  mNumActiveRef(0),
-				  mNumTotalRef(0),
-				  mMutexPool(NULL),
-				  mMutexp(NULL)
-{
-	//create mutex
-	if(!is_local) //not a local apr_pool, that is: shared by multiple threads.
-	{
-		apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex
-		apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool);
-	}
-}
-
-LLVolatileAPRPool::~LLVolatileAPRPool()
-{
-	//delete mutex
-	if(mMutexp)
-	{
-		apr_thread_mutex_destroy(mMutexp);
-		apr_pool_destroy(mMutexPool);
-	}
-}
-
-//
-//define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
-//
-//virtual 
-apr_pool_t* LLVolatileAPRPool::getAPRPool() 
-{
-	return LLVolatileAPRPool::getVolatileAPRPool() ;
-}
-
-apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() 
-{	
-	LLScopedLock lock(mMutexp) ;
-
-	mNumTotalRef++ ;
-	mNumActiveRef++ ;
-
-	if(!mPool)
-	{
-		createAPRPool() ;
-	}
-	
-	return mPool ;
-}
-
-void LLVolatileAPRPool::clearVolatileAPRPool() 
-{
-	LLScopedLock lock(mMutexp) ;
-
-	if(mNumActiveRef > 0)
-	{
-		mNumActiveRef--;
-		if(mNumActiveRef < 1)
-		{
-			if(isFull()) 
-			{
-				mNumTotalRef = 0 ;
-
-				//destroy the apr_pool.
-				releaseAPRPool() ;
-			}
-			else 
-			{
-				//This does not actually free the memory, 
-				//it just allows the pool to re-use this memory for the next allocation. 
-				apr_pool_clear(mPool) ;
-			}
-		}
-	}
-	else
-	{
-		llassert_always(mNumActiveRef > 0) ;
-	}
-
-	//paranoia check if the pool is jammed.
-	//will remove the check before going to release.
-	llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
-}
-
-BOOL LLVolatileAPRPool::isFull()
-{
-	return mNumTotalRef > FULL_VOLATILE_APR_POOL ;
-}
 //---------------------------------------------------------------------
 //
 // LLScopedLock
@@ -313,15 +109,17 @@ void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle)
 //
 LLAPRFile::LLAPRFile()
 	: mFile(NULL),
-	  mCurrentFilePoolp(NULL)
+	  mVolatileFilePoolp(NULL),
+	  mRegularFilePoolp(NULL)
 {
 }
 
-LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool)
+LLAPRFile::LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep, access_t access_type)
 	: mFile(NULL),
-	  mCurrentFilePoolp(NULL)
+	  mVolatileFilePoolp(NULL),
+	  mRegularFilePoolp(NULL)
 {
-	open(filename, flags, pool);
+	open(filename, flags, access_type, sizep);
 }
 
 LLAPRFile::~LLAPRFile()
@@ -338,36 +136,58 @@ apr_status_t LLAPRFile::close()
 		mFile = NULL ;
 	}
 
-	if(mCurrentFilePoolp)
+	if (mVolatileFilePoolp)
 	{
-		mCurrentFilePoolp->clearVolatileAPRPool() ;
-		mCurrentFilePoolp = NULL ;
+		mVolatileFilePoolp->clearVolatileAPRPool() ;
+		mVolatileFilePoolp = NULL ;
+	}
+
+	if (mRegularFilePoolp)
+	{
+		delete mRegularFilePoolp;
+		mRegularFilePoolp = NULL;
 	}
 
 	return ret ;
 }
 
-apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep)
+apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, access_t access_type, S32* sizep)
 {
-	apr_status_t s ;
-
-	//check if already open some file
-	llassert_always(!mFile) ;
-	llassert_always(!mCurrentFilePoolp) ;
-	
-	apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ;
-	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool));
+	llassert_always(!mFile);
+	llassert_always(!mVolatileFilePoolp && !mRegularFilePoolp);
 
-	if (s != APR_SUCCESS || !mFile)
+	apr_status_t status;
+	{
+		apr_pool_t* apr_file_open_pool;	// The use of apr_pool_t is OK here.
+										// This is a temporary variable for a pool that is passed directly to apr_file_open below.
+		if (access_type == short_lived)
+		{
+			// Use a "volatile" thread-local pool.
+			mVolatileFilePoolp = &LLThreadLocalData::tldata().mVolatileAPRPool;
+			// Access the pool and increment its reference count.
+			// The reference count of LLVolatileAPRPool objects will be decremented
+			// again in LLAPRFile::close by calling mVolatileFilePoolp->clearVolatileAPRPool().
+			apr_file_open_pool = mVolatileFilePoolp->getVolatileAPRPool();
+		}
+		else
+		{
+			mRegularFilePoolp = new LLAPRPool(LLThreadLocalData::tldata().mRootPool);
+			apr_file_open_pool = (*mRegularFilePoolp)();
+		}
+		status = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_file_open_pool);
+	}
+	if (status != APR_SUCCESS || !mFile)
 	{
 		mFile = NULL ;
-		
+		close() ;
 		if (sizep)
 		{
 			*sizep = 0;
 		}
+		return status;
 	}
-	else if (sizep)
+
+	if (sizep)
 	{
 		S32 file_size = 0;
 		apr_off_t offset = 0;
@@ -381,49 +201,7 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLV
 		*sizep = file_size;
 	}
 
-	if(!mCurrentFilePoolp)
-	{
-		mCurrentFilePoolp = pool ;
-
-		if(!mFile)
-		{
-			close() ;
-		}
-	}
-
-	return s ;
-}
-
-//use gAPRPoolp.
-apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
-{
-	apr_status_t s;
-
-	//check if already open some file
-	llassert_always(!mFile) ;
-	llassert_always(!mCurrentFilePoolp) ;
-	llassert_always(use_global_pool) ; //be aware of using gAPRPoolp.
-	
-	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp);
-	if (s != APR_SUCCESS || !mFile)
-	{
-		mFile = NULL ;
-		close() ;
-		return s;
-	}
-
-	return s;
-}
-
-apr_pool_t* LLAPRFile::getAPRFilePool(apr_pool_t* pool)
-{	
-	if(!pool)
-	{
-		mCurrentFilePoolp = sAPRFilePoolp ;
-		return mCurrentFilePoolp->getVolatileAPRPool() ;
-	}
-
-	return pool ;
+	return status;
 }
 
 // File I/O
@@ -481,45 +259,6 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
 //static components of LLAPRFile
 //
 
-//static
-apr_status_t LLAPRFile::close(apr_file_t* file_handle, LLVolatileAPRPool* pool) 
-{
-	apr_status_t ret = APR_SUCCESS ;
-	if(file_handle)
-	{
-		ret = apr_file_close(file_handle);
-		file_handle = NULL ;
-	}
-
-	if(pool)
-	{
-		pool->clearVolatileAPRPool() ;
-	}
-
-	return ret ;
-}
-
-//static
-apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
-{
-	apr_status_t s;
-	apr_file_t* file_handle ;
-
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-
-	s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
-	if (s != APR_SUCCESS || !file_handle)
-	{
-		ll_apr_warn_status(s);
-		LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL;
-		file_handle = NULL ;
-		close(file_handle, pool) ;
-		return NULL;
-	}
-
-	return file_handle ;
-}
-
 //static
 S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
 {
@@ -553,13 +292,15 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
 }
 
 //static
-S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
+S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes)
 {
-	//*****************************************
-	apr_file_t* file_handle = open(filename, pool, APR_READ|APR_BINARY); 
-	//*****************************************	
-	if (!file_handle)
+	apr_file_t* file_handle;
+	LLScopedVolatileAPRPool pool;
+	apr_status_t s = apr_file_open(&file_handle, filename.c_str(), APR_READ|APR_BINARY, APR_OS_DEFAULT, pool);
+	if (s != APR_SUCCESS || !file_handle)
 	{
+		ll_apr_warn_status(s);
+		LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL;
 		return 0;
 	}
 
@@ -589,14 +330,13 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb
 		}
 	}
 	
-	//*****************************************
-	close(file_handle, pool) ; 
-	//*****************************************
+	apr_file_close(file_handle);
+
 	return (S32)bytes_read;
 }
 
 //static
-S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)
+S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes)
 {
 	apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
 	if (offset < 0)
@@ -605,11 +345,13 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
 		offset = 0;
 	}
 	
-	//*****************************************
-	apr_file_t* file_handle = open(filename, pool, flags);
-	//*****************************************
-	if (!file_handle)
+	apr_file_t* file_handle;
+	LLScopedVolatileAPRPool pool;
+	apr_status_t s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool);
+	if (s != APR_SUCCESS || !file_handle)
 	{
+		ll_apr_warn_status(s);
+		LL_WARNS("APR") << " while attempting to open file \"" << filename << '"' << LL_ENDL;
 		return 0;
 	}
 
@@ -639,21 +381,18 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
 		}
 	}
 
-	//*****************************************
-	LLAPRFile::close(file_handle, pool);
-	//*****************************************
+	apr_file_close(file_handle);
 
 	return (S32)bytes_written;
 }
 
 //static
-bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
+bool LLAPRFile::remove(const std::string& filename)
 {
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_remove(filename.c_str(), pool->getVolatileAPRPool());
-	pool->clearVolatileAPRPool() ;
+	LLScopedVolatileAPRPool pool;
+	s = apr_file_remove(filename.c_str(), pool);
 
 	if (s != APR_SUCCESS)
 	{
@@ -665,13 +404,12 @@ bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
 }
 
 //static
-bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool)
+bool LLAPRFile::rename(const std::string& filename, const std::string& newname)
 {
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_rename(filename.c_str(), newname.c_str(), pool->getVolatileAPRPool());
-	pool->clearVolatileAPRPool() ;
+	LLScopedVolatileAPRPool pool;
+	s = apr_file_rename(filename.c_str(), newname.c_str(), pool);
 	
 	if (s != APR_SUCCESS)
 	{
@@ -683,49 +421,44 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname,
 }
 
 //static
-bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags)
+bool LLAPRFile::isExist(const std::string& filename, apr_int32_t flags)
 {
-	apr_file_t* apr_file;
+	apr_file_t* file_handle;
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());	
+	LLScopedVolatileAPRPool pool;
+	s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool);
 
-	if (s != APR_SUCCESS || !apr_file)
+	if (s != APR_SUCCESS || !file_handle)
 	{
-		pool->clearVolatileAPRPool() ;
 		return false;
 	}
 	else
 	{
-		apr_file_close(apr_file) ;
-		pool->clearVolatileAPRPool() ;
+		apr_file_close(file_handle);
 		return true;
 	}
 }
 
 //static
-S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
+S32 LLAPRFile::size(const std::string& filename)
 {
-	apr_file_t* apr_file;
+	apr_file_t* file_handle;
 	apr_finfo_t info;
 	apr_status_t s;
 	
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool->getVolatileAPRPool());
+	LLScopedVolatileAPRPool pool;
+	s = apr_file_open(&file_handle, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool);
 	
-	if (s != APR_SUCCESS || !apr_file)
+	if (s != APR_SUCCESS || !file_handle)
 	{		
-		pool->clearVolatileAPRPool() ;
-		
 		return 0;
 	}
 	else
 	{
-		apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file);		
+		apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, file_handle);
 
-		apr_file_close(apr_file) ;
-		pool->clearVolatileAPRPool() ;
+		apr_file_close(file_handle) ;
 		
 		if (s == APR_SUCCESS)
 		{
@@ -739,31 +472,29 @@ S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool)
 }
 
 //static
-bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)
+bool LLAPRFile::makeDir(const std::string& dirname)
 {
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool->getVolatileAPRPool());
-	pool->clearVolatileAPRPool() ;
+	LLScopedVolatileAPRPool pool;
+	s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool);
 		
 	if (s != APR_SUCCESS)
 	{
 		ll_apr_warn_status(s);
-		LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL;
+		LL_WARNS("APR") << " while attempting to make directory: " << dirname << LL_ENDL;
 		return false;
 	}
 	return true;
 }
 
 //static
-bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)
+bool LLAPRFile::removeDir(const std::string& dirname)
 {
 	apr_status_t s;
 
-	pool = pool ? pool : LLAPRFile::sAPRFilePoolp ;
-	s = apr_file_remove(dirname.c_str(), pool->getVolatileAPRPool());
-	pool->clearVolatileAPRPool() ;
+	LLScopedVolatileAPRPool pool;
+	s = apr_file_remove(dirname.c_str(), pool);
 	
 	if (s != APR_SUCCESS)
 	{
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index af33ce666f1558193d3d2818cf0c3a5e98d6ee7a..3f846f13145034e0d26c33b5f50a09064ddff737 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -50,71 +50,9 @@
 #include "apr_atomic.h"
 #include "llstring.h"
 
-extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
-extern apr_thread_mutex_t* gCallStacksLogMutexp;
-
 struct apr_dso_handle_t;
-
-/** 
- * @brief initialize the common apr constructs -- apr itself, the
- * global pool, and a mutex.
- */
-void LL_COMMON_API ll_init_apr();
-
-/** 
- * @brief Cleanup those common apr constructs.
- */
-void LL_COMMON_API ll_cleanup_apr();
-
-//
-//LL apr_pool
-//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
-//
-class LL_COMMON_API LLAPRPool
-{
-public:
-	LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
-	virtual ~LLAPRPool() ;
-
-	virtual apr_pool_t* getAPRPool() ;
-	apr_status_t getStatus() {return mStatus ; }
-
-protected:
-	void releaseAPRPool() ;
-	void createAPRPool() ;
-
-protected:
-	apr_pool_t*  mPool ;              //pointing to an apr_pool
-	apr_pool_t*  mParent ;			  //parent pool
-	apr_size_t   mMaxSize ;           //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
-	apr_status_t mStatus ;            //status when creating the pool
-	BOOL         mReleasePoolFlag ;   //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
-};
-
-//
-//volatile LL apr_pool
-//which clears memory automatically.
-//so it can not hold static data or data after memory is cleared
-//
-class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool
-{
-public:
-	LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
-	virtual ~LLVolatileAPRPool();
-
-	/*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
-	apr_pool_t* getVolatileAPRPool() ;	
-	void        clearVolatileAPRPool() ;
-
-	BOOL        isFull() ;
-	
-private:
-	S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
-	S32 mNumTotalRef ;  //number of total pointers pointing to the apr_pool since last creating.  
-
-	apr_thread_mutex_t *mMutexp;
-	apr_pool_t         *mMutexPool;
-} ;
+class LLAPRPool;
+class LLVolatileAPRPool;
 
 /** 
  * @class LLScopedLock
@@ -205,15 +143,20 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
 	// make this non copyable since a copy closes the file
 private:
 	apr_file_t* mFile ;
-	LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. 
+	LLVolatileAPRPool* mVolatileFilePoolp;	// (Thread local) APR pool currently in use.
+	LLAPRPool* mRegularFilePoolp;		// ...or a regular pool.
 
 public:
+	enum access_t {
+		long_lived,		// Use a global pool for long-lived file accesses.
+		short_lived		// Use a volatile pool for short-lived file accesses.
+	};
+
 	LLAPRFile() ;
-	LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL);
+	LLAPRFile(std::string const& filename, apr_int32_t flags, S32* sizep = NULL, access_t access_type = short_lived);
 	~LLAPRFile() ;
-	
-	apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL);
-	apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp.
+
+	apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL);
 	apr_status_t close() ;
 
 	// Returns actual offset, -1 if seek fails
@@ -226,32 +169,24 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
 	
 	apr_file_t* getFileHandle() {return mFile;}	
 
-private:
-	apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;	
-	
 //
 //*******************************************************************************************************************************
 //static components
 //
-public:
-	static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
-
 private:
-	static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
-	static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
 	static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
 public:
 	// returns false if failure:
-	static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
-	static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
-	static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
-	static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
-	static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
-	static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
+	static bool remove(const std::string& filename);
+	static bool rename(const std::string& filename, const std::string& newname);
+	static bool isExist(const std::string& filename, apr_int32_t flags = APR_READ);
+	static S32 size(const std::string& filename);
+	static bool makeDir(const std::string& dirname);
+	static bool removeDir(const std::string& dirname);
 
 	// Returns bytes read/written, 0 if read/write fails:
-	static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	
-	static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append
+	static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes);	
+	static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes); // offset<0 means append
 //*******************************************************************************************************************************
 };
 
@@ -267,6 +202,4 @@ bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* han
 void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
 void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle);
 
-extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
-
 #endif // LL_LLAPR_H
diff --git a/indra/llcommon/llaprpool.cpp b/indra/llcommon/llaprpool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6f21b61b65e23df52654d4e3dd70a43828c4cc0d
--- /dev/null
+++ b/indra/llcommon/llaprpool.cpp
@@ -0,0 +1,202 @@
+/**
+ * @file llaprpool.cpp
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ *
+ * CHANGELOG
+ *   and additional copyright holders.
+ *
+ *   04/04/2010
+ *   - Initial version, written by Aleric Inglewood @ SL
+ *
+ *   10/11/2010
+ *   - Added APR_HAS_THREADS #if's to allow creation and destruction
+ *     of subpools by threads other than the parent pool owner.
+ */
+
+#include "linden_common.h"
+
+#include "llerror.h"
+#include "llaprpool.h"
+#include "llthread.h"
+
+// Create a subpool from parent.
+void LLAPRPool::create(LLAPRPool& parent)
+{
+	llassert(!mPool);			// Must be non-initialized.
+	mParent = &parent;
+	if (!mParent)				// Using the default parameter?
+	{
+		// By default use the root pool of the current thread.
+		mParent = &LLThreadLocalData::tldata().mRootPool;
+	}
+	llassert(mParent->mPool);	// Parent must be initialized.
+#if APR_HAS_THREADS
+	// As per the documentation of APR (ie http://apr.apache.org/docs/apr/1.4/apr__pools_8h.html):
+	//
+	// Note that most operations on pools are not thread-safe: a single pool should only be
+	// accessed by a single thread at any given time. The one exception to this rule is creating
+	// a subpool of a given pool: one or more threads can safely create subpools at the same
+	// time that another thread accesses the parent pool.
+	//
+	// In other words, it's safe for any thread to create a (sub)pool, independent of who
+	// owns the parent pool.
+	mOwner = apr_os_thread_current();
+#else
+	mOwner = mParent->mOwner;
+	llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+#endif
+	apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, mParent->mPool);
+	llassert_always(apr_pool_create_status == APR_SUCCESS);
+	llassert(mPool);			// Initialized.
+	apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null);
+}
+
+// Destroy the (sub)pool, if any.
+void LLAPRPool::destroy(void)
+{
+	// Only do anything if we are not already (being) destroyed.
+	if (mPool)
+	{
+#if !APR_HAS_THREADS
+		// If we are a root pool, then every thread may destruct us: in that case
+		// we have to assume that no other thread will use this pool concurrently,
+		// of course. Otherwise, if we are a subpool, only the thread that owns
+		// the parent may destruct us, since that is the pool that is still alive,
+		// possibly being used by others and being altered here.
+		llassert(!mParent || apr_os_thread_equal(mParent->mOwner, apr_os_thread_current()));
+#endif
+		apr_pool_t* pool = mPool;	// The use of apr_pool_t is OK here.
+									// Temporary store before destroying the pool.
+		mPool = NULL;				// Mark that we are BEING destructed.
+		apr_pool_cleanup_kill(pool, this, &s_plain_cleanup);
+		apr_pool_destroy(pool);
+	}
+}
+
+bool LLAPRPool::parent_is_being_destructed(void)
+{
+	return mParent && (!mParent->mPool || mParent->parent_is_being_destructed());
+}
+
+LLAPRInitialization::LLAPRInitialization(void)
+{
+	static bool apr_initialized = false;
+
+	if (!apr_initialized)
+	{
+		apr_initialize();
+	}
+
+	apr_initialized = true;
+}
+
+bool LLAPRRootPool::sCountInitialized = false;
+apr_uint32_t volatile LLAPRRootPool::sCount;
+
+apr_thread_mutex_t* gLogMutexp;
+apr_thread_mutex_t* gCallStacksLogMutexp;
+
+LLAPRRootPool::LLAPRRootPool(void) : LLAPRInitialization(), LLAPRPool(0)
+{
+	// sCountInitialized don't need locking because when we get here there is still only a single thread.
+	if (!sCountInitialized)
+	{
+		// Initialize the logging mutex
+		apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool);
+		apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool);
+
+		apr_status_t status = apr_atomic_init(mPool);
+		llassert_always(status == APR_SUCCESS);
+		apr_atomic_set32(&sCount, 1);	// Set to 1 to account for the global root pool.
+		sCountInitialized = true;
+
+		// Initialize thread-local APR pool support.
+		// Because this recursively calls LLAPRRootPool::LLAPRRootPool(void)
+		// it must be done last, so that sCount is already initialized.
+		LLThreadLocalData::init();
+	}
+	apr_atomic_inc32(&sCount);
+}
+
+LLAPRRootPool::~LLAPRRootPool()
+{
+	if (!apr_atomic_dec32(&sCount))
+	{
+		// The last pool was destructed. Cleanup remainder of APR.
+		LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
+
+		if (gLogMutexp)
+		{
+			// Clean up the logging mutex
+
+			// All other threads NEED to be done before we clean up APR, so this is okay.
+			apr_thread_mutex_destroy(gLogMutexp);
+			gLogMutexp = NULL;
+		}
+		if (gCallStacksLogMutexp)
+		{
+			// Clean up the logging mutex
+
+			// All other threads NEED to be done before we clean up APR, so this is okay.
+			apr_thread_mutex_destroy(gCallStacksLogMutexp);
+			gCallStacksLogMutexp = NULL;
+		}
+
+		// Must destroy ALL, and therefore this last LLAPRRootPool, before terminating APR.
+		static_cast<LLAPRRootPool*>(this)->destroy();
+
+		apr_terminate();
+	}
+}
+
+//static
+// Return a global root pool that is independent of LLThreadLocalData.
+// Normally you should NOT use this. Only use for early initialization
+// (before main) and deinitialization (after main).
+LLAPRRootPool& LLAPRRootPool::get(void)
+{
+  static LLAPRRootPool global_APRpool(0);
+  return global_APRpool;
+}
+
+void LLVolatileAPRPool::clearVolatileAPRPool()
+{
+	llassert_always(mNumActiveRef > 0);
+	if (--mNumActiveRef == 0)
+	{
+		if (isOld())
+		{
+			destroy();
+			mNumTotalRef = 0 ;
+		}
+		else
+		{
+			// This does not actually free the memory,
+			// it just allows the pool to re-use this memory for the next allocation.
+			clear();
+		}
+	}
+
+	// Paranoia check if the pool is jammed.
+	llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
+}
diff --git a/indra/llcommon/llaprpool.h b/indra/llcommon/llaprpool.h
new file mode 100644
index 0000000000000000000000000000000000000000..bf4102c5849e98f1e78095ee22131b8263d5b744
--- /dev/null
+++ b/indra/llcommon/llaprpool.h
@@ -0,0 +1,256 @@
+/**
+ * @file llaprpool.h
+ * @brief Implementation of LLAPRPool
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ *
+ * CHANGELOG
+ *   and additional copyright holders.
+ *
+ *   04/04/2010
+ *   - Initial version, written by Aleric Inglewood @ SL
+ *
+ *   10/11/2010
+ *   - Added APR_HAS_THREADS #if's to allow creation and destruction
+ *     of subpools by threads other than the parent pool owner.
+ *
+ *   05/02/2011
+ *   - Fixed compilation on windows: Suppress compile warning 4996
+ *     and include <winsock2.h> before including <ws2tcpip.h>,
+ *     by Merov Linden @ SL.
+ */
+
+#ifndef LL_LLAPRPOOL_H
+#define LL_LLAPRPOOL_H
+
+#ifdef LL_WINDOWS
+#pragma warning(push)
+#pragma warning(disable:4996)
+#include <winsock2.h>
+#include <ws2tcpip.h>		// Needed before including apr_portable.h
+#pragma warning(pop)
+#endif
+
+#include "apr_portable.h"
+#include "apr_pools.h"
+#include "llerror.h"
+
+extern void ll_init_apr();
+
+/**
+ * @brief A wrapper around the APR memory pool API.
+ *
+ * Usage of this class should be restricted to passing it to libapr-1 function calls that need it.
+ *
+ */
+class LL_COMMON_API LLAPRPool
+{
+protected:
+	//! Pointer to the underlaying pool. NULL if not initialized.
+	apr_pool_t* mPool;		// The use of apr_pool_t is OK here.
+							// This is the wrapped pointer that it is all about!
+	//! Pointer to the parent pool, if any. Only valid when mPool is non-zero.
+	LLAPRPool* mParent;
+	//! The thread that owns this memory pool. Only valid when mPool is non-zero.
+	apr_os_thread_t mOwner;
+
+public:
+	/// Construct an uninitialized (destructed) pool.
+	LLAPRPool(void) : mPool(NULL) { }
+
+	/// Construct a subpool from an existing pool.
+	/// This is not a copy-constructor, this class doesn't have one!
+	LLAPRPool(LLAPRPool& parent) : mPool(NULL) { create(parent); }
+
+	/// Destruct the memory pool (free all of its subpools and allocated memory).
+	~LLAPRPool() { destroy(); }
+
+protected:
+	/// Create a pool that is allocated from the Operating System. Only used by LLAPRRootPool.
+	LLAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
+	{
+		apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL);
+		llassert_always(apr_pool_create_status == APR_SUCCESS);
+		llassert(mPool);
+		apr_pool_cleanup_register(mPool, this, &s_plain_cleanup, &apr_pool_cleanup_null);
+	}
+
+public:
+	/// Create a subpool from parent. May only be called for an uninitialized/destroyed pool.
+	/// The default parameter causes the root pool of the current thread to be used.
+	void create(LLAPRPool& parent = *static_cast<LLAPRPool*>(NULL));
+
+	/// Destroy the (sub)pool, if any.
+	void destroy(void);
+
+	// Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool.
+	typedef LLAPRPool* const LLAPRPool::* const bool_type;
+	/// Return true if the pool is initialized.
+	operator bool_type() const { return mPool ? &LLAPRPool::mParent : 0; }
+
+	/// Painful, but we have to either provide access to this, or wrap
+	/// every APR function call that needs an apr pool as argument.
+	/// NEVER destroy a pool that is returned by this function!
+	apr_pool_t* operator()(void) const		// The use of apr_pool_t is OK here.
+	  										// This is the accessor for passing the pool to libapr-1 functions.
+	{
+		llassert(mPool);
+		llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+		return mPool;
+	}
+
+	/// Free all memory without destructing the pool.
+	void clear(void)
+	{
+		llassert(mPool);
+		llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+		apr_pool_clear(mPool);
+	}
+
+// These methods would make this class 'complete' (as wrapper around the libapr
+// pool functions), but we don't use memory pools in the viewer (only when
+// we are forced to pass one to a libapr call), so don't define them in order
+// not to encourage people to use them.
+#if 0
+	void* palloc(size_t size)
+	{
+		llassert(mPool);
+		llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+		return apr_palloc(mPool, size);
+	}
+	void* pcalloc(size_t size)
+	{
+		llassert(mPool);
+		llassert(apr_os_thread_equal(mOwner, apr_os_thread_current()));
+		return apr_pcalloc(mPool, size);
+	}
+#endif
+
+private:
+	bool parent_is_being_destructed(void);
+	static apr_status_t s_plain_cleanup(void* userdata) { return static_cast<LLAPRPool*>(userdata)->plain_cleanup(); }
+
+	apr_status_t plain_cleanup(void)
+	{
+		if (mPool && 						// We are not being destructed,
+			parent_is_being_destructed())	// but our parent is.
+		  // This means the pool is being destructed recursively by libapr
+		  // because one of its parents is being destructed.
+		{
+			mPool = NULL;	// Stop destroy() from destructing the pool again.
+		}
+		return APR_SUCCESS;
+	}
+};
+
+class LLAPRInitialization
+{
+public:
+	LLAPRInitialization(void);
+};
+
+/**
+ * @brief Root memory pool (allocates memory from the operating system).
+ *
+ * This class should only be used by LLThreadLocalData
+ * (and LLMutexRootPool when APR_HAS_THREADS isn't defined).
+ */
+class LL_COMMON_API LLAPRRootPool : public LLAPRInitialization, public LLAPRPool
+{
+private:
+	/// Construct a root memory pool. Should only be used by LLThreadLocalData and LLMutexRootPool.
+	friend class LLThreadLocalData;
+#if !APR_HAS_THREADS
+	friend class LLMutexRootPool;
+#endif
+	/// Construct a root memory pool.
+	/// Should only be used by LLThreadLocalData.
+	LLAPRRootPool(void);
+	~LLAPRRootPool();
+
+private:
+	// Keep track of how many root pools exist and when the last one is destructed.
+	static bool sCountInitialized;
+	static apr_uint32_t volatile sCount;
+
+public:
+	// Return a global root pool that is independent of LLThreadLocalData.
+	// Normally you should not use this. Only use for early initialization
+	// (before main) and deinitialization (after main).
+	static LLAPRRootPool& get(void);
+
+#if APR_POOL_DEBUG
+	void grab_ownership(void)
+	{
+		// You need a patched libapr to use this.
+		// See http://web.archiveorange.com/archive/v/5XO9y2zoxUOMt6Gmi1OI
+		apr_pool_owner_set(mPool);
+	}
+#endif
+
+private:
+	// Used for constructing the Special Global Root Pool (returned by LLAPRRootPool::get).
+	// It is the same as the default constructor but omits to increment sCount. As a result,
+	// we must be sure that at least one other LLAPRRootPool is created before termination
+	// of the application (which is the case: we create one LLAPRRootPool per thread).
+	LLAPRRootPool(int) : LLAPRInitialization(), LLAPRPool(0) { }
+};
+
+/** Volatile memory pool
+ *
+ * 'Volatile' APR memory pool which normally only clears memory,
+ * and does not destroy the pool (the same pool is reused) for
+ * greater efficiency. However, as a safe guard the apr pool
+ * is destructed every FULL_VOLATILE_APR_POOL uses to allow
+ * the system memory to be allocated more efficiently and not
+ * get scattered through RAM.
+ */
+class LL_COMMON_API LLVolatileAPRPool : protected LLAPRPool
+{
+public:
+	LLVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
+
+	void clearVolatileAPRPool(void);
+
+	bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; }
+	bool isUnused() const { return mNumActiveRef == 0; }
+
+private:
+	friend class LLScopedVolatileAPRPool;
+	friend class LLAPRFile;
+	apr_pool_t* getVolatileAPRPool(void)	// The use of apr_pool_t is OK here.
+	{
+		if (!mPool) create();
+		++mNumActiveRef;
+		++mNumTotalRef;
+		return LLAPRPool::operator()();
+	}
+
+private:
+	S32 mNumActiveRef;	// Number of active uses of the pool.
+	S32 mNumTotalRef;	// Number of total uses of the pool since last creation.
+
+	// Maximum number of references to LLVolatileAPRPool until the pool is recreated.
+	static S32 const FULL_VOLATILE_APR_POOL = 1024;
+};
+
+#endif // LL_LLAPRPOOL_H
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 8be9e4f4de28ef135295efef826e5eb4608e1373..b8a739485250f74f4f70285bc12a7f779cc0d1df 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -30,18 +30,10 @@
 #include "llmemory.h"
 #include "llthread.h"
 
-//static
-BOOL LLCommon::sAprInitialized = FALSE;
-
 //static
 void LLCommon::initClass()
 {
 	LLMemory::initClass();
-	if (!sAprInitialized)
-	{
-		ll_init_apr();
-		sAprInitialized = TRUE;
-	}
 	LLTimer::initClass();
 	LLThreadSafeRefCount::initThreadSafeRefCount();
 // 	LLWorkerThread::initClass();
@@ -55,10 +47,5 @@ void LLCommon::cleanupClass()
 // 	LLWorkerThread::cleanupClass();
 	LLThreadSafeRefCount::cleanupThreadSafeRefCount();
 	LLTimer::cleanupClass();
-	if (sAprInitialized)
-	{
-		ll_cleanup_apr();
-		sAprInitialized = FALSE;
-	}
 	LLMemory::cleanupClass();
 }
diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h
index ca9cad5d05ed9d8a744cd68a9c59c9d000bc2e6b..171590f3d807ba667457c4533e6c8e6037780f70 100644
--- a/indra/llcommon/llcommon.h
+++ b/indra/llcommon/llcommon.h
@@ -35,8 +35,6 @@ class LL_COMMON_API LLCommon
 public:
 	static void initClass();
 	static void cleanupClass();
-private:
-	static BOOL sAprInitialized;
 };
 
 #endif
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index c35799bbb91761845f1ca616a1c3e87ffefdc7a6..bda9d7c177467ca8d4e5fd0a9676d0929740c7b6 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -866,6 +866,9 @@ You get:
 	
 */
 
+extern apr_thread_mutex_t* gLogMutexp;
+extern apr_thread_mutex_t* gCallStacksLogMutexp;
+
 namespace {
 	bool checkLevelMap(const LevelMap& map, const std::string& key,
 						LLError::ELevel& level)
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index b3e604f8e83f177c6a2285c524fea201b7e30bbb..369f2a7a97a7d8e2b976f9d9583a02e072519b43 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -296,5 +296,4 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
 		Such computation is done iff the message will be logged.
 	*/
 
-
 #endif // LL_LLERROR_H
diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp
index d394f179fb52fd674854f724c9fd2721f00ec567..4b5cdbe28859dccd6c84d30e90f96133138b5696 100644
--- a/indra/llcommon/llfixedbuffer.cpp
+++ b/indra/llcommon/llfixedbuffer.cpp
@@ -30,8 +30,7 @@
 
 LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
 	: LLLineBuffer(),
-	  mMaxLines(max_lines),
-	  mMutex(NULL)
+	  mMaxLines(max_lines)
 {
 	mTimer.reset();
 }
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index 21d1c84d695d4a5868e21fc1825f05db63db58d9..8c02ad82908c17618a6905f94a0c1dfedc6e1f01 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -26,14 +26,13 @@
 
 #include "linden_common.h"
 
-#include "llmemory.h"
 
-#if MEM_TRACK_MEM
+//#if MEM_TRACK_MEM
 #include "llthread.h"
-#endif
+//#endif
 
 #if defined(LL_WINDOWS)
-# include <windows.h>
+//# include <windows.h>
 # include <psapi.h>
 #elif defined(LL_DARWIN)
 # include <sys/types.h>
@@ -43,10 +42,24 @@
 # include <unistd.h>
 #endif
 
+#include "llmemory.h"
+
+#include "llsys.h"
+#include "llframetimer.h"
 //----------------------------------------------------------------------------
 
 //static
 char* LLMemory::reserveMem = 0;
+U32 LLMemory::sAvailPhysicalMemInKB = U32_MAX ;
+U32 LLMemory::sMaxPhysicalMemInKB = 0;
+U32 LLMemory::sAllocatedMemInKB = 0;
+U32 LLMemory::sAllocatedPageSizeInKB = 0 ;
+U32 LLMemory::sMaxHeapSizeInKB = U32_MAX ;
+BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE;
+
+#if __DEBUG_PRIVATE_MEM__
+LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sMemAllocationTracker;
+#endif
 
 //static
 void LLMemory::initClass()
@@ -71,6 +84,148 @@ void LLMemory::freeReserve()
 	reserveMem = NULL;
 }
 
+//static 
+void LLMemory::initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure)
+{
+	sMaxHeapSizeInKB = (U32)(max_heap_size_gb * 1024 * 1024) ;
+	sEnableMemoryFailurePrevention = prevent_heap_failure ;
+}
+
+//static 
+void LLMemory::updateMemoryInfo() 
+{
+#if LL_WINDOWS	
+	HANDLE self = GetCurrentProcess();
+	PROCESS_MEMORY_COUNTERS counters;
+	
+	if (!GetProcessMemoryInfo(self, &counters, sizeof(counters)))
+	{
+		llwarns << "GetProcessMemoryInfo failed" << llendl;
+		return ;
+	}
+
+	sAllocatedMemInKB = (U32)(counters.WorkingSetSize / 1024) ;
+	sAllocatedPageSizeInKB = (U32)(counters.PagefileUsage / 1024) ;
+
+	U32 avail_phys, avail_virtual;
+	LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ;
+	sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB);
+
+	if(sMaxPhysicalMemInKB > sAllocatedMemInKB)
+	{
+		sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ;
+	}
+	else
+	{
+		sAvailPhysicalMemInKB = 0 ;
+	}
+#else
+	//not valid for other systems for now.
+	sAllocatedMemInKB = (U32)(LLMemory::getCurrentRSS() / 1024) ;
+	sMaxPhysicalMemInKB = U32_MAX ;
+	sAvailPhysicalMemInKB = U32_MAX ;
+#endif
+
+	return ;
+}
+
+//
+//this function is to test if there is enough space with the size in the virtual address space.
+//it does not do any real allocation
+//if success, it returns the address where the memory chunk can fit in;
+//otherwise it returns NULL.
+//
+//static 
+void* LLMemory::tryToAlloc(void* address, U32 size)
+{
+#if LL_WINDOWS
+	address = VirtualAlloc(address, size, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS) ;
+	if(address)
+	{
+		if(!VirtualFree(address, 0, MEM_RELEASE))
+		{
+			llerrs << "error happens when free some memory reservation." << llendl ;
+		}
+	}
+	return address ;
+#else
+	return (void*)0x01 ; //skip checking
+#endif	
+}
+
+//static 
+void LLMemory::logMemoryInfo(BOOL update)
+{
+	if(update)
+	{
+		updateMemoryInfo() ;
+	}
+
+	llinfos << "Current allocated physical memory(KB): " << sAllocatedMemInKB << llendl ;
+	llinfos << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << llendl ;
+	llinfos << "Current availabe physical memory(KB): " << sAvailPhysicalMemInKB << llendl ;
+	llinfos << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << llendl ;
+}
+
+//return 0: everything is normal;
+//return 1: the memory pool is low, but not in danger;
+//return -1: the memory pool is in danger, is about to crash.
+//static 
+S32 LLMemory::isMemoryPoolLow()
+{
+	static const U32 LOW_MEMEOY_POOL_THRESHOLD_KB = 64 * 1024 ; //64 MB for emergency use
+
+	if(!sEnableMemoryFailurePrevention)
+	{
+		return 0 ; //no memory failure prevention.
+	}
+
+	if(sAvailPhysicalMemInKB < (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2)) //out of physical memory
+	{
+		return -1 ;
+	}
+
+	if(sAllocatedPageSizeInKB + (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2) > sMaxHeapSizeInKB) //out of virtual address space.
+	{
+		return -1 ;
+	}
+
+	return (S32)(sAvailPhysicalMemInKB < LOW_MEMEOY_POOL_THRESHOLD_KB || 
+		sAllocatedPageSizeInKB + LOW_MEMEOY_POOL_THRESHOLD_KB > sMaxHeapSizeInKB) ;
+}
+
+//static 
+U32 LLMemory::getAvailableMemKB() 
+{
+	return sAvailPhysicalMemInKB ;
+}
+
+//static 
+U32 LLMemory::getMaxMemKB() 
+{
+	return sMaxPhysicalMemInKB ;
+}
+
+//static 
+U32 LLMemory::getAllocatedMemKB() 
+{
+	return sAllocatedMemInKB ;
+}
+
+void* ll_allocate (size_t size)
+{
+	if (size == 0)
+	{
+		llwarns << "Null allocation" << llendl;
+	}
+	void *p = malloc(size);
+	if (p == NULL)
+	{
+		LLMemory::freeReserve();
+		llerrs << "Out of memory Error" << llendl;
+	}
+	return p;
+}
 
 //----------------------------------------------------------------------------
 
@@ -237,7 +392,7 @@ U64 LLMemory::getCurrentRSS()
 
 U32 LLMemory::getWorkingSetSize()
 {
-	return 0 ;
+	return 0;
 }
 
 #endif
@@ -258,7 +413,7 @@ LLMemTracker::LLMemTracker()
 	mDrawnIndex = 0 ;
 	mPaused = FALSE ;
 
-	mMutexp = new LLMutex(NULL) ;
+	mMutexp = new LLMutex() ;
 	mStringBuffer = new char*[128] ;
 	mStringBuffer[0] = new char[mCapacity * 128] ;
 	for(S32 i = 1 ; i < mCapacity ; i++)
@@ -376,3 +531,1661 @@ const char* LLMemTracker::getNextLine()
 #endif //MEM_TRACK_MEM
 //--------------------------------------------------------------------------------------------------
 
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+//minimum slot size and minimal slot size interval
+const U32 ATOMIC_MEM_SLOT = 16 ; //bytes
+
+//minimum block sizes (page size) for small allocation, medium allocation, large allocation 
+const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 << 10, 16 << 10} ; //
+
+//maximum block sizes for small allocation, medium allocation, large allocation 
+const U32 MAX_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {64 << 10, 1 << 20, 4 << 20} ;
+
+//minimum slot sizes for small allocation, medium allocation, large allocation 
+const U32 MIN_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION]  = {ATOMIC_MEM_SLOT, 2 << 10, 512 << 10};
+
+//maximum slot sizes for small allocation, medium allocation, large allocation 
+const U32 MAX_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION]  = {(2 << 10) - ATOMIC_MEM_SLOT, (512 - 2) << 10, 4 << 20};
+
+//size of a block with multiple slots can not exceed CUT_OFF_SIZE
+const U32 CUT_OFF_SIZE = (64 << 10) ; //64 KB
+
+//max number of slots in a block
+const U32 MAX_NUM_SLOTS_IN_A_BLOCK = llmin(MIN_BLOCK_SIZES[0] / ATOMIC_MEM_SLOT, ATOMIC_MEM_SLOT * 8) ;
+
+//-------------------------------------------------------------
+//align val to be integer times of ATOMIC_MEM_SLOT
+U32 align(U32 val)
+{
+	U32 aligned = (val / ATOMIC_MEM_SLOT) * ATOMIC_MEM_SLOT ;
+	if(aligned < val)
+	{
+		aligned += ATOMIC_MEM_SLOT ;
+	}
+
+	return aligned ;
+}
+
+//-------------------------------------------------------------
+//class LLPrivateMemoryPool::LLMemoryBlock
+//-------------------------------------------------------------
+//
+//each memory block could fit for two page sizes: 0.75 * mSlotSize, which starts from the beginning of the memory chunk and grow towards the end of the
+//the block; another is mSlotSize, which starts from the end of the block and grows towards the beginning of the block.
+//
+LLPrivateMemoryPool::LLMemoryBlock::LLMemoryBlock()
+{
+	//empty
+}
+		
+LLPrivateMemoryPool::LLMemoryBlock::~LLMemoryBlock() 
+{
+	//empty
+}
+
+//create and initialize a memory block
+void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 slot_size)
+{
+	mBuffer = buffer ;
+	mBufferSize = buffer_size ;
+	mSlotSize = slot_size ;
+	mTotalSlots = buffer_size / mSlotSize ;	
+	
+	llassert_always(buffer_size / mSlotSize <= MAX_NUM_SLOTS_IN_A_BLOCK) ; //max number is 128
+	
+	mAllocatedSlots = 0 ;
+	mDummySize = 0 ;
+
+	//init the bit map.
+	//mark free bits	
+	if(mTotalSlots > 32) //reserve extra space from mBuffer to store bitmap if needed.
+	{
+		mDummySize = ATOMIC_MEM_SLOT ;		
+		mTotalSlots -= (mDummySize + mSlotSize - 1) / mSlotSize ;
+		mUsageBits = 0 ;
+
+		S32 usage_bit_len = (mTotalSlots + 31) / 32 ;
+		
+		for(S32 i = 0 ; i < usage_bit_len - 1 ; i++)
+		{
+			*((U32*)mBuffer + i) = 0 ;
+		}
+		for(S32 i = usage_bit_len - 1 ; i < mDummySize / sizeof(U32) ; i++)
+		{
+			*((U32*)mBuffer + i) = 0xffffffff ;
+		}
+
+		if(mTotalSlots & 31)
+		{
+			*((U32*)mBuffer + usage_bit_len - 2) = (0xffffffff << (mTotalSlots & 31)) ;
+		}		
+	}	
+	else//no extra bitmap space reserved
+	{
+		mUsageBits = 0 ;
+		if(mTotalSlots & 31)
+		{
+			mUsageBits = (0xffffffff << (mTotalSlots & 31)) ;
+		}
+	}
+
+	mSelf = this ;
+	mNext = NULL ;
+	mPrev = NULL ;
+
+	llassert_always(mTotalSlots > 0) ;
+}
+
+//mark this block to be free with the memory [mBuffer, mBuffer + mBufferSize).
+void LLPrivateMemoryPool::LLMemoryBlock::setBuffer(char* buffer, U32 buffer_size)
+{
+	mBuffer = buffer ;
+	mBufferSize = buffer_size ;
+	mSelf = NULL ;
+	mTotalSlots = 0 ; //set the block is free.
+}
+
+//reserve a slot
+char* LLPrivateMemoryPool::LLMemoryBlock::allocate() 
+{
+	llassert_always(mAllocatedSlots < mTotalSlots) ;
+	
+	//find a free slot
+	U32* bits = NULL ;
+	U32  k = 0 ;
+	if(mUsageBits != 0xffffffff)
+	{
+		bits = &mUsageBits ;
+	}
+	else if(mDummySize > 0)//go to extra space
+	{		
+		for(S32 i = 0 ; i < mDummySize / sizeof(U32); i++)
+		{
+			if(*((U32*)mBuffer + i) != 0xffffffff)
+			{
+				bits = (U32*)mBuffer + i ;
+				k = i + 1 ;
+				break ;
+			}
+		}
+	}	
+	S32 idx = 0 ;
+	U32 tmp = *bits ;
+	for(; tmp & 1 ; tmp >>= 1, idx++) ;
+
+	//set the slot reserved
+	if(!idx)
+	{
+		*bits |= 1 ;
+	}
+	else
+	{
+		*bits |= (1 << idx) ;
+	}
+
+	mAllocatedSlots++ ;
+	
+	return mBuffer + mDummySize + (k * 32 + idx) * mSlotSize ;
+}
+
+//free a slot
+void  LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr) 
+{
+	//bit index
+	U32 idx = ((U32)addr - (U32)mBuffer - mDummySize) / mSlotSize ;
+
+	U32* bits = &mUsageBits ;
+	if(idx >= 32)
+	{
+		bits = (U32*)mBuffer + (idx - 32) / 32 ;
+	}
+
+	//reset the bit
+	if(idx & 31)
+	{
+		*bits &= ~(1 << (idx & 31)) ;
+	}
+	else
+	{
+		*bits &= ~1 ;
+	}
+
+	mAllocatedSlots-- ;
+}
+
+//for debug use: reset the entire bitmap.
+void  LLPrivateMemoryPool::LLMemoryBlock::resetBitMap()
+{
+	for(S32 i = 0 ; i < mDummySize / sizeof(U32) ; i++)
+	{
+		*((U32*)mBuffer + i) = 0 ;
+	}
+	mUsageBits = 0 ;
+}
+//-------------------------------------------------------------------
+//class LLMemoryChunk
+//--------------------------------------------------------------------
+LLPrivateMemoryPool::LLMemoryChunk::LLMemoryChunk()
+{
+	//empty
+}
+
+LLPrivateMemoryPool::LLMemoryChunk::~LLMemoryChunk()
+{
+	//empty
+}
+
+//create and init a memory chunk
+void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) 
+{
+	mBuffer = buffer ;
+	mBufferSize = buffer_size ;
+	mAlloatedSize = 0 ;
+
+	mMetaBuffer = mBuffer + sizeof(LLMemoryChunk) ;
+
+	mMinBlockSize = min_block_size; //page size
+	mMinSlotSize = min_slot_size;
+	mMaxSlotSize = max_slot_size ;
+	mBlockLevels = mMaxSlotSize / mMinSlotSize ;
+	mPartitionLevels = max_block_size / mMinBlockSize + 1 ;
+
+	S32 max_num_blocks = (buffer_size - sizeof(LLMemoryChunk) - mBlockLevels * sizeof(LLMemoryBlock*) - mPartitionLevels * sizeof(LLMemoryBlock*)) / 
+		                 (mMinBlockSize + sizeof(LLMemoryBlock)) ;
+	//meta data space
+	mBlocks = (LLMemoryBlock*)mMetaBuffer ; //space reserved for all memory blocks.
+	mAvailBlockList = (LLMemoryBlock**)((char*)mBlocks + sizeof(LLMemoryBlock) * max_num_blocks) ; 
+	mFreeSpaceList = (LLMemoryBlock**)((char*)mAvailBlockList + sizeof(LLMemoryBlock*) * mBlockLevels) ; 
+	
+	//data buffer, which can be used for allocation
+	mDataBuffer = (char*)mFreeSpaceList + sizeof(LLMemoryBlock*) * mPartitionLevels ;
+	
+	//alignmnet
+	mDataBuffer = mBuffer + align(mDataBuffer - mBuffer) ;
+	
+	//init
+	for(U32 i = 0 ; i < mBlockLevels; i++)
+	{
+		mAvailBlockList[i] = NULL ;
+	}
+	for(U32 i = 0 ; i < mPartitionLevels ; i++)
+	{
+		mFreeSpaceList[i] = NULL ;
+	}
+
+	//assign the entire chunk to the first block
+	mBlocks[0].mPrev = NULL ;
+	mBlocks[0].mNext = NULL ;
+	mBlocks[0].setBuffer(mDataBuffer, buffer_size - (mDataBuffer - mBuffer)) ;
+	addToFreeSpace(&mBlocks[0]) ;
+
+	mNext = NULL ;
+	mPrev = NULL ;
+}
+
+//static 
+U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_slot_size, 
+													   U32 max_slot_size, U32 min_block_size, U32 max_block_size)
+{
+	//for large allocations, reserve some extra memory for meta data to avoid wasting much 
+	if(data_buffer_size / min_slot_size < 64) //large allocations
+	{
+		U32 overhead = sizeof(LLMemoryChunk) + (data_buffer_size / min_block_size) * sizeof(LLMemoryBlock) +
+			sizeof(LLMemoryBlock*) * (max_slot_size / min_slot_size) + sizeof(LLMemoryBlock*) * (max_block_size / min_block_size + 1) ;
+
+		//round to integer times of min_block_size
+		overhead = ((overhead + min_block_size - 1) / min_block_size) * min_block_size ;
+		return overhead ;
+	}
+	else
+	{
+		return 0 ; //do not reserve extra overhead if for small allocations
+	}
+}
+
+char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size)
+{
+	if(mMinSlotSize > size)
+	{
+		size = mMinSlotSize ;
+	}
+	if(mAlloatedSize + size  > mBufferSize - (mDataBuffer - mBuffer))
+	{
+		return NULL ; //no enough space in this chunk.
+	}
+
+	char* p = NULL ;
+	U32 blk_idx = getBlockLevel(size);
+
+	LLMemoryBlock* blk = NULL ;
+
+	//check if there is free block available
+	if(mAvailBlockList[blk_idx])
+	{
+		blk = mAvailBlockList[blk_idx] ;
+		p = blk->allocate() ;
+		
+		if(blk->isFull())
+		{
+			popAvailBlockList(blk_idx) ;
+		}
+	}
+
+	//ask for a new block
+	if(!p)
+	{
+		blk = addBlock(blk_idx) ;
+		if(blk)
+		{
+			p = blk->allocate() ;
+
+			if(blk->isFull())
+			{
+				popAvailBlockList(blk_idx) ;
+			}
+		}
+	}
+
+	//ask for space from larger blocks
+	if(!p)
+	{
+		for(S32 i = blk_idx + 1 ; i < mBlockLevels; i++)
+		{
+			if(mAvailBlockList[i])
+			{
+				blk = mAvailBlockList[i] ;
+				p = blk->allocate() ;
+
+				if(blk->isFull())
+				{
+					popAvailBlockList(i) ;
+				}
+				break ;
+			}
+		}
+	}
+
+	if(p && blk)
+	{		
+		mAlloatedSize += blk->getSlotSize() ;
+	}
+	return p ;
+}
+
+void LLPrivateMemoryPool::LLMemoryChunk::freeMem(void* addr)
+{	
+	U32 blk_idx = getPageIndex((U32)addr) ;
+	LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ;
+	blk = blk->mSelf ;
+
+	bool was_full = blk->isFull() ;
+	blk->freeMem(addr) ;
+	mAlloatedSize -= blk->getSlotSize() ;
+
+	if(blk->empty())
+	{
+		removeBlock(blk) ;
+	}
+	else if(was_full)
+	{
+		addToAvailBlockList(blk) ;
+	}	
+}
+
+bool LLPrivateMemoryPool::LLMemoryChunk::empty()
+{
+	return !mAlloatedSize ;
+}
+
+bool LLPrivateMemoryPool::LLMemoryChunk::containsAddress(const char* addr) const
+{
+	return (U32)mBuffer <= (U32)addr && (U32)mBuffer + mBufferSize > (U32)addr ;
+}
+
+//debug use
+void LLPrivateMemoryPool::LLMemoryChunk::dump()
+{
+#if 0
+	//sanity check
+	//for(S32 i = 0 ; i < mBlockLevels ; i++)
+	//{
+	//	LLMemoryBlock* blk = mAvailBlockList[i] ;
+	//	while(blk)
+	//	{
+	//		blk_list.push_back(blk) ;
+	//		blk = blk->mNext ;
+	//	}
+	//}
+	for(S32 i = 0 ; i < mPartitionLevels ; i++)
+	{
+		LLMemoryBlock* blk = mFreeSpaceList[i] ;
+		while(blk)
+		{
+			blk_list.push_back(blk) ;
+			blk = blk->mNext ;
+		}
+	}
+
+	std::sort(blk_list.begin(), blk_list.end(), LLMemoryBlock::CompareAddress());
+
+	U32 total_size = blk_list[0]->getBufferSize() ;
+	for(U32 i = 1 ; i < blk_list.size(); i++)
+	{
+		total_size += blk_list[i]->getBufferSize() ;
+		if((U32)blk_list[i]->getBuffer() < (U32)blk_list[i-1]->getBuffer() + blk_list[i-1]->getBufferSize())
+		{
+			llerrs << "buffer corrupted." << llendl ;
+		}
+	}
+
+	llassert_always(total_size + mMinBlockSize >= mBufferSize - ((U32)mDataBuffer - (U32)mBuffer)) ;
+
+	U32 blk_num = (mBufferSize - (mDataBuffer - mBuffer)) / mMinBlockSize ;
+	for(U32 i = 0 ; i < blk_num ; )
+	{
+		LLMemoryBlock* blk = &mBlocks[i] ;
+		if(blk->mSelf)
+		{
+			U32 end = blk->getBufferSize() / mMinBlockSize ;
+			for(U32 j = 0 ; j < end ; j++)
+			{
+				llassert_always(blk->mSelf == blk || !blk->mSelf) ;
+			}
+			i += end ;
+		}
+		else
+		{
+			llerrs << "gap happens" << llendl ;
+		}
+	}
+#endif
+#if 0
+	llinfos << "---------------------------" << llendl ;
+	llinfos << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << llendl ;
+
+	llinfos << "available blocks ... " << llendl ;
+	for(S32 i = 0 ; i < mBlockLevels ; i++)
+	{
+		LLMemoryBlock* blk = mAvailBlockList[i] ;
+		while(blk)
+		{
+			llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ;
+			blk = blk->mNext ;
+		}
+	}
+
+	llinfos << "free blocks ... " << llendl ;
+	for(S32 i = 0 ; i < mPartitionLevels ; i++)
+	{
+		LLMemoryBlock* blk = mFreeSpaceList[i] ;
+		while(blk)
+		{
+			llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ;
+			blk = blk->mNext ;
+		}
+	}
+#endif
+}
+
+//compute the size for a block, the size is round to integer times of mMinBlockSize.
+U32 LLPrivateMemoryPool::LLMemoryChunk::calcBlockSize(U32 slot_size)
+{
+	//
+	//Note: we try to make a block to have 32 slots if the size is not over 32 pages
+	//32 is the number of bits of an integer in a 32-bit system
+	//
+
+	U32 block_size;
+	U32 cut_off_size = llmin(CUT_OFF_SIZE, (U32)(mMinBlockSize << 5)) ;
+
+	if((slot_size << 5) <= mMinBlockSize)//for small allocations, return one page 
+	{
+		block_size = mMinBlockSize ;
+	}
+	else if(slot_size >= cut_off_size)//for large allocations, return one-slot block
+	{
+		block_size = (slot_size / mMinBlockSize) * mMinBlockSize ;
+		if(block_size < slot_size)
+		{
+			block_size += mMinBlockSize ;
+		}
+	}
+	else //medium allocations
+	{
+		if((slot_size << 5) >= cut_off_size)
+		{
+			block_size = cut_off_size ;
+		}
+		else
+		{
+			block_size = ((slot_size << 5) / mMinBlockSize) * mMinBlockSize ;
+		}
+	}
+
+	llassert_always(block_size >= slot_size) ;
+
+	return block_size ;
+}
+
+//create a new block in the chunk
+LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock(U32 blk_idx)
+{	
+	U32 slot_size = mMinSlotSize * (blk_idx + 1) ;
+	U32 preferred_block_size = calcBlockSize(slot_size) ;	
+	U16 idx = getPageLevel(preferred_block_size); 
+	LLMemoryBlock* blk = NULL ;
+	
+	if(mFreeSpaceList[idx])//if there is free slot for blk_idx
+	{
+		blk = createNewBlock(mFreeSpaceList[idx], preferred_block_size, slot_size, blk_idx) ;
+	}
+	else if(mFreeSpaceList[mPartitionLevels - 1]) //search free pool
+	{		
+		blk = createNewBlock(mFreeSpaceList[mPartitionLevels - 1], preferred_block_size, slot_size, blk_idx) ;
+	}
+	else //search for other non-preferred but enough space slot.
+	{
+		S32 min_idx = 0 ;
+		if(slot_size > mMinBlockSize)
+		{
+			min_idx = getPageLevel(slot_size) ;
+		}
+		for(S32 i = (S32)idx - 1 ; i >= min_idx ; i--) //search the small slots first
+		{
+			if(mFreeSpaceList[i])
+			{
+				U32 new_preferred_block_size = mFreeSpaceList[i]->getBufferSize();
+				new_preferred_block_size = (new_preferred_block_size / mMinBlockSize) * mMinBlockSize ; //round to integer times of mMinBlockSize.
+
+				//create a NEW BLOCK THERE.
+				if(new_preferred_block_size >= slot_size) //at least there is space for one slot.
+				{
+					
+					blk = createNewBlock(mFreeSpaceList[i], new_preferred_block_size, slot_size, blk_idx) ;
+				}
+				break ;
+			} 
+		}
+
+		if(!blk)
+		{
+			for(U16 i = idx + 1 ; i < mPartitionLevels - 1; i++) //search the large slots 
+			{
+				if(mFreeSpaceList[i])
+				{
+					//create a NEW BLOCK THERE.
+					blk = createNewBlock(mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ;
+					break ;
+				} 
+			}
+		}
+	}
+
+	return blk ;
+}
+
+//create a new block at the designed location
+LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx)
+{
+	//unlink from the free space
+	removeFromFreeSpace(blk) ;
+
+	//check the rest space
+	U32 new_free_blk_size = blk->getBufferSize() - buffer_size ;	
+	if(new_free_blk_size < mMinBlockSize) //can not partition the memory into size smaller than mMinBlockSize
+	{
+		new_free_blk_size = 0 ; //discard the last small extra space.
+	}			
+
+	//add the rest space back to the free list
+	if(new_free_blk_size > 0) //blk still has free space
+	{
+		LLMemoryBlock* next_blk = blk + (buffer_size / mMinBlockSize) ;
+		next_blk->mPrev = NULL ;
+		next_blk->mNext = NULL ;
+		next_blk->setBuffer(blk->getBuffer() + buffer_size, new_free_blk_size) ;
+		addToFreeSpace(next_blk) ;
+	}
+
+	blk->init(blk->getBuffer(), buffer_size, slot_size) ;
+	//insert to the available block list...
+	mAvailBlockList[blk_idx] = blk ;
+
+	//mark the address map: all blocks covered by this block space pointing back to this block.
+	U32 end = (buffer_size / mMinBlockSize) ;
+	for(U32 i = 1 ; i < end ; i++)
+	{
+		(blk + i)->mSelf = blk ;
+	}
+
+	return blk ;
+}
+
+//delete a block, release the block to the free pool.
+void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk)
+{
+	//remove from the available block list
+	if(blk->mPrev)
+	{
+		blk->mPrev->mNext = blk->mNext ;
+	}
+	if(blk->mNext)
+	{
+		blk->mNext->mPrev = blk->mPrev ;
+	}
+	U32 blk_idx = getBlockLevel(blk->getSlotSize());
+	if(mAvailBlockList[blk_idx] == blk)
+	{
+		mAvailBlockList[blk_idx] = blk->mNext ;
+	}
+
+	blk->mNext = NULL ;
+	blk->mPrev = NULL ;
+	
+	//mark it free
+	blk->setBuffer(blk->getBuffer(), blk->getBufferSize()) ;
+
+#if 1
+	//merge blk with neighbors if possible
+	if(blk->getBuffer() > mDataBuffer) //has the left neighbor
+	{
+		if((blk - 1)->mSelf->isFree())
+		{
+			LLMemoryBlock* left_blk = (blk - 1)->mSelf ;
+			removeFromFreeSpace((blk - 1)->mSelf);
+			left_blk->setBuffer(left_blk->getBuffer(), left_blk->getBufferSize() + blk->getBufferSize()) ;
+			blk = left_blk ;
+		}
+	}
+	if(blk->getBuffer() + blk->getBufferSize() <= mBuffer + mBufferSize - mMinBlockSize) //has the right neighbor
+	{
+		U32 d = blk->getBufferSize() / mMinBlockSize ;
+		if((blk + d)->isFree())
+		{
+			LLMemoryBlock* right_blk = blk + d ;
+			removeFromFreeSpace(blk + d) ;
+			blk->setBuffer(blk->getBuffer(), blk->getBufferSize() + right_blk->getBufferSize()) ;
+		}
+	}
+#endif
+	
+	addToFreeSpace(blk) ;
+
+	return ;
+}
+
+//the top block in the list is full, pop it out of the list
+void LLPrivateMemoryPool::LLMemoryChunk::popAvailBlockList(U32 blk_idx) 
+{
+	if(mAvailBlockList[blk_idx])
+	{
+		LLMemoryBlock* next = mAvailBlockList[blk_idx]->mNext ;
+		if(next)
+		{
+			next->mPrev = NULL ;
+		}
+		mAvailBlockList[blk_idx]->mPrev = NULL ;
+		mAvailBlockList[blk_idx]->mNext = NULL ;
+		mAvailBlockList[blk_idx] = next ;
+	}
+}
+
+//add the block back to the free pool
+void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) 
+{
+	llassert_always(!blk->mPrev) ;
+	llassert_always(!blk->mNext) ;
+
+	U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1;
+
+	(blk + free_idx)->mSelf = blk ; //mark the end pointing back to the head.
+	free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ;
+
+	blk->mNext = mFreeSpaceList[free_idx] ;
+	if(mFreeSpaceList[free_idx])
+	{
+		mFreeSpaceList[free_idx]->mPrev = blk ;
+	}
+	mFreeSpaceList[free_idx] = blk ;
+	blk->mPrev = NULL ;
+	blk->mSelf = blk ;
+	
+	return ;
+}
+
+//remove the space from the free pool
+void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) 
+{
+	U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1;
+	free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ;
+
+	if(mFreeSpaceList[free_idx] == blk)
+	{
+		mFreeSpaceList[free_idx] = blk->mNext ;
+	}
+	if(blk->mPrev)
+	{
+		blk->mPrev->mNext = blk->mNext ;
+	}
+	if(blk->mNext)
+	{
+		blk->mNext->mPrev = blk->mPrev ;
+	}
+	blk->mNext = NULL ;
+	blk->mPrev = NULL ;
+	blk->mSelf = NULL ;
+
+	return ;
+}
+
+void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) 
+{
+	llassert_always(!blk->mPrev) ;
+	llassert_always(!blk->mNext) ;
+
+	U32 blk_idx = getBlockLevel(blk->getSlotSize());
+
+	blk->mNext = mAvailBlockList[blk_idx] ;
+	if(blk->mNext)
+	{
+		blk->mNext->mPrev = blk ;
+	}
+	blk->mPrev = NULL ;
+	mAvailBlockList[blk_idx] = blk ;
+
+	return ;
+}
+
+U32 LLPrivateMemoryPool::LLMemoryChunk::getPageIndex(U32 addr)
+{
+	return (addr - (U32)mDataBuffer) / mMinBlockSize ;
+}
+
+//for mAvailBlockList
+U32 LLPrivateMemoryPool::LLMemoryChunk::getBlockLevel(U32 size)
+{
+	llassert(size >= mMinSlotSize && size <= mMaxSlotSize) ;
+
+	//start from 0
+	return (size + mMinSlotSize - 1) / mMinSlotSize - 1 ;
+}
+
+//for mFreeSpaceList
+U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size)
+{
+	//start from 0
+	U16 level = size / mMinBlockSize - 1 ;
+	if(level >= mPartitionLevels)
+	{
+		level = mPartitionLevels - 1 ;
+	}
+	return level ;
+}
+
+//-------------------------------------------------------------------
+//class LLPrivateMemoryPool
+//--------------------------------------------------------------------
+const U32 CHUNK_SIZE = 4 << 20 ; //4 MB
+const U32 LARGE_CHUNK_SIZE = 4 * CHUNK_SIZE ; //16 MB
+LLPrivateMemoryPool::LLPrivateMemoryPool(S32 type) :
+	mMutexp(NULL),	
+	mReservedPoolSize(0),
+	mHashFactor(1),
+	mType(type)
+{
+	const U32 MAX_POOL_SIZE = 256 * 1024 * 1024 ; //256 MB
+
+	mMaxPoolSize = MAX_POOL_SIZE ;
+	if(type == STATIC_THREADED || type == VOLATILE_THREADED)
+	{
+		mMutexp = new LLMutex ;
+	}
+
+	for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++)
+	{
+		mChunkList[i] = NULL ;
+	}	
+	
+	mNumOfChunks = 0 ;
+}
+
+LLPrivateMemoryPool::~LLPrivateMemoryPool()
+{
+	destroyPool();
+	delete mMutexp ;
+}
+
+char* LLPrivateMemoryPool::allocate(U32 size)
+{	
+	if(!size)
+	{
+		return NULL ;
+	}
+
+	//if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it
+	if(size >= CHUNK_SIZE)
+	{
+		return (char*)malloc(size) ;
+	}
+
+	char* p = NULL ;
+
+	//find the appropriate chunk
+	S32 chunk_idx = getChunkIndex(size) ;
+	
+	lock() ;
+
+	LLMemoryChunk* chunk = mChunkList[chunk_idx];
+	while(chunk)
+	{
+		if((p = chunk->allocate(size)))
+		{
+			break ;
+		}
+		chunk = chunk->mNext ;
+	}
+	
+	//fetch new memory chunk
+	if(!p)
+	{
+		if(mReservedPoolSize + CHUNK_SIZE > mMaxPoolSize)
+		{
+			chunk = mChunkList[chunk_idx];
+			while(chunk)
+			{
+				if((p = chunk->allocate(size)))
+				{
+					break ;
+				}
+				chunk = chunk->mNext ;
+			}
+		}
+
+		chunk = addChunk(chunk_idx) ;
+		if(chunk)
+		{
+			p = chunk->allocate(size) ;
+		}
+	}
+
+	unlock() ;
+
+	return p ;
+}
+
+void LLPrivateMemoryPool::freeMem(void* addr)
+{
+	if(!addr)
+	{
+		return ;
+	}
+	
+	lock() ;
+	
+	LLMemoryChunk* chunk = findChunk((char*)addr) ;
+	
+	if(!chunk)
+	{
+		free(addr) ; //release from heap
+	}
+	else
+	{
+		chunk->freeMem(addr) ;
+
+		if(chunk->empty())
+		{
+			removeChunk(chunk) ;
+		}
+	}
+	
+	unlock() ;
+}
+
+void LLPrivateMemoryPool::dump()
+{
+}
+
+U32 LLPrivateMemoryPool::getTotalAllocatedSize()
+{
+	U32 total_allocated = 0 ;
+
+	LLMemoryChunk* chunk ;
+	for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++)
+	{
+		chunk = mChunkList[i];
+		while(chunk)
+		{
+			total_allocated += chunk->getAllocatedSize() ;
+			chunk = chunk->mNext ;
+		}
+	}
+
+	return total_allocated ;
+}
+
+void LLPrivateMemoryPool::lock()
+{
+	if(mMutexp)
+	{
+		mMutexp->lock() ;
+	}
+}
+
+void LLPrivateMemoryPool::unlock()
+{
+	if(mMutexp)
+	{
+		mMutexp->unlock() ;
+	}
+}
+
+S32  LLPrivateMemoryPool::getChunkIndex(U32 size) 
+{
+	S32 i ;
+	for(i = 0 ; size > MAX_SLOT_SIZES[i]; i++);
+	
+	llassert_always(i < SUPER_ALLOCATION);
+
+	return i ;
+}
+
+//destroy the entire pool
+void  LLPrivateMemoryPool::destroyPool()
+{
+	lock() ;
+
+	if(mNumOfChunks > 0)
+	{
+		llwarns << "There is some memory not freed when destroy the memory pool!" << llendl ;
+	}
+
+	mNumOfChunks = 0 ;
+	mChunkHashList.clear() ;
+	mHashFactor = 1 ;
+	for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++)
+	{
+		mChunkList[i] = NULL ;
+	}
+
+	unlock() ;
+}
+
+void  LLPrivateMemoryPool::checkSize(U32 asked_size)
+{
+	if(mReservedPoolSize + asked_size > mMaxPoolSize)
+	{
+		llinfos << "Max pool size: " << mMaxPoolSize << llendl ;
+		llinfos << "Total reserved size: " << mReservedPoolSize + asked_size << llendl ;
+		llinfos << "Total_allocated Size: " << getTotalAllocatedSize() << llendl ;
+
+		llerrs << "The pool is overflowing..." << llendl ;
+	}
+}
+
+LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_index)
+{
+	U32 preferred_size ;
+	U32 overhead ;
+	if(chunk_index < LARGE_ALLOCATION)
+	{
+		preferred_size = CHUNK_SIZE ; //4MB
+		overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_SLOT_SIZES[chunk_index],
+			MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ;
+	}
+	else
+	{
+		preferred_size = LARGE_CHUNK_SIZE ; //16MB
+		overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_SLOT_SIZES[chunk_index], 
+			MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ;
+	}
+
+	checkSize(preferred_size + overhead) ;
+	mReservedPoolSize += preferred_size + overhead ;
+
+	char* buffer = (char*)malloc(preferred_size + overhead) ;
+	if(!buffer)
+	{
+		return NULL ;
+	}
+	
+	LLMemoryChunk* chunk = new (buffer) LLMemoryChunk() ;
+	chunk->init(buffer, preferred_size + overhead, MIN_SLOT_SIZES[chunk_index],
+		MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ;
+
+	//add to the tail of the linked list
+	{
+		if(!mChunkList[chunk_index])
+		{
+			mChunkList[chunk_index] = chunk ;
+		}
+		else
+		{
+			LLMemoryChunk* cur = mChunkList[chunk_index] ;
+			while(cur->mNext)
+			{
+				cur = cur->mNext ;
+			}
+			cur->mNext = chunk ;
+			chunk->mPrev = cur ;
+		}
+	}
+
+	//insert into the hash table
+	addToHashTable(chunk) ;
+	
+	mNumOfChunks++;
+
+	return chunk ;
+}
+
+void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) 
+{
+	if(!chunk)
+	{
+		return ;
+	}
+
+	//remove from the linked list
+	for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++)
+	{
+		if(mChunkList[i] == chunk)
+		{
+			mChunkList[i] = chunk->mNext ;
+		}
+	}
+
+	if(chunk->mPrev)
+	{
+		chunk->mPrev->mNext = chunk->mNext ;
+	}
+	if(chunk->mNext)
+	{
+		chunk->mNext->mPrev = chunk->mPrev ;
+	}
+
+	//remove from the hash table
+	removeFromHashTable(chunk) ;
+	
+	mNumOfChunks--;
+	mReservedPoolSize -= chunk->getBufferSize() ;
+	
+	//release memory
+	free(chunk->getBuffer()) ;
+}
+
+U16 LLPrivateMemoryPool::findHashKey(const char* addr)
+{
+	return (((U32)addr) / CHUNK_SIZE) % mHashFactor ;
+}
+
+LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr)
+{
+	U16 key = findHashKey(addr) ;	
+	if(mChunkHashList.size() <= key)
+	{
+		return NULL ;
+	}
+
+	return mChunkHashList[key].findChunk(addr) ;	
+}
+
+void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) 
+{
+	static const U16 HASH_FACTORS[] = {41, 83, 193, 317, 419, 523, 0xFFFF}; 
+	
+	U16 i ;
+	if(mChunkHashList.empty())
+	{
+		mHashFactor = HASH_FACTORS[0] ;
+		rehash() ;		
+	}
+
+	U16 start_key = findHashKey(chunk->getBuffer()) ;
+	U16 end_key = findHashKey(chunk->getBuffer() + chunk->getBufferSize() - 1) ;
+	bool need_rehash = false ;
+	
+	if(mChunkHashList[start_key].hasElement(chunk))
+	{
+		return; //already inserted.
+	}
+	need_rehash = mChunkHashList[start_key].add(chunk) ;
+	
+	if(start_key == end_key && !need_rehash)
+	{
+		return ; //done
+	}
+
+	if(!need_rehash)
+	{
+		need_rehash = mChunkHashList[end_key].add(chunk) ;
+	}
+
+	if(!need_rehash)
+	{
+		if(end_key < start_key)
+		{
+			need_rehash = fillHashTable(start_key + 1, mHashFactor, chunk) ;
+			if(!need_rehash)
+			{
+				need_rehash = fillHashTable(0, end_key, chunk) ;
+			}
+		}
+		else
+		{
+			need_rehash = fillHashTable(start_key + 1, end_key, chunk) ;
+		}
+	}
+	
+	if(need_rehash)
+	{
+		i = 0 ;
+		while(HASH_FACTORS[i] <= mHashFactor) i++;
+
+		mHashFactor = HASH_FACTORS[i] ;
+		llassert_always(mHashFactor != 0xFFFF) ;//stop point to prevent endlessly recursive calls
+
+		rehash() ;
+	}
+}
+
+void LLPrivateMemoryPool::removeFromHashTable(LLMemoryChunk* chunk) 
+{
+	U16 start_key = findHashKey(chunk->getBuffer()) ;
+	U16 end_key = findHashKey(chunk->getBuffer() + chunk->getBufferSize() - 1) ;
+	
+	mChunkHashList[start_key].remove(chunk) ;
+	if(start_key == end_key)
+	{
+		return ; //done
+	}
+
+	mChunkHashList[end_key].remove(chunk) ;
+	
+	if(end_key < start_key)
+	{
+		for(U16 i = start_key + 1 ; i < mHashFactor; i++)
+		{
+			mChunkHashList[i].remove(chunk) ;
+		}
+		for(U16 i = 0 ; i < end_key; i++)
+		{
+			mChunkHashList[i].remove(chunk) ;
+		}
+	}
+	else
+	{
+		for(U16 i = start_key + 1 ; i < end_key; i++)
+		{
+			mChunkHashList[i].remove(chunk) ;
+		}
+	}
+}
+
+void LLPrivateMemoryPool::rehash()
+{
+	llinfos << "new hash factor: " << mHashFactor << llendl ;
+
+	mChunkHashList.clear() ;
+	mChunkHashList.resize(mHashFactor) ;
+
+	LLMemoryChunk* chunk ;
+	for(U16 i = 0 ; i < SUPER_ALLOCATION ; i++)
+	{
+		chunk = mChunkList[i] ; 
+		while(chunk)
+		{
+			addToHashTable(chunk) ;
+			chunk = chunk->mNext ;
+		}
+	}
+}
+
+bool LLPrivateMemoryPool::fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk)
+{
+	for(U16 i = start; i < end; i++)
+	{
+		if(mChunkHashList[i].add(chunk))
+		{			
+			return true ;
+		}		
+	}
+
+	return false ;
+}
+
+//--------------------------------------------------------------------
+// class LLChunkHashElement
+//--------------------------------------------------------------------
+LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::LLChunkHashElement::findChunk(const char* addr)
+{
+	if(mFirst && mFirst->containsAddress(addr))
+	{
+		return mFirst ;
+	}
+	else if(mSecond && mSecond->containsAddress(addr))
+	{
+		return mSecond ;
+	}
+
+	return NULL ;
+}
+
+//return false if successfully inserted to the hash slot.
+bool LLPrivateMemoryPool::LLChunkHashElement::add(LLPrivateMemoryPool::LLMemoryChunk* chunk)
+{
+	llassert_always(!hasElement(chunk)) ;
+
+	if(!mFirst)
+	{
+		mFirst = chunk ;
+	}
+	else if(!mSecond)
+	{
+		mSecond = chunk ;
+	}
+	else
+	{
+		return true ; //failed
+	}
+
+	return false ;
+}
+
+void LLPrivateMemoryPool::LLChunkHashElement::remove(LLPrivateMemoryPool::LLMemoryChunk* chunk)
+{
+	if(mFirst == chunk)
+	{
+		mFirst = NULL ;
+	}
+	else if(mSecond ==chunk)
+	{
+		mSecond = NULL ;
+	}
+	else
+	{
+		llerrs << "This slot does not contain this chunk!" << llendl ;
+	}
+}
+
+//--------------------------------------------------------------------
+//class LLPrivateMemoryPoolManager
+//--------------------------------------------------------------------
+LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ;
+
+LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager(BOOL enabled) 
+{
+	mPoolList.resize(LLPrivateMemoryPool::MAX_TYPES) ;
+
+	for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++)
+	{
+		mPoolList[i] = NULL ;
+	}
+
+	mPrivatePoolEnabled = enabled ;
+}
+
+LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() 
+{
+
+#if __DEBUG_PRIVATE_MEM__
+	if(!sMemAllocationTracker.empty())
+	{
+		llwarns << "there is potential memory leaking here. The list of not freed memory blocks are from: " <<llendl ;
+
+		S32 k = 0 ;
+		for(mem_allocation_info_t::iterator iter = sMemAllocationTracker.begin() ; iter != sMemAllocationTracker.end() ; ++iter)
+		{
+			llinfos << k++ << ", " << iter->second << llendl ;
+		}
+		sMemAllocationTracker.clear() ;
+	}
+#endif
+
+#if 0
+	//all private pools should be released by their owners before reaching here.
+	for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++)
+	{
+		llassert_always(!mPoolList[i]) ;
+	}
+	mPoolList.clear() ;
+
+#else
+	//forcefully release all memory
+	for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++)
+	{
+		if(mPoolList[i])
+		{
+			delete mPoolList[i] ;
+			mPoolList[i] = NULL ;
+		}
+	}
+	mPoolList.clear() ;
+#endif
+}
+
+//static 
+void LLPrivateMemoryPoolManager::initClass(BOOL enabled) 
+{
+	llassert_always(!sInstance) ;
+
+	sInstance = new LLPrivateMemoryPoolManager(enabled) ;
+}
+
+//static 
+LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::getInstance() 
+{
+	//if(!sInstance)
+	//{
+	//	sInstance = new LLPrivateMemoryPoolManager(FALSE) ;
+	//}
+	return sInstance ;
+}
+	
+//static 
+void LLPrivateMemoryPoolManager::destroyClass() 
+{
+	if(sInstance)
+	{
+		delete sInstance ;
+		sInstance = NULL ;
+	}
+}
+
+LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(S32 type) 
+{
+	if(!mPrivatePoolEnabled)
+	{
+		return NULL ;
+	}
+
+	if(!mPoolList[type])
+	{
+		mPoolList[type] = new LLPrivateMemoryPool(type) ;
+	}
+
+	return mPoolList[type] ;
+}
+
+void LLPrivateMemoryPoolManager::deletePool(LLPrivateMemoryPool* pool) 
+{
+	if(pool && pool->isEmpty())
+	{
+		mPoolList[pool->getType()] = NULL ;
+		delete pool;
+	}
+}
+
+//debug
+void LLPrivateMemoryPoolManager::updateStatistics()
+{
+	mTotalReservedSize = 0 ;
+	mTotalAllocatedSize = 0 ;
+
+	for(U32 i = 0; i < mPoolList.size(); i++)
+	{
+		if(mPoolList[i])
+		{
+			mTotalReservedSize += mPoolList[i]->getTotalReservedSize() ;
+			mTotalAllocatedSize += mPoolList[i]->getTotalAllocatedSize() ;
+		}
+	}
+}
+
+#if __DEBUG_PRIVATE_MEM__
+//static 
+char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) 
+{
+	char* p ;
+
+	if(!poolp)
+	{
+		p = (char*)malloc(size) ;
+	}
+	else
+	{
+		p = poolp->allocate(size) ;
+	}
+	
+	if(p)
+	{
+		char num[16] ;
+		sprintf(num, " line: %d ", line) ;
+		std::string str(function) ;
+		str += num; 
+
+		sMemAllocationTracker[p] = str ;
+	}
+
+	return p ;
+}	
+#else
+//static 
+char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size) 
+{
+	if(poolp)
+	{
+		return poolp->allocate(size) ;		
+	}
+	else
+	{
+		return (char*)malloc(size) ;
+	}
+}
+#endif
+
+//static 
+void  LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr) 
+{
+	if(!addr)
+	{
+		return ;
+	}
+
+#if __DEBUG_PRIVATE_MEM__
+	sMemAllocationTracker.erase((char*)addr) ;
+#endif
+
+	if(poolp)
+	{
+		poolp->freeMem(addr) ;
+	}
+	else
+	{
+		free(addr) ;
+	}	
+}
+
+//--------------------------------------------------------------------
+//class LLPrivateMemoryPoolTester
+//--------------------------------------------------------------------
+#if 0
+LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::sInstance = NULL ;
+LLPrivateMemoryPool* LLPrivateMemoryPoolTester::sPool = NULL ;
+LLPrivateMemoryPoolTester::LLPrivateMemoryPoolTester()
+{	
+}
+	
+LLPrivateMemoryPoolTester::~LLPrivateMemoryPoolTester() 
+{	
+}
+
+//static 
+LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::getInstance() 
+{
+	if(!sInstance)
+	{
+		sInstance = ::new LLPrivateMemoryPoolTester() ;
+	}
+	return sInstance ;
+}
+
+//static 
+void LLPrivateMemoryPoolTester::destroy()
+{
+	if(sInstance)
+	{
+		::delete sInstance ;
+		sInstance = NULL ;
+	}
+
+	if(sPool)
+	{
+		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ;
+		sPool = NULL ;
+	}
+}
+
+void LLPrivateMemoryPoolTester::run(S32 type) 
+{
+	if(sPool)
+	{
+		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ;
+	}
+	sPool = LLPrivateMemoryPoolManager::getInstance()->newPool(type) ;
+
+	//run the test
+	correctnessTest() ;
+	performanceTest() ;
+	//fragmentationtest() ;
+
+	//release pool.
+	LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ;
+	sPool = NULL ;
+}
+
+void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 times, 
+									 bool random_deletion, bool output_statistics)
+{
+	U32 levels = (max_size - min_size) / stride + 1 ;
+	char*** p ;
+	U32 i, j ;
+	U32 total_allocated_size = 0 ;
+
+	//allocate space for p ;
+	if(!(p = ::new char**[times]) || !(*p = ::new char*[times * levels]))
+	{
+		llerrs << "memory initialization for p failed" << llendl ;
+	}
+
+	//init
+	for(i = 0 ; i < times; i++)
+	{
+		p[i] = *p + i * levels ;
+		for(j = 0 ; j < levels; j++)
+		{
+			p[i][j] = NULL ;
+		}
+	}
+
+	//allocation
+	U32 size ;
+	for(i = 0 ; i < times ; i++)
+	{
+		for(j = 0 ; j < levels; j++) 
+		{
+			size = min_size + j * stride ;
+			p[i][j] = ALLOCATE_MEM(sPool, size) ;
+
+			total_allocated_size+= size ;
+
+			*(U32*)p[i][j] = i ;
+			*((U32*)p[i][j] + 1) = j ;
+			//p[i][j][size - 1] = '\0' ; //access the last element to verify the success of the allocation.
+
+			//randomly release memory
+			if(random_deletion)
+			{
+				S32 k = rand() % levels ;
+
+				if(p[i][k])
+				{
+					llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ;
+					FREE_MEM(sPool, p[i][k]) ;
+					total_allocated_size -= min_size + k * stride ;
+					p[i][k] = NULL ;
+				}
+			}
+		}
+	}
+
+	//output pool allocation statistics
+	if(output_statistics)
+	{
+	}
+
+	//release all memory allocations
+	for(i = 0 ; i < times; i++)
+	{
+		for(j = 0 ; j < levels; j++)
+		{
+			if(p[i][j])
+			{
+				llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ;
+				FREE_MEM(sPool, p[i][j]) ;
+				total_allocated_size -= min_size + j * stride ;
+				p[i][j] = NULL ;
+			}
+		}
+	}
+
+	::delete[] *p ;
+	::delete[] p ;
+}
+
+void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times)
+{
+	LLTimer timer ;
+
+	llinfos << " -**********************- " << llendl ;
+	llinfos << "test size: " << size << " test times: " << times << llendl ;
+
+	timer.reset() ;
+	char** p = new char*[times] ;
+		
+	//using the customized memory pool
+	//allocation
+	for(U32 i = 0 ; i < times; i++)
+	{
+		p[i] = ALLOCATE_MEM(sPool, size) ;
+		if(!p[i])
+		{
+			llerrs << "allocation failed" << llendl ;
+		}
+	}
+	//de-allocation
+	for(U32 i = 0 ; i < times; i++)
+	{
+		FREE_MEM(sPool, p[i]) ;
+		p[i] = NULL ;
+	}
+	llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ;
+
+	timer.reset() ;
+
+	//using the standard allocator/de-allocator:
+	//allocation
+	for(U32 i = 0 ; i < times; i++)
+	{
+		p[i] = ::new char[size] ;
+		if(!p[i])
+		{
+			llerrs << "allocation failed" << llendl ;
+		}
+	}
+	//de-allocation
+	for(U32 i = 0 ; i < times; i++)
+	{
+		::delete[] p[i] ;
+		p[i] = NULL ;
+	}
+	llinfos << "time spent using standard allocator/de-allocator: " << timer.getElapsedTimeF32() << llendl ;
+
+	delete[] p;
+}
+
+void LLPrivateMemoryPoolTester::correctnessTest() 
+{
+	//try many different sized allocation, and all kinds of edge cases, access the allocated memory 
+	//to see if allocation is right.
+	
+	//edge case
+	char* p = ALLOCATE_MEM(sPool, 0) ;
+	FREE_MEM(sPool, p) ;
+
+	//small sized
+	// [8 bytes, 2KB), each asks for 256 allocations and deallocations
+	test(8, 2040, 8, 256, true, true) ;
+	
+	//medium sized
+	//[2KB, 512KB), each asks for 16 allocations and deallocations
+	test(2048, 512 * 1024 - 2048, 2048, 16, true, true) ;
+
+	//large sized
+	//[512KB, 4MB], each asks for 8 allocations and deallocations
+	test(512 * 1024, 4 * 1024 * 1024, 64 * 1024, 6, true, true) ;
+}
+
+void LLPrivateMemoryPoolTester::performanceTest() 
+{
+	U32 test_size[3] = {768, 3* 1024, 3* 1024 * 1024};
+	
+	//small sized
+	testAndTime(test_size[0], 8) ;
+	
+	//medium sized
+	testAndTime(test_size[1], 8) ;
+
+	//large sized
+	testAndTime(test_size[2], 8) ;
+}
+
+void LLPrivateMemoryPoolTester::fragmentationtest() 
+{
+	//for internal fragmentation statistics:
+	//every time when asking for a new chunk during correctness test, and performance test,
+	//print out the chunk usage statistices.
+}
+#endif
+//--------------------------------------------------------------------
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 3bd14035768e31b1859e33645f4924d8319cffed..db753f0d8ba19c239decb6024f983f60d491b6d5 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -27,7 +27,6 @@
 #define LLMEMORY_H
 
 #include "llmemtype.h"
-
 #if LL_DEBUG
 inline void* ll_aligned_malloc( size_t size, int align )
 {
@@ -105,6 +104,10 @@ inline void ll_aligned_free_32(void *p)
 #define ll_aligned_free_32 free
 #endif // LL_DEBUG
 
+#ifndef __DEBUG_PRIVATE_MEM__
+#define __DEBUG_PRIVATE_MEM__  0
+#endif
+
 class LL_COMMON_API LLMemory
 {
 public:
@@ -115,8 +118,24 @@ class LL_COMMON_API LLMemory
 	// Return value is zero if not known.
 	static U64 getCurrentRSS();
 	static U32 getWorkingSetSize();
+	static void* tryToAlloc(void* address, U32 size);
+	static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure);
+	static void updateMemoryInfo() ;
+	static void logMemoryInfo(BOOL update = FALSE);
+	static S32  isMemoryPoolLow();
+
+	static U32 getAvailableMemKB() ;
+	static U32 getMaxMemKB() ;
+	static U32 getAllocatedMemKB() ;
 private:
 	static char* reserveMem;
+	static U32 sAvailPhysicalMemInKB ;
+	static U32 sMaxPhysicalMemInKB ;
+	static U32 sAllocatedMemInKB;
+	static U32 sAllocatedPageSizeInKB ;
+
+	static U32 sMaxHeapSizeInKB;
+	static BOOL sEnableMemoryFailurePrevention;
 };
 
 //----------------------------------------------------------------------------
@@ -163,6 +182,326 @@ class LL_COMMON_API LLMemTracker
 
 //----------------------------------------------------------------------------
 
+
+//
+//class LLPrivateMemoryPool defines a private memory pool for an application to use, so the application does not
+//need to access the heap directly fro each memory allocation. Throught this, the allocation speed is faster, 
+//and reduces virtaul address space gragmentation problem.
+//Note: this class is thread-safe by passing true to the constructor function. However, you do not need to do this unless
+//you are sure the memory allocation and de-allocation will happen in different threads. To make the pool thread safe
+//increases allocation and deallocation cost.
+//
+class LL_COMMON_API LLPrivateMemoryPool
+{
+	friend class LLPrivateMemoryPoolManager ;
+
+public:
+	class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly
+	{
+	public: 
+		LLMemoryBlock() ;
+		~LLMemoryBlock() ;
+
+		void init(char* buffer, U32 buffer_size, U32 slot_size) ;
+		void setBuffer(char* buffer, U32 buffer_size) ;
+
+		char* allocate() ;
+		void  freeMem(void* addr) ;
+
+		bool empty() {return !mAllocatedSlots;}
+		bool isFull() {return mAllocatedSlots == mTotalSlots;}
+		bool isFree() {return !mTotalSlots;}
+
+		U32  getSlotSize()const {return mSlotSize;}
+		U32  getTotalSlots()const {return mTotalSlots;}
+		U32  getBufferSize()const {return mBufferSize;}
+		char* getBuffer() const {return mBuffer;}
+
+		//debug use
+		void resetBitMap() ;
+	private:
+		char* mBuffer;
+		U32   mSlotSize ; //when the block is not initialized, it is the buffer size.
+		U32   mBufferSize ;
+		U32   mUsageBits ;
+		U8    mTotalSlots ;
+		U8    mAllocatedSlots ;
+		U8    mDummySize ; //size of extra bytes reserved for mUsageBits.
+
+	public:
+		LLMemoryBlock* mPrev ;
+		LLMemoryBlock* mNext ;
+		LLMemoryBlock* mSelf ;
+
+		struct CompareAddress
+		{
+			bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs)
+			{
+				return (U32)lhs->getBuffer() < (U32)rhs->getBuffer();
+			}
+		};
+	};
+
+	class LL_COMMON_API LLMemoryChunk //is divided into memory blocks.
+	{
+	public:
+		LLMemoryChunk() ;
+		~LLMemoryChunk() ;
+
+		void init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
+		void setBuffer(char* buffer, U32 buffer_size) ;
+
+		bool empty() ;
+		
+		char* allocate(U32 size) ;
+		void  freeMem(void* addr) ;
+
+		char* getBuffer() const {return mBuffer;}
+		U32 getBufferSize() const {return mBufferSize;}
+		U32 getAllocatedSize() const {return mAlloatedSize;}
+
+		bool containsAddress(const char* addr) const;
+
+		static U32 getMaxOverhead(U32 data_buffer_size, U32 min_slot_size, 
+													   U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
+	
+		void dump() ;
+
+	private:
+		U32 getPageIndex(U32 addr) ;
+		U32 getBlockLevel(U32 size) ;
+		U16 getPageLevel(U32 size) ;
+		LLMemoryBlock* addBlock(U32 blk_idx) ;
+		void popAvailBlockList(U32 blk_idx) ;
+		void addToFreeSpace(LLMemoryBlock* blk) ;
+		void removeFromFreeSpace(LLMemoryBlock* blk) ;
+		void removeBlock(LLMemoryBlock* blk) ;
+		void addToAvailBlockList(LLMemoryBlock* blk) ;
+		U32  calcBlockSize(U32 slot_size);
+		LLMemoryBlock* createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) ;
+
+	private:
+		LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize
+		LLMemoryBlock** mFreeSpaceList;
+		LLMemoryBlock*  mBlocks ; //index of blocks by address.
+		
+		char* mBuffer ;
+		U32   mBufferSize ;
+		char* mDataBuffer ;
+		char* mMetaBuffer ;
+		U32   mMinBlockSize ;
+		U32   mMinSlotSize ;
+		U32   mMaxSlotSize ;
+		U32   mAlloatedSize ;
+		U16   mBlockLevels;
+		U16   mPartitionLevels;
+
+	public:
+		//form a linked list
+		LLMemoryChunk* mNext ;
+		LLMemoryChunk* mPrev ;
+	} ;
+
+private:
+	LLPrivateMemoryPool(S32 type) ;
+	~LLPrivateMemoryPool() ;
+
+	char *allocate(U32 size) ;
+	void  freeMem(void* addr) ;
+	
+	void  dump() ;
+	U32   getTotalAllocatedSize() ;
+	U32   getTotalReservedSize() {return mReservedPoolSize;}
+	S32   getType() const {return mType; }
+	bool  isEmpty() const {return !mNumOfChunks; }
+
+private:
+	void lock() ;
+	void unlock() ;	
+	S32 getChunkIndex(U32 size) ;
+	LLMemoryChunk*  addChunk(S32 chunk_index) ;
+	void checkSize(U32 asked_size) ;
+	void removeChunk(LLMemoryChunk* chunk) ;
+	U16  findHashKey(const char* addr);
+	void addToHashTable(LLMemoryChunk* chunk) ;
+	void removeFromHashTable(LLMemoryChunk* chunk) ;
+	void rehash() ;
+	bool fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) ;
+	LLMemoryChunk* findChunk(const char* addr) ;
+
+	void destroyPool() ;
+
+public:
+	enum
+	{
+		SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB.
+		MEDIUM_ALLOCATION,    //from 2KB to 512KB(exclusive), page size 32KB, max chunk size 4MB
+		LARGE_ALLOCATION,     //from 512KB to 4MB(inclusive), page size 64KB, max chunk size 16MB
+		SUPER_ALLOCATION      //allocation larger than 4MB.
+	};
+
+	enum
+	{
+		STATIC = 0 ,       //static pool(each alllocation stays for a long time) without threading support
+		VOLATILE,          //Volatile pool(each allocation stays for a very short time) without threading support
+		STATIC_THREADED,   //static pool with threading support
+		VOLATILE_THREADED, //volatile pool with threading support
+		MAX_TYPES
+	}; //pool types
+
+private:
+	LLMutex* mMutexp ;
+	U32  mMaxPoolSize;
+	U32  mReservedPoolSize ;	
+
+	LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address	
+	U16 mNumOfChunks ;
+	U16 mHashFactor ;
+
+	S32 mType ;
+
+	class LLChunkHashElement
+	{
+	public:
+		LLChunkHashElement() {mFirst = NULL ; mSecond = NULL ;}
+
+		bool add(LLMemoryChunk* chunk) ;
+		void remove(LLMemoryChunk* chunk) ;
+		LLMemoryChunk* findChunk(const char* addr) ;
+
+		bool empty() {return !mFirst && !mSecond; }
+		bool full()  {return mFirst && mSecond; }
+		bool hasElement(LLMemoryChunk* chunk) {return mFirst == chunk || mSecond == chunk;}
+
+	private:
+		LLMemoryChunk* mFirst ;
+		LLMemoryChunk* mSecond ;
+	};
+	std::vector<LLChunkHashElement> mChunkHashList ;
+};
+
+class LL_COMMON_API LLPrivateMemoryPoolManager
+{
+private:
+	LLPrivateMemoryPoolManager(BOOL enabled) ;
+	~LLPrivateMemoryPoolManager() ;
+
+public:	
+	static LLPrivateMemoryPoolManager* getInstance() ;
+	static void initClass(BOOL enabled) ;
+	static void destroyClass() ;
+
+	LLPrivateMemoryPool* newPool(S32 type) ;
+	void deletePool(LLPrivateMemoryPool* pool) ;
+
+private:
+	static LLPrivateMemoryPoolManager* sInstance ;
+	std::vector<LLPrivateMemoryPool*> mPoolList ;
+	BOOL mPrivatePoolEnabled;
+
+public:
+	//debug and statistics info.
+	void updateStatistics() ;
+
+	U32 mTotalReservedSize ;
+	U32 mTotalAllocatedSize ;
+
+public:
+#if __DEBUG_PRIVATE_MEM__
+	static char* allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) ;	
+	
+	typedef std::map<char*, std::string> mem_allocation_info_t ;
+	static mem_allocation_info_t sMemAllocationTracker;
+#else
+	static char* allocate(LLPrivateMemoryPool* poolp, U32 size) ;	
+#endif
+	static void  freeMem(LLPrivateMemoryPool* poolp, void* addr) ;
+};
+
+//-------------------------------------------------------------------------------------
+#if __DEBUG_PRIVATE_MEM__
+#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size), __FUNCTION__, __LINE__)
+#else
+#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size))
+#endif
+#define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr))
+//-------------------------------------------------------------------------------------
+
+//
+//the below singleton is used to test the private memory pool.
+//
+#if 0
+class LL_COMMON_API LLPrivateMemoryPoolTester
+{
+private:
+	LLPrivateMemoryPoolTester() ;
+	~LLPrivateMemoryPoolTester() ;
+
+public:
+	static LLPrivateMemoryPoolTester* getInstance() ;
+	static void destroy() ;
+
+	void run(S32 type) ;	
+
+private:
+	void correctnessTest() ;
+	void performanceTest() ;
+	void fragmentationtest() ;
+
+	void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ;
+	void testAndTime(U32 size, U32 times) ;
+
+#if 0
+public:
+	void* operator new(size_t size)
+	{
+		return (void*)sPool->allocate(size) ;
+	}
+    void  operator delete(void* addr)
+	{
+		sPool->freeMem(addr) ;
+	}
+	void* operator new[](size_t size)
+	{
+		return (void*)sPool->allocate(size) ;
+	}
+    void  operator delete[](void* addr)
+	{
+		sPool->freeMem(addr) ;
+	}
+#endif
+
+private:
+	static LLPrivateMemoryPoolTester* sInstance;
+	static LLPrivateMemoryPool* sPool ;
+	static LLPrivateMemoryPool* sThreadedPool ;
+};
+#if 0
+//static
+void* LLPrivateMemoryPoolTester::operator new(size_t size)
+{
+	return (void*)sPool->allocate(size) ;
+}
+
+//static
+void  LLPrivateMemoryPoolTester::operator delete(void* addr)
+{
+	sPool->free(addr) ;
+}
+
+//static
+void* LLPrivateMemoryPoolTester::operator new[](size_t size)
+{
+	return (void*)sPool->allocate(size) ;
+}
+
+//static
+void  LLPrivateMemoryPoolTester::operator delete[](void* addr)
+{
+	sPool->free(addr) ;
+}
+#endif
+#endif
 // LLRefCount moved to llrefcount.h
 
 // LLPointer moved to llpointer.h
diff --git a/indra/llcommon/llscopedvolatileaprpool.h b/indra/llcommon/llscopedvolatileaprpool.h
new file mode 100644
index 0000000000000000000000000000000000000000..dbaf4edcad96d1591b2ca3cd8eee13bb360a9628
--- /dev/null
+++ b/indra/llcommon/llscopedvolatileaprpool.h
@@ -0,0 +1,52 @@
+/**
+ * @file llscopedvolatileaprpool.h
+ * @brief Implementation of LLScopedVolatileAPRPool
+ *
+ * $LicenseInfo:firstyear=2010&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLSCOPEDVOLATILEAPRPOOL_H
+#define LL_LLSCOPEDVOLATILEAPRPOOL_H
+
+#include "llthread.h"
+
+/** Scoped volatile memory pool.
+ *
+ * As the LLVolatileAPRPool should never keep allocations very
+ * long, its most common use is for allocations with a lifetime
+ * equal to it's scope.
+ *
+ * This is a convenience class that makes just a little easier to type.
+ */
+class LL_COMMON_API LLScopedVolatileAPRPool
+{
+private:
+	LLVolatileAPRPool& mPool;
+	apr_pool_t* mScopedAPRpool;		// The use of apr_pool_t is OK here.
+public:
+	LLScopedVolatileAPRPool() : mPool(LLThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { }
+	~LLScopedVolatileAPRPool() { mPool.clearVolatileAPRPool(); }
+	//! @attention Only use this to pass the underlaying pointer to a libapr-1 function that requires it.
+	operator apr_pool_t*() const { return mScopedAPRpool; }		// The use of apr_pool_t is OK here.
+};
+
+#endif
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index f3b48b0156060fa66709849fd253dcf4de54edf6..e7fe6568085e8b0691f160bf312359f6f7822c42 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -936,13 +936,18 @@ LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr,
 {
 	const std::string delims (",");
 	
-	// Find the first ]
-	size_type pos2 = instr.find(']', start);
+	// Find the first [
+	size_type pos1 = instr.find('[', start);
+	if (pos1 == std::string::npos)
+		return std::string::npos;
+
+	//Find the first ] after the initial [
+	size_type pos2 = instr.find(']', pos1);
 	if (pos2 == std::string::npos)
 		return std::string::npos;
 
-	// Find the last [ before ]
-	size_type pos1 = instr.find_last_of('[', pos2-1);
+	// Find the last [ before ] in case of nested [[]]
+	pos1 = instr.find_last_of('[', pos2-1);
 	if (pos1 == std::string::npos || pos1 < start)
 		return std::string::npos;
 	
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 4063cc730b49e5b470c6f534f19dc49b4e015218..bdde1b5c48fdb4ed345029920c80a5834b71dd50 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -36,6 +36,12 @@
 #include <sched.h>
 #endif
 
+#if !LL_DARWIN
+U32 ll_thread_local local_thread_ID = 0;
+#endif 
+
+U32 LLThread::sIDIter = 0;
+
 //----------------------------------------------------------------------------
 // Usage:
 // void run_func(LLThread* thread)
@@ -56,12 +62,6 @@
 // 
 //----------------------------------------------------------------------------
 
-#if !LL_DARWIN
-U32 ll_thread_local sThreadID = 0;
-#endif 
-
-U32 LLThread::sIDIter = 0;
-
 LL_COMMON_API void assert_main_thread()
 {
 	static U32 s_thread_id = LLThread::currentID();
@@ -79,9 +79,12 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
 	LLThread *threadp = (LLThread *)datap;
 
 #if !LL_DARWIN
-	sThreadID = threadp->mID;
+	local_thread_ID = threadp->mID;
 #endif
 
+	// Create a thread local data.
+	LLThreadLocalData::create(threadp);
+
 	// Run the user supplied function
 	threadp->run();
 
@@ -94,40 +97,22 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
 }
 
 
-LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
-	mPaused(FALSE),
+LLThread::LLThread(std::string const& name) :
+	mPaused(false),
 	mName(name),
 	mAPRThreadp(NULL),
-	mStatus(STOPPED)
+	mStatus(STOPPED),
+	mThreadLocalData(NULL)
 {
-	mID = ++sIDIter;
+	mID = ++sIDIter; //flaw: assume this is called only in the main thread!
 
-	// Thread creation probably CAN be paranoid about APR being initialized, if necessary
-	if (poolp)
-	{
-		mIsLocalPool = FALSE;
-		mAPRPoolp = poolp;
-	}
-	else
-	{
-		mIsLocalPool = TRUE;
-		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
-	}
-	mRunCondition = new LLCondition(mAPRPoolp);
-
-	mLocalAPRFilePoolp = NULL ;
+	mRunCondition = new LLCondition;
 }
 
 
 LLThread::~LLThread()
 {
 	shutdown();
-
-	if(mLocalAPRFilePoolp)
-	{
-		delete mLocalAPRFilePoolp ;
-		mLocalAPRFilePoolp = NULL ;
-	}
 }
 
 void LLThread::shutdown()
@@ -164,7 +149,7 @@ void LLThread::shutdown()
 		if (!isStopped())
 		{
 			// This thread just wouldn't stop, even though we gave it time
-			//llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
+			//llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl;
 			// Put a stake in its heart.
 			apr_thread_exit(mAPRThreadp, -1);
 			return;
@@ -174,15 +159,8 @@ void LLThread::shutdown()
 
 	delete mRunCondition;
 	mRunCondition = 0;
-	
-	if (mIsLocalPool && mAPRPoolp)
-	{
-		apr_pool_destroy(mAPRPoolp);
-		mAPRPoolp = 0;
-	}
 }
 
-
 void LLThread::start()
 {
 	llassert(isStopped());
@@ -191,7 +169,7 @@ void LLThread::start()
 	mStatus = RUNNING;
 
 	apr_status_t status =
-		apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
+		apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
 	
 	if(status == APR_SUCCESS)
 	{	
@@ -216,7 +194,7 @@ void LLThread::pause()
 	if (!mPaused)
 	{
 		// this will cause the thread to stop execution as soon as checkPause() is called
-		mPaused = 1;		// Does not need to be atomic since this is only set/unset from the main thread
+		mPaused = true;		// Does not need to be atomic since this is only set/unset from the main thread
 	}	
 }
 
@@ -224,7 +202,7 @@ void LLThread::unpause()
 {
 	if (mPaused)
 	{
-		mPaused = 0;
+		mPaused = false;
 	}
 
 	wake(); // wake up the thread if necessary
@@ -301,116 +279,76 @@ void LLThread::wakeLocked()
 	}
 }
 
-//============================================================================
-
-LLMutex::LLMutex(apr_pool_t *poolp) :
-	mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
-{
-	//if (poolp)
-	//{
-	//	mIsLocalPool = FALSE;
-	//	mAPRPoolp = poolp;
-	//}
-	//else
-	{
-		mIsLocalPool = TRUE;
-		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
-	}
-	apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
-}
+#ifdef SHOW_ASSERT
+// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread.
+static apr_os_thread_t main_thread_id;
+LL_COMMON_API bool is_main_thread(void) { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); }
+#endif
 
+// The thread private handle to access the LLThreadLocalData instance.
+apr_threadkey_t* LLThreadLocalData::sThreadLocalDataKey;
 
-LLMutex::~LLMutex()
+//static
+void LLThreadLocalData::init(void)
 {
-#if MUTEX_DEBUG
-	//bad assertion, the subclass LLSignal might be "locked", and that's OK
-	//llassert_always(!isLocked()); // better not be locked!
-#endif
-	apr_thread_mutex_destroy(mAPRMutexp);
-	mAPRMutexp = NULL;
-	if (mIsLocalPool)
+	// Only do this once.
+	if (sThreadLocalDataKey)
 	{
-		apr_pool_destroy(mAPRPoolp);
+		return;
 	}
-}
 
+	apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &LLThreadLocalData::destroy, LLAPRRootPool::get()());
+	ll_apr_assert_status(status);   // Or out of memory, or system-imposed limit on the
+									// total number of keys per process {PTHREAD_KEYS_MAX}
+									// has been exceeded.
 
-void LLMutex::lock()
-{
-#if LL_DARWIN
-	if (mLockingThread == LLThread::currentID())
-#else
-	if (mLockingThread == sThreadID)
-#endif
-	{ //redundant lock
-		mCount++;
-		return;
-	}
-	
-	apr_thread_mutex_lock(mAPRMutexp);
-	
-#if MUTEX_DEBUG
-	// Have to have the lock before we can access the debug info
-	U32 id = LLThread::currentID();
-	if (mIsLocked[id] != FALSE)
-		llerrs << "Already locked in Thread: " << id << llendl;
-	mIsLocked[id] = TRUE;
-#endif
+	// Create the thread-local data for the main thread (this function is called by the main thread).
+	LLThreadLocalData::create(NULL);
 
-#if LL_DARWIN
-	mLockingThread = LLThread::currentID();
-#else
-	mLockingThread = sThreadID;
+#ifdef SHOW_ASSERT
+	// This function is called by the main thread.
+	main_thread_id = apr_os_thread_current();
 #endif
 }
 
-void LLMutex::unlock()
+// This is called once for every thread when the thread is destructed.
+//static
+void LLThreadLocalData::destroy(void* thread_local_data)
 {
-	if (mCount > 0)
-	{ //not the root unlock
-		mCount--;
-		return;
-	}
-	
-#if MUTEX_DEBUG
-	// Access the debug info while we have the lock
-	U32 id = LLThread::currentID();
-	if (mIsLocked[id] != TRUE)
-		llerrs << "Not locked in Thread: " << id << llendl;	
-	mIsLocked[id] = FALSE;
-#endif
-
-	mLockingThread = NO_THREAD;
-	apr_thread_mutex_unlock(mAPRMutexp);
+	delete static_cast<LLThreadLocalData*>(thread_local_data);
 }
 
-bool LLMutex::isLocked()
+//static
+void LLThreadLocalData::create(LLThread* threadp)
 {
-	apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
-	if (APR_STATUS_IS_EBUSY(status))
+	LLThreadLocalData* new_tld = new LLThreadLocalData;
+	if (threadp)
 	{
-		return true;
-	}
-	else
-	{
-		apr_thread_mutex_unlock(mAPRMutexp);
-		return false;
+		threadp->mThreadLocalData = new_tld;
 	}
+	apr_status_t status = apr_threadkey_private_set(new_tld, sThreadLocalDataKey);
+	llassert_always(status == APR_SUCCESS);
 }
 
-U32 LLMutex::lockingThread() const
+//static
+LLThreadLocalData& LLThreadLocalData::tldata(void)
 {
-	return mLockingThread;
+	if (!sThreadLocalDataKey)
+	{
+		LLThreadLocalData::init();
+	}
+
+	void* data;
+	apr_status_t status = apr_threadkey_private_get(&data, sThreadLocalDataKey);
+	llassert_always(status == APR_SUCCESS);
+	return *static_cast<LLThreadLocalData*>(data);
 }
 
 //============================================================================
 
-LLCondition::LLCondition(apr_pool_t *poolp) :
-	LLMutex(poolp)
+LLCondition::LLCondition(LLAPRPool& parent) : LLMutex(parent)
 {
-	// base class (LLMutex) has already ensured that mAPRPoolp is set up.
-
-	apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
+	apr_thread_cond_create(&mAPRCondp, mPool());
 }
 
 
@@ -423,15 +361,6 @@ LLCondition::~LLCondition()
 
 void LLCondition::wait()
 {
-	if (!isLocked())
-	{ //mAPRMutexp MUST be locked before calling apr_thread_cond_wait
-		apr_thread_mutex_lock(mAPRMutexp);
-#if MUTEX_DEBUG
-		// avoid asserts on destruction in non-release builds
-		U32 id = LLThread::currentID();
-		mIsLocked[id] = TRUE;
-#endif
-	}
 	apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
 }
 
@@ -446,6 +375,44 @@ void LLCondition::broadcast()
 }
 
 //============================================================================
+LLMutexBase::LLMutexBase() :
+	mLockingThread(NO_THREAD),
+	mCount(0)
+{
+}
+
+void LLMutexBase::lock() 
+{ 
+#if LL_DARWIN
+	if (mLockingThread == LLThread::currentID())
+#else
+	if (mLockingThread == local_thread_ID)
+#endif
+	{ //redundant lock
+		mCount++;
+		return;
+	}
+
+	apr_thread_mutex_lock(mAPRMutexp); 
+
+#if LL_DARWIN
+	mLockingThread = LLThread::currentID();
+#else
+	mLockingThread = local_thread_ID;
+#endif
+}
+
+void LLMutexBase::unlock() 
+{ 
+	if (mCount > 0)
+	{ //not the root unlock
+		mCount--;
+		return;
+	}
+	mLockingThread = NO_THREAD;
+
+	apr_thread_mutex_unlock(mAPRMutexp); 
+}
 
 //----------------------------------------------------------------------------
 
@@ -457,7 +424,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount()
 {
 	if (!sMutex)
 	{
-		sMutex = new LLMutex(0);
+		sMutex = new LLMutex;
 	}
 }
 
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index 40291a25693717f212f835c9909ceb48ad79cd0d..c732e3bc77999ad8b5b697aa30270a9e6ea8396a 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -29,7 +29,13 @@
 
 #include "llapp.h"
 #include "llapr.h"
+#include "llmemory.h"
 #include "apr_thread_cond.h"
+#include "llaprpool.h"
+
+#ifdef SHOW_ASSERT
+extern LL_COMMON_API bool is_main_thread(void);
+#endif
 
 class LLThread;
 class LLMutex;
@@ -41,6 +47,22 @@ class LLCondition;
 #define ll_thread_local __thread
 #endif
 
+class LL_COMMON_API LLThreadLocalData
+{
+private:
+	static apr_threadkey_t* sThreadLocalDataKey;
+
+public:
+	// Thread-local memory pools.
+	LLAPRRootPool mRootPool;
+	LLVolatileAPRPool mVolatileAPRPool;
+
+	static void init(void);
+	static void destroy(void* thread_local_data);
+	static void create(LLThread* pthread);
+	static LLThreadLocalData& tldata(void);
+};
+
 class LL_COMMON_API LLThread
 {
 private:
@@ -54,7 +76,7 @@ class LL_COMMON_API LLThread
 		QUITTING= 2 	// Someone wants this thread to quit
 	} EThreadStatus;
 
-	LLThread(const std::string& name, apr_pool_t *poolp = NULL);
+	LLThread(std::string const& name);
 	virtual ~LLThread(); // Warning!  You almost NEVER want to destroy a thread unless it's in the STOPPED state.
 	virtual void shutdown(); // stops the thread
 	
@@ -69,7 +91,7 @@ class LL_COMMON_API LLThread
 	// Called from MAIN THREAD.
 	void pause();
 	void unpause();
-	bool isPaused() { return isStopped() || mPaused == TRUE; }
+	bool isPaused() { return isStopped() || mPaused; }
 	
 	// Cause the thread to wake up and check its condition
 	void wake();
@@ -83,13 +105,11 @@ class LL_COMMON_API LLThread
 	// this kicks off the apr thread
 	void start(void);
 
-	apr_pool_t *getAPRPool() { return mAPRPoolp; }
-	LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
-
-	U32 getID() const { return mID; }
+	// Return thread-local data for the current thread.
+	static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); }
 
 private:
-	BOOL				mPaused;
+	bool				mPaused;
 	
 	// static function passed to APR thread creation routine
 	static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
@@ -99,15 +119,11 @@ class LL_COMMON_API LLThread
 	LLCondition*		mRunCondition;
 
 	apr_thread_t		*mAPRThreadp;
-	apr_pool_t			*mAPRPoolp;
-	BOOL				mIsLocalPool;
 	EThreadStatus		mStatus;
 	U32					mID;
-
-	//a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
-	//Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
-	//      otherwise it will cause severe memory leaking!!! --bao
-	LLVolatileAPRPool  *mLocalAPRFilePoolp ; 
+	
+	friend void LLThreadLocalData::create(LLThread* threadp);
+	LLThreadLocalData*	mThreadLocalData;
 
 	void setQuitting();
 	
@@ -137,7 +153,15 @@ class LL_COMMON_API LLThread
 
 #define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
 
-class LL_COMMON_API LLMutex
+#ifdef MUTEX_DEBUG
+// We really shouldn't be using recursive locks. Make sure of that in debug mode.
+#define MUTEX_FLAG APR_THREAD_MUTEX_UNNESTED
+#else
+// Use the fastest platform-optimal lock behavior (can be recursive or non-recursive).
+#define MUTEX_FLAG APR_THREAD_MUTEX_DEFAULT
+#endif
+
+class LL_COMMON_API LLMutexBase
 {
 public:
 	typedef enum
@@ -145,32 +169,73 @@ class LL_COMMON_API LLMutex
 		NO_THREAD = 0xFFFFFFFF
 	} e_locking_thread;
 
-	LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
-	virtual ~LLMutex();
-	
-	void lock();		// blocks
-	void unlock();
-	bool isLocked(); 	// non-blocking, but does do a lock/unlock so not free
-	U32 lockingThread() const; //get ID of locking thread
-	
+	LLMutexBase() ;
+
+	void lock() ;
+	void unlock() ;
+	// Returns true if lock was obtained successfully.
+	bool trylock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); }
+
+	// non-blocking, but does do a lock/unlock so not free
+	bool isLocked() { bool is_not_locked = trylock(); if (is_not_locked) unlock(); return !is_not_locked; }
+
 protected:
-	apr_thread_mutex_t *mAPRMutexp;
+	// mAPRMutexp is initialized and uninitialized in the derived class.
+	apr_thread_mutex_t* mAPRMutexp;
 	mutable U32			mCount;
 	mutable U32			mLockingThread;
-	
-	apr_pool_t			*mAPRPoolp;
-	BOOL				mIsLocalPool;
-	
-#if MUTEX_DEBUG
-	std::map<U32, BOOL> mIsLocked;
+};
+
+class LL_COMMON_API LLMutex : public LLMutexBase
+{
+public:
+	LLMutex(LLAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent)
+	{
+		apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mPool());
+	}
+	~LLMutex()
+	{
+		llassert(!isLocked()); // better not be locked!
+		apr_thread_mutex_destroy(mAPRMutexp);
+		mAPRMutexp = NULL;
+	}
+
+protected:
+	LLAPRPool mPool;
+};
+
+#if APR_HAS_THREADS
+// No need to use a root pool in this case.
+typedef LLMutex LLMutexRootPool;
+#else // APR_HAS_THREADS
+class LL_COMMON_API LLMutexRootPool : public LLMutexBase
+{
+public:
+	LLMutexRootPool(void)
+	{
+		apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mRootPool());
+	}
+	~LLMutexRootPool()
+	{
+#if APR_POOL_DEBUG
+		// It is allowed to destruct root pools from a different thread.
+		mRootPool.grab_ownership();
 #endif
+		llassert(!isLocked());
+		apr_thread_mutex_destroy(mAPRMutexp);
+		mAPRMutexp = NULL;
+	}
+
+protected:
+	LLAPRRootPool mRootPool;
 };
+#endif // APR_HAS_THREADS
 
 // Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
 class LL_COMMON_API LLCondition : public LLMutex
 {
 public:
-	LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
+	LLCondition(LLAPRPool& parent = LLThread::tldata().mRootPool);
 	~LLCondition();
 	
 	void wait();		// blocks
@@ -181,10 +246,10 @@ class LL_COMMON_API LLCondition : public LLMutex
 	apr_thread_cond_t *mAPRCondp;
 };
 
-class LLMutexLock
+class LL_COMMON_API LLMutexLock
 {
 public:
-	LLMutexLock(LLMutex* mutex)
+	LLMutexLock(LLMutexBase* mutex)
 	{
 		mMutex = mutex;
 		mMutex->lock();
@@ -194,7 +259,7 @@ class LLMutexLock
 		mMutex->unlock();
 	}
 private:
-	LLMutex* mMutex;
+	LLMutexBase* mMutex;
 };
 
 //============================================================================
diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp
index 8a73e632a9ada2249b4353f88828d5d66fcfe00d..05d24944f3e3ae4223eb35ca998fb284c5614967 100644
--- a/indra/llcommon/llthreadsafequeue.cpp
+++ b/indra/llcommon/llthreadsafequeue.cpp
@@ -34,19 +34,11 @@
 //-----------------------------------------------------------------------------
 
 
-LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity):
-	mOwnsPool(pool == 0),
-	mPool(pool),
+LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(unsigned int capacity):
 	mQueue(0)
 {
-	if(mOwnsPool) {
-		apr_status_t status = apr_pool_create(&mPool, 0);
-		if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool");
-	} else {
-		; // No op.
-	}
-	
-	apr_status_t status = apr_queue_create(&mQueue, capacity, mPool);
+	mPool.create();
+	apr_status_t status = apr_queue_create(&mQueue, capacity, mPool());
 	if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
 }
 
@@ -59,7 +51,6 @@ LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation()
 			" elements;" << "memory will be leaked" << LL_ENDL;
 		apr_queue_term(mQueue);
 	}
-	if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool);
 }
 
 
diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h
index 58cac38769cd2d3801fc9f01b1d1cc2a010ae0c6..43d0b396f2494059192e0ae61533f64a69ae4b17 100644
--- a/indra/llcommon/llthreadsafequeue.h
+++ b/indra/llcommon/llthreadsafequeue.h
@@ -30,9 +30,9 @@
 
 #include <string>
 #include <stdexcept>
+#include "llaprpool.h"
 
 
-struct apr_pool_t; // From apr_pools.h
 class LLThreadSafeQueueImplementation; // See below.
 
 
@@ -75,7 +75,7 @@ struct apr_queue_t; // From apr_queue.h
 class LL_COMMON_API LLThreadSafeQueueImplementation
 {
 public:
-	LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity);
+	LLThreadSafeQueueImplementation(unsigned int capacity);
 	~LLThreadSafeQueueImplementation();
 	void pushFront(void * element);
 	bool tryPushFront(void * element);
@@ -84,8 +84,7 @@ class LL_COMMON_API LLThreadSafeQueueImplementation
 	size_t size();
 	
 private:
-	bool mOwnsPool;
-	apr_pool_t * mPool;
+	LLAPRPool mPool;			// The pool used for mQueue.
 	apr_queue_t * mQueue;
 };
 
@@ -99,9 +98,8 @@ class LLThreadSafeQueue
 public:
 	typedef ElementT value_type;
 	
-	// If the pool is set to NULL one will be allocated and managed by this
-	// queue.
-	LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024);
+	// Constructor.
+	LLThreadSafeQueue(unsigned int capacity = 1024);
 	
 	// Add an element to the front of queue (will block if the queue has
 	// reached capacity).
@@ -139,8 +137,8 @@ class LLThreadSafeQueue
 
 
 template<typename ElementT>
-LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
-	mImplementation(pool, capacity)
+LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(unsigned int capacity) :
+	mImplementation(capacity)
 {
 	; // No op.
 }
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index 324507fe7a5aff6357ea0a11e548330e865a77b7..ef55cfec893e83cd731263a0db46dfe234294bb7 100755
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -29,7 +29,7 @@
 
 const S32 LL_VERSION_MAJOR = 3;
 const S32 LL_VERSION_MINOR = 0;
-const S32 LL_VERSION_PATCH = 4;
+const S32 LL_VERSION_PATCH = 5;
 const S32 LL_VERSION_BUILD = 0;
 
 const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index 3ac50832fda64969a0bedcb6707216999e7c69cd..6b308bb9179eeff39de601357c054ebcc51c0771 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -37,12 +37,7 @@
 LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) :
 	LLQueuedThread(name, threaded)
 {
-	mDeleteMutex = new LLMutex(NULL);
-
-	if(!mLocalAPRFilePoolp)
-	{
-		mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
-	}
+	mDeleteMutex = new LLMutex;
 }
 
 LLWorkerThread::~LLWorkerThread()
@@ -204,7 +199,6 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
 	  mWorkerClassName(name),
 	  mRequestHandle(LLWorkerThread::nullHandle()),
 	  mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
-	  mMutex(NULL),
 	  mWorkFlags(0)
 {
 	if (!mWorkerThread)
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index 9bff18303eb944312d83cb9eaa5e249d325de5bc..bef5ef53fe4fd4f97753429e09bd4c5fd1ba8708 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -94,7 +94,6 @@ class LL_COMMON_API LLWorkerThread : public LLQueuedThread
 
 private:
 	void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
-	
 };
 
 //============================================================================
@@ -194,7 +193,7 @@ class LL_COMMON_API LLWorkerClass
 	U32 mRequestPriority; // last priority set
 
 private:
-	LLMutex mMutex;
+	LLMutexRootPool mMutex;		// Use LLMutexRootPool since this object is created and destructed by multiple threads.
 	LLAtomicU32 mWorkFlags;
 };
 
diff --git a/indra/llcommon/tests/llstring_test.cpp b/indra/llcommon/tests/llstring_test.cpp
index 304e91ed927ed434c90764869ae3556850c82cfa..6a1cbf652a2ff9442db30eea5d317338a56e796d 100644
--- a/indra/llcommon/tests/llstring_test.cpp
+++ b/indra/llcommon/tests/llstring_test.cpp
@@ -624,6 +624,14 @@ namespace tut
 		subcount = LLStringUtil::format(s, fmt_map);
 		ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "?Am I not a long string?short[A]bbbaaaba[A]");
 		ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount);
+		
+		// Test on nested brackets
+		std::string srcs6 = "[[TRICK1]][[A]][[B]][[AAA]][[BBB]][[TRICK2]][[KEYLONGER]][[KEYSHORTER]]?[[DELETE]]";
+		s = srcs6;
+		subcount = LLStringUtil::format(s, fmt_map);
+		ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "[[A]][a][b][aaa][bbb][[A]][short][Am I not a long string?]?[]");
+		ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount);
+
 
 		// Test an assorted substitution
 		std::string srcs8 = "foo[DELETE]bar?";
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index 331a1692ee8abff68e12d4d02173634011f1741d..514ef6011f82363b6f264eded30a6b8719c1ec80 100644
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -414,8 +414,7 @@ bool LLCrashLogger::init()
 		return false;
 	}
 
-	gServicePump = new LLPumpIO(gAPRPoolp);
-	gServicePump->prime(gAPRPoolp);
+	gServicePump = new LLPumpIO;
 	LLHTTPClient::setPump(*gServicePump);
 
 	//If we've opened the crash logger, assume we can delete the marker file if it exists
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index f0d15d9607f6d49597337da5cfcba535c0b2bcf6..23adbf68c88ea913fce5fb859343e9d730dfa5fe 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -39,6 +39,7 @@
 #include "llimagepng.h"
 #include "llimagedxt.h"
 #include "llimageworker.h"
+#include "llmemory.h"
 
 //---------------------------------------------------------------------------
 // LLImage
@@ -47,11 +48,14 @@
 //static
 std::string LLImage::sLastErrorMessage;
 LLMutex* LLImage::sMutex = NULL;
+LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ;
 
 //static
 void LLImage::initClass()
 {
-	sMutex = new LLMutex(NULL);
+	sMutex = new LLMutex;
+
+	LLImageBase::createPrivatePool() ;
 }
 
 //static
@@ -59,6 +63,8 @@ void LLImage::cleanupClass()
 {
 	delete sMutex;
 	sMutex = NULL;
+
+	LLImageBase::destroyPrivatePool() ;
 }
 
 //static
@@ -97,6 +103,25 @@ LLImageBase::~LLImageBase()
 	deleteData(); // virtual
 }
 
+//static 
+void LLImageBase::createPrivatePool() 
+{
+	if(!sPrivatePoolp)
+	{
+		sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC_THREADED) ;
+	}
+}
+	
+//static 
+void LLImageBase::destroyPrivatePool() 
+{
+	if(sPrivatePoolp)
+	{
+		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ;
+		sPrivatePoolp = NULL ;
+	}
+}
+
 // virtual
 void LLImageBase::dump()
 {
@@ -130,7 +155,7 @@ void LLImageBase::sanityCheck()
 // virtual
 void LLImageBase::deleteData()
 {
-	delete[] mData;
+	FREE_MEM(sPrivatePoolp, mData) ;
 	mData = NULL;
 	mDataSize = 0;
 }
@@ -167,7 +192,7 @@ U8* LLImageBase::allocateData(S32 size)
 	{
 		deleteData(); // virtual
 		mBadBufferAllocation = false ;
-		mData = new U8[size];
+		mData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
 		if (!mData)
 		{
 			llwarns << "allocate image data: " << size << llendl;
@@ -185,7 +210,7 @@ U8* LLImageBase::allocateData(S32 size)
 U8* LLImageBase::reallocateData(S32 size)
 {
 	LLMemType mt1(mMemType);
-	U8 *new_datap = new U8[size];
+	U8 *new_datap = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
 	if (!new_datap)
 	{
 		llwarns << "Out of memory in LLImageBase::reallocateData" << llendl;
@@ -195,7 +220,7 @@ U8* LLImageBase::reallocateData(S32 size)
 	{
 		S32 bytes = llmin(mDataSize, size);
 		memcpy(new_datap, mData, bytes);	/* Flawfinder: ignore */
-		delete[] mData;
+		FREE_MEM(sPrivatePoolp, mData) ;
 	}
 	mData = new_datap;
 	mDataSize = size;
@@ -341,6 +366,7 @@ BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
 	return TRUE;
 }
 
+#if 0
 U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
 {
 	LLMemType mt1(mMemType);
@@ -361,6 +387,7 @@ U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const
 	}
 	return data;
 }
+#endif
 
 BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
 							 const U8 *data, U32 stride, BOOL reverse_y)
@@ -830,6 +857,7 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
 	}
 }
 
+#if 0
 //scale down image by not blending a pixel with its neighbors.
 BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
 {
@@ -853,7 +881,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
 	ratio_x -= 1.0f ;
 	ratio_y -= 1.0f ;
 
-	U8* new_data = new U8[new_data_size] ;
+	U8* new_data = allocateMemory(new_data_size) ;
 	llassert_always(new_data != NULL) ;
 
 	U8* old_data = getData() ;
@@ -875,6 +903,7 @@ BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
 	
 	return TRUE ;
 }
+#endif
 
 BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
 {
@@ -1506,6 +1535,7 @@ void LLImageFormatted::setData(U8 *data, S32 size)
 	{
 		deleteData();
 		setDataAndSize(data, size); // Access private LLImageBase members
+
 		sGlobalFormattedMemory += getDataSize();
 	}
 }
@@ -1524,7 +1554,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size)
 			S32 newsize = cursize + size;
 			reallocateData(newsize);
 			memcpy(getData() + cursize, data, size);
-			delete[] data;
+			FREE_MEM(LLImageBase::getPrivatePool(), data);
 		}
 	}
 }
@@ -1536,8 +1566,7 @@ BOOL LLImageFormatted::load(const std::string &filename)
 	resetLastError();
 
 	S32 file_size = 0;
-	LLAPRFile infile ;
-	infile.open(filename, LL_APR_RB, NULL, &file_size);
+	LLAPRFile infile(filename, LL_APR_RB, &file_size);
 	apr_file_t* apr_file = infile.getFileHandle();
 	if (!apr_file)
 	{
@@ -1572,8 +1601,7 @@ BOOL LLImageFormatted::save(const std::string &filename)
 {
 	resetLastError();
 
-	LLAPRFile outfile ;
-	outfile.open(filename, LL_APR_WB);
+	LLAPRFile outfile(filename, LL_APR_WB);
 	if (!outfile.getFileHandle())
 	{
 		setLastError("Unable to open file for writing", filename);
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index c464c3b2b67e01fe2a692331978bd9771d282852..4469c9e86025e628d2b1100c6d8c85baaa604c93 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -29,7 +29,6 @@
 
 #include "lluuid.h"
 #include "llstring.h"
-//#include "llmemory.h"
 #include "llthread.h"
 #include "llmemtype.h"
 
@@ -69,6 +68,7 @@ const S32 MAX_IMG_PACKET_SIZE = 1000;
 class LLImageFormatted;
 class LLImageRaw;
 class LLColor4U;
+class LLPrivateMemoryPool;
 
 typedef enum e_image_codec
 {
@@ -140,7 +140,7 @@ class LLImageBase : public LLThreadSafeRefCount
 
 protected:
 	// special accessor to allow direct setting of mData and mDataSize by LLImageFormatted
-	void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; }
+	void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; }	
 	
 public:
 	static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels);
@@ -151,6 +151,10 @@ class LLImageBase : public LLThreadSafeRefCount
 
 	static EImageCodec getCodecFromExtension(const std::string& exten);
 	
+	static void createPrivatePool() ;
+	static void destroyPrivatePool() ;
+	static LLPrivateMemoryPool* getPrivatePool() {return sPrivatePoolp;}
+
 private:
 	U8 *mData;
 	S32 mDataSize;
@@ -162,6 +166,8 @@ class LLImageBase : public LLThreadSafeRefCount
 
 	bool mBadBufferAllocation ;
 	bool mAllowOverSize ;
+
+	static LLPrivateMemoryPool* sPrivatePoolp ;
 public:
 	LLMemType::DeclareMemType& mMemType; // debug
 };
@@ -185,7 +191,7 @@ class LLImageRaw : public LLImageBase
 	
 	BOOL resize(U16 width, U16 height, S8 components);
 
-	U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const;
+	//U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const;
 	BOOL setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height,
 					 const U8 *data, U32 stride = 0, BOOL reverse_y = FALSE);
 
@@ -197,7 +203,7 @@ class LLImageRaw : public LLImageBase
 	void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
 	void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
 	BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
-	BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
+	//BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
 
 	// Fill the buffer with a constant color
 	void fill( const LLColor4U& color );
diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp
index c6bfa50b403a3babfb42c30096e8a3f188456632..926c74914520986403b59ed476f021466c28baec 100644
--- a/indra/llimage/llimagedimensionsinfo.cpp
+++ b/indra/llimage/llimagedimensionsinfo.cpp
@@ -40,7 +40,7 @@ bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
 	mSrcFilename = src_filename;
 
 	S32 file_size = 0;
-	apr_status_t s = mInfile.open(src_filename, LL_APR_RB, NULL, &file_size);
+	apr_status_t s = mInfile.open(src_filename, LL_APR_RB, LLAPRFile::long_lived, &file_size);
 
 	if (s != APR_SUCCESS)
 	{
diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp
index 4bd3efddaae3eaead08d0a45400c987d86ca2401..2867f5e6f0aa7c5807396c655f6e0ff781695aec 100644
--- a/indra/llimage/llimagedxt.cpp
+++ b/indra/llimage/llimagedxt.cpp
@@ -429,7 +429,7 @@ bool LLImageDXT::convertToDXR()
 	S32 nmips = calcNumMips(width,height);
 	S32 total_bytes = getDataSize();
 	U8* olddata = getData();
-	U8* newdata = new U8[total_bytes];
+	U8* newdata = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_bytes);
 	if (!newdata)
 	{
 		llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl;
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 44e6b89dd34ac5072c74c87c26b0e26a58b8976c..8c5dc63e9ddac751de93c0f2aebd6b199a8013ae 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -370,8 +370,7 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
 	resetLastError();
 
 	S32 file_size = 0;
-	LLAPRFile infile ;
-	infile.open(filename, LL_APR_RB, NULL, &file_size);
+	LLAPRFile infile(filename, LL_APR_RB, &file_size);
 	apr_file_t* apr_file = infile.getFileHandle() ;
 	if (!apr_file)
 	{
@@ -385,14 +384,14 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
 	}
 	else
 	{
-		U8 *data = new U8[file_size];
+		U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size);
 		apr_size_t bytes_read = file_size;
 		apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read	
 		infile.close() ;
 
 		if (s != APR_SUCCESS || (S32)bytes_read != file_size)
 		{
-			delete[] data;
+			FREE_MEM(LLImageBase::getPrivatePool(), data);
 			setLastError("Unable to read entire file");
 			res = FALSE;
 		}
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 28dc3bd313365a58409042d40c9ad4601b0332c5..2c6d6f31eadd2e0ed425a0c9c1a53c5941b8e823 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -35,20 +35,18 @@
 LLImageDecodeThread::LLImageDecodeThread(bool threaded)
 	: LLQueuedThread("imagedecode", threaded)
 {
-	mCreationMutex = new LLMutex(getAPRPool());
 }
 
 //virtual 
 LLImageDecodeThread::~LLImageDecodeThread()
 {
-	delete mCreationMutex ;
 }
 
 // MAIN THREAD
 // virtual
 S32 LLImageDecodeThread::update(U32 max_time_ms)
 {
-	LLMutexLock lock(mCreationMutex);
+	LLMutexLock lock(&mCreationMutex);
 	for (creation_list_t::iterator iter = mCreationList.begin();
 		 iter != mCreationList.end(); ++iter)
 	{
@@ -71,7 +69,7 @@ S32 LLImageDecodeThread::update(U32 max_time_ms)
 LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image, 
 	U32 priority, S32 discard, BOOL needs_aux, Responder* responder)
 {
-	LLMutexLock lock(mCreationMutex);
+	LLMutexLock lock(&mCreationMutex);
 	handle_t handle = generateHandle();
 	mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
 	return handle;
@@ -81,7 +79,7 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted*
 // Returns the size of the mutex guarded list as an indication of sanity
 S32 LLImageDecodeThread::tut_size()
 {
-	LLMutexLock lock(mCreationMutex);
+	LLMutexLock lock(&mCreationMutex);
 	S32 res = mCreationList.size();
 	return res;
 }
diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h
index c684222fa5f85f10794ed51217b59c35cebf1570..6a24b7522ab29d026959ba559379a67c3c948f4c 100644
--- a/indra/llimage/llimageworker.h
+++ b/indra/llimage/llimageworker.h
@@ -98,7 +98,7 @@ class LLImageDecodeThread : public LLQueuedThread
 	};
 	typedef std::list<creation_info> creation_list_t;
 	creation_list_t mCreationList;
-	LLMutex* mCreationMutex;
+	LLMutex mCreationMutex;
 };
 
 #endif
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index c60b75008837f770c63c324e57f917f5f6e97153..42180197feb14e04ea0a4aeb2376518eeaf4feb0 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -49,7 +49,7 @@ LLVolumeMgr::LLVolumeMgr()
 {
 	// the LLMutex magic interferes with easy unit testing,
 	// so you now must manually call useMutex() to use it
-	//mDataMutex = new LLMutex(gAPRPoolp);
+	//mDataMutex = new LLMutex;
 }
 
 LLVolumeMgr::~LLVolumeMgr()
@@ -216,7 +216,7 @@ void LLVolumeMgr::useMutex()
 { 
 	if (!mDataMutex)
 	{
-		mDataMutex = new LLMutex(gAPRPoolp);
+		mDataMutex = new LLMutex;
 	}
 }
 
diff --git a/indra/llmath/tests/v3math_test.cpp b/indra/llmath/tests/v3math_test.cpp
index df7a77002fc2d9950f55ece6c14a2abe0535d672..e4ae1c10efafc62e59c022a823b0ebd3e8637e24 100644
--- a/indra/llmath/tests/v3math_test.cpp
+++ b/indra/llmath/tests/v3math_test.cpp
@@ -564,4 +564,22 @@ namespace tut
 		z1 = U8_to_F32(F32_to_U8(z, lowerz, upperz), lowerz, upperz);
 		ensure("2:quantize8: Fail ", is_approx_equal(x1, vec3a.mV[VX]) && is_approx_equal(y1, vec3a.mV[VY]) && is_approx_equal(z1, vec3a.mV[VZ]));
 	}
+
+	template<> template<>
+	void v3math_object::test<35>()
+	{
+		LLSD sd = LLSD::emptyArray();
+		sd[0] = 1.f;
+
+		LLVector3 parsed_1(sd);
+		ensure("1:LLSD parse: Fail ", is_approx_equal(parsed_1.mV[VX], 1.f) && is_approx_equal(parsed_1.mV[VY], 0.f) && is_approx_equal(parsed_1.mV[VZ], 0.f));
+
+		sd[1] = 2.f;
+		LLVector3 parsed_2(sd);
+		ensure("2:LLSD parse: Fail ", is_approx_equal(parsed_2.mV[VX], 1.f) && is_approx_equal(parsed_2.mV[VY], 2.f) && is_approx_equal(parsed_2.mV[VZ], 0.f));
+
+		sd[2] = 3.f;
+		LLVector3 parsed_3(sd);
+		ensure("3:LLSD parse: Fail ", is_approx_equal(parsed_3.mV[VX], 1.f) && is_approx_equal(parsed_3.mV[VY], 2.f) && is_approx_equal(parsed_3.mV[VZ], 3.f));
+	}
 }
diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp
index 5a67035ed15fff56a9d42742c26c74dee8b36f4f..fab9858b697f76e49847afa58ec1cb43ab902b46 100644
--- a/indra/llmessage/llares.cpp
+++ b/indra/llmessage/llares.cpp
@@ -28,6 +28,7 @@
 
 #include "linden_common.h"
 #include "llares.h"
+#include "llscopedvolatileaprpool.h"
 
 #include <ares_dns.h>
 #include <ares_version.h>
@@ -464,11 +465,6 @@ void LLAres::search(const std::string &query, LLResType type,
 
 bool LLAres::process(U64 timeout)
 {
-	if (!gAPRPoolp)
-	{
-		ll_init_apr();
-	}
-
 	ares_socket_t socks[ARES_GETSOCK_MAXNUM];
 	apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
 	apr_int32_t nsds = 0;	
@@ -482,10 +478,7 @@ bool LLAres::process(U64 timeout)
 		return nsds > 0;
 	}
 
-	apr_status_t status;
-	LLAPRPool pool;
-	status = pool.getStatus() ;
-	ll_apr_assert_status(status);
+	LLScopedVolatileAPRPool scoped_pool;
 
 	for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
 	{
@@ -502,7 +495,7 @@ bool LLAres::process(U64 timeout)
 
 		apr_socket_t *aprSock = NULL;
 
-		status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool());
+		apr_status_t status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], scoped_pool);
 		if (status != APR_SUCCESS)
 		{
 			ll_apr_warn_status(status);
@@ -511,7 +504,7 @@ bool LLAres::process(U64 timeout)
 
 		aprFds[nactive].desc.s = aprSock;
 		aprFds[nactive].desc_type = APR_POLL_SOCKET;
-		aprFds[nactive].p = pool.getAPRPool();
+		aprFds[nactive].p = scoped_pool;
 		aprFds[nactive].rtnevents = 0;
 		aprFds[nactive].client_data = &socks[i];
 
@@ -520,7 +513,7 @@ bool LLAres::process(U64 timeout)
 
 	if (nactive > 0)
 	{
-		status = apr_poll(aprFds, nactive, &nsds, timeout);
+		apr_status_t status = apr_poll(aprFds, nactive, &nsds, timeout);
 
 		if (status != APR_SUCCESS && status != APR_TIMEUP)
 		{
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 785d07acb8b161f9b12453ee80781bb6c3060b30..14e169c6b1011a351d582a0ae8e9b131e2daaf19 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -531,7 +531,7 @@ LLCurl::Multi::Multi()
 	mThreaded = LLCurl::sMultiThreaded && LLThread::currentID() == sMainThreadID;
 	if (mThreaded)
 	{
-		mSignal = new LLCondition(NULL);
+		mSignal = new LLCondition();
 	}
 	else
 	{
@@ -1178,13 +1178,13 @@ void LLCurl::initClass(bool multi_threaded)
 
 	check_curl_code(code);
 	
-	Easy::sHandleMutex = new LLMutex(NULL);
+	Easy::sHandleMutex = new LLMutex();
 
 #if SAFE_SSL
 	S32 mutex_count = CRYPTO_num_locks();
 	for (S32 i=0; i<mutex_count; i++)
 	{
-		sSSLMutex.push_back(new LLMutex(NULL));
+		sSSLMutex.push_back(new LLMutex);
 	}
 	CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
 	CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index 73e8a690851800ca5bf7a69314e15ee446bc316e..920a57ab55420a40bf6509460232aa0e687d0591 100644
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -963,13 +963,9 @@ class LLHTTPResponseFactory : public LLChainIOFactory
 
 
 // static
-LLHTTPNode& LLIOHTTPServer::create(
-	apr_pool_t* pool, LLPumpIO& pump, U16 port)
+LLHTTPNode& LLIOHTTPServer::create(LLPumpIO& pump, U16 port)
 {
-	LLSocket::ptr_t socket = LLSocket::create(
-        pool,
-        LLSocket::STREAM_TCP,
-        port);
+	LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP, port);
     if(!socket)
     {
         llerrs << "Unable to initialize socket" << llendl;
@@ -978,7 +974,7 @@ LLHTTPNode& LLIOHTTPServer::create(
     LLHTTPResponseFactory* factory = new LLHTTPResponseFactory;
 	boost::shared_ptr<LLChainIOFactory> factory_ptr(factory);
 
-    LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr);
+    LLIOServerSocket* server = new LLIOServerSocket(socket, factory_ptr);
 
 	LLPumpIO::chain_t chain;
     chain.push_back(LLIOPipe::ptr_t(server));
diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h
index 5c1b0531ff2693de45fd6b15147523e27f7e725f..2294e4b8ae2c07eadaf66f6b0827de938d4f0ed2 100644
--- a/indra/llmessage/lliohttpserver.h
+++ b/indra/llmessage/lliohttpserver.h
@@ -50,7 +50,7 @@ class LLIOHTTPServer
 public:
 	typedef void (*timing_callback_t)(const char* hashed_name, F32 time, void* data);
 
-	static LLHTTPNode& create(apr_pool_t* pool, LLPumpIO& pump, U16 port);
+	static LLHTTPNode& create(LLPumpIO& pump, U16 port);
 	/**< Creates an HTTP wire server on the pump for the given TCP port.
 	 *
 	 *   Returns the root node of the new server.  Add LLHTTPNode instances
diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp
index ee9379f20585f0d1407984a4620a770f8a92ae80..a885ba8ee15ce7a4b69e7c5325875c57e8258d0f 100644
--- a/indra/llmessage/lliosocket.cpp
+++ b/indra/llmessage/lliosocket.cpp
@@ -35,6 +35,7 @@
 #include "llhost.h"
 #include "llmemtype.h"
 #include "llpumpio.h"
+#include "llthread.h"
 
 //
 // constants
@@ -98,51 +99,31 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock)
 ///
 
 // static
-LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
+LLSocket::ptr_t LLSocket::create(EType type, U16 port)
 {
 	LLMemType m1(LLMemType::MTYPE_IO_TCP);
-	LLSocket::ptr_t rv;
-	apr_socket_t* socket = NULL;
-	apr_pool_t* new_pool = NULL;
 	apr_status_t status = APR_EGENERAL;
-
-	// create a pool for the socket
-	status = apr_pool_create(&new_pool, pool);
-	if(ll_apr_warn_status(status))
-	{
-		if(new_pool) apr_pool_destroy(new_pool);
-		return rv;
-	}
+	LLSocket::ptr_t rv(new LLSocket);
 
 	if(STREAM_TCP == type)
 	{
-		status = apr_socket_create(
-			&socket,
-			APR_INET,
-			SOCK_STREAM,
-			APR_PROTO_TCP,
-			new_pool);
+		status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, rv->mPool());
 	}
 	else if(DATAGRAM_UDP == type)
 	{
-		status = apr_socket_create(
-			&socket,
-			APR_INET,
-			SOCK_DGRAM,
-			APR_PROTO_UDP,
-			new_pool);
+		status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, rv->mPool());
 	}
 	else
 	{
-		if(new_pool) apr_pool_destroy(new_pool);
+		rv.reset();
 		return rv;
 	}
 	if(ll_apr_warn_status(status))
 	{
-		if(new_pool) apr_pool_destroy(new_pool);
+		rv->mSocket = NULL;
+		rv.reset();
 		return rv;
 	}
-	rv = ptr_t(new LLSocket(socket, new_pool));
 	if(port > 0)
 	{
 		apr_sockaddr_t* sa = NULL;
@@ -152,7 +133,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
 			APR_UNSPEC,
 			port,
 			0,
-			new_pool);
+			rv->mPool());
 		if(ll_apr_warn_status(status))
 		{
 			rv.reset();
@@ -160,8 +141,8 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
 		}
 		// This allows us to reuse the address on quick down/up. This
 		// is unlikely to create problems.
-		ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1));
-		status = apr_socket_bind(socket, sa);
+		ll_apr_warn_status(apr_socket_opt_set(rv->mSocket, APR_SO_REUSEADDR, 1));
+		status = apr_socket_bind(rv->mSocket, sa);
 		if(ll_apr_warn_status(status))
 		{
 			rv.reset();
@@ -175,7 +156,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
 			// to keep a queue of incoming connections for ACCEPT.
 			lldebugs << "Setting listen state for socket." << llendl;
 			status = apr_socket_listen(
-				socket,
+				rv->mSocket,
 				LL_DEFAULT_LISTEN_BACKLOG);
 			if(ll_apr_warn_status(status))
 			{
@@ -196,21 +177,28 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
 }
 
 // static
-LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool)
+LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket)
 {
 	LLMemType m1(LLMemType::MTYPE_IO_TCP);
-	LLSocket::ptr_t rv;
-	if(!socket)
+	if (!listen_socket->getSocket())
+	{
+		status = APR_ENOSOCKET;
+		return LLSocket::ptr_t();
+	}
+	LLSocket::ptr_t rv(new LLSocket);
+	lldebugs << "accepting socket" << llendl;
+	status = apr_socket_accept(&rv->mSocket, listen_socket->getSocket(), rv->mPool());
+	if (status != APR_SUCCESS)
 	{
+		rv->mSocket = NULL;
+		rv.reset();
 		return rv;
 	}
-	rv = ptr_t(new LLSocket(socket, pool));
 	rv->mPort = PORT_EPHEMERAL;
 	rv->setNonBlocking();
 	return rv;
 }
 
-
 bool LLSocket::blockingConnect(const LLHost& host)
 {
 	if(!mSocket) return false;
@@ -223,7 +211,7 @@ bool LLSocket::blockingConnect(const LLHost& host)
 		APR_UNSPEC,
 		host.getPort(),
 		0,
-		mPool)))
+		mPool())))
 	{
 		return false;
 	}
@@ -234,13 +222,11 @@ bool LLSocket::blockingConnect(const LLHost& host)
 	return true;
 }
 
-LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) :
-	mSocket(socket),
-	mPool(pool),
+LLSocket::LLSocket() :
+	mSocket(NULL),
+	mPool(LLThread::tldata().mRootPool),
 	mPort(PORT_INVALID)
 {
-	ll_debug_socket("Constructing wholely formed socket", mSocket);
-	LLMemType m1(LLMemType::MTYPE_IO_TCP);
 }
 
 LLSocket::~LLSocket()
@@ -253,11 +239,6 @@ LLSocket::~LLSocket()
 		apr_socket_close(mSocket);
 		mSocket = NULL;
 	}
-	if(mPool)
-	{
-		apr_pool_destroy(mPool);
-		mPool = NULL;
-	}
 }
 
 // See http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html#ss13.4
@@ -539,10 +520,8 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
 ///
 
 LLIOServerSocket::LLIOServerSocket(
-	apr_pool_t* pool,
 	LLIOServerSocket::socket_t listener,
 	factory_t factory) :
-	mPool(pool),
 	mListenSocket(listener),
 	mReactor(factory),
 	mInitialized(false),
@@ -604,21 +583,15 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
 	lldebugs << "accepting socket" << llendl;
 
 	PUMP_DEBUG;
-	apr_pool_t* new_pool = NULL;
-	apr_status_t status = apr_pool_create(&new_pool, mPool);
-	apr_socket_t* socket = NULL;
-	status = apr_socket_accept(
-		&socket,
-		mListenSocket->getSocket(),
-		new_pool);
-	LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool));
+	apr_status_t status;
+	LLSocket::ptr_t llsocket(LLSocket::create(status, mListenSocket));
 	//EStatus rv = STATUS_ERROR;
-	if(llsocket)
+	if(llsocket && status == APR_SUCCESS)
 	{
 		PUMP_DEBUG;
 
 		apr_sockaddr_t* remote_addr;
-		apr_socket_addr_get(&remote_addr, APR_REMOTE, socket);
+		apr_socket_addr_get(&remote_addr, APR_REMOTE, llsocket->getSocket());
 		
 		char* remote_host_string;
 		apr_sockaddr_ip_get(&remote_host_string, remote_addr);
@@ -633,7 +606,6 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
 		{
 			chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket)));
 			pump->addChain(chain, mResponseTimeout);
-			status = STATUS_OK;
 		}
 		else
 		{
@@ -642,7 +614,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
 	}
 	else
 	{
-		llwarns << "Unable to create linden socket." << llendl;
+		char buf[256];
+		llwarns << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << llendl;
 	}
 
 	PUMP_DEBUG;
@@ -655,11 +628,10 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
 #if 0
 LLIODataSocket::LLIODataSocket(
 	U16 suggested_port,
-	U16 start_discovery_port,
-	apr_pool_t* pool) : 
+	U16 start_discovery_port) :
 	mSocket(NULL)
 {
-	if(!pool || (PORT_INVALID == suggested_port)) return;
+	if(PORT_INVALID == suggested_port) return;
 	if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return;
 	apr_sockaddr_t* sa = NULL;
 	if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return;
diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h
index be0f7dfcc655e1e47ac2ccdf8f967037ac4458a8..f0a6f256573afb557122a25ab6a219fd401e2588 100644
--- a/indra/llmessage/lliosocket.h
+++ b/indra/llmessage/lliosocket.h
@@ -38,7 +38,6 @@
  */
 
 #include "lliopipe.h"
-#include "apr_pools.h"
 #include "apr_network_io.h"
 #include "llchainio.h"
 
@@ -88,34 +87,22 @@ class LLSocket
 	 * socket. If you intend the socket to be known to external
 	 * clients without prior port notification, do not use
 	 * PORT_EPHEMERAL.
-	 * @param pool The apr pool to use. A child pool will be created
-	 * and associated with the socket.
 	 * @param type The type of socket to create
 	 * @param port The port for the socket
 	 * @return A valid socket shared pointer if the call worked.
 	 */
 	static ptr_t create(
-		apr_pool_t* pool,
 		EType type,
 		U16 port = PORT_EPHEMERAL);
 
 	/** 
-	 * @brief Create a LLSocket when you already have an apr socket.
+	 * @brief Create a LLSocket by accepting a connection from a listen socket.
 	 *
-	 * This method assumes an ephemeral port. This is typically used
-	 * by calls which spawn a socket such as a call to
-	 * <code>accept()</code> as in the server socket. This call should
-	 * not fail if you have a valid apr socket.
-	 * Because of the nature of how accept() works, you are expected
-	 * to create a new pool for the socket, use that pool for the
-	 * accept, and pass it in here where it will be bound with the
-	 * socket and destroyed at the same time.
-	 * @param socket The apr socket to use 
-	 * @param pool The pool used to create the socket. *NOTE: The pool
-	 * passed in will be DESTROYED.
+	 * @param status Output. Status of the accept if a valid listen socket was passed.
+	 * @param listen_socket The listen socket to use.
 	 * @return A valid socket shared pointer if the call worked.
 	 */
-	static ptr_t create(apr_socket_t* socket, apr_pool_t* pool);
+	static ptr_t create(apr_status_t& status, ptr_t& listen_socket);
 
 	/** 
 	 * @brief Perform a blocking connect to a host. Do not use in production.
@@ -145,6 +132,12 @@ class LLSocket
 	 */
 	apr_socket_t* getSocket() const { return mSocket; }
 
+	/** 
+	 * @brief Protected constructor since should only make sockets
+	 * with one of the two <code>create()</code> calls.
+	 */
+	LLSocket(void);
+
 	/** 
 	 * @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us.
 	 * @param timeout Number of microseconds to wait on this socket. Any
@@ -174,8 +167,8 @@ class LLSocket
 	// The apr socket.
 	apr_socket_t* mSocket;
 
-	// our memory pool
-	apr_pool_t* mPool;
+	// Our memory pool.
+	LLAPRPool mPool;
 
 	// The port if we know it.
 	U16 mPort;
@@ -300,7 +293,7 @@ class LLIOServerSocket : public LLIOPipe
 public:
 	typedef LLSocket::ptr_t socket_t;
 	typedef boost::shared_ptr<LLChainIOFactory> factory_t;
-	LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor);
+	LLIOServerSocket(socket_t listener, factory_t reactor);
 	virtual ~LLIOServerSocket();
 
 	/** 
@@ -332,7 +325,6 @@ class LLIOServerSocket : public LLIOPipe
 	//@}
 
 protected:
-	apr_pool_t* mPool;
 	socket_t mListenSocket;
 	factory_t mReactor;
 	bool mInitialized;
@@ -366,8 +358,7 @@ class LLIODataSocket : public LLIOSocket
 	 */
 	LLIODataSocket(
 		U16 suggested_port,
-		U16 start_discovery_port,
-		apr_pool_t* pool);
+		U16 start_discovery_port);
 	virtual ~LLIODataSocket();
 
 protected:
diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp
index 08b31e9c7a29b45cdc61fde26fd5a79a25fba74d..8a898ab1b0b41c301952ac7d493479e600eb098b 100644
--- a/indra/llmessage/llmail.cpp
+++ b/indra/llmessage/llmail.cpp
@@ -50,6 +50,7 @@
 #include "llstring.h"
 #include "lluuid.h"
 #include "net.h"
+#include "llaprpool.h"
 
 //
 // constants
@@ -57,7 +58,7 @@
 const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
 
 static bool gMailEnabled = true;
-static apr_pool_t* gMailPool;
+static LLAPRPool gMailPool;
 static apr_sockaddr_t* gSockAddr;
 static apr_socket_t* gMailSocket;
 
@@ -82,7 +83,7 @@ bool connect_smtp()
 		gSockAddr->sa.sin.sin_family,
 		SOCK_STREAM,
 		APR_PROTO_TCP,
-		gMailPool);
+		gMailPool());
 	if(ll_apr_warn_status(status)) return false;
 	status = apr_socket_connect(gMailSocket, gSockAddr);
 	if(ll_apr_warn_status(status))
@@ -139,19 +140,19 @@ BOOL LLMail::send(
 }
 
 // static
-void LLMail::init(const std::string& hostname, apr_pool_t* pool)
+void LLMail::init(const std::string& hostname)
 {
 	gMailSocket = NULL;
-	if(hostname.empty() || !pool)
+	if (hostname.empty())
 	{
-		gMailPool = NULL;
 		gSockAddr = NULL;
+		gMailPool.destroy();
 	}
 	else
 	{
-		gMailPool = pool;
+		gMailPool.create();
 
-		// collect all the information into a socaddr sturcture. the
+		// Collect all the information into a sockaddr structure. the
 		// documentation is a bit unclear, but I either have to
 		// specify APR_UNSPEC or not specify any flags. I am not sure
 		// which option is better.
@@ -161,7 +162,7 @@ void LLMail::init(const std::string& hostname, apr_pool_t* pool)
 			APR_UNSPEC,
 			25,
 			APR_IPV4_ADDR_OK,
-			gMailPool);
+			gMailPool());
 		ll_apr_warn_status(status);
 	}
 }
diff --git a/indra/llmessage/llmail.h b/indra/llmessage/llmail.h
index 37917143639aae2b224d7543a234f6545e58ae6f..0a5c532088334812a37dfe0db3ae6a096bc33090 100644
--- a/indra/llmessage/llmail.h
+++ b/indra/llmessage/llmail.h
@@ -27,15 +27,13 @@
 #ifndef LL_LLMAIL_H
 #define LL_LLMAIL_H
 
-typedef struct apr_pool_t apr_pool_t;
-
 #include "llsd.h"
 
 class LLMail
 {
 public:
 	// if hostname is NULL, then the host is resolved as 'mail'
-	static void init(const std::string& hostname, apr_pool_t* pool);
+	static void init(const std::string& hostname);
 
 	// Allow all email transmission to be disabled/enabled.
 	static void enable(bool mail_enabled);
diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp
index b26ac42899a84ba17b3b7ea3cee616b52bb1c531..3ffe6d2d3bee52b4c59f0cf0ca78168442bad7f1 100644
--- a/indra/llmessage/llproxy.cpp
+++ b/indra/llmessage/llproxy.cpp
@@ -44,12 +44,12 @@ bool LLProxy::sUDPProxyEnabled = false;
 
 // Some helpful TCP static functions.
 static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake
-static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host); // Open a TCP channel to a given host
+static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host
 static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel
 
 LLProxy::LLProxy():
 		mHTTPProxyEnabled(false),
-		mProxyMutex(0),
+		mProxyMutex(),
 		mUDPProxy(),
 		mTCPProxy(),
 		mHTTPProxy(),
@@ -210,7 +210,7 @@ S32 LLProxy::startSOCKSProxy(LLHost host)
 	// Close any running SOCKS connection.
 	stopSOCKSProxy();
 
-	mProxyControlChannel = tcp_open_channel(gAPRPoolp, mTCPProxy);
+	mProxyControlChannel = tcp_open_channel(mTCPProxy);
 	if (!mProxyControlChannel)
 	{
 		return SOCKS_HOST_CONNECT_FAILED;
@@ -515,13 +515,12 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
  *
  * Checks for a successful connection, and makes sure the connection is closed if it fails.
  *
- * @param pool		APR pool to pass into the LLSocket.
  * @param host		The host to open the connection to.
  * @return			The created socket.  Will evaluate as NULL if the connection is unsuccessful.
  */
-static LLSocket::ptr_t tcp_open_channel(apr_pool_t* pool, LLHost host)
+static LLSocket::ptr_t tcp_open_channel(LLHost host)
 {
-	LLSocket::ptr_t socket = LLSocket::create(pool, LLSocket::STREAM_TCP);
+	LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP);
 	bool connected = socket->blockingConnect(host);
 	if (!connected)
 	{
diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp
index a8d2a0a22409e03b021626f57e34d8f4223d2dc6..89cfd66e1b25d931db2aa237bc4e58b2c0b46880 100644
--- a/indra/llmessage/llpumpio.cpp
+++ b/indra/llmessage/llpumpio.cpp
@@ -37,6 +37,7 @@
 #include "llmemtype.h"
 #include "llstl.h"
 #include "llstat.h"
+#include "llthread.h"
 
 // These should not be enabled in production, but they can be
 // intensely useful during development for finding certain kinds of
@@ -162,14 +163,12 @@ struct ll_delete_apr_pollset_fd_client_data
 /**
  * LLPumpIO
  */
-LLPumpIO::LLPumpIO(apr_pool_t* pool) :
+LLPumpIO::LLPumpIO(void) :
 	mState(LLPumpIO::NORMAL),
 	mRebuildPollset(false),
 	mPollset(NULL),
 	mPollsetClientID(0),
 	mNextLock(0),
-	mPool(NULL),
-	mCurrentPool(NULL),
 	mCurrentPoolReallocCount(0),
 	mChainsMutex(NULL),
 	mCallbackMutex(NULL),
@@ -178,21 +177,24 @@ LLPumpIO::LLPumpIO(apr_pool_t* pool) :
 	mCurrentChain = mRunningChains.end();
 
 	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
-	initialize(pool);
+	initialize();
 }
 
 LLPumpIO::~LLPumpIO()
 {
 	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
-	cleanup();
-}
-
-bool LLPumpIO::prime(apr_pool_t* pool)
-{
-	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
-	cleanup();
-	initialize(pool);
-	return ((pool == NULL) ? false : true);
+#if LL_THREADS_APR
+	if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
+	if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
+#endif
+	mChainsMutex = NULL;
+	mCallbackMutex = NULL;
+	if(mPollset)
+	{
+//		lldebugs << "cleaning up pollset" << llendl;
+		apr_pollset_destroy(mPollset);
+		mPollset = NULL;
+	}
 }
 
 bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
@@ -352,8 +354,7 @@ bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll)
 	{
 		// each fd needs a pool to work with, so if one was
 		// not specified, use this pool.
-		// *FIX: Should it always be this pool?
-		value.second.p = mPool;
+		value.second.p = (*mCurrentChain).mDescriptorsPool->operator()();
 	}
 	value.second.client_data = new S32(++mPollsetClientID);
 	(*mCurrentChain).mDescriptors.push_back(value);
@@ -825,39 +826,15 @@ void LLPumpIO::control(LLPumpIO::EControl op)
 	}
 }
 
-void LLPumpIO::initialize(apr_pool_t* pool)
+void LLPumpIO::initialize(void)
 {
 	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
-	if(!pool) return;
+	mPool.create();
 #if LL_THREADS_APR
 	// SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly.
-	apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, pool);
-	apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, pool);
-#endif
-	mPool = pool;
-}
-
-void LLPumpIO::cleanup()
-{
-	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
-#if LL_THREADS_APR
-	if(mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
-	if(mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
+	apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
+	apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
 #endif
-	mChainsMutex = NULL;
-	mCallbackMutex = NULL;
-	if(mPollset)
-	{
-//		lldebugs << "cleaning up pollset" << llendl;
-		apr_pollset_destroy(mPollset);
-		mPollset = NULL;
-	}
-	if(mCurrentPool)
-	{
-		apr_pool_destroy(mCurrentPool);
-		mCurrentPool = NULL;
-	}
-	mPool = NULL;
 }
 
 void LLPumpIO::rebuildPollset()
@@ -885,21 +862,19 @@ void LLPumpIO::rebuildPollset()
 		if(mCurrentPool
 		   && (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT)))
 		{
-			apr_pool_destroy(mCurrentPool);
-			mCurrentPool = NULL;
+			mCurrentPool.destroy();
 			mCurrentPoolReallocCount = 0;
 		}
 		if(!mCurrentPool)
 		{
-			apr_status_t status = apr_pool_create(&mCurrentPool, mPool);
-			(void)ll_apr_warn_status(status);
+			mCurrentPool.create(mPool);
 		}
 
 		// add all of the file descriptors
 		run_it = mRunningChains.begin();
 		LLChainInfo::conditionals_t::iterator fd_it;
 		LLChainInfo::conditionals_t::iterator fd_end;
-		apr_pollset_create(&mPollset, size, mCurrentPool, 0);
+		apr_pollset_create(&mPollset, size, mCurrentPool(), 0);
 		for(; run_it != run_end; ++run_it)
 		{
 			fd_it = (*run_it).mDescriptors.begin();
@@ -1157,7 +1132,8 @@ bool LLPumpIO::handleChainError(
 LLPumpIO::LLChainInfo::LLChainInfo() :
 	mInit(false),
 	mLock(0),
-	mEOS(false)
+	mEOS(false),
+	mDescriptorsPool(new LLAPRPool(LLThread::tldata().mRootPool))
 {
 	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 	mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS);
diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h
index 9303c9d7fcf994e728f49507e292a49e797b8128..75c35ae7ab95291ed4e6a28abd10aeb70490fd36 100644
--- a/indra/llmessage/llpumpio.h
+++ b/indra/llmessage/llpumpio.h
@@ -30,11 +30,12 @@
 #define LL_LLPUMPIO_H
 
 #include <set>
+#include <boost/shared_ptr.hpp>
 #if LL_LINUX  // needed for PATH_MAX in APR.
 #include <sys/param.h>
 #endif
 
-#include "apr_pools.h"
+#include "llaprpool.h"
 #include "llbuffer.h"
 #include "llframetimer.h"
 #include "lliopipe.h"
@@ -58,9 +59,8 @@ extern const F32 NEVER_CHAIN_EXPIRY_SECS;
  * <code>pump()</code> on a thread used for IO and call
  * <code>respond()</code> on a thread that is expected to do higher
  * level processing. You can call almost any other method from any
- * thread - see notes for each method for details. In order for the
- * threading abstraction to work, you need to call <code>prime()</code>
- * with a valid apr pool.
+ * thread - see notes for each method for details.
+ *
  * A pump instance manages much of the state for the pipe, including
  * the list of pipes in the chain, the channel for each element in the
  * chain, the buffer, and if any pipe has marked the stream or process
@@ -79,24 +79,13 @@ class LLPumpIO
 	/**
 	 * @brief Constructor.
 	 */
-	LLPumpIO(apr_pool_t* pool);
+	LLPumpIO(void);
 
 	/**
 	 * @brief Destructor.
 	 */
 	~LLPumpIO();
 
-	/**
-	 * @brief Prepare this pump for usage.
-	 *
-	 * If you fail to call this method prior to use, the pump will
-	 * try to work, but will not come with any thread locking
-	 * mechanisms.
-	 * @param pool The apr pool to use.
-	 * @return Returns true if the pump is primed.
-	 */
-	bool prime(apr_pool_t* pool);
-
 	/**
 	 * @brief Typedef for having a chain of pipes.
 	 */
@@ -368,6 +357,7 @@ class LLPumpIO
 		typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t;
 		typedef std::vector<pipe_conditional_t> conditionals_t;
 		conditionals_t mDescriptors;
+		boost::shared_ptr<LLAPRPool> mDescriptorsPool;
 	};
 
 	// All the running chains & info
@@ -386,9 +376,9 @@ class LLPumpIO
 	callbacks_t mPendingCallbacks;
 	callbacks_t mCallbacks;
 
-	// memory allocator for pollsets & mutexes.
-	apr_pool_t* mPool;
-	apr_pool_t* mCurrentPool;
+	// Memory pool for pollsets & mutexes.
+	LLAPRPool mPool;
+	LLAPRPool mCurrentPool;
 	S32 mCurrentPoolReallocCount;
 
 #if LL_THREADS_APR
@@ -400,8 +390,7 @@ class LLPumpIO
 #endif
 
 protected:
-	void initialize(apr_pool_t* pool);
-	void cleanup();
+	void initialize();
 
 	/** 
 	 * @brief Given the internal state of the chains, rebuild the pollset
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index d5400e41696c3e46002031564846e269edf5228e..91a5a8ce2cf6d8a0e813fcf208ca5cf99c9e65b4 100644
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -41,6 +41,7 @@
 #include "llstring.h"
 #include "apr_env.h"
 #include "llapr.h"
+#include "llscopedvolatileaprpool.h"
 static const U32 HTTP_STATUS_PIPE_ERROR = 499;
 
 /**
@@ -211,26 +212,31 @@ void LLURLRequest::setCallback(LLURLRequestComplete* callback)
 // is called with use_proxy = FALSE
 void LLURLRequest::useProxy(bool use_proxy)
 {
-    static char *env_proxy;
+    static std::string env_proxy;
 
-    if (use_proxy && (env_proxy == NULL))
+    if (use_proxy && env_proxy.empty())
     {
-        apr_status_t status;
-        LLAPRPool pool;
-		status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool());
+		char* env_proxy_str;
+        LLScopedVolatileAPRPool scoped_pool;
+        apr_status_t status = apr_env_get(&env_proxy_str, "ALL_PROXY", scoped_pool);
         if (status != APR_SUCCESS)
         {
-			status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool());
+			status = apr_env_get(&env_proxy_str, "http_proxy", scoped_pool);
         }
         if (status != APR_SUCCESS)
         {
-           use_proxy = FALSE;
+            use_proxy = false;
         }
+		else
+		{
+			// env_proxy_str is stored in the scoped_pool, so we have to make a copy.
+			env_proxy = env_proxy_str;
+		}
     }
 
-    LL_DEBUGS("Proxy") << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << LL_ENDL;
+    LL_DEBUGS("Proxy") << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (!env_proxy.empty() ? env_proxy : "(null)") << LL_ENDL;
 
-    if (env_proxy && use_proxy)
+    if (use_proxy && !env_proxy.empty())
     {
 		mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy);
     }
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index d0b0e178b83625400f790737d0f45eb1d5aba00a..7d21e35f96a386c65bd5efed4b6e3436df580b1b 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -97,8 +97,10 @@ std::string get_shared_secret();
 class LLMessagePollInfo
 {
 public:
+	LLMessagePollInfo(void) : mPool(LLThread::tldata().mRootPool) { }
 	apr_socket_t *mAPRSocketp;
 	apr_pollfd_t mPollFD;
+	LLAPRPool mPool;
 };
 
 namespace
@@ -287,20 +289,13 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port,
 	}
 //	LL_DEBUGS("Messaging") <<  << "*** port: " << mPort << llendl;
 
-	//
-	// Create the data structure that we can poll on
-	//
-	if (!gAPRPoolp)
-	{
-		LL_ERRS("Messaging") << "No APR pool before message system initialization!" << llendl;
-		ll_init_apr();
-	}
+	mPollInfop = new LLMessagePollInfo;
+
 	apr_socket_t *aprSocketp = NULL;
-	apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, gAPRPoolp);
+	apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, mPollInfop->mPool());
 
-	mPollInfop = new LLMessagePollInfo;
 	mPollInfop->mAPRSocketp = aprSocketp;
-	mPollInfop->mPollFD.p = gAPRPoolp;
+	mPollInfop->mPollFD.p = mPollInfop->mPool();
 	mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET;
 	mPollInfop->mPollFD.reqevents = APR_POLLIN;
 	mPollInfop->mPollFD.rtnevents = 0;
diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h
index 2aff90ca1ef8657f0c56cced2cc9a33c02f98041..23e1c791f470db900d2ea13fd5687edc3dfa8bd7 100644
--- a/indra/llmessage/tests/networkio.h
+++ b/indra/llmessage/tests/networkio.h
@@ -30,7 +30,6 @@
 #define LL_NETWORKIO_H
 
 #include "llmemory.h"               // LLSingleton
-#include "llapr.h"
 #include "llares.h"
 #include "llpumpio.h"
 #include "llhttpclient.h"
@@ -48,14 +47,8 @@ class NetworkIO: public LLSingleton<NetworkIO>
         mServicePump(NULL),
         mDone(false)
     {
-        ll_init_apr();
-        if (! gAPRPoolp)
-        {
-            throw std::runtime_error("Can't initialize APR");
-        }
-
         // Create IO Pump to use for HTTP Requests.
-        mServicePump = new LLPumpIO(gAPRPoolp);
+        mServicePump = new LLPumpIO;
         LLHTTPClient::setPump(*mServicePump);
         if (ll_init_ares() == NULL || !gAres->isInitialized())
         {
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index d081109acc57e3298b1a2940e1f58962e7f56064..9cd3216ab27af27e48b27020948a39548bbf4510 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -1,1424 +1,1445 @@
-/** 
- * @file llpluginclassmedia.cpp
- * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
- *
- * @cond
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- * @endcond
- */
-
-#include "linden_common.h"
-#include "indra_constants.h"
-
-#include "llpluginclassmedia.h"
-#include "llpluginmessageclasses.h"
-
-#include "llqtwebkit.h"
-
-static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
-
-static int nextPowerOf2( int value )
-{
-	int next_power_of_2 = 1;
-	while ( next_power_of_2 < value )
-	{
-		next_power_of_2 <<= 1;
-	}
-	
-	return next_power_of_2;
-}
-
-LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
-{
-	mOwner = owner;
-	mPlugin = NULL;
-	reset();
-
-	//debug use
-	mDeleteOK = true ;
-}
-
-
-LLPluginClassMedia::~LLPluginClassMedia()
-{
-	llassert_always(mDeleteOK) ;
-	reset();
-}
-
-bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
-{	
-	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
-	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
-	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
-	
-	mPlugin = new LLPluginProcessParent(this);
-	mPlugin->setSleepTime(mSleepTime);
-	
-	// Queue up the media init message -- it will be sent after all the currently queued messages.
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
-	message.setValue("target", mTarget);
-	sendMessage(message);
-	
-	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
-
-	return true;
-}
-
-
-void LLPluginClassMedia::reset()
-{
-	if(mPlugin != NULL)
-	{
-		delete mPlugin;
-		mPlugin = NULL;
-	}
-
-	mTextureParamsReceived = false;
-	mRequestedTextureDepth = 0;
-	mRequestedTextureInternalFormat = 0;
-	mRequestedTextureFormat = 0;
-	mRequestedTextureType = 0;
-	mRequestedTextureSwapBytes = false;
-	mRequestedTextureCoordsOpenGL = false;
-	mTextureSharedMemorySize = 0;
-	mTextureSharedMemoryName.clear();
-	mDefaultMediaWidth = 0;
-	mDefaultMediaHeight = 0;
-	mNaturalMediaWidth = 0;
-	mNaturalMediaHeight = 0;
-	mSetMediaWidth = -1;
-	mSetMediaHeight = -1;
-	mRequestedMediaWidth = 0;
-	mRequestedMediaHeight = 0;
-	mRequestedTextureWidth = 0;
-	mRequestedTextureHeight = 0;
-	mFullMediaWidth = 0;
-	mFullMediaHeight = 0;
-	mTextureWidth = 0;
-	mTextureHeight = 0;
-	mMediaWidth = 0;
-	mMediaHeight = 0;
-	mDirtyRect = LLRect::null;	
-	mAutoScaleMedia = false;
-	mRequestedVolume = 1.0f;
-	mPriority = PRIORITY_NORMAL;
-	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
-	mAllowDownsample = false;
-	mPadding = 0;
-	mLastMouseX = 0;
-	mLastMouseY = 0;
-	mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
-	mSleepTime = 1.0f / 100.0f;
-	mCanCut = false;
-	mCanCopy = false;
-	mCanPaste = false;
-	mMediaName.clear();
-	mMediaDescription.clear();
-	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
-	
-	// media_browser class
-	mNavigateURI.clear();
-	mNavigateResultCode = -1;
-	mNavigateResultString.clear();
-	mHistoryBackAvailable = false;
-	mHistoryForwardAvailable = false;
-	mStatusText.clear();
-	mProgressPercent = 0;	
-	mClickURL.clear();
-	mClickNavType.clear();
-	mClickTarget.clear();
-	mClickUUID.clear();
-	mStatusCode = 0;
-	
-	// media_time class
-	mCurrentTime = 0.0f;
-	mDuration = 0.0f;
-	mCurrentRate = 0.0f;
-	mLoadedDuration = 0.0f;
-}
-
-void LLPluginClassMedia::idle(void)
-{
-	if(mPlugin)
-	{
-		mPlugin->idle();
-	}
-	
-	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
-	{
-		// Can't process a size change at this time
-	}
-	else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight))
-	{
-		// Calculate the correct size for the media texture
-		mRequestedTextureHeight = mRequestedMediaHeight;
-		if(mPadding < 0)
-		{
-			// negative values indicate the plugin wants a power of 2
-			mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth);
-		}
-		else
-		{
-			mRequestedTextureWidth = mRequestedMediaWidth;
-			
-			if(mPadding > 1)
-			{
-				// Pad up to a multiple of the specified number of bytes per row
-				int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth;
-				int pad = rowbytes % mPadding;
-				if(pad != 0)
-				{
-					rowbytes += mPadding - pad;
-				}
-				
-				if(rowbytes % mRequestedTextureDepth == 0)
-				{
-					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
-				}
-				else
-				{
-					LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL;
-				}
-			}
-		}
-
-		
-		// Size change has been requested but not initiated yet.
-		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
-
-		// Add an extra line for padding, just in case.
-		newsize += mRequestedTextureWidth * mRequestedTextureDepth;
-
-		if(newsize != mTextureSharedMemorySize)
-		{
-			if(!mTextureSharedMemoryName.empty())
-			{
-				// Tell the plugin to remove the old memory segment
-				mPlugin->removeSharedMemory(mTextureSharedMemoryName);
-				mTextureSharedMemoryName.clear();
-			}
-			
-			mTextureSharedMemorySize = newsize;
-			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
-			if(!mTextureSharedMemoryName.empty())
-			{
-				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
-				
-				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
-				memset( addr, 0x00, newsize );
-				
-				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
-				// so it may not be worthwhile.
-				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
-			}
-		}
-		
-		// This is our local indicator that a change is in progress.
-		mTextureWidth = -1;
-		mTextureHeight = -1;
-		mMediaWidth = -1;
-		mMediaHeight = -1;
-
-		// This invalidates any existing dirty rect.
-		resetDirty();
-		
-		// Send a size change message to the plugin
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
-			message.setValue("name", mTextureSharedMemoryName);
-			message.setValueS32("width", mRequestedMediaWidth);
-			message.setValueS32("height", mRequestedMediaHeight);
-			message.setValueS32("texture_width", mRequestedTextureWidth);
-			message.setValueS32("texture_height", mRequestedTextureHeight);
-			message.setValueReal("background_r", mBackgroundColor.mV[VX]);
-			message.setValueReal("background_g", mBackgroundColor.mV[VY]);
-			message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
-			message.setValueReal("background_a", mBackgroundColor.mV[VW]);
-			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
-			
-			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
-		}
-	}
-	
-	if(mPlugin && mPlugin->isRunning())
-	{
-		// Send queued messages
-		while(!mSendQueue.empty())
-		{
-			LLPluginMessage message = mSendQueue.front();
-			mSendQueue.pop();
-			mPlugin->sendMessage(message);
-		}
-	}
-}
-
-int LLPluginClassMedia::getTextureWidth() const
-{
-	return nextPowerOf2(mTextureWidth);
-}
-
-int LLPluginClassMedia::getTextureHeight() const
-{
-	return nextPowerOf2(mTextureHeight);
-}
-
-unsigned char* LLPluginClassMedia::getBitsData()
-{
-	unsigned char *result = NULL;
-	if((mPlugin != NULL) && !mTextureSharedMemoryName.empty())
-	{
-		result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
-	}
-	return result;
-}
-
-void LLPluginClassMedia::setSize(int width, int height)
-{
-	if((width > 0) && (height > 0))
-	{
-		mSetMediaWidth = width;
-		mSetMediaHeight = height;
-	}
-	else
-	{
-		mSetMediaWidth = -1;
-		mSetMediaHeight = -1;
-	}
-
-	setSizeInternal();
-}
-
-void LLPluginClassMedia::setSizeInternal(void)
-{
-	if((mSetMediaWidth > 0) && (mSetMediaHeight > 0))
-	{
-		mRequestedMediaWidth = mSetMediaWidth;
-		mRequestedMediaHeight = mSetMediaHeight;
-	}
-	else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0))
-	{
-		mRequestedMediaWidth = mNaturalMediaWidth;
-		mRequestedMediaHeight = mNaturalMediaHeight;
-	}
-	else
-	{
-		mRequestedMediaWidth = mDefaultMediaWidth;
-		mRequestedMediaHeight = mDefaultMediaHeight;
-	}
-	
-	// Save these for size/interest calculations
-	mFullMediaWidth = mRequestedMediaWidth;
-	mFullMediaHeight = mRequestedMediaHeight;
-	
-	if(mAllowDownsample)
-	{
-		switch(mPriority)
-		{
-			case PRIORITY_SLIDESHOW:
-			case PRIORITY_LOW:
-				// Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit
-				while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit))
-				{
-					mRequestedMediaWidth /= 2;
-					mRequestedMediaHeight /= 2;
-				}
-			break;
-			
-			default:
-				// Don't adjust texture size
-			break;
-		}
-	}
-	
-	if(mAutoScaleMedia)
-	{
-		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
-		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
-	}
-	
-	if(mRequestedMediaWidth > 2048)
-		mRequestedMediaWidth = 2048;
-
-	if(mRequestedMediaHeight > 2048)
-		mRequestedMediaHeight = 2048;
-}
-
-void LLPluginClassMedia::setAutoScale(bool auto_scale)
-{
-	if(auto_scale != mAutoScaleMedia)
-	{
-		mAutoScaleMedia = auto_scale;
-		setSizeInternal();
-	}
-}
-
-bool LLPluginClassMedia::textureValid(void)
-{
-	if(
-		!mTextureParamsReceived ||
-		mTextureWidth <= 0 ||
-		mTextureHeight <= 0 ||
-		mMediaWidth <= 0 ||
-		mMediaHeight <= 0 ||
-		mRequestedMediaWidth != mMediaWidth ||
-		mRequestedMediaHeight != mMediaHeight ||
-		getBitsData() == NULL
-	)	
-		return false;
-	
-	return true;
-}
-
-bool LLPluginClassMedia::getDirty(LLRect *dirty_rect)
-{
-	bool result = !mDirtyRect.isEmpty();
-
-	if(dirty_rect != NULL)
-	{
-		*dirty_rect = mDirtyRect;
-	}
-
-	return result;
-}
-
-void LLPluginClassMedia::resetDirty(void)
-{
-	mDirtyRect = LLRect::null;
-}
-
-std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
-{
-	std::string result;
-	
-	
-	if(modifiers & MASK_CONTROL)
-	{
-		result += "control|";
-	}
-
-	if(modifiers & MASK_ALT)
-	{
-		result += "alt|";
-	}
-
-	if(modifiers & MASK_SHIFT)
-	{
-		result += "shift|";
-	}
-
-	// TODO: should I deal with platform differences here or in callers?
-	// TODO: how do we deal with the Mac "command" key?
-/*
-	if(modifiers & MASK_SOMETHING)
-	{
-		result += "meta|";
-	}
-*/	
-	return result;
-}
-
-void LLPluginClassMedia::jsEnableObject( bool enable )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object");
-	message.setValueBoolean( "enable", enable );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location");
-	message.setValueReal( "x", x );
-	message.setValueReal( "y", y );
-	message.setValueReal( "z", z );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location");
-	message.setValueReal( "x", x );
-	message.setValueReal( "y", y );
-	message.setValueReal( "z", z );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentOrientationEvent( double angle )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation");
-	message.setValueReal( "angle", angle );
-
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language");
-	message.setValue( "language", language );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region");
-	message.setValue( "region", region );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity )
-{
-	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
-	{
-		return;
-	}
-
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity");
-	message.setValue( "maturity", maturity );
-	sendMessage( message );
-}
-
-void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers)
-{
-	if(type == MOUSE_EVENT_MOVE)
-	{
-		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
-		{
-			// Don't queue up mouse move events that can't be delivered.
-			return;
-		}
-
-		if((x == mLastMouseX) && (y == mLastMouseY))
-		{
-			// Don't spam unnecessary mouse move events.
-			return;
-		}
-		
-		mLastMouseX = x;
-		mLastMouseY = y;
-	}
-	
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
-	std::string temp;
-	switch(type)
-	{
-		case MOUSE_EVENT_DOWN:			temp = "down";			break;
-		case MOUSE_EVENT_UP:			temp = "up";			break;
-		case MOUSE_EVENT_MOVE:			temp = "move";			break;
-		case MOUSE_EVENT_DOUBLE_CLICK:	temp = "double_click";	break;
-	}
-	message.setValue("event", temp);
-
-	message.setValueS32("button", button);
-
-	message.setValueS32("x", x);
-	
-	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
-	if(!mRequestedTextureCoordsOpenGL)
-	{
-		// TODO: Should I use mMediaHeight or mRequestedMediaHeight here?
-		y = mMediaHeight - y;
-	}
-	message.setValueS32("y", y);
-
-	message.setValue("modifiers", translateModifiers(modifiers));
-	
-	sendMessage(message);
-}
-
-bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
-{
-	bool result = true;
-	
-	// FIXME:
-	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
-	// For now, return false for the ones the webkit plugin won't handle properly.
-	
-	switch(key_code)
-	{
-		case KEY_BACKSPACE:		
-		case KEY_TAB:			
-		case KEY_RETURN:		
-		case KEY_PAD_RETURN:	
-		case KEY_SHIFT:			
-		case KEY_CONTROL:		
-		case KEY_ALT:			
-		case KEY_CAPSLOCK:		
-		case KEY_ESCAPE:		
-		case KEY_PAGE_UP:		
-		case KEY_PAGE_DOWN:		
-		case KEY_END:			
-		case KEY_HOME:			
-		case KEY_LEFT:			
-		case KEY_UP:			
-		case KEY_RIGHT:			
-		case KEY_DOWN:			
-		case KEY_INSERT:		
-		case KEY_DELETE:
-			// These will be handled		
-		break;
-		
-		default:
-			// regular ASCII characters will also be handled
-			if(key_code >= KEY_SPECIAL)
-			{
-				// Other "special" codes will not work properly.
-				result = false;
-			}
-		break;
-	}
-
-#if LL_DARWIN	
-	if(modifiers & MASK_ALT)
-	{
-		// Option-key modified characters should be handled by the unicode input path instead of this one.
-		result = false;
-	}
-#endif
-
-	if(result)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
-		std::string temp;
-		switch(type)
-		{
-			case KEY_EVENT_DOWN:			temp = "down";			break;
-			case KEY_EVENT_UP:				temp = "up";			break;
-			case KEY_EVENT_REPEAT:			temp = "repeat";		break;
-		}
-		message.setValue("event", temp);
-		
-		message.setValueS32("key", key_code);
-
-		message.setValue("modifiers", translateModifiers(modifiers));
-		message.setValueLLSD("native_key_data", native_key_data);
-		
-		sendMessage(message);
-	}
-		
-	return result;
-}
-
-void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event");
-
-	message.setValueS32("x", x);
-	message.setValueS32("y", y);
-	message.setValue("modifiers", translateModifiers(modifiers));
-	
-	sendMessage(message);
-}
-	
-bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
-
-	message.setValue("text", text);
-	message.setValue("modifiers", translateModifiers(modifiers));
-	message.setValueLLSD("native_key_data", native_key_data);
-	
-	sendMessage(message);
-	
-	return true;
-}
-
-void LLPluginClassMedia::loadURI(const std::string &uri)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
-
-	message.setValue("uri", uri);
-	
-	sendMessage(message);
-}
-
-const char* LLPluginClassMedia::priorityToString(EPriority priority)
-{
-	const char* result = "UNKNOWN";
-	switch(priority)
-	{
-		case PRIORITY_UNLOADED:		result = "unloaded";	break;
-		case PRIORITY_STOPPED:		result = "stopped";		break;
-		case PRIORITY_HIDDEN:		result = "hidden";		break;
-		case PRIORITY_SLIDESHOW:	result = "slideshow";	break;
-		case PRIORITY_LOW:			result = "low";			break;
-		case PRIORITY_NORMAL:		result = "normal";		break;
-		case PRIORITY_HIGH:			result = "high";		break;
-	}
-	
-	return result;
-}
-
-void LLPluginClassMedia::setPriority(EPriority priority)
-{
-	if(mPriority != priority)
-	{
-		mPriority = priority;
-
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
-		
-		std::string priority_string = priorityToString(priority);
-		switch(priority)
-		{
-			case PRIORITY_UNLOADED:	
-				mSleepTime = 1.0f;
-			break;
-			case PRIORITY_STOPPED:	
-				mSleepTime = 1.0f;
-			break;
-			case PRIORITY_HIDDEN:	
-				mSleepTime = 1.0f;
-			break;
-			case PRIORITY_SLIDESHOW:
-				mSleepTime = 1.0f;
-			break;
-			case PRIORITY_LOW:		
-				mSleepTime = 1.0f / 25.0f;
-			break;
-			case PRIORITY_NORMAL:	
-				mSleepTime = 1.0f / 50.0f;
-			break;
-			case PRIORITY_HIGH:		
-				mSleepTime = 1.0f / 100.0f;
-			break;
-		}
-		
-		message.setValue("priority", priority_string);
-
-		sendMessage(message);
-		
-		if(mPlugin)
-		{
-			mPlugin->setSleepTime(mSleepTime);
-		}
-		
-		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
-		
-		// This may affect the calculated size, so recalculate it here.
-		setSizeInternal();
-	}
-}
-
-void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
-{
-	int power = nextPowerOf2(size);
-	if(mLowPrioritySizeLimit != power)
-	{
-		mLowPrioritySizeLimit = power;
-
-		// This may affect the calculated size, so recalculate it here.
-		setSizeInternal();
-	}
-}
-
-F64 LLPluginClassMedia::getCPUUsage()
-{
-	F64 result = 0.0f;
-	
-	if(mPlugin)
-	{
-		result = mPlugin->getCPUUsage();
-	}
-	
-	return result;
-}
-
-void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
-	message.setValue("file", file);
-	if(mPlugin && mPlugin->isBlocked())
-	{
-		// If the plugin sent a blocking pick-file request, the response should unblock it.
-		message.setValueBoolean("blocking_response", true);
-	}
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response");
-	message.setValueBoolean("ok", ok);
-	message.setValue("username", username);
-	message.setValue("password", password);
-	if(mPlugin && mPlugin->isBlocked())
-	{
-		// If the plugin sent a blocking pick-file request, the response should unblock it.
-		message.setValueBoolean("blocking_response", true);
-	}
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::cut()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::copy()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::paste()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
-	message.setValue("path", user_data_path);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code");
-	message.setValue("language", language_code);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
-	message.setValueBoolean("enable", enabled);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
-	message.setValueBoolean("enable", enabled);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setTarget(const std::string &target)
-{
-	mTarget = target;
-}
-
-/* virtual */ 
-void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
-{
-	std::string message_class = message.getClass();
-	
-	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
-	{
-		std::string message_name = message.getName();
-		if(message_name == "texture_params")
-		{
-			mRequestedTextureDepth = message.getValueS32("depth");
-			mRequestedTextureInternalFormat = message.getValueU32("internalformat");
-			mRequestedTextureFormat = message.getValueU32("format");
-			mRequestedTextureType = message.getValueU32("type");
-			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
-			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			
-			
-			// These two are optional, and will default to 0 if they're not specified.
-			mDefaultMediaWidth = message.getValueS32("default_width");
-			mDefaultMediaHeight = message.getValueS32("default_height");
-			
-			mAllowDownsample = message.getValueBoolean("allow_downsample");
-			mPadding = message.getValueS32("padding");
-
-			setSizeInternal();
-			
-			mTextureParamsReceived = true;
-		}
-		else if(message_name == "updated")
-		{			
-			if(message.hasValue("left"))
-			{
-				LLRect newDirtyRect;
-				newDirtyRect.mLeft = message.getValueS32("left");
-				newDirtyRect.mTop = message.getValueS32("top");
-				newDirtyRect.mRight = message.getValueS32("right");
-				newDirtyRect.mBottom = message.getValueS32("bottom");
-							
-				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
-				// If they're backwards, swap them.
-				if(newDirtyRect.mTop < newDirtyRect.mBottom)
-				{
-					S32 temp = newDirtyRect.mTop;
-					newDirtyRect.mTop = newDirtyRect.mBottom;
-					newDirtyRect.mBottom = temp;
-				}
-				
-				if(mDirtyRect.isEmpty())
-				{
-					mDirtyRect = newDirtyRect;
-				}
-				else
-				{
-					mDirtyRect.unionWith(newDirtyRect);
-				}
-
-				LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" 
-					<< newDirtyRect.mLeft << ", "
-					<< newDirtyRect.mTop << ", "
-					<< newDirtyRect.mRight << ", "
-					<< newDirtyRect.mBottom << "), new dirty rect is: ("
-					<< mDirtyRect.mLeft << ", "
-					<< mDirtyRect.mTop << ", "
-					<< mDirtyRect.mRight << ", "
-					<< mDirtyRect.mBottom << ")"
-					<< LL_ENDL;
-				
-				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
-			}			
-			
-
-			bool time_duration_updated = false;
-			int previous_percent = mProgressPercent;
-
-			if(message.hasValue("current_time"))
-			{
-				mCurrentTime = message.getValueReal("current_time");
-				time_duration_updated = true;
-			}
-			if(message.hasValue("duration"))
-			{
-				mDuration = message.getValueReal("duration");
-				time_duration_updated = true;
-			}
-
-			if(message.hasValue("current_rate"))
-			{
-				mCurrentRate = message.getValueReal("current_rate");
-			}
-			
-			if(message.hasValue("loaded_duration"))
-			{
-				mLoadedDuration = message.getValueReal("loaded_duration");
-				time_duration_updated = true;
-			}
-			else
-			{
-				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
-				mLoadedDuration = mDuration;
-			}
-			
-			// Calculate a percentage based on the loaded duration and total duration.
-			if(mDuration != 0.0f)	// Don't divide by zero.
-			{
-				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
-			}
-
-			if(time_duration_updated)
-			{
-				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
-			}
-			
-			if(previous_percent != mProgressPercent)
-			{
-				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
-			}
-		}
-		else if(message_name == "media_status")
-		{
-			std::string status = message.getValue("status");
-			
-			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
-			
-			if(status == "loading")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
-			}
-			else if(status == "loaded")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_LOADED;
-			}
-			else if(status == "error")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_ERROR;
-			}
-			else if(status == "playing")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING;
-			}
-			else if(status == "paused")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;
-			}
-			else if(status == "done")
-			{
-				mStatus = LLPluginClassMediaOwner::MEDIA_DONE;
-			}
-			else
-			{
-				// empty string or any unknown string
-				mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
-			}
-		}
-		else if(message_name == "size_change_request")
-		{
-			S32 width = message.getValueS32("width");
-			S32 height = message.getValueS32("height");
-			std::string name = message.getValue("name");
-
-			// TODO: check that name matches?
-			mNaturalMediaWidth = width;
-			mNaturalMediaHeight = height;
-			
-			setSizeInternal();
-		}
-		else if(message_name == "size_change_response")
-		{
-			std::string name = message.getValue("name");
-			
-			// TODO: check that name matches?
-			
-			mTextureWidth = message.getValueS32("texture_width");
-			mTextureHeight = message.getValueS32("texture_height");
-			mMediaWidth = message.getValueS32("width");
-			mMediaHeight = message.getValueS32("height");
-			
-			// This invalidates any existing dirty rect.
-			resetDirty();
-			
-			// TODO: should we verify that the plugin sent back the right values?  
-			// Two size changes in a row may cause them to not match, due to queueing, etc.
-
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
-		}
-		else if(message_name == "cursor_changed")
-		{
-			mCursorName = message.getValue("name");
-
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED);
-		}
-		else if(message_name == "edit_state")
-		{
-			if(message.hasValue("cut"))
-			{
-				mCanCut = message.getValueBoolean("cut");
-			}
-			if(message.hasValue("copy"))
-			{
-				mCanCopy = message.getValueBoolean("copy");
-			}
-			if(message.hasValue("paste"))
-			{
-				mCanPaste = message.getValueBoolean("paste");
-			}
-		}
-		else if(message_name == "name_text")
-		{
-			mMediaName = message.getValue("name");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
-		}
-		else if(message_name == "pick_file")
-		{
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
-		}
-		else if(message_name == "auth_request")
-		{
-			mAuthURL = message.getValue("url");
-			mAuthRealm = message.getValue("realm");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
-		}
-		else
-		{
-			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
-		}
-	}
-	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
-	{
-		std::string message_name = message.getName();
-		if(message_name == "navigate_begin")
-		{
-			mNavigateURI = message.getValue("uri");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN);
-		}
-		else if(message_name == "navigate_complete")
-		{
-			mNavigateURI = message.getValue("uri");
-			mNavigateResultCode = message.getValueS32("result_code");
-			mNavigateResultString = message.getValue("result_string");
-			mHistoryBackAvailable = message.getValueBoolean("history_back_available");
-			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
-			
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
-		}
-		else if(message_name == "progress")
-		{
-			mProgressPercent = message.getValueS32("percent");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
-		}
-		else if(message_name == "status_text")
-		{
-			mStatusText = message.getValue("status");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED);
-		}
-		else if(message_name == "location_changed")
-		{
-			mLocation = message.getValue("uri");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED);
-		}
-		else if(message_name == "click_href")
-		{
-			mClickURL = message.getValue("uri");
-			mClickTarget = message.getValue("target");
-			mClickUUID = message.getValue("uuid");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
-		}
-		else if(message_name == "click_nofollow")
-		{
-			mClickURL = message.getValue("uri");
-			mClickNavType = message.getValue("nav_type");
-			mClickTarget.clear();
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
-		}
-		else if(message_name == "navigate_error_page")
-		{
-			mStatusCode = message.getValueS32("status_code");
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE);
-		}
-		else if(message_name == "cookie_set")
-		{
-			if(mOwner)
-			{
-				mOwner->handleCookieSet(this, message.getValue("cookie"));
-			}
-		}
-		else if(message_name == "close_request")
-		{
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST);
-		}
-		else if(message_name == "geometry_change")
-		{
-			mClickUUID = message.getValue("uuid");
-			mGeometryX = message.getValueS32("x");
-			mGeometryY = message.getValueS32("y");
-			mGeometryWidth = message.getValueS32("width");
-			mGeometryHeight = message.getValueS32("height");
-				
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
-		}
-		else if(message_name == "link_hovered")
-		{
-			// text is not currently used -- the tooltip hover text is taken from the "title".
-			mHoverLink = message.getValue("link");
-			mHoverText = message.getValue("title");
-			// message.getValue("text");
-				
-			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
-		}
-		else
-		{
-			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
-		}
-	}
-	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
-	{
-		std::string message_name = message.getName();
-
-		// This class hasn't defined any incoming messages yet.
-//		if(message_name == "message_name")
-//		{
-//		}
-//		else 
-		{
-			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
-		}
-	}
-
-}
-
-/* virtual */ 
-void LLPluginClassMedia::pluginLaunchFailed()
-{
-	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
-}
-
-/* virtual */ 
-void LLPluginClassMedia::pluginDied()
-{
-	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
-}
-
-void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event)
-{
-	if(mOwner)
-	{
-		mOwner->handleMediaEvent(this, event);
-	}
-}
-
-void LLPluginClassMedia::sendMessage(const LLPluginMessage &message)
-{
-	if(mPlugin && mPlugin->isRunning())
-	{
-		mPlugin->sendMessage(message);
-	}
-	else
-	{
-		// The plugin isn't set up yet -- queue this message to be sent after initialization.
-		mSendQueue.push(message);
-	}
-}
-
-////////////////////////////////////////////////////////////
-// MARK: media_browser class functions
-bool LLPluginClassMedia::pluginSupportsMediaBrowser(void)
-{
-	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER);
-	return !version.empty();
-}
-
-void LLPluginClassMedia::focus(bool focused)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
-
-	message.setValueBoolean("focused", focused);
-	
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::clear_cache()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::clear_cookies()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::set_cookies(const std::string &cookies)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
-	message.setValue("cookies", cookies);	
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::enable_cookies(bool enable)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
-	message.setValueBoolean("enable", enable);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup");
-
-	message.setValueBoolean("enable", enable);
-	message.setValue("host", host);
-	message.setValueS32("port", port);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::browse_stop()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::browse_reload(bool ignore_cache)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
-
-	message.setValueBoolean("ignore_cache", ignore_cache);
-	
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::browse_forward()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::browse_back()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent");
-
-	message.setValue("user_agent", user_agent);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened");
-
-	message.setValue("target", target);
-	message.setValue("uuid", uuid);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed");
-
-	message.setValue("uuid", uuid);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors");
-	message.setValueBoolean("ignore", ignore);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path");
-	message.setValue("path", path);
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::crashPlugin()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::hangPlugin()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang");
-
-	sendMessage(message);
-}
-
-
-////////////////////////////////////////////////////////////
-// MARK: media_time class functions
-bool LLPluginClassMedia::pluginSupportsMediaTime(void)
-{
-	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME);
-	return !version.empty();
-}
-
-void LLPluginClassMedia::stop()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::start(float rate)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start");
-
-	message.setValueReal("rate", rate);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::pause()
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause");
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::seek(float time)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
-
-	message.setValueReal("time", time);
-	
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setLoop(bool loop)
-{
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop");
-
-	message.setValueBoolean("loop", loop);
-
-	sendMessage(message);
-}
-
-void LLPluginClassMedia::setVolume(float volume)
-{
-	if(volume != mRequestedVolume)
-	{
-		mRequestedVolume = volume;
-		
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
-
-		message.setValueReal("volume", volume);
-		
-		sendMessage(message);
-	}
-}
-
-float LLPluginClassMedia::getVolume()
-{
-	return mRequestedVolume;
-}
-
-void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
-{
-	// Send URL history to plugin
-	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history");
-	message.setValueLLSD("history", url_history);
-	sendMessage(message);
-
-	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
-}
-
+/** 
+ * @file llpluginclassmedia.cpp
+ * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
+ *
+ * @cond
+ * $LicenseInfo:firstyear=2008&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ * @endcond
+ */
+
+#include "linden_common.h"
+#include "indra_constants.h"
+
+#include "llpluginclassmedia.h"
+#include "llpluginmessageclasses.h"
+
+#include "llqtwebkit.h"
+
+static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
+
+static int nextPowerOf2( int value )
+{
+	int next_power_of_2 = 1;
+	while ( next_power_of_2 < value )
+	{
+		next_power_of_2 <<= 1;
+	}
+	
+	return next_power_of_2;
+}
+
+LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
+{
+	mOwner = owner;
+	mPlugin = NULL;
+	reset();
+
+	//debug use
+	mDeleteOK = true ;
+}
+
+
+LLPluginClassMedia::~LLPluginClassMedia()
+{
+	llassert_always(mDeleteOK) ;
+	reset();
+}
+
+bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
+{	
+	LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
+	LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
+	LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
+	
+	mPlugin = new LLPluginProcessParent(this);
+	mPlugin->setSleepTime(mSleepTime);
+	
+	// Queue up the media init message -- it will be sent after all the currently queued messages.
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
+	message.setValue("target", mTarget);
+	sendMessage(message);
+	
+	mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
+
+	return true;
+}
+
+
+void LLPluginClassMedia::reset()
+{
+	if(mPlugin != NULL)
+	{
+		delete mPlugin;
+		mPlugin = NULL;
+	}
+
+	mTextureParamsReceived = false;
+	mRequestedTextureDepth = 0;
+	mRequestedTextureInternalFormat = 0;
+	mRequestedTextureFormat = 0;
+	mRequestedTextureType = 0;
+	mRequestedTextureSwapBytes = false;
+	mRequestedTextureCoordsOpenGL = false;
+	mTextureSharedMemorySize = 0;
+	mTextureSharedMemoryName.clear();
+	mDefaultMediaWidth = 0;
+	mDefaultMediaHeight = 0;
+	mNaturalMediaWidth = 0;
+	mNaturalMediaHeight = 0;
+	mSetMediaWidth = -1;
+	mSetMediaHeight = -1;
+	mRequestedMediaWidth = 0;
+	mRequestedMediaHeight = 0;
+	mRequestedTextureWidth = 0;
+	mRequestedTextureHeight = 0;
+	mFullMediaWidth = 0;
+	mFullMediaHeight = 0;
+	mTextureWidth = 0;
+	mTextureHeight = 0;
+	mMediaWidth = 0;
+	mMediaHeight = 0;
+	mDirtyRect = LLRect::null;	
+	mAutoScaleMedia = false;
+	mRequestedVolume = 1.0f;
+	mPriority = PRIORITY_NORMAL;
+	mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
+	mAllowDownsample = false;
+	mPadding = 0;
+	mLastMouseX = 0;
+	mLastMouseY = 0;
+	mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
+	mSleepTime = 1.0f / 100.0f;
+	mCanCut = false;
+	mCanCopy = false;
+	mCanPaste = false;
+	mMediaName.clear();
+	mMediaDescription.clear();
+	mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
+	
+	// media_browser class
+	mNavigateURI.clear();
+	mNavigateResultCode = -1;
+	mNavigateResultString.clear();
+	mHistoryBackAvailable = false;
+	mHistoryForwardAvailable = false;
+	mStatusText.clear();
+	mProgressPercent = 0;	
+	mClickURL.clear();
+	mClickNavType.clear();
+	mClickTarget.clear();
+	mClickUUID.clear();
+	mStatusCode = 0;
+	
+	// media_time class
+	mCurrentTime = 0.0f;
+	mDuration = 0.0f;
+	mCurrentRate = 0.0f;
+	mLoadedDuration = 0.0f;
+}
+
+void LLPluginClassMedia::idle(void)
+{
+	if(mPlugin)
+	{
+		mPlugin->idle();
+	}
+	
+	if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
+	{
+		// Can't process a size change at this time
+	}
+	else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight))
+	{
+		// Calculate the correct size for the media texture
+		mRequestedTextureHeight = mRequestedMediaHeight;
+		if(mPadding < 0)
+		{
+			// negative values indicate the plugin wants a power of 2
+			mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth);
+		}
+		else
+		{
+			mRequestedTextureWidth = mRequestedMediaWidth;
+			
+			if(mPadding > 1)
+			{
+				// Pad up to a multiple of the specified number of bytes per row
+				int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth;
+				int pad = rowbytes % mPadding;
+				if(pad != 0)
+				{
+					rowbytes += mPadding - pad;
+				}
+				
+				if(rowbytes % mRequestedTextureDepth == 0)
+				{
+					mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
+				}
+				else
+				{
+					LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL;
+				}
+			}
+		}
+
+		
+		// Size change has been requested but not initiated yet.
+		size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
+
+		// Add an extra line for padding, just in case.
+		newsize += mRequestedTextureWidth * mRequestedTextureDepth;
+
+		if(newsize != mTextureSharedMemorySize)
+		{
+			if(!mTextureSharedMemoryName.empty())
+			{
+				// Tell the plugin to remove the old memory segment
+				mPlugin->removeSharedMemory(mTextureSharedMemoryName);
+				mTextureSharedMemoryName.clear();
+			}
+			
+			mTextureSharedMemorySize = newsize;
+			mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
+			if(!mTextureSharedMemoryName.empty())
+			{
+				void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
+				
+				// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
+				memset( addr, 0x00, newsize );
+				
+				// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
+				// so it may not be worthwhile.
+				// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
+			}
+		}
+		
+		// This is our local indicator that a change is in progress.
+		mTextureWidth = -1;
+		mTextureHeight = -1;
+		mMediaWidth = -1;
+		mMediaHeight = -1;
+
+		// This invalidates any existing dirty rect.
+		resetDirty();
+		
+		// Send a size change message to the plugin
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
+			message.setValue("name", mTextureSharedMemoryName);
+			message.setValueS32("width", mRequestedMediaWidth);
+			message.setValueS32("height", mRequestedMediaHeight);
+			message.setValueS32("texture_width", mRequestedTextureWidth);
+			message.setValueS32("texture_height", mRequestedTextureHeight);
+			message.setValueReal("background_r", mBackgroundColor.mV[VX]);
+			message.setValueReal("background_g", mBackgroundColor.mV[VY]);
+			message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
+			message.setValueReal("background_a", mBackgroundColor.mV[VW]);
+			mPlugin->sendMessage(message);	// DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
+			
+			LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
+		}
+	}
+	
+	if(mPlugin && mPlugin->isRunning())
+	{
+		// Send queued messages
+		while(!mSendQueue.empty())
+		{
+			LLPluginMessage message = mSendQueue.front();
+			mSendQueue.pop();
+			mPlugin->sendMessage(message);
+		}
+	}
+}
+
+int LLPluginClassMedia::getTextureWidth() const
+{
+	return nextPowerOf2(mTextureWidth);
+}
+
+int LLPluginClassMedia::getTextureHeight() const
+{
+	return nextPowerOf2(mTextureHeight);
+}
+
+unsigned char* LLPluginClassMedia::getBitsData()
+{
+	unsigned char *result = NULL;
+	if((mPlugin != NULL) && !mTextureSharedMemoryName.empty())
+	{
+		result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
+	}
+	return result;
+}
+
+void LLPluginClassMedia::setSize(int width, int height)
+{
+	if((width > 0) && (height > 0))
+	{
+		mSetMediaWidth = width;
+		mSetMediaHeight = height;
+	}
+	else
+	{
+		mSetMediaWidth = -1;
+		mSetMediaHeight = -1;
+	}
+
+	setSizeInternal();
+}
+
+void LLPluginClassMedia::setSizeInternal(void)
+{
+	if((mSetMediaWidth > 0) && (mSetMediaHeight > 0))
+	{
+		mRequestedMediaWidth = mSetMediaWidth;
+		mRequestedMediaHeight = mSetMediaHeight;
+	}
+	else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0))
+	{
+		mRequestedMediaWidth = mNaturalMediaWidth;
+		mRequestedMediaHeight = mNaturalMediaHeight;
+	}
+	else
+	{
+		mRequestedMediaWidth = mDefaultMediaWidth;
+		mRequestedMediaHeight = mDefaultMediaHeight;
+	}
+	
+	// Save these for size/interest calculations
+	mFullMediaWidth = mRequestedMediaWidth;
+	mFullMediaHeight = mRequestedMediaHeight;
+	
+	if(mAllowDownsample)
+	{
+		switch(mPriority)
+		{
+			case PRIORITY_SLIDESHOW:
+			case PRIORITY_LOW:
+				// Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit
+				while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit))
+				{
+					mRequestedMediaWidth /= 2;
+					mRequestedMediaHeight /= 2;
+				}
+			break;
+			
+			default:
+				// Don't adjust texture size
+			break;
+		}
+	}
+	
+	if(mAutoScaleMedia)
+	{
+		mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
+		mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
+	}
+	
+	if(mRequestedMediaWidth > 2048)
+		mRequestedMediaWidth = 2048;
+
+	if(mRequestedMediaHeight > 2048)
+		mRequestedMediaHeight = 2048;
+}
+
+void LLPluginClassMedia::setAutoScale(bool auto_scale)
+{
+	if(auto_scale != mAutoScaleMedia)
+	{
+		mAutoScaleMedia = auto_scale;
+		setSizeInternal();
+	}
+}
+
+bool LLPluginClassMedia::textureValid(void)
+{
+	if(
+		!mTextureParamsReceived ||
+		mTextureWidth <= 0 ||
+		mTextureHeight <= 0 ||
+		mMediaWidth <= 0 ||
+		mMediaHeight <= 0 ||
+		mRequestedMediaWidth != mMediaWidth ||
+		mRequestedMediaHeight != mMediaHeight ||
+		getBitsData() == NULL
+	)	
+		return false;
+	
+	return true;
+}
+
+bool LLPluginClassMedia::getDirty(LLRect *dirty_rect)
+{
+	bool result = !mDirtyRect.isEmpty();
+
+	if(dirty_rect != NULL)
+	{
+		*dirty_rect = mDirtyRect;
+	}
+
+	return result;
+}
+
+void LLPluginClassMedia::resetDirty(void)
+{
+	mDirtyRect = LLRect::null;
+}
+
+std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
+{
+	std::string result;
+	
+	
+	if(modifiers & MASK_CONTROL)
+	{
+		result += "control|";
+	}
+
+	if(modifiers & MASK_ALT)
+	{
+		result += "alt|";
+	}
+
+	if(modifiers & MASK_SHIFT)
+	{
+		result += "shift|";
+	}
+
+	// TODO: should I deal with platform differences here or in callers?
+	// TODO: how do we deal with the Mac "command" key?
+/*
+	if(modifiers & MASK_SOMETHING)
+	{
+		result += "meta|";
+	}
+*/	
+	return result;
+}
+
+void LLPluginClassMedia::jsEnableObject( bool enable )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_enable_object");
+	message.setValueBoolean( "enable", enable );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentLocationEvent( double x, double y, double z )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_location");
+	message.setValueReal( "x", x );
+	message.setValueReal( "y", y );
+	message.setValueReal( "z", z );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentGlobalLocationEvent( double x, double y, double z )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_global_location");
+	message.setValueReal( "x", x );
+	message.setValueReal( "y", y );
+	message.setValueReal( "z", z );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentOrientationEvent( double angle )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_orientation");
+	message.setValueReal( "angle", angle );
+
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentLanguageEvent( const std::string& language )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_language");
+	message.setValue( "language", language );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentRegionEvent( const std::string& region )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_region");
+	message.setValue( "region", region );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::jsAgentMaturityEvent( const std::string& maturity )
+{
+	if( ! mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked() )
+	{
+		return;
+	}
+
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "js_agent_maturity");
+	message.setValue( "maturity", maturity );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers)
+{
+	if(type == MOUSE_EVENT_MOVE)
+	{
+		if(!mPlugin || !mPlugin->isRunning() || mPlugin->isBlocked())
+		{
+			// Don't queue up mouse move events that can't be delivered.
+			return;
+		}
+
+		if((x == mLastMouseX) && (y == mLastMouseY))
+		{
+			// Don't spam unnecessary mouse move events.
+			return;
+		}
+		
+		mLastMouseX = x;
+		mLastMouseY = y;
+	}
+	
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
+	std::string temp;
+	switch(type)
+	{
+		case MOUSE_EVENT_DOWN:			temp = "down";			break;
+		case MOUSE_EVENT_UP:			temp = "up";			break;
+		case MOUSE_EVENT_MOVE:			temp = "move";			break;
+		case MOUSE_EVENT_DOUBLE_CLICK:	temp = "double_click";	break;
+	}
+	message.setValue("event", temp);
+
+	message.setValueS32("button", button);
+
+	message.setValueS32("x", x);
+	
+	// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
+	if(!mRequestedTextureCoordsOpenGL)
+	{
+		// TODO: Should I use mMediaHeight or mRequestedMediaHeight here?
+		y = mMediaHeight - y;
+	}
+	message.setValueS32("y", y);
+
+	message.setValue("modifiers", translateModifiers(modifiers));
+	
+	sendMessage(message);
+}
+
+bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
+{
+	bool result = true;
+	
+	// FIXME:
+	// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
+	// For now, return false for the ones the webkit plugin won't handle properly.
+	
+	switch(key_code)
+	{
+		case KEY_BACKSPACE:		
+		case KEY_TAB:			
+		case KEY_RETURN:		
+		case KEY_PAD_RETURN:	
+		case KEY_SHIFT:			
+		case KEY_CONTROL:		
+		case KEY_ALT:			
+		case KEY_CAPSLOCK:		
+		case KEY_ESCAPE:		
+		case KEY_PAGE_UP:		
+		case KEY_PAGE_DOWN:		
+		case KEY_END:			
+		case KEY_HOME:			
+		case KEY_LEFT:			
+		case KEY_UP:			
+		case KEY_RIGHT:			
+		case KEY_DOWN:			
+		case KEY_INSERT:		
+		case KEY_DELETE:
+			// These will be handled		
+		break;
+		
+		default:
+			// regular ASCII characters will also be handled
+			if(key_code >= KEY_SPECIAL)
+			{
+				// Other "special" codes will not work properly.
+				result = false;
+			}
+		break;
+	}
+
+#if LL_DARWIN	
+	if(modifiers & MASK_ALT)
+	{
+		// Option-key modified characters should be handled by the unicode input path instead of this one.
+		result = false;
+	}
+#endif
+
+	if(result)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
+		std::string temp;
+		switch(type)
+		{
+			case KEY_EVENT_DOWN:			temp = "down";			break;
+			case KEY_EVENT_UP:				temp = "up";			break;
+			case KEY_EVENT_REPEAT:			temp = "repeat";		break;
+		}
+		message.setValue("event", temp);
+		
+		message.setValueS32("key", key_code);
+
+		message.setValue("modifiers", translateModifiers(modifiers));
+		message.setValueLLSD("native_key_data", native_key_data);
+		
+		sendMessage(message);
+	}
+		
+	return result;
+}
+
+void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event");
+
+	message.setValueS32("x", x);
+	message.setValueS32("y", y);
+	message.setValue("modifiers", translateModifiers(modifiers));
+	
+	sendMessage(message);
+}
+	
+bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
+
+	message.setValue("text", text);
+	message.setValue("modifiers", translateModifiers(modifiers));
+	message.setValueLLSD("native_key_data", native_key_data);
+	
+	sendMessage(message);
+	
+	return true;
+}
+
+void LLPluginClassMedia::loadURI(const std::string &uri)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
+
+	message.setValue("uri", uri);
+	
+	sendMessage(message);
+}
+
+const char* LLPluginClassMedia::priorityToString(EPriority priority)
+{
+	const char* result = "UNKNOWN";
+	switch(priority)
+	{
+		case PRIORITY_UNLOADED:		result = "unloaded";	break;
+		case PRIORITY_STOPPED:		result = "stopped";		break;
+		case PRIORITY_HIDDEN:		result = "hidden";		break;
+		case PRIORITY_SLIDESHOW:	result = "slideshow";	break;
+		case PRIORITY_LOW:			result = "low";			break;
+		case PRIORITY_NORMAL:		result = "normal";		break;
+		case PRIORITY_HIGH:			result = "high";		break;
+	}
+	
+	return result;
+}
+
+void LLPluginClassMedia::setPriority(EPriority priority)
+{
+	if(mPriority != priority)
+	{
+		mPriority = priority;
+
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
+		
+		std::string priority_string = priorityToString(priority);
+		switch(priority)
+		{
+			case PRIORITY_UNLOADED:	
+				mSleepTime = 1.0f;
+			break;
+			case PRIORITY_STOPPED:	
+				mSleepTime = 1.0f;
+			break;
+			case PRIORITY_HIDDEN:	
+				mSleepTime = 1.0f;
+			break;
+			case PRIORITY_SLIDESHOW:
+				mSleepTime = 1.0f;
+			break;
+			case PRIORITY_LOW:		
+				mSleepTime = 1.0f / 25.0f;
+			break;
+			case PRIORITY_NORMAL:	
+				mSleepTime = 1.0f / 50.0f;
+			break;
+			case PRIORITY_HIGH:		
+				mSleepTime = 1.0f / 100.0f;
+			break;
+		}
+		
+		message.setValue("priority", priority_string);
+
+		sendMessage(message);
+		
+		if(mPlugin)
+		{
+			mPlugin->setSleepTime(mSleepTime);
+		}
+		
+		LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
+		
+		// This may affect the calculated size, so recalculate it here.
+		setSizeInternal();
+	}
+}
+
+void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
+{
+	int power = nextPowerOf2(size);
+	if(mLowPrioritySizeLimit != power)
+	{
+		mLowPrioritySizeLimit = power;
+
+		// This may affect the calculated size, so recalculate it here.
+		setSizeInternal();
+	}
+}
+
+F64 LLPluginClassMedia::getCPUUsage()
+{
+	F64 result = 0.0f;
+	
+	if(mPlugin)
+	{
+		result = mPlugin->getCPUUsage();
+	}
+	
+	return result;
+}
+
+void LLPluginClassMedia::sendPickFileResponse(const std::string &file)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response");
+	message.setValue("file", file);
+	if(mPlugin && mPlugin->isBlocked())
+	{
+		// If the plugin sent a blocking pick-file request, the response should unblock it.
+		message.setValueBoolean("blocking_response", true);
+	}
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, const std::string &password)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_response");
+	message.setValueBoolean("ok", ok);
+	message.setValue("username", username);
+	message.setValue("password", password);
+	if(mPlugin && mPlugin->isBlocked())
+	{
+		// If the plugin sent a blocking pick-file request, the response should unblock it.
+		message.setValueBoolean("blocking_response", true);
+	}
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::cut()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::copy()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::paste()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
+	message.setValue("path", user_data_path);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_language_code");
+	message.setValue("language", language_code);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
+	message.setValueBoolean("enable", enabled);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
+	message.setValueBoolean("enable", enabled);
+	sendMessage(message);
+}
+
+
+void LLPluginClassMedia::enableMediaPluginDebugging( bool enable )
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "enable_media_plugin_debugging");
+	message.setValueBoolean( "enable", enable );
+	sendMessage( message );
+}
+
+void LLPluginClassMedia::setTarget(const std::string &target)
+{
+	mTarget = target;
+}
+
+/* virtual */ 
+void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
+{
+	std::string message_class = message.getClass();
+	
+	if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+	{
+		std::string message_name = message.getName();
+		if(message_name == "texture_params")
+		{
+			mRequestedTextureDepth = message.getValueS32("depth");
+			mRequestedTextureInternalFormat = message.getValueU32("internalformat");
+			mRequestedTextureFormat = message.getValueU32("format");
+			mRequestedTextureType = message.getValueU32("type");
+			mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
+			mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");			
+			
+			// These two are optional, and will default to 0 if they're not specified.
+			mDefaultMediaWidth = message.getValueS32("default_width");
+			mDefaultMediaHeight = message.getValueS32("default_height");
+			
+			mAllowDownsample = message.getValueBoolean("allow_downsample");
+			mPadding = message.getValueS32("padding");
+
+			setSizeInternal();
+			
+			mTextureParamsReceived = true;
+		}
+		else if(message_name == "updated")
+		{			
+			if(message.hasValue("left"))
+			{
+				LLRect newDirtyRect;
+				newDirtyRect.mLeft = message.getValueS32("left");
+				newDirtyRect.mTop = message.getValueS32("top");
+				newDirtyRect.mRight = message.getValueS32("right");
+				newDirtyRect.mBottom = message.getValueS32("bottom");
+							
+				// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
+				// If they're backwards, swap them.
+				if(newDirtyRect.mTop < newDirtyRect.mBottom)
+				{
+					S32 temp = newDirtyRect.mTop;
+					newDirtyRect.mTop = newDirtyRect.mBottom;
+					newDirtyRect.mBottom = temp;
+				}
+				
+				if(mDirtyRect.isEmpty())
+				{
+					mDirtyRect = newDirtyRect;
+				}
+				else
+				{
+					mDirtyRect.unionWith(newDirtyRect);
+				}
+
+				LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" 
+					<< newDirtyRect.mLeft << ", "
+					<< newDirtyRect.mTop << ", "
+					<< newDirtyRect.mRight << ", "
+					<< newDirtyRect.mBottom << "), new dirty rect is: ("
+					<< mDirtyRect.mLeft << ", "
+					<< mDirtyRect.mTop << ", "
+					<< mDirtyRect.mRight << ", "
+					<< mDirtyRect.mBottom << ")"
+					<< LL_ENDL;
+				
+				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
+			}			
+			
+
+			bool time_duration_updated = false;
+			int previous_percent = mProgressPercent;
+
+			if(message.hasValue("current_time"))
+			{
+				mCurrentTime = message.getValueReal("current_time");
+				time_duration_updated = true;
+			}
+			if(message.hasValue("duration"))
+			{
+				mDuration = message.getValueReal("duration");
+				time_duration_updated = true;
+			}
+
+			if(message.hasValue("current_rate"))
+			{
+				mCurrentRate = message.getValueReal("current_rate");
+			}
+			
+			if(message.hasValue("loaded_duration"))
+			{
+				mLoadedDuration = message.getValueReal("loaded_duration");
+				time_duration_updated = true;
+			}
+			else
+			{
+				// If the message doesn't contain a loaded_duration param, assume it's equal to duration
+				mLoadedDuration = mDuration;
+			}
+			
+			// Calculate a percentage based on the loaded duration and total duration.
+			if(mDuration != 0.0f)	// Don't divide by zero.
+			{
+				mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
+			}
+
+			if(time_duration_updated)
+			{
+				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
+			}
+			
+			if(previous_percent != mProgressPercent)
+			{
+				mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
+			}
+		}
+		else if(message_name == "media_status")
+		{
+			std::string status = message.getValue("status");
+			
+			LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
+			
+			if(status == "loading")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
+			}
+			else if(status == "loaded")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_LOADED;
+			}
+			else if(status == "error")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_ERROR;
+			}
+			else if(status == "playing")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING;
+			}
+			else if(status == "paused")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;
+			}
+			else if(status == "done")
+			{
+				mStatus = LLPluginClassMediaOwner::MEDIA_DONE;
+			}
+			else
+			{
+				// empty string or any unknown string
+				mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
+			}
+		}
+		else if(message_name == "size_change_request")
+		{
+			S32 width = message.getValueS32("width");
+			S32 height = message.getValueS32("height");
+			std::string name = message.getValue("name");
+
+			// TODO: check that name matches?
+			mNaturalMediaWidth = width;
+			mNaturalMediaHeight = height;
+			
+			setSizeInternal();
+		}
+		else if(message_name == "size_change_response")
+		{
+			std::string name = message.getValue("name");
+			
+			// TODO: check that name matches?
+			
+			mTextureWidth = message.getValueS32("texture_width");
+			mTextureHeight = message.getValueS32("texture_height");
+			mMediaWidth = message.getValueS32("width");
+			mMediaHeight = message.getValueS32("height");
+			
+			// This invalidates any existing dirty rect.
+			resetDirty();
+			
+			// TODO: should we verify that the plugin sent back the right values?  
+			// Two size changes in a row may cause them to not match, due to queueing, etc.
+
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
+		}
+		else if(message_name == "cursor_changed")
+		{
+			mCursorName = message.getValue("name");
+
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED);
+		}
+		else if(message_name == "edit_state")
+		{
+			if(message.hasValue("cut"))
+			{
+				mCanCut = message.getValueBoolean("cut");
+			}
+			if(message.hasValue("copy"))
+			{
+				mCanCopy = message.getValueBoolean("copy");
+			}
+			if(message.hasValue("paste"))
+			{
+				mCanPaste = message.getValueBoolean("paste");
+			}
+		}
+		else if(message_name == "name_text")
+		{
+			mMediaName = message.getValue("name");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
+		}
+		else if(message_name == "pick_file")
+		{
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST);
+		}
+		else if(message_name == "auth_request")
+		{
+			mAuthURL = message.getValue("url");
+			mAuthRealm = message.getValue("realm");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
+		}		
+		else if(message_name == "debug_message")
+		{
+			mDebugMessageText = message.getValue("message_text");
+			mDebugMessageLevel = message.getValue("message_level");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_DEBUG_MESSAGE);
+		}
+		else
+		{
+			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
+		}
+	}
+	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
+	{
+		std::string message_name = message.getName();
+		if(message_name == "navigate_begin")
+		{
+			mNavigateURI = message.getValue("uri");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN);
+		}
+		else if(message_name == "navigate_complete")
+		{
+			mNavigateURI = message.getValue("uri");
+			mNavigateResultCode = message.getValueS32("result_code");
+			mNavigateResultString = message.getValue("result_string");
+			mHistoryBackAvailable = message.getValueBoolean("history_back_available");
+			mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
+			
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
+		}
+		else if(message_name == "progress")
+		{
+			mProgressPercent = message.getValueS32("percent");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
+		}
+		else if(message_name == "status_text")
+		{
+			mStatusText = message.getValue("status");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED);
+		}
+		else if(message_name == "location_changed")
+		{
+			mLocation = message.getValue("uri");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED);
+		}
+		else if(message_name == "click_href")
+		{
+			mClickURL = message.getValue("uri");
+			mClickTarget = message.getValue("target");
+			mClickUUID = message.getValue("uuid");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
+		}
+		else if(message_name == "click_nofollow")
+		{
+			mClickURL = message.getValue("uri");
+			mClickNavType = message.getValue("nav_type");
+			mClickTarget.clear();
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
+		}
+		else if(message_name == "navigate_error_page")
+		{
+			mStatusCode = message.getValueS32("status_code");
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE);
+		}
+		else if(message_name == "cookie_set")
+		{
+			if(mOwner)
+			{
+				mOwner->handleCookieSet(this, message.getValue("cookie"));
+			}
+		}
+		else if(message_name == "close_request")
+		{
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST);
+		}
+		else if(message_name == "geometry_change")
+		{
+			mClickUUID = message.getValue("uuid");
+			mGeometryX = message.getValueS32("x");
+			mGeometryY = message.getValueS32("y");
+			mGeometryWidth = message.getValueS32("width");
+			mGeometryHeight = message.getValueS32("height");
+				
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
+		}
+		else if(message_name == "link_hovered")
+		{
+			// text is not currently used -- the tooltip hover text is taken from the "title".
+			mHoverLink = message.getValue("link");
+			mHoverText = message.getValue("title");
+			// message.getValue("text");
+				
+			mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
+		}
+		else
+		{
+			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
+		}
+	}
+	else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+	{
+		std::string message_name = message.getName();
+
+		// This class hasn't defined any incoming messages yet.
+//		if(message_name == "message_name")
+//		{
+//		}
+//		else 
+		{
+			LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
+		}
+	}
+
+}
+
+/* virtual */ 
+void LLPluginClassMedia::pluginLaunchFailed()
+{
+	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
+}
+
+/* virtual */ 
+void LLPluginClassMedia::pluginDied()
+{
+	mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
+}
+
+void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event)
+{
+	if(mOwner)
+	{
+		mOwner->handleMediaEvent(this, event);
+	}
+}
+
+void LLPluginClassMedia::sendMessage(const LLPluginMessage &message)
+{
+	if(mPlugin && mPlugin->isRunning())
+	{
+		mPlugin->sendMessage(message);
+	}
+	else
+	{
+		// The plugin isn't set up yet -- queue this message to be sent after initialization.
+		mSendQueue.push(message);
+	}
+}
+
+////////////////////////////////////////////////////////////
+// MARK: media_browser class functions
+bool LLPluginClassMedia::pluginSupportsMediaBrowser(void)
+{
+	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER);
+	return !version.empty();
+}
+
+void LLPluginClassMedia::focus(bool focused)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
+
+	message.setValueBoolean("focused", focused);
+	
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::clear_cache()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::clear_cookies()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::set_cookies(const std::string &cookies)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
+	message.setValue("cookies", cookies);	
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::enable_cookies(bool enable)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
+	message.setValueBoolean("enable", enable);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup");
+
+	message.setValueBoolean("enable", enable);
+	message.setValue("host", host);
+	message.setValueS32("port", port);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::browse_stop()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::browse_reload(bool ignore_cache)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
+
+	message.setValueBoolean("ignore_cache", ignore_cache);
+	
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::browse_forward()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::browse_back()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent");
+
+	message.setValue("user_agent", user_agent);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::showWebInspector( bool show )
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "show_web_inspector");
+	message.setValueBoolean("show", true);	// only open for now - closed manually by user
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::proxyWindowOpened(const std::string &target, const std::string &uuid)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_opened");
+
+	message.setValue("target", target);
+	message.setValue("uuid", uuid);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::proxyWindowClosed(const std::string &uuid)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_window_closed");
+
+	message.setValue("uuid", uuid);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::ignore_ssl_cert_errors(bool ignore)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "ignore_ssl_cert_errors");
+	message.setValueBoolean("ignore", ignore);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::addCertificateFilePath(const std::string& path)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "add_certificate_file_path");
+	message.setValue("path", path);
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::crashPlugin()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::hangPlugin()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang");
+
+	sendMessage(message);
+}
+
+
+////////////////////////////////////////////////////////////
+// MARK: media_time class functions
+bool LLPluginClassMedia::pluginSupportsMediaTime(void)
+{
+	std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME);
+	return !version.empty();
+}
+
+void LLPluginClassMedia::stop()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::start(float rate)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start");
+
+	message.setValueReal("rate", rate);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::pause()
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause");
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::seek(float time)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
+
+	message.setValueReal("time", time);
+	
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setLoop(bool loop)
+{
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop");
+
+	message.setValueBoolean("loop", loop);
+
+	sendMessage(message);
+}
+
+void LLPluginClassMedia::setVolume(float volume)
+{
+	if(volume != mRequestedVolume)
+	{
+		mRequestedVolume = volume;
+		
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
+
+		message.setValueReal("volume", volume);
+		
+		sendMessage(message);
+	}
+}
+
+float LLPluginClassMedia::getVolume()
+{
+	return mRequestedVolume;
+}
+
+void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
+{
+	// Send URL history to plugin
+	LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history");
+	message.setValueLLSD("history", url_history);
+	sendMessage(message);
+
+	LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
+}
+
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index d32cb0afe9d77b79d07c2ad0d298edb3ebd020d9..1f548f8cc02e6657716f3e15fd404b23abe2fdfe 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -118,6 +118,9 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 
 	void scrollEvent(int x, int y, MASK modifiers);
 
+	// enable/disable media plugin debugging messages and info spam
+	void enableMediaPluginDebugging( bool enable );
+
 	// Javascript <-> viewer events
 	void jsEnableObject( bool enable );
 	void jsAgentLocationEvent( double x, double y, double z );
@@ -209,6 +212,7 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	void browse_forward();
 	void browse_back();
 	void setBrowserUserAgent(const std::string& user_agent);
+	void showWebInspector( bool show );
 	void proxyWindowOpened(const std::string &target, const std::string &uuid);
 	void proxyWindowClosed(const std::string &uuid);
 	void ignore_ssl_cert_errors(bool ignore);
@@ -244,6 +248,10 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	// This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE
 	std::string getClickUUID() const { return mClickUUID; };
 
+	// These are valid during MEDIA_EVENT_DEBUG_MESSAGE
+	std::string getDebugMessageText() const { return mDebugMessageText; };
+	std::string getDebugMessageLevel() const { return mDebugMessageLevel; };
+
 	// This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE
 	S32 getStatusCode() const { return mStatusCode; };
 	
@@ -395,6 +403,8 @@ class LLPluginClassMedia : public LLPluginProcessParentOwner
 	std::string		mClickNavType;
 	std::string		mClickTarget;
 	std::string		mClickUUID;
+	std::string		mDebugMessageText;
+	std::string		mDebugMessageLevel;
 	S32				mGeometryX;
 	S32				mGeometryY;
 	S32				mGeometryWidth;
diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h
index 5a4fb1ce906f8872a19604d62d307e0671ec0dee..2f3edba7f368d5488ce02d892e7b45730a6ce345 100644
--- a/indra/llplugin/llpluginclassmediaowner.h
+++ b/indra/llplugin/llpluginclassmediaowner.h
@@ -64,6 +64,8 @@ class LLPluginClassMediaOwner
 
 		MEDIA_EVENT_AUTH_REQUEST,			// The plugin wants to display an auth dialog
 
+		MEDIA_EVENT_DEBUG_MESSAGE,			// plugin sending back debug information for host to process
+
 		MEDIA_EVENT_LINK_HOVERED			// Got a "link hovered" event from the plugin
 		
 	} EMediaEvent;
diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp
index 7cde82a20e6d58aedafe33fe776a165fc8129b97..e8efb233ffbe44daa25751c87d4fd8b4b1cdbfdf 100644
--- a/indra/llplugin/llplugininstance.cpp
+++ b/indra/llplugin/llplugininstance.cpp
@@ -29,8 +29,7 @@
 #include "linden_common.h"
 
 #include "llplugininstance.h"
-
-#include "llapr.h"
+#include "llthread.h"			// Needed for LLThread::tldata().mRootPool
 
 #if LL_WINDOWS
 #include "direct.h"	// needed for _chdir()
@@ -52,6 +51,7 @@ const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoin
  * @param[in] owner Plugin instance. TODO:DOC is this a good description of what "owner" is?
  */
 LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) :
+	mDSOHandlePool(LLThread::tldata().mRootPool),
 	mDSOHandle(NULL),
 	mPluginUserData(NULL),
 	mPluginSendMessageFunction(NULL)
@@ -97,7 +97,7 @@ int LLPluginInstance::load(const std::string& plugin_dir, std::string &plugin_fi
 
 	int result = apr_dso_load(&mDSOHandle,
 					  plugin_file.c_str(),
-					  gAPRPoolp);
+					  mDSOHandlePool());
 	if(result != APR_SUCCESS)
 	{
 		char buf[1024];
diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h
index 3643a15d8c27cb1da54ea87cde7f538efa731487..ee28f68e8369f87463d34a9ecfa83d0f744f8b97 100644
--- a/indra/llplugin/llplugininstance.h
+++ b/indra/llplugin/llplugininstance.h
@@ -30,6 +30,7 @@
 
 #include "llstring.h"
 #include "llapr.h"
+#include "llaprpool.h"
 
 #include "apr_dso.h"
 
@@ -88,6 +89,7 @@ class LLPluginInstance
 	static void staticReceiveMessage(const char *message_string, void **user_data);
 	void receiveMessage(const char *message_string);
 
+	LLAPRPool mDSOHandlePool;
 	apr_dso_handle_t *mDSOHandle;
 	
 	void *mPluginUserData;
diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp
index 8d13e38ad5c501c69749f5158219534485185a07..dd47300b9c676706a43d71d6317d4366929a3ee5 100644
--- a/indra/llplugin/llpluginmessagepipe.cpp
+++ b/indra/llplugin/llpluginmessagepipe.cpp
@@ -92,8 +92,6 @@ void LLPluginMessagePipeOwner::killMessagePipe(void)
 }
 
 LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket):
-	mInputMutex(gAPRPoolp),
-	mOutputMutex(gAPRPoolp),
 	mOwner(owner),
 	mSocket(socket)
 {
diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp
index f8a282184ed6d99a5d3144071fbd1f0a7b7ccec9..fd63fdde81629c0c51670ce67af25e67180b5237 100644
--- a/indra/llplugin/llpluginprocesschild.cpp
+++ b/indra/llplugin/llpluginprocesschild.cpp
@@ -40,7 +40,7 @@ LLPluginProcessChild::LLPluginProcessChild()
 {
 	mState = STATE_UNINITIALIZED;
 	mInstance = NULL;
-	mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
+	mSocket = LLSocket::create(LLSocket::STREAM_TCP);
 	mSleepTime = PLUGIN_IDLE_SECONDS;	// default: send idle messages at 100Hz
 	mCPUElapsed = 0.0f;
 	mBlockingRequest = false;
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index 110fac0f2388abe4a39bb009cd660fe899e89e52..7aec72731eef0bf55379f4a7783c0f7ec9d8182d 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -33,6 +33,7 @@
 #include "llpluginmessageclasses.h"
 
 #include "llapr.h"
+#include "llscopedvolatileaprpool.h"
 
 //virtual 
 LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
@@ -42,6 +43,7 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
 
 bool LLPluginProcessParent::sUseReadThread = false;
 apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
+LLAPRPool LLPluginProcessParent::sPollSetPool;
 bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
 LLMutex *LLPluginProcessParent::sInstancesMutex;
 std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances;
@@ -52,7 +54,7 @@ class LLPluginProcessParentPollThread: public LLThread
 {
 public:
 	LLPluginProcessParentPollThread() :
-		LLThread("LLPluginProcessParentPollThread", gAPRPoolp)
+		LLThread("LLPluginProcessParentPollThread")
 	{
 	}
 protected:
@@ -77,12 +79,11 @@ class LLPluginProcessParentPollThread: public LLThread
 
 };
 
-LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
-	mIncomingQueueMutex(gAPRPoolp)
+LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner* owner)
 {
 	if(!sInstancesMutex)
 	{
-		sInstancesMutex = new LLMutex(gAPRPoolp);
+		sInstancesMutex = new LLMutex;
 	}
 	
 	mOwner = owner;
@@ -95,6 +96,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
 	mBlocked = false;
 	mPolledInput = false;
 	mPollFD.client_data = NULL;
+	mPollFDPool.create();
 
 	mPluginLaunchTimeout = 60.0f;
 	mPluginLockupTimeout = 15.0f;
@@ -171,44 +173,28 @@ void LLPluginProcessParent::init(const std::string &launcher_filename, const std
 bool LLPluginProcessParent::accept()
 {
 	bool result = false;
-	
 	apr_status_t status = APR_EGENERAL;
-	apr_socket_t *new_socket = NULL;
-	
-	status = apr_socket_accept(
-		&new_socket,
-		mListenSocket->getSocket(),
-		gAPRPoolp);
 
+	mSocket = LLSocket::create(status, mListenSocket);
 	
 	if(status == APR_SUCCESS)
 	{
 //		llinfos << "SUCCESS" << llendl;
 		// Success.  Create a message pipe on the new socket
-
-		// we MUST create a new pool for the LLSocket, since it will take ownership of it and delete it in its destructor!
-		apr_pool_t* new_pool = NULL;
-		status = apr_pool_create(&new_pool, gAPRPoolp);
-
-		mSocket = LLSocket::create(new_socket, new_pool);
 		new LLPluginMessagePipe(this, mSocket);
 
 		result = true;
 	}
-	else if(APR_STATUS_IS_EAGAIN(status))
-	{
-//		llinfos << "EAGAIN" << llendl;
-
-		// No incoming connections.  This is not an error.
-		status = APR_SUCCESS;
-	}
 	else
 	{
-//		llinfos << "Error:" << llendl;
-		ll_apr_warn_status(status);
-		
-		// Some other error.
-		errorState();
+		mSocket.reset();
+		// EAGAIN means "No incoming connections". This is not an error.
+		if (!APR_STATUS_IS_EAGAIN(status))
+		{
+			// Some other error.
+			ll_apr_warn_status(status);
+			errorState();
+		}
 	}
 	
 	return result;	
@@ -274,10 +260,10 @@ void LLPluginProcessParent::idle(void)
 
 			case STATE_INITIALIZED:
 			{
-	
 				apr_status_t status = APR_SUCCESS;
+				LLScopedVolatileAPRPool addr_pool;
 				apr_sockaddr_t* addr = NULL;
-				mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
+				mListenSocket = LLSocket::create(LLSocket::STREAM_TCP);
 				mBoundPort = 0;
 				
 				// This code is based on parts of LLSocket::create() in lliosocket.cpp.
@@ -288,7 +274,7 @@ void LLPluginProcessParent::idle(void)
 					APR_INET,
 					0,	// port 0 = ephemeral ("find me a port")
 					0,
-					gAPRPoolp);
+					addr_pool);
 					
 				if(ll_apr_warn_status(status))
 				{
@@ -601,7 +587,7 @@ void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe)
 	if(message_pipe != NULL)
 	{
 		// Set up the apr_pollfd_t
-		mPollFD.p = gAPRPoolp;
+		mPollFD.p = mPollFDPool();
 		mPollFD.desc_type = APR_POLL_SOCKET;
 		mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP;
 		mPollFD.rtnevents = 0;
@@ -648,6 +634,7 @@ void LLPluginProcessParent::updatePollset()
 		// delete the existing pollset.
 		apr_pollset_destroy(sPollSet);
 		sPollSet = NULL;
+		sPollSetPool.destroy();
 	}
 	
 	std::list<LLPluginProcessParent*>::iterator iter;
@@ -670,12 +657,14 @@ void LLPluginProcessParent::updatePollset()
 		{
 #ifdef APR_POLLSET_NOCOPY
 			// The pollset doesn't exist yet.  Create it now.
-			apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY);
+			sPollSetPool.create();
+			apr_status_t status = apr_pollset_create(&sPollSet, count, sPollSetPool(), APR_POLLSET_NOCOPY);
 			if(status != APR_SUCCESS)
 			{
 #endif // APR_POLLSET_NOCOPY
 				LL_WARNS("PluginPoll") << "Couldn't create pollset.  Falling back to non-pollset mode." << LL_ENDL;
 				sPollSet = NULL;
+				sPollSetPool.destroy();
 #ifdef APR_POLLSET_NOCOPY
 			}
 			else
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index 26c6b0c4027e5438464749561b562a5a91c341af..74b7e9f50cd1b5ec2a365851dc60b89074e35bcd 100644
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -178,7 +178,9 @@ class LLPluginProcessParent : public LLPluginMessagePipeOwner
 
 	static bool sUseReadThread;
 	apr_pollfd_t mPollFD;
+	LLAPRPool mPollFDPool;
 	static apr_pollset_t *sPollSet;
+	static LLAPRPool sPollSetPool;
 	static bool sPollsetNeedsRebuild;
 	static LLMutex *sInstancesMutex;
 	static std::list<LLPluginProcessParent*> sInstances;
diff --git a/indra/llplugin/llpluginsharedmemory.cpp b/indra/llplugin/llpluginsharedmemory.cpp
index 63ff5085c6e1705f180d0c361a45bf305a1fe196..e2ff645a9c5ae7ddb88ad6683a5d85f9544b93bc 100644
--- a/indra/llplugin/llpluginsharedmemory.cpp
+++ b/indra/llplugin/llpluginsharedmemory.cpp
@@ -187,7 +187,8 @@ bool LLPluginSharedMemory::create(size_t size)
 	mName += createName();
 	mSize = size;
 	
-	apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), gAPRPoolp );
+	mPool.create();
+	apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), mPool());
 	
 	if(ll_apr_warn_status(status))
 	{
@@ -210,7 +211,7 @@ bool LLPluginSharedMemory::destroy(void)
 		}
 		mImpl->mAprSharedMemory = NULL;
 	}
-	
+	mPool.destroy();
 	return true;
 }
 
@@ -219,7 +220,8 @@ bool LLPluginSharedMemory::attach(const std::string &name, size_t size)
 	mName = name;
 	mSize = size;
 	
-	apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), gAPRPoolp );
+	mPool.create();
+	apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), mPool() );
 	
 	if(ll_apr_warn_status(status))
 	{
@@ -241,6 +243,7 @@ bool LLPluginSharedMemory::detach(void)
 		}
 		mImpl->mAprSharedMemory = NULL;
 	}
+	mPool.destroy();
 	
 	return true;
 }
diff --git a/indra/llplugin/llpluginsharedmemory.h b/indra/llplugin/llpluginsharedmemory.h
index c6cd49cabb7e119b0f9c326cc3ea358ed9f408d7..84b7a58c328c27f90e99186e1c71420607bb70d8 100644
--- a/indra/llplugin/llpluginsharedmemory.h
+++ b/indra/llplugin/llpluginsharedmemory.h
@@ -28,6 +28,8 @@
 #ifndef LL_LLPLUGINSHAREDMEMORY_H
 #define LL_LLPLUGINSHAREDMEMORY_H
 
+#include "llaprpool.h"
+
 class LLPluginSharedMemoryPlatformImpl;
 
 /**
@@ -108,6 +110,7 @@ class LLPluginSharedMemory
 	bool close(void);
 	bool unlink(void);
 	
+	LLAPRPool mPool;
 	std::string mName;
 	size_t mSize;
 	void *mMappedAddress;
diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp
index 516a58db8836115afd18cf276a95c0b30e445b5c..ff86e4e1351ce10f1d2de229f43f2e391edbe6a0 100644
--- a/indra/llplugin/slplugin/slplugin.cpp
+++ b/indra/llplugin/slplugin/slplugin.cpp
@@ -176,8 +176,6 @@ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdL
 int main(int argc, char **argv)
 #endif
 {
-	ll_init_apr();
-
 	// Set up llerror logging
 	{
 		LLError::initForApplication(".");
@@ -393,8 +391,6 @@ int main(int argc, char **argv)
 
 	delete plugin;
 
-	ll_cleanup_apr();
-
 	return 0;
 }
 
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index d72918b15d0b61b682e6d7f4284004f6b9060449..edcc47aa1471ab65ddd90506c0c562e3c2c0d1c2 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -927,13 +927,7 @@ LLRender::LLRender()
     mMode(LLRender::TRIANGLES),
     mCurrTextureUnitIndex(0),
     mMaxAnisotropy(0.f) 
-{
-	mBuffer = new LLVertexBuffer(immediate_mask, 0);
-	mBuffer->allocateBuffer(4096, 0, TRUE);
-	mBuffer->getVertexStrider(mVerticesp);
-	mBuffer->getTexCoord0Strider(mTexcoordsp);
-	mBuffer->getColorStrider(mColorsp);
-	
+{	
 	mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS);
 	for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++)
 	{
@@ -964,6 +958,17 @@ LLRender::~LLRender()
 	shutdown();
 }
 
+void LLRender::init()
+{
+	llassert_always(mBuffer.isNull()) ;
+
+	mBuffer = new LLVertexBuffer(immediate_mask, 0);
+	mBuffer->allocateBuffer(4096, 0, TRUE);
+	mBuffer->getVertexStrider(mVerticesp);
+	mBuffer->getTexCoord0Strider(mTexcoordsp);
+	mBuffer->getColorStrider(mColorsp);
+}
+
 void LLRender::shutdown()
 {
 	for (U32 i = 0; i < mTexUnits.size(); i++)
@@ -979,6 +984,7 @@ void LLRender::shutdown()
 		delete mLightState[i];
 	}
 	mLightState.clear();
+	mBuffer = NULL ;
 }
 
 void LLRender::refreshState(void)
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 9eedebe2ce08efb9d74d45871c70466b5883da86..8f7ee30d87e53f704387e232be8dd9ca731a556d 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -310,6 +310,7 @@ class LLRender
 
 	LLRender();
 	~LLRender();
+	void init() ;
 	void shutdown();
 	
 	// Refreshes renderer state to the cached values
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index b6a252e8fa82bf5b2f7735e8c278f1d9ef7373eb..8fd11937801b8eba7f68933bd5692a82e19ef3cf 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -25,7 +25,6 @@
  */
 
 #include "linden_common.h"
-#include "llmemory.h"
 
 #include <boost/static_assert.hpp>
 #include "llsys.h"
@@ -36,6 +35,7 @@
 #include "llrender.h"
 #include "llvector4a.h"
 #include "llglslshader.h"
+#include "llmemory.h"
 
 
 //============================================================================
@@ -46,6 +46,7 @@ LLVBOPool LLVertexBuffer::sDynamicVBOPool;
 LLVBOPool LLVertexBuffer::sStreamIBOPool;
 LLVBOPool LLVertexBuffer::sDynamicIBOPool;
 
+LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ;
 U32 LLVertexBuffer::sBindCount = 0;
 U32 LLVertexBuffer::sSetCount = 0;
 S32 LLVertexBuffer::sCount = 0;
@@ -443,6 +444,11 @@ void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
 	}
 
 	sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ;
+
+	if(!sPrivatePoolp)
+	{
+		sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ;
+	}
 }
 
 //static 
@@ -472,7 +478,11 @@ void LLVertexBuffer::cleanupClass()
 	unbind();
 	clientCopy(); // deletes GL buffers
 
-	//llassert_always(!sCount) ;
+	if(sPrivatePoolp)
+	{
+		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ;
+		sPrivatePoolp = NULL ;
+	}
 }
 
 void LLVertexBuffer::clientCopy(F64 max_time)
@@ -722,7 +732,7 @@ void LLVertexBuffer::createGLBuffer()
 	{
 		static int gl_buffer_idx = 0;
 		mGLBuffer = ++gl_buffer_idx;
-		mMappedData = (U8*) ll_aligned_malloc_16(size);
+		mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
 	}
 }
 
@@ -756,7 +766,7 @@ void LLVertexBuffer::createGLIndices()
 	}
 	else
 	{
-		mMappedIndexData = (U8*) ll_aligned_malloc_16(size);
+		mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
 		static int gl_buffer_idx = 0;
 		mGLIndices = ++gl_buffer_idx;
 	}
@@ -779,7 +789,7 @@ void LLVertexBuffer::destroyGLBuffer()
 		}
 		else
 		{
-			ll_aligned_free_16(mMappedData);
+			FREE_MEM(sPrivatePoolp, mMappedData) ;
 			mMappedData = NULL;
 			mEmpty = TRUE;
 		}
@@ -808,7 +818,7 @@ void LLVertexBuffer::destroyGLIndices()
 		}
 		else
 		{
-			ll_aligned_free_16(mMappedIndexData);
+			FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
 			mMappedIndexData = NULL;
 			mEmpty = TRUE;
 		}
@@ -941,8 +951,8 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 			{
 				if (!useVBOs())
 				{
-					ll_aligned_free_16(mMappedData);
-					mMappedData = (U8*) ll_aligned_malloc_16(newsize);
+					FREE_MEM(sPrivatePoolp, mMappedData);
+					mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, newsize);
 				}
 				mResized = TRUE;
 			}
@@ -962,8 +972,8 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 			{
 				if (!useVBOs())
 				{
-					ll_aligned_free_16(mMappedIndexData);
-					mMappedIndexData = (U8*) ll_aligned_malloc_16(new_index_size);
+					FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
+					mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, new_index_size);
 				}
 				mResized = TRUE;
 			}
@@ -998,8 +1008,8 @@ void LLVertexBuffer::freeClientBuffer()
 {
 	if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData))
 	{
-		ll_aligned_free_16(mMappedData) ;
-		ll_aligned_free_16(mMappedIndexData) ;
+		FREE_MEM(sPrivatePoolp, mMappedData) ;
+		FREE_MEM(sPrivatePoolp, mMappedIndexData) ;
 		mMappedData = NULL ;
 		mMappedIndexData = NULL ;
 	}
@@ -1009,7 +1019,7 @@ void LLVertexBuffer::allocateClientVertexBuffer()
 {
 	if(!mMappedData)
 	{
-		mMappedData = (U8*)ll_aligned_malloc_16(getSize());
+		mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getSize());
 	}
 }
 
@@ -1017,7 +1027,7 @@ void LLVertexBuffer::allocateClientIndexBuffer()
 {
 	if(!mMappedIndexData)
 	{
-		mMappedIndexData = (U8*)ll_aligned_malloc_16(getIndicesSize());
+		mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, getIndicesSize());		
 	}
 }
 
@@ -1159,12 +1169,9 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
 			{
 				log_glerror();
 
-				//check the availability of memory
-				U32 avail_phy_mem, avail_vir_mem;
-				LLMemoryInfo::getAvailableMemoryKB(avail_phy_mem, avail_vir_mem) ;
-				llinfos << "Available physical mwmory(KB): " << avail_phy_mem << llendl ; 
-				llinfos << "Available virtual memory(KB): " << avail_vir_mem << llendl;
-
+			//check the availability of memory
+			LLMemory::logMemoryInfo(TRUE) ; 
+			
 				if(!sDisableVBOMapping)
 				{			
 					//--------------------
@@ -1324,6 +1331,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 		if (!mMappedIndexData)
 		{
 			log_glerror();
+			LLMemory::logMemoryInfo(TRUE) ;
 
 			if(!sDisableVBOMapping)
 			{
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index cc5d11e1c29018ff1ec085da20c4e7045d33600d..578cec38859c6d88d4eda6964fad47efa7cf9f0e 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -79,7 +79,7 @@ class LLGLFence
 
 //============================================================================
 // base class 
-
+class LLPrivateMemoryPool ;
 class LLVertexBuffer : public LLRefCount
 {
 public:
@@ -282,6 +282,9 @@ class LLVertexBuffer : public LLRefCount
 	void waitFence() const;
 
 
+private:
+	static LLPrivateMemoryPool* sPrivatePoolp ;
+
 public:
 	static S32 sCount;
 	static S32 sGLCount;
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index cddda03faf9ce538bf02692421918ab43c6ca325..89d8842393be9247c54273ad7ea40589fd0635eb 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -525,15 +525,12 @@ void LLComboBox::createLineEditor(const LLComboBox::Params& p)
 	else
 	{
 		mButton->setRect(rect);
-		mButton->setTabStop(TRUE);
-		mButton->setHAlign(LLFontGL::LEFT);
 		mButton->setLabel(mLabel.getString());
 		
 		if (mTextEntry)
 		{
 			mTextEntry->setVisible(FALSE);
 		}
-		mButton->setFollowsAll();
 	}
 }
 
diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp
index 3d3ed9f6d4d32f34999a3b36bc659b19461e6a8b..bf49b9668e6cfd212ddefbf4b7d05f5d299d597a 100644
--- a/indra/llvfs/lllfsthread.cpp
+++ b/indra/llvfs/lllfsthread.cpp
@@ -67,10 +67,6 @@ LLLFSThread::LLLFSThread(bool threaded) :
 	LLQueuedThread("LFS", threaded),
 	mPriorityCounter(PRIORITY_LOWBITS)
 {
-	if(!mLocalAPRFilePoolp)
-	{
-		mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
-	}
 }
 
 LLLFSThread::~LLLFSThread()
@@ -182,8 +178,7 @@ bool LLLFSThread::Request::processRequest()
 	if (mOperation ==  FILE_READ)
 	{
 		llassert(mOffset >= 0);
-		LLAPRFile infile ; // auto-closes
-		infile.open(mFileName, LL_APR_RB, mThread->getLocalAPRFilePool());
+		LLAPRFile infile(mFileName, LL_APR_RB);
 		if (!infile.getFileHandle())
 		{
 			llwarns << "LLLFS: Unable to read file: " << mFileName << llendl;
@@ -205,8 +200,7 @@ bool LLLFSThread::Request::processRequest()
 		apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
 		if (mOffset < 0)
 			flags |= APR_APPEND;
-		LLAPRFile outfile ; // auto-closes
-		outfile.open(mFileName, flags, mThread->getLocalAPRFilePool());
+		LLAPRFile outfile(mFileName, flags);
 		if (!outfile.getFileHandle())
 		{
 			llwarns << "LLLFS: Unable to write file: " << mFileName << llendl;
diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp
index 82c926620a07960695337df7148752bdb9aa5f0a..ade19f8103e06d4be7399b57d1a82e402bdb21ce 100644
--- a/indra/llvfs/llvfs.cpp
+++ b/indra/llvfs/llvfs.cpp
@@ -234,7 +234,7 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename
 	mDataFP(NULL),
 	mIndexFP(NULL)
 {
-	mDataMutex = new LLMutex(0);
+	mDataMutex = new LLMutex;
 
 	S32 i;
 	for (i = 0; i < VFSLOCK_COUNT; i++)
@@ -2098,8 +2098,7 @@ void LLVFS::dumpFiles()
 			std::string filename = id.asString() + extension;
 			llinfos << " Writing " << filename << llendl;
 			
-			LLAPRFile outfile;
-			outfile.open(filename, LL_APR_WB);
+			LLAPRFile outfile(filename, LL_APR_WB);
 			outfile.write(&buffer[0], size);
 			outfile.close();
 
diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h
index e402061e1f55902c0798bca0121f141778e0dc3d..050d4b729f5a4aa3b3a3755e2181efbd9e8ee8d3 100644
--- a/indra/llxml/llcontrol.h
+++ b/indra/llxml/llcontrol.h
@@ -385,7 +385,8 @@ class LLCachedControl
 {
 public:
 	LLCachedControl(LLControlGroup& group,
-					const std::string& name, 
+					const std::string& name,
+
 					const T& default_value, 
 					const std::string& comment = "Declared In Code")
 	{
diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h
index 6bc272c009aa5e6c87721c6057c2eae9bc917253..77d6d196633efd775f2279c2a03ccc12d8a2333c 100644
--- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h
+++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h
@@ -37,7 +37,6 @@ extern "C" {
 #include <stdio.h>
 #include <gst/gst.h>
 
-#include "apr_pools.h"
 #include "apr_dso.h"
 }
 
diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp
index 2e4baaa9eb23744e7b185f873565ac36abb5be09..93a10424dde4d521b48aeee049de9bc342c78290 100644
--- a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp
+++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp
@@ -28,16 +28,18 @@
 
 #if LL_GSTREAMER010_ENABLED
 
+#include "linden_common.h"
+
 #include <string>
 
 extern "C" {
 #include <gst/gst.h>
 
-#include "apr_pools.h"
 #include "apr_dso.h"
 }
 
 #include "llmediaimplgstreamertriviallogging.h"
+#include "llaprpool.h"
 
 #define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL
 #include "llmediaimplgstreamer_syms_raw.inc"
@@ -56,7 +58,7 @@ void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname)
 }
 
 static bool sSymsGrabbed = false;
-static apr_pool_t *sSymGSTDSOMemoryPool = NULL;
+static LLAPRPool sSymGSTDSOMemoryPool;
 static apr_dso_handle_t *sSymGSTDSOHandleG = NULL;
 static apr_dso_handle_t *sSymGSTDSOHandleV = NULL;
 
@@ -78,11 +80,11 @@ bool grab_gst_syms(std::string gst_dso_name,
 #define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0)
 
 	//attempt to load the shared libraries
-	apr_pool_create(&sSymGSTDSOMemoryPool, NULL);
+	sSymGSTDSOMemoryPool.create();
   
 	if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle,
 					       gst_dso_name.c_str(),
-					       sSymGSTDSOMemoryPool) ))
+					       sSymGSTDSOMemoryPool()) ))
 	{
 		INFOMSG("Found DSO: %s", gst_dso_name.c_str());
 #include "llmediaimplgstreamer_syms_raw.inc"
@@ -96,7 +98,7 @@ bool grab_gst_syms(std::string gst_dso_name,
 		if ( APR_SUCCESS ==
 		     (rv = apr_dso_load(&sSymGSTDSOHandle,
 					gst_dso_name_vid.c_str(),
-					sSymGSTDSOMemoryPool) ))
+					sSymGSTDSOMemoryPool()) ))
 		{
 			INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str());
 #include "llmediaimplgstreamer_syms_rawv.inc"
@@ -150,8 +152,7 @@ void ungrab_gst_syms()
 	
 	if ( sSymGSTDSOMemoryPool )
 	{
-		apr_pool_destroy(sSymGSTDSOMemoryPool);
-		sSymGSTDSOMemoryPool = NULL;
+		sSymGSTDSOMemoryPool.destroy();
 	}
 	
 	// NULL-out all of the symbols we'd grabbed
diff --git a/indra/media_plugins/webkit/linux_volume_catcher.cpp b/indra/media_plugins/webkit/linux_volume_catcher.cpp
index 91be3a89e9a6e58cee506e4312cc250647440351..94dfd80700306ff32170cee44dff5b031c25879f 100644
--- a/indra/media_plugins/webkit/linux_volume_catcher.cpp
+++ b/indra/media_plugins/webkit/linux_volume_catcher.cpp
@@ -65,7 +65,7 @@ extern "C" {
 #undef LL_PA_SYM
 
 static bool sSymsGrabbed = false;
-static apr_pool_t *sSymPADSOMemoryPool = NULL;
+static LLAPRPool sSymPADSOMemoryPool;
 static apr_dso_handle_t *sSymPADSOHandleG = NULL;
 
 bool grab_pa_syms(std::string pulse_dso_name)
@@ -84,11 +84,11 @@ bool grab_pa_syms(std::string pulse_dso_name)
 #define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##PASYM, sSymPADSOHandle, #PASYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #PASYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #PASYM, (void*)ll##PASYM);}while(0)
 
 	//attempt to load the shared library
-	apr_pool_create(&sSymPADSOMemoryPool, NULL);
+	sSymPADSOMemoryPool.create();
   
 	if ( APR_SUCCESS == (rv = apr_dso_load(&sSymPADSOHandle,
 					       pulse_dso_name.c_str(),
-					       sSymPADSOMemoryPool) ))
+					       sSymPADSOMemoryPool()) ))
 	{
 		INFOMSG("Found DSO: %s", pulse_dso_name.c_str());
 
@@ -130,12 +130,8 @@ void ungrab_pa_syms()
 		apr_dso_unload(sSymPADSOHandleG);
 		sSymPADSOHandleG = NULL;
 	}
-	
-	if ( sSymPADSOMemoryPool )
-	{
-		apr_pool_destroy(sSymPADSOMemoryPool);
-		sSymPADSOMemoryPool = NULL;
-	}
+
+	sSymPADSOMemoryPool.destroy();
 	
 	// NULL-out all of the symbols we'd grabbed
 #define LL_PA_SYM(REQUIRED, PASYM, RTN, ...) do{ll##PASYM = NULL;}while(0)
diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp
index 96f642f2a04f2341b02ee7d210533c57e9abb042..430ae9d4dc19f94853822842cd66c28a6068a5d3 100644
--- a/indra/media_plugins/webkit/media_plugin_webkit.cpp
+++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp
@@ -1,1394 +1,1447 @@
-/** 
- * @file media_plugin_webkit.cpp
- * @brief Webkit plugin for LLMedia API plugin system
- *
- * @cond
- * $LicenseInfo:firstyear=2008&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- * @endcond
- */
-
-#include "llqtwebkit.h"
-
-#include "linden_common.h"
-#include "indra_constants.h" // for indra keyboard codes
-
-#include "llgl.h"
-
-#include "llplugininstance.h"
-#include "llpluginmessage.h"
-#include "llpluginmessageclasses.h"
-#include "media_plugin_base.h"
-
-// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified
-#if LL_LINUX
-# define LL_QTWEBKIT_USES_PIXMAPS 0
-extern "C" {
-# include <glib.h>
-# include <glib-object.h>
-}
-#else
-# define LL_QTWEBKIT_USES_PIXMAPS 0
-#endif // LL_LINUX
-
-# include "volume_catcher.h"
-
-#if LL_WINDOWS
-# include <direct.h>
-#else
-# include <unistd.h>
-# include <stdlib.h>
-#endif
-
-#if LL_WINDOWS
-	// *NOTE:Mani - This captures the module handle for the dll. This is used below
-	// to get the path to this dll for webkit initialization.
-	// I don't know how/if this can be done with apr...
-	namespace {	HMODULE gModuleHandle;};
-	BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
-	{
-		gModuleHandle = (HMODULE) hinstDLL;
-		return TRUE;
-	}
-#endif
-
-////////////////////////////////////////////////////////////////////////////////
-//
-class MediaPluginWebKit : 
-		public MediaPluginBase,
-		public LLEmbeddedBrowserWindowObserver
-{
-public:
-	MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
-	~MediaPluginWebKit();
-
-	/*virtual*/ void receiveMessage(const char *message_string);
-
-private:
-
-	std::string mProfileDir;
-	std::string mHostLanguage;
-	std::string mUserAgent;
-	bool mCookiesEnabled;
-	bool mJavascriptEnabled;
-	bool mPluginsEnabled;
-
-	enum
-	{
-		INIT_STATE_UNINITIALIZED,		// LLQtWebkit hasn't been set up yet
-		INIT_STATE_INITIALIZED,			// LLQtWebkit has been set up, but no browser window has been created yet.
-		INIT_STATE_NAVIGATING,			// Browser instance has been set up and initial navigate to about:blank has been issued
-		INIT_STATE_NAVIGATE_COMPLETE,	// initial navigate to about:blank has completed
-		INIT_STATE_WAIT_REDRAW,			// First real navigate begin has been received, waiting for page changed event to start handling redraws
-		INIT_STATE_WAIT_COMPLETE,		// Waiting for first real navigate complete event
-		INIT_STATE_RUNNING				// All initialization gymnastics are complete.
-	};
-	int mBrowserWindowId;
-	int mInitState;
-	std::string mInitialNavigateURL;
-	bool mNeedsUpdate;
-
-	bool	mCanCut;
-	bool	mCanCopy;
-	bool	mCanPaste;
-	int mLastMouseX;
-	int mLastMouseY;
-	bool mFirstFocus;
-	F32 mBackgroundR;
-	F32 mBackgroundG;
-	F32 mBackgroundB;
-	std::string mTarget;
-	
-	VolumeCatcher mVolumeCatcher;
-
-	void setInitState(int state)
-	{
-//		std::cerr << "changing init state to " << state << std::endl;
-		mInitState = state;
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void update(int milliseconds)
-	{
-#if LL_QTLINUX_DOESNT_HAVE_GLIB
-		// pump glib generously, as Linux browser plugins are on the
-		// glib main loop, even if the browser itself isn't - ugh
-		// This is NOT NEEDED if Qt itself was built with glib
-		// mainloop integration.
-		GMainContext *mainc = g_main_context_default();
-		while(g_main_context_iteration(mainc, FALSE));
-#endif // LL_QTLINUX_DOESNT_HAVE_GLIB
-
-		// pump qt
-		LLQtWebKit::getInstance()->pump( milliseconds );
-		
-		mVolumeCatcher.pump();
-
-		checkEditState();
-		
-		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			if(!mInitialNavigateURL.empty())
-			{
-				// We already have the initial navigate URL -- kick off the navigate.
-				LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL );
-				mInitialNavigateURL.clear();
-			}
-		}
-		
-		if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate )
-		{
-			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
-
-			unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId );
-			unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
-#if !LL_QTWEBKIT_USES_PIXMAPS
-			unsigned int buffer_size = rowspan * height;
-#endif // !LL_QTWEBKIT_USES_PIXMAPS
-			
-//			std::cerr << "webkit plugin: updating" << std::endl;
-			
-			// TODO: should get rid of this memcpy if possible
-			if ( mPixels && browser_pixels )
-			{
-//				std::cerr << "    memcopy of " << buffer_size << " bytes" << std::endl;
-
-#if LL_QTWEBKIT_USES_PIXMAPS
-				// copy the pixel data upside-down because of the co-ord system
-				for (int y=0; y<height; ++y)
-				{
-					memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan );
-				}
-#else
-				memcpy( mPixels, browser_pixels, buffer_size );
-#endif // LL_QTWEBKIT_USES_PIXMAPS
-			}
-
-			if ( mWidth > 0 && mHeight > 0 )
-			{
-//				std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl;
-				setDirty( 0, 0, mWidth, mHeight );
-			}
-
-			mNeedsUpdate = false;
-		};
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	bool initBrowser()
-	{
-		// already initialized
-		if ( mInitState > INIT_STATE_UNINITIALIZED )
-			return true;
-
-		// set up directories
-		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use
-		if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
-		{
-			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl;
-			return false;
-		}
-		std::string application_dir = std::string( cwd );
-
-#if LL_LINUX
-		// take care to initialize glib properly, because some
-		// versions of Qt don't, and we indirectly need it for (some
-		// versions of) Flash to not crash the browser.
-		if (!g_thread_supported ()) g_thread_init (NULL);
-		g_type_init();
-#endif
-
-#if LL_DARWIN
-		// When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on.
-		// This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger.
-		// This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it
-		// which gets hit when the plugin is probed by webkit.
-		// Unsetting the environment variable here works around this issue.
-		unsetenv("USERBREAK");
-#endif
-
-#if LL_WINDOWS
-		//*NOTE:Mani - On windows, at least, the component path is the
-		// location of this dll's image file. 
-		std::string component_dir;
-		char dll_path[_MAX_PATH];
-		DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH);
-		while(len && dll_path[ len ] != ('\\') )
-		{
-			len--;
-		}
-		if(len >= 0)
-		{
-			dll_path[len] = 0;
-			component_dir = dll_path;
-		}
-		else
-		{
-			// *NOTE:Mani - This case should be an rare exception. 
-			// GetModuleFileNameA should always give you a full path, no?
-			component_dir = application_dir;
-		}
-#else
-		std::string component_dir = application_dir;
-#endif
-
-		// window handle - needed on Windows and must be app window.
-#if LL_WINDOWS
-		char window_title[ MAX_PATH ];
-		GetConsoleTitleA( window_title, MAX_PATH );
-		void* native_window_handle = (void*)FindWindowA( NULL, window_title );
-#else
-		void* native_window_handle = 0;
-#endif
-
-		// main browser initialization
-		bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle );
-		if ( result )
-		{
-			mInitState = INIT_STATE_INITIALIZED;
-			
-			return true;
-		};
-
-		return false;
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	bool initBrowserWindow()
-	{
-		// already initialized
-		if ( mInitState > INIT_STATE_INITIALIZED )
-			return true;
-
-		// not enough information to initialize the browser yet.
-		if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || 
-				mTextureWidth < 0 || mTextureHeight < 0 )
-		{
-			return false;
-		};
-		
-		// Set up host language before creating browser window
-		if(!mHostLanguage.empty())
-		{
-			LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage);
-		}
-
-		// turn on/off cookies based on what host app tells us
-		LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
-
-		// turn on/off plugins based on what host app tells us
-		LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
-
-		// turn on/off Javascript based on what host app tells us
-		LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
-		
-		// create single browser window
-		mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget);
-
-		// tell LLQtWebKit about the size of the browser window
-		LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
-
-		// observer events that LLQtWebKit emits
-		LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this );
-
-		// append details to agent string
-		LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
-		
-#if !LL_QTWEBKIT_USES_PIXMAPS
-		// don't flip bitmap
-		LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
-#endif // !LL_QTWEBKIT_USES_PIXMAPS
-
-		// set background color
-		// convert background color channels from [0.0, 1.0] to [0, 255];
-		LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) );
-
-		// Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns.
-		setInitState(INIT_STATE_NAVIGATING);
-
-		// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
-		// FIXME: Re-added this because navigating to a "page" initializes things correctly - especially
-		// for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date.
-		// Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E"
-		// where RRGGBB is the background color in HTML style
-		std::stringstream url;
-		
-		url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#";
-		// convert background color channels from [0.0, 1.0] to [0, 255];
-		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f);
-		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f);
-		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f);
-		url << "%22%3E%3C/body%3E%3C/html%3E";
-		
-		//lldebugs << "data url is: " << url.str() << llendl;
-					
-		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() );
-//		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
-
-		return true;	
-	}
-
-	void setVolume(F32 vol);
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onCursorChanged(const EventType& event)
-	{
-		LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue();
-		std::string name;
-
-		switch(llqt_cursor)
-		{
-			case LLQtWebKit::C_ARROW:
-				name = "arrow";
-			break;
-			case LLQtWebKit::C_IBEAM:
-				name = "ibeam";
-			break;
-			case LLQtWebKit::C_SPLITV:
-				name = "splitv";
-			break;
-			case LLQtWebKit::C_SPLITH:
-				name = "splith";
-			break;
-			case LLQtWebKit::C_POINTINGHAND:
-				name = "hand";
-			break;
-			
-			default:
-				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl;
-			break;
-		}
-		
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
-		message.setValue("name", name);
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onPageChanged( const EventType& event )
-	{
-		if(mInitState == INIT_STATE_WAIT_REDRAW)
-		{
-			setInitState(INIT_STATE_WAIT_COMPLETE);
-		}
-		
-		// flag that an update is required
-		mNeedsUpdate = true;
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateBegin(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
-			message.setValue("uri", event.getEventUri());
-			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
-			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
-			sendMessage(message);
-		
-			setStatus(STATUS_LOADING);
-		}
-
-		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			// Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary.
-//			setInitState(INIT_STATE_WAIT_REDRAW);
-			setInitState(INIT_STATE_WAIT_COMPLETE);
-		}
-		
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateComplete(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			if(mInitState < INIT_STATE_RUNNING)
-			{
-				setInitState(INIT_STATE_RUNNING);
-				
-				// Clear the history, so the "back" button doesn't take you back to "about:blank".
-				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
-			}
-			
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
-			message.setValue("uri", event.getEventUri());
-			message.setValueS32("result_code", event.getIntValue());
-			message.setValue("result_string", event.getStringValue());
-			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
-			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
-			sendMessage(message);
-			
-			setStatus(STATUS_LOADED);
-		}
-		else if(mInitState == INIT_STATE_NAVIGATING)
-		{
-			setInitState(INIT_STATE_NAVIGATE_COMPLETE);
-		}
-
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onUpdateProgress(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
-			message.setValueS32("percent", event.getIntValue());
-			sendMessage(message);
-		}
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onStatusTextChange(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
-			message.setValue("status", event.getStringValue());
-			sendMessage(message);
-		}
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onTitleChange(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
-			message.setValue("name", event.getStringValue());
-			sendMessage(message);
-		}
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onNavigateErrorPage(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page");
-		message.setValueS32("status_code", event.getIntValue());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onLocationChange(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
-			message.setValue("uri", event.getEventUri());
-			sendMessage(message);
-		}
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onClickLinkHref(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
-		message.setValue("uri", event.getEventUri());
-		message.setValue("target", event.getStringValue());
-		message.setValue("uuid", event.getStringValue2());
-		sendMessage(message);
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onClickLinkNoFollow(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
-		message.setValue("uri", event.getEventUri());
-#if LLQTWEBKIT_API_VERSION >= 7
-		message.setValue("nav_type", event.getNavigationType());
-#else
-		message.setValue("nav_type", "clicked");
-#endif
-		sendMessage(message);
-	}
-	
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onCookieChanged(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set");
-		message.setValue("cookie", event.getStringValue());
-		// These could be passed through as well, but aren't really needed.
-//		message.setValue("uri", event.getEventUri());
-//		message.setValueBoolean("dead", (event.getIntValue() != 0))
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onWindowCloseRequested(const EventType& event)
-	{
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request");
-		message.setValue("uuid", event.getStringValue());
-		sendMessage(message);
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onWindowGeometryChangeRequested(const EventType& event)
-	{
-		int x, y, width, height;
-		event.getRectValue(x, y, width, height);
-
-		// This sometimes gets called with a zero-size request.  Don't pass these along.
-		if(width > 0 && height > 0)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change");
-			message.setValue("uuid", event.getStringValue());
-			message.setValueS32("x", x);
-			message.setValueS32("y", y);
-			message.setValueS32("width", width);
-			message.setValueS32("height", height);
-			sendMessage(message);
-		}
-	}
-
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	std::string onRequestFilePicker( const EventType& eventIn )
-	{
-		return blockingPickFile();
-	}
-	
-	std::string mAuthUsername;
-	std::string mAuthPassword;
-	bool mAuthOK;
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password)
-	{
-		mAuthOK = false;
-
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
-		message.setValue("url", in_url);
-		message.setValue("realm", in_realm);
-		message.setValueBoolean("blocking_request", true);
-				
-		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
-		sendMessage(message);
-		
-		if(mAuthOK)
-		{
-			out_username = mAuthUsername;
-			out_password = mAuthPassword;
-		}
-		
-		return mAuthOK;
-	}
-	
-	void authResponse(LLPluginMessage &message)
-	{
-		mAuthOK = message.getValueBoolean("ok");
-		if(mAuthOK)
-		{
-			mAuthUsername = message.getValue("username");
-			mAuthPassword = message.getValue("password");
-		}
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	// virtual
-	void onLinkHovered(const EventType& event)
-	{
-		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered");
-			message.setValue("link", event.getEventUri());
-			message.setValue("title", event.getStringValue());
-			message.setValue("text", event.getStringValue2());
-			sendMessage(message);
-		}
-	}
-	
-	LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)
-	{
-		int result = 0;
-		
-		if(modifiers.find("shift") != std::string::npos)
-			result |= LLQtWebKit::KM_MODIFIER_SHIFT;
-
-		if(modifiers.find("alt") != std::string::npos)
-			result |= LLQtWebKit::KM_MODIFIER_ALT;
-		
-		if(modifiers.find("control") != std::string::npos)
-			result |= LLQtWebKit::KM_MODIFIER_CONTROL;
-		
-		if(modifiers.find("meta") != std::string::npos)
-			result |= LLQtWebKit::KM_MODIFIER_META;
-		
-		return (LLQtWebKit::EKeyboardModifier)result;
-	}
-	
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers )
-	{
-		native_scan_code = 0;
-		native_virtual_key = 0;
-		native_modifiers = 0;
-		
-		if( native_key_data.isMap() )
-		{
-#if LL_DARWIN
-			native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
-			native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
-			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
-#elif LL_WINDOWS
-			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
-			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
-			// TODO: I don't think we need to do anything with native modifiers here -- please verify
-#elif LL_LINUX
-			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
-			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
-			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
-#else
-			// Add other platforms here as needed
-#endif
-		};
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
-	{
-		// The incoming values for 'key' will be the ones from indra_constants.h
-		std::string utf8_text;
-		
-		if(key < KEY_SPECIAL)
-		{
-			// Low-ascii characters need to get passed through.
-			utf8_text = (char)key;
-		}
-		
-		// Any special-case handling we want to do for particular keys...
-		switch((KEY)key)
-		{
-			// ASCII codes for some standard keys
-			case LLQtWebKit::KEY_BACKSPACE:		utf8_text = (char)8;		break;
-			case LLQtWebKit::KEY_TAB:			utf8_text = (char)9;		break;
-			case LLQtWebKit::KEY_RETURN:		utf8_text = (char)13;		break;
-			case LLQtWebKit::KEY_PAD_RETURN:	utf8_text = (char)13;		break;
-			case LLQtWebKit::KEY_ESCAPE:		utf8_text = (char)27;		break;
-			
-			default:  
-			break;
-		}
-		
-//		std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl;
-		
-		uint32_t native_scan_code = 0;
-		uint32_t native_virtual_key = 0;
-		uint32_t native_modifiers = 0;
-		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
-		
-		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
-
-		checkEditState();
-	};
-
-	////////////////////////////////////////////////////////////////////////////////
-	//
-	void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
-	{		
-		uint32_t key = LLQtWebKit::KEY_NONE;
-		
-//		std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl;
-		
-		if(utf8str.size() == 1)
-		{
-			// The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character.
-			// In this case, use it as the key value.
-			key = utf8str[0];
-		}
-
-		uint32_t native_scan_code = 0;
-		uint32_t native_virtual_key = 0;
-		uint32_t native_modifiers = 0;
-		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
-		
-		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
-		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
-
-		checkEditState();
-	};
-	
-	void checkEditState(void)
-	{
-		bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT);
-		bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY);
-		bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE);
-					
-		if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
-		{
-			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
-			
-			if(can_cut != mCanCut)
-			{
-				mCanCut = can_cut;
-				message.setValueBoolean("cut", can_cut);
-			}
-
-			if(can_copy != mCanCopy)
-			{
-				mCanCopy = can_copy;
-				message.setValueBoolean("copy", can_copy);
-			}
-
-			if(can_paste != mCanPaste)
-			{
-				mCanPaste = can_paste;
-				message.setValueBoolean("paste", can_paste);
-			}
-			
-			sendMessage(message);
-			
-		}
-	}
-	
-	std::string mPickedFile;
-	
-	std::string blockingPickFile(void)
-	{
-		mPickedFile.clear();
-		
-		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
-		message.setValueBoolean("blocking_request", true);
-		
-		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
-		sendMessage(message);
-		
-		return mPickedFile;
-	}
-
-	void onPickFileResponse(const std::string &file)
-	{
-		mPickedFile = file;
-	}
-
-};
-
-MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
-	MediaPluginBase(host_send_func, host_user_data)
-{
-//	std::cerr << "MediaPluginWebKit constructor" << std::endl;
-
-	mBrowserWindowId = 0;
-	mInitState = INIT_STATE_UNINITIALIZED;
-	mNeedsUpdate = true;
-	mCanCut = false;
-	mCanCopy = false;
-	mCanPaste = false;
-	mLastMouseX = 0;
-	mLastMouseY = 0;
-	mFirstFocus = true;
-	mBackgroundR = 0.0f;
-	mBackgroundG = 0.0f;
-	mBackgroundB = 0.0f;
-
-	mHostLanguage = "en";		// default to english
-	mJavascriptEnabled = true;	// default to on
-	mPluginsEnabled = true;		// default to on
-	mUserAgent = "LLPluginMedia Web Browser";
-}
-
-MediaPluginWebKit::~MediaPluginWebKit()
-{
-	// unhook observer
-	LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
-
-	// clean up
-	LLQtWebKit::getInstance()->reset();
-
-//	std::cerr << "MediaPluginWebKit destructor" << std::endl;
-}
-
-void MediaPluginWebKit::receiveMessage(const char *message_string)
-{
-//	std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
-	LLPluginMessage message_in;
-	
-	if(message_in.parse(message_string) >= 0)
-	{
-		std::string message_class = message_in.getClass();
-		std::string message_name = message_in.getName();
-		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
-		{
-			if(message_name == "init")
-			{
-				LLPluginMessage message("base", "init_response");
-				LLSD versions = LLSD::emptyMap();
-				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
-				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
-				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
-				message.setValueLLSD("versions", versions);
-
-				std::string plugin_version = "Webkit media plugin, Webkit version ";
-				plugin_version += LLQtWebKit::getInstance()->getVersion();
-				message.setValue("plugin_version", plugin_version);
-				sendMessage(message);
-			}
-			else if(message_name == "idle")
-			{
-				// no response is necessary here.
-				F64 time = message_in.getValueReal("time");
-				
-				// Convert time to milliseconds for update()
-				update((int)(time * 1000.0f));
-			}
-			else if(message_name == "cleanup")
-			{
-				// DTOR most likely won't be called but the recent change to the way this process
-				// is (not) killed means we see this message and can do what we need to here.
-				// Note: this cleanup is ultimately what writes cookies to the disk
-				LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
-				LLQtWebKit::getInstance()->reset();
-			}
-			else if(message_name == "shm_added")
-			{
-				SharedSegmentInfo info;
-				info.mAddress = message_in.getValuePointer("address");
-				info.mSize = (size_t)message_in.getValueS32("size");
-				std::string name = message_in.getValue("name");
-				
-//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name 
-//					<< ", size: " << info.mSize 
-//					<< ", address: " << info.mAddress 
-//					<< std::endl;
-
-				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
-			
-			}
-			else if(message_name == "shm_remove")
-			{
-				std::string name = message_in.getValue("name");
-				
-//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl;
-
-				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
-				if(iter != mSharedSegments.end())
-				{
-					if(mPixels == iter->second.mAddress)
-					{
-						// This is the currently active pixel buffer.  Make sure we stop drawing to it.
-						mPixels = NULL;
-						mTextureSegmentName.clear();
-					}
-					mSharedSegments.erase(iter);
-				}
-				else
-				{
-//					std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
-				}
-
-				// Send the response so it can be cleaned up.
-				LLPluginMessage message("base", "shm_remove_response");
-				message.setValue("name", name);
-				sendMessage(message);
-			}
-			else
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
-			}
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
-		{
-			if(message_name == "set_volume")
-			{
-				F32 volume = message_in.getValueReal("volume");
-				setVolume(volume);
-			}
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
-		{
-			if(message_name == "init")
-			{
-				mTarget = message_in.getValue("target");
-				
-				// This is the media init message -- all necessary data for initialization should have been received.
-				if(initBrowser())
-				{
-					
-					// Plugin gets to decide the texture parameters to use.
-					mDepth = 4;
-
-					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
-					message.setValueS32("default_width", 1024);
-					message.setValueS32("default_height", 1024);
-					message.setValueS32("depth", mDepth);
-					message.setValueU32("internalformat", GL_RGBA);
-	#if LL_QTWEBKIT_USES_PIXMAPS
-					message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it?  If so, we'll have to check the root window's pixel layout or something... yuck.
-	#else
-					message.setValueU32("format", GL_RGBA);
-	#endif // LL_QTWEBKIT_USES_PIXMAPS
-					message.setValueU32("type", GL_UNSIGNED_BYTE);
-					message.setValueBoolean("coords_opengl", true);
-					sendMessage(message);
-				}
-				else
-				{
-					// if initialization failed, we're done.
-					mDeleteMe = true;
-				}
-
-			}
-			else if(message_name == "set_user_data_path")
-			{
-				std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter
-				mProfileDir = user_data_path + "browser_profile";
-
-				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
-			}
-			else if(message_name == "set_language_code")
-			{
-				mHostLanguage = message_in.getValue("language");
-
-				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
-			}
-			else if(message_name == "plugins_enabled")
-			{
-				mPluginsEnabled = message_in.getValueBoolean("enable");
-			}
-			else if(message_name == "javascript_enabled")
-			{
-				mJavascriptEnabled = message_in.getValueBoolean("enable");
-			}
-			else if(message_name == "size_change")
-			{
-				std::string name = message_in.getValue("name");
-				S32 width = message_in.getValueS32("width");
-				S32 height = message_in.getValueS32("height");
-				S32 texture_width = message_in.getValueS32("texture_width");
-				S32 texture_height = message_in.getValueS32("texture_height");
-				mBackgroundR = message_in.getValueReal("background_r");
-				mBackgroundG = message_in.getValueReal("background_g");
-				mBackgroundB = message_in.getValueReal("background_b");
-//				mBackgroundA = message_in.setValueReal("background_a");		// Ignore any alpha
-								
-				if(!name.empty())
-				{
-					// Find the shared memory region with this name
-					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
-					if(iter != mSharedSegments.end())
-					{
-						mPixels = (unsigned char*)iter->second.mAddress;
-						mWidth = width;
-						mHeight = height;
-
-						if(initBrowserWindow())
-						{
-
-							// size changed so tell the browser
-							LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
-							
-	//						std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight 
-	//								<< ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl;
-									
-							S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); 
-							
-							// The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response.
-							if(real_width <= texture_width)
-							{
-								texture_width = real_width;
-							}
-							else
-							{
-								// This won't work -- it'll be bigger than the allocated memory.  This is a fatal error.
-	//							std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl;
-								mDeleteMe = true;
-								return;
-							}
-						}
-						else
-						{
-							// Setting up the browser window failed.  This is a fatal error.
-							mDeleteMe = true;
-						}
-
-						
-						mTextureWidth = texture_width;
-						mTextureHeight = texture_height;
-						
-					};
-				};
-
-				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
-				message.setValue("name", name);
-				message.setValueS32("width", width);
-				message.setValueS32("height", height);
-				message.setValueS32("texture_width", texture_width);
-				message.setValueS32("texture_height", texture_height);
-				sendMessage(message);
-
-			}
-			else if(message_name == "load_uri")
-			{
-				std::string uri = message_in.getValue("uri");
-
-//				std::cout << "loading URI: " << uri << std::endl;
-				
-				if(!uri.empty())
-				{
-					if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
-					{
-						LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri );
-					}
-					else
-					{
-						mInitialNavigateURL = uri;
-					}
-				}
-			}
-			else if(message_name == "mouse_event")
-			{
-				std::string event = message_in.getValue("event");
-				S32 button = message_in.getValueS32("button");
-				mLastMouseX = message_in.getValueS32("x");
-				mLastMouseY = message_in.getValueS32("y");
-				std::string modifiers = message_in.getValue("modifiers");
-				
-				// Treat unknown mouse events as mouse-moves.
-				LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE;
-				if(event == "down")
-				{
-					mouse_event = LLQtWebKit::ME_MOUSE_DOWN;
-				}
-				else if(event == "up")
-				{
-					mouse_event = LLQtWebKit::ME_MOUSE_UP;
-				}
-				else if(event == "double_click")
-				{
-					mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK;
-				}
-				
-				LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers));
-				checkEditState();
-			}
-			else if(message_name == "scroll_event")
-			{
-				S32 x = message_in.getValueS32("x");
-				S32 y = message_in.getValueS32("y");
-				std::string modifiers = message_in.getValue("modifiers");
-				
-				// Incoming scroll events are adjusted so that 1 detent is approximately 1 unit.
-				// Qt expects 1 detent to be 120 units.
-				// It also seems that our y scroll direction is inverted vs. what Qt expects.
-				
-				x *= 120;
-				y *= -120;
-				
-				LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers));
-			}
-			else if(message_name == "key_event")
-			{
-				std::string event = message_in.getValue("event");
-				S32 key = message_in.getValueS32("key");
-				std::string modifiers = message_in.getValue("modifiers");
-				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
-				
-				// Treat unknown events as key-up for safety.
-				LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP;
-				if(event == "down")
-				{
-					key_event = LLQtWebKit::KE_KEY_DOWN;
-				}
-				else if(event == "repeat")
-				{
-					key_event = LLQtWebKit::KE_KEY_REPEAT;
-				}
-				
-				keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
-			}
-			else if(message_name == "text_event")
-			{
-				std::string text = message_in.getValue("text");
-				std::string modifiers = message_in.getValue("modifiers");
-				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
-				
-				unicodeInput(text, decodeModifiers(modifiers), native_key_data);
-			}
-			if(message_name == "edit_cut")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT );
-				checkEditState();
-			}
-			if(message_name == "edit_copy")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY );
-				checkEditState();
-			}
-			if(message_name == "edit_paste")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
-				checkEditState();
-			}
-			if(message_name == "pick_file_response")
-			{
-				onPickFileResponse(message_in.getValue("file"));
-			}
-			if(message_name == "auth_response")
-			{
-				authResponse(message_in);
-			}
-			else
-			if(message_name == "js_enable_object")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				bool enable = message_in.getValueBoolean( "enable" );
-				LLQtWebKit::getInstance()->setSLObjectEnabled( enable );
-#endif
-			}
-			else
-			if(message_name == "js_agent_location")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				F32 x = message_in.getValueReal("x");
-				F32 y = message_in.getValueReal("y");
-				F32 z = message_in.getValueReal("z");
-				LLQtWebKit::getInstance()->setAgentLocation( x, y, z );
-				LLQtWebKit::getInstance()->emitLocation();
-#endif
-			}
-			else
-			if(message_name == "js_agent_global_location")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				F32 x = message_in.getValueReal("x");
-				F32 y = message_in.getValueReal("y");
-				F32 z = message_in.getValueReal("z");
-				LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z );
-				LLQtWebKit::getInstance()->emitLocation();
-#endif
-			}
-			else			
-			if(message_name == "js_agent_orientation")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				F32 angle = message_in.getValueReal("angle");
-				LLQtWebKit::getInstance()->setAgentOrientation( angle );
-				LLQtWebKit::getInstance()->emitLocation();
-#endif
-			}
-			else
-			if(message_name == "js_agent_region")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				const std::string& region = message_in.getValue("region");
-				LLQtWebKit::getInstance()->setAgentRegion( region );
-				LLQtWebKit::getInstance()->emitLocation();
-#endif
-			}
-			else
-				if(message_name == "js_agent_maturity")
-				{
-#if LLQTWEBKIT_API_VERSION >= 9
-					const std::string& maturity = message_in.getValue("maturity");
-					LLQtWebKit::getInstance()->setAgentMaturity( maturity );
-					LLQtWebKit::getInstance()->emitMaturity();
-#endif
-				}
-			else
-			if(message_name == "js_agent_language")
-			{
-#if LLQTWEBKIT_API_VERSION >= 9
-				const std::string& language = message_in.getValue("language");
-				LLQtWebKit::getInstance()->setAgentLanguage( language );
-				LLQtWebKit::getInstance()->emitLanguage();
-#endif
-			}
-			else
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
-			}
-		}
-		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
-		{
-			if(message_name == "focus")
-			{
-				bool val = message_in.getValueBoolean("focused");
-				LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val );
-				
-				if(mFirstFocus && val)
-				{
-					// On the first focus, post a tab key event.  This fixes a problem with initial focus.
-					std::string empty;
-					keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty));
-					keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty));
-					mFirstFocus = false;
-				}
-			}
-			else if(message_name == "clear_cache")
-			{
-				LLQtWebKit::getInstance()->clearCache();
-			}
-			else if(message_name == "clear_cookies")
-			{
-				LLQtWebKit::getInstance()->clearAllCookies();
-			}
-			else if(message_name == "enable_cookies")
-			{
-				mCookiesEnabled = message_in.getValueBoolean("enable");
-				LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
-			}
-			else if(message_name == "enable_plugins")
-			{
-				mPluginsEnabled = message_in.getValueBoolean("enable");
-				LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
-			}
-			else if(message_name == "enable_javascript")
-			{
-				mJavascriptEnabled = message_in.getValueBoolean("enable");
-				//LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
-			}
-			else if(message_name == "set_cookies")
-			{
-				LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies"));
-			}
-			else if(message_name == "proxy_setup")
-			{
-				bool val = message_in.getValueBoolean("enable");
-				std::string host = message_in.getValue("host");
-				int port = message_in.getValueS32("port");
-				LLQtWebKit::getInstance()->enableProxy( val, host, port );
-			}
-			else if(message_name == "browse_stop")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP );
-			}
-			else if(message_name == "browse_reload")
-			{
-				// foo = message_in.getValueBoolean("ignore_cache");
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD );
-			}
-			else if(message_name == "browse_forward")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD );
-			}
-			else if(message_name == "browse_back")
-			{
-				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK );
-			}
-			else if(message_name == "set_status_redirect")
-			{
-				int code = message_in.getValueS32("code");
-				std::string url = message_in.getValue("url");
-				if ( 404 == code )	// browser lib only supports 404 right now
-				{
-#if LLQTWEBKIT_API_VERSION < 8
-				 	LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
-#endif
-				};
-			}
-			else if(message_name == "set_user_agent")
-			{
-				mUserAgent = message_in.getValue("user_agent");
-				LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
-			}
-			else if(message_name == "ignore_ssl_cert_errors")
-			{
-#if LLQTWEBKIT_API_VERSION >= 3
-				LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") );
-#else
-				llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl;
-#endif
-			}
-			else if(message_name == "add_certificate_file_path")
-			{
-#if LLQTWEBKIT_API_VERSION >= 6
-				LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") );
-#else
-				llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl;
-#endif
-			}
-			else if(message_name == "init_history")
-			{
-				// Initialize browser history
-				LLSD history = message_in.getValueLLSD("history");
-				// First, clear the URL history
-				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
-				// Then, add the history items in order
-				LLSD::array_iterator iter_history = history.beginArray();
-				LLSD::array_iterator end_history = history.endArray();
-				for(; iter_history != end_history; ++iter_history)
-				{
-					std::string url = (*iter_history).asString();
-					if(! url.empty()) {
-						LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url);
-					}
-				}
-			}
-			else if(message_name == "proxy_window_opened")
-			{
-				std::string target = message_in.getValue("target");
-				std::string uuid = message_in.getValue("uuid");
-				LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid);
-			}
-			else if(message_name == "proxy_window_closed")
-			{
-				std::string uuid = message_in.getValue("uuid");
-				LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid);
-			}
-			else
-			{
-//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
-			};
-		}
-		else
-		{
-//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
-		};
-	}
-}
-
-void MediaPluginWebKit::setVolume(F32 volume)
-{
-	mVolumeCatcher.setVolume(volume);
-}
-
-int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
-{
-	MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data);
-	*plugin_send_func = MediaPluginWebKit::staticReceiveMessage;
-	*plugin_user_data = (void*)self;
-
-	return 0;
-}
-
-
+/** 
+ * @file media_plugin_webkit.cpp
+ * @brief Webkit plugin for LLMedia API plugin system
+ *
+ * @cond
+ * $LicenseInfo:firstyear=2008&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ * @endcond
+ */
+
+#include "llqtwebkit.h"
+
+#include "linden_common.h"
+#include "indra_constants.h" // for indra keyboard codes
+
+#include "llgl.h"
+
+#include "llplugininstance.h"
+#include "llpluginmessage.h"
+#include "llpluginmessageclasses.h"
+#include "media_plugin_base.h"
+
+// set to 1 if you're using the version of llqtwebkit that's QPixmap-ified
+#if LL_LINUX
+# define LL_QTWEBKIT_USES_PIXMAPS 0
+extern "C" {
+# include <glib.h>
+# include <glib-object.h>
+}
+#else
+# define LL_QTWEBKIT_USES_PIXMAPS 0
+#endif // LL_LINUX
+
+# include "volume_catcher.h"
+
+#if LL_WINDOWS
+# include <direct.h>
+#else
+# include <unistd.h>
+# include <stdlib.h>
+#endif
+
+#if LL_WINDOWS
+	// *NOTE:Mani - This captures the module handle for the dll. This is used below
+	// to get the path to this dll for webkit initialization.
+	// I don't know how/if this can be done with apr...
+	namespace {	HMODULE gModuleHandle;};
+	BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+	{
+		gModuleHandle = (HMODULE) hinstDLL;
+		return TRUE;
+	}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+//
+class MediaPluginWebKit : 
+		public MediaPluginBase,
+		public LLEmbeddedBrowserWindowObserver
+{
+public:
+	MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data);
+	~MediaPluginWebKit();
+
+	/*virtual*/ void receiveMessage(const char *message_string);
+
+private:
+
+	std::string mProfileDir;
+	std::string mHostLanguage;
+	std::string mUserAgent;
+	bool mCookiesEnabled;
+	bool mJavascriptEnabled;
+	bool mPluginsEnabled;
+	bool mEnableMediaPluginDebugging;
+
+	enum
+	{
+		INIT_STATE_UNINITIALIZED,		// LLQtWebkit hasn't been set up yet
+		INIT_STATE_INITIALIZED,			// LLQtWebkit has been set up, but no browser window has been created yet.
+		INIT_STATE_NAVIGATING,			// Browser instance has been set up and initial navigate to about:blank has been issued
+		INIT_STATE_NAVIGATE_COMPLETE,	// initial navigate to about:blank has completed
+		INIT_STATE_WAIT_REDRAW,			// First real navigate begin has been received, waiting for page changed event to start handling redraws
+		INIT_STATE_WAIT_COMPLETE,		// Waiting for first real navigate complete event
+		INIT_STATE_RUNNING				// All initialization gymnastics are complete.
+	};
+	int mBrowserWindowId;
+	int mInitState;
+	std::string mInitialNavigateURL;
+	bool mNeedsUpdate;
+
+	bool	mCanCut;
+	bool	mCanCopy;
+	bool	mCanPaste;
+	int mLastMouseX;
+	int mLastMouseY;
+	bool mFirstFocus;
+	F32 mBackgroundR;
+	F32 mBackgroundG;
+	F32 mBackgroundB;
+	std::string mTarget;
+	
+	VolumeCatcher mVolumeCatcher;
+
+	void postDebugMessage( const std::string& msg )
+	{
+		if ( mEnableMediaPluginDebugging )
+		{
+			LLPluginMessage debug_message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "debug_message");
+			debug_message.setValue("message_text", "Media> " + msg);
+			debug_message.setValue("message_level", "info");
+			sendMessage(debug_message);
+		}
+	}
+	
+	void setInitState(int state)
+	{
+//		std::cerr << "changing init state to " << state << std::endl;
+		mInitState = state;
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void update(int milliseconds)
+	{
+#if LL_QTLINUX_DOESNT_HAVE_GLIB
+		// pump glib generously, as Linux browser plugins are on the
+		// glib main loop, even if the browser itself isn't - ugh
+		// This is NOT NEEDED if Qt itself was built with glib
+		// mainloop integration.
+		GMainContext *mainc = g_main_context_default();
+		while(g_main_context_iteration(mainc, FALSE));
+#endif // LL_QTLINUX_DOESNT_HAVE_GLIB
+
+		// pump qt
+		LLQtWebKit::getInstance()->pump( milliseconds );
+		
+		mVolumeCatcher.pump();
+
+		checkEditState();
+		
+		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			if(!mInitialNavigateURL.empty())
+			{
+				// We already have the initial navigate URL -- kick off the navigate.
+				LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mInitialNavigateURL );
+				mInitialNavigateURL.clear();
+			}
+		}
+		
+		if ( (mInitState > INIT_STATE_WAIT_REDRAW) && mNeedsUpdate )
+		{
+			const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId );
+
+			unsigned int rowspan = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId );
+			unsigned int height = LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId );
+#if !LL_QTWEBKIT_USES_PIXMAPS
+			unsigned int buffer_size = rowspan * height;
+#endif // !LL_QTWEBKIT_USES_PIXMAPS
+			
+//			std::cerr << "webkit plugin: updating" << std::endl;
+			
+			// TODO: should get rid of this memcpy if possible
+			if ( mPixels && browser_pixels )
+			{
+//				std::cerr << "    memcopy of " << buffer_size << " bytes" << std::endl;
+
+#if LL_QTWEBKIT_USES_PIXMAPS
+				// copy the pixel data upside-down because of the co-ord system
+				for (int y=0; y<height; ++y)
+				{
+					memcpy( &mPixels[(height-y-1)*rowspan], &browser_pixels[y*rowspan], rowspan );
+				}
+#else
+				memcpy( mPixels, browser_pixels, buffer_size );
+#endif // LL_QTWEBKIT_USES_PIXMAPS
+			}
+
+			if ( mWidth > 0 && mHeight > 0 )
+			{
+//				std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl;
+				setDirty( 0, 0, mWidth, mHeight );
+			}
+
+			mNeedsUpdate = false;
+		};
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	bool initBrowser()
+	{
+		// already initialized
+		if ( mInitState > INIT_STATE_UNINITIALIZED )
+			return true;
+
+		// set up directories
+		char cwd[ FILENAME_MAX ];	// I *think* this is defined on all platforms we use
+		if (NULL == getcwd( cwd, FILENAME_MAX - 1 ))
+		{
+			llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl;
+			return false;
+		}
+		std::string application_dir = std::string( cwd );
+
+#if LL_LINUX
+		// take care to initialize glib properly, because some
+		// versions of Qt don't, and we indirectly need it for (some
+		// versions of) Flash to not crash the browser.
+		if (!g_thread_supported ()) g_thread_init (NULL);
+		g_type_init();
+#endif
+
+#if LL_DARWIN
+		// When running under the Xcode debugger, there's a setting called "Break on Debugger()/DebugStr()" which defaults to being turned on.
+		// This causes the environment variable USERBREAK to be set to 1, which causes these legacy calls to break into the debugger.
+		// This wouldn't cause any problems except for the fact that the current release version of the Flash plugin has a call to Debugger() in it
+		// which gets hit when the plugin is probed by webkit.
+		// Unsetting the environment variable here works around this issue.
+		unsetenv("USERBREAK");
+#endif
+
+#if LL_WINDOWS
+		//*NOTE:Mani - On windows, at least, the component path is the
+		// location of this dll's image file. 
+		std::string component_dir;
+		char dll_path[_MAX_PATH];
+		DWORD len = GetModuleFileNameA(gModuleHandle, (LPCH)&dll_path, _MAX_PATH);
+		while(len && dll_path[ len ] != ('\\') )
+		{
+			len--;
+		}
+		if(len >= 0)
+		{
+			dll_path[len] = 0;
+			component_dir = dll_path;
+		}
+		else
+		{
+			// *NOTE:Mani - This case should be an rare exception. 
+			// GetModuleFileNameA should always give you a full path, no?
+			component_dir = application_dir;
+		}
+#else
+		std::string component_dir = application_dir;
+#endif
+
+		// debug spam sent to viewer and displayed in the log as usual
+		postDebugMessage( "Component dir set to: " + component_dir );
+
+		// window handle - needed on Windows and must be app window.
+#if LL_WINDOWS
+		char window_title[ MAX_PATH ];
+		GetConsoleTitleA( window_title, MAX_PATH );
+		void* native_window_handle = (void*)FindWindowA( NULL, window_title );
+#else
+		void* native_window_handle = 0;
+#endif
+
+		// main browser initialization
+		bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, mProfileDir, native_window_handle );
+		if ( result )
+		{
+			mInitState = INIT_STATE_INITIALIZED;
+
+			// debug spam sent to viewer and displayed in the log as usual
+			postDebugMessage( "browser initialized okay" );
+
+			return true;
+		};
+
+		// debug spam sent to viewer and displayed in the log as usual
+		postDebugMessage( "browser nOT initialized." );
+
+		return false;
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	bool initBrowserWindow()
+	{
+		// already initialized
+		if ( mInitState > INIT_STATE_INITIALIZED )
+			return true;
+
+		// not enough information to initialize the browser yet.
+		if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || 
+				mTextureWidth < 0 || mTextureHeight < 0 )
+		{
+			return false;
+		};
+		
+		// Set up host language before creating browser window
+		if(!mHostLanguage.empty())
+		{
+			LLQtWebKit::getInstance()->setHostLanguage(mHostLanguage);
+			postDebugMessage( "Setting language to " + mHostLanguage );
+		}
+
+		// turn on/off cookies based on what host app tells us
+		LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
+		
+		// turn on/off plugins based on what host app tells us
+		LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
+
+		// turn on/off Javascript based on what host app tells us
+		LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
+
+		std::stringstream str;
+		str << "Cookies enabled = " << mCookiesEnabled << ", plugins enabled = " << mPluginsEnabled << ", Javascript enabled = " << mJavascriptEnabled;
+		postDebugMessage( str.str() );
+
+		// create single browser window
+		mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight, mTarget);
+
+		str.str("");
+		str.clear();
+		str << "Setting browser window size to " << mWidth << " x " << mHeight;
+		postDebugMessage( str.str() );
+
+		// tell LLQtWebKit about the size of the browser window
+		LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
+
+		// observer events that LLQtWebKit emits
+		LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this );
+
+		// append details to agent string
+		LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
+		postDebugMessage( "Updating user agent with " + mUserAgent );
+		
+#if !LL_QTWEBKIT_USES_PIXMAPS
+		// don't flip bitmap
+		LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true );
+#endif // !LL_QTWEBKIT_USES_PIXMAPS
+
+		// set background color
+		// convert background color channels from [0.0, 1.0] to [0, 255];
+		LLQtWebKit::getInstance()->setBackgroundColor( mBrowserWindowId, int(mBackgroundR * 255.0f), int(mBackgroundG * 255.0f), int(mBackgroundB * 255.0f) );
+
+		// Set state _before_ starting the navigate, since onNavigateBegin might get called before this call returns.
+		setInitState(INIT_STATE_NAVIGATING);
+
+		// Don't do this here -- it causes the dreaded "white flash" when loading a browser instance.
+		// FIXME: Re-added this because navigating to a "page" initializes things correctly - especially
+		// for the HTTP AUTH dialog issues (DEV-41731). Will fix at a later date.
+		// Build a data URL like this: "data:text/html,%3Chtml%3E%3Cbody bgcolor=%22#RRGGBB%22%3E%3C/body%3E%3C/html%3E"
+		// where RRGGBB is the background color in HTML style
+		std::stringstream url;
+		
+		url << "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#";
+		// convert background color channels from [0.0, 1.0] to [0, 255];
+		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundR * 255.0f);
+		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundG * 255.0f);
+		url << std::setfill('0') << std::setw(2) << std::hex << int(mBackgroundB * 255.0f);
+		url << "%22%3E%3C/body%3E%3C/html%3E";
+		
+		//lldebugs << "data url is: " << url.str() << llendl;
+					
+		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, url.str() );
+//		LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" );
+
+		return true;	
+	}
+
+	void setVolume(F32 vol);
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onCursorChanged(const EventType& event)
+	{
+		LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue();
+		std::string name;
+
+		switch(llqt_cursor)
+		{
+			case LLQtWebKit::C_ARROW:
+				name = "arrow";
+			break;
+			case LLQtWebKit::C_IBEAM:
+				name = "ibeam";
+			break;
+			case LLQtWebKit::C_SPLITV:
+				name = "splitv";
+			break;
+			case LLQtWebKit::C_SPLITH:
+				name = "splith";
+			break;
+			case LLQtWebKit::C_POINTINGHAND:
+				name = "hand";
+			break;
+			
+			default:
+				llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl;
+			break;
+		}
+		
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed");
+		message.setValue("name", name);
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onPageChanged( const EventType& event )
+	{
+		if(mInitState == INIT_STATE_WAIT_REDRAW)
+		{
+			setInitState(INIT_STATE_WAIT_COMPLETE);
+		}
+		
+		// flag that an update is required
+		mNeedsUpdate = true;
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onNavigateBegin(const EventType& event)
+	{
+		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin");
+			message.setValue("uri", event.getEventUri());
+			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
+			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
+			sendMessage(message);
+
+			// debug spam sent to viewer and displayed in the log as usual
+			postDebugMessage( "Navigate begin event at: " + event.getEventUri() );
+
+			setStatus(STATUS_LOADING);
+		}
+
+		if(mInitState == INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			// Skip the WAIT_REDRAW state now -- with the right background color set, it should no longer be necessary.
+//			setInitState(INIT_STATE_WAIT_REDRAW);
+			setInitState(INIT_STATE_WAIT_COMPLETE);
+		}
+		
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onNavigateComplete(const EventType& event)
+	{
+		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			if(mInitState < INIT_STATE_RUNNING)
+			{
+				setInitState(INIT_STATE_RUNNING);
+				
+				// Clear the history, so the "back" button doesn't take you back to "about:blank".
+				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
+			}
+			
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete");
+			message.setValue("uri", event.getEventUri());
+			message.setValueS32("result_code", event.getIntValue());
+			message.setValue("result_string", event.getStringValue());
+			message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK));
+			message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD));
+			sendMessage(message);
+			
+			setStatus(STATUS_LOADED);
+		}
+		else if(mInitState == INIT_STATE_NAVIGATING)
+		{
+			setInitState(INIT_STATE_NAVIGATE_COMPLETE);
+		}
+
+		// debug spam sent to viewer and displayed in the log as usual
+		postDebugMessage( "Navigate complete event at: " + event.getEventUri() );
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onUpdateProgress(const EventType& event)
+	{
+		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress");
+			message.setValueS32("percent", event.getIntValue());
+			sendMessage(message);
+		}
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onStatusTextChange(const EventType& event)
+	{
+		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text");
+			message.setValue("status", event.getStringValue());
+			sendMessage(message);
+		}
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onTitleChange(const EventType& event)
+	{
+		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "name_text");
+			message.setValue("name", event.getStringValue());
+			sendMessage(message);
+		}
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onNavigateErrorPage(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page");
+		message.setValueS32("status_code", event.getIntValue());
+		sendMessage(message);
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onLocationChange(const EventType& event)
+	{
+		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed");
+			message.setValue("uri", event.getEventUri());
+			sendMessage(message);
+		}
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onClickLinkHref(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href");
+		message.setValue("uri", event.getEventUri());
+		message.setValue("target", event.getStringValue());
+		message.setValue("uuid", event.getStringValue2());
+		sendMessage(message);
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onClickLinkNoFollow(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow");
+		message.setValue("uri", event.getEventUri());
+#if LLQTWEBKIT_API_VERSION >= 7
+		message.setValue("nav_type", event.getNavigationType());
+#else
+		message.setValue("nav_type", "clicked");
+#endif
+		sendMessage(message);
+	}
+	
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onCookieChanged(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookie_set");
+		message.setValue("cookie", event.getStringValue());
+		// These could be passed through as well, but aren't really needed.
+//		message.setValue("uri", event.getEventUri());
+//		message.setValueBoolean("dead", (event.getIntValue() != 0))
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onWindowCloseRequested(const EventType& event)
+	{
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "close_request");
+		message.setValue("uuid", event.getStringValue());
+		sendMessage(message);
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onWindowGeometryChangeRequested(const EventType& event)
+	{
+		int x, y, width, height;
+		event.getRectValue(x, y, width, height);
+
+		// This sometimes gets called with a zero-size request.  Don't pass these along.
+		if(width > 0 && height > 0)
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "geometry_change");
+			message.setValue("uuid", event.getStringValue());
+			message.setValueS32("x", x);
+			message.setValueS32("y", y);
+			message.setValueS32("width", width);
+			message.setValueS32("height", height);
+			sendMessage(message);
+		}
+	}
+
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	std::string onRequestFilePicker( const EventType& eventIn )
+	{
+		return blockingPickFile();
+	}
+	
+	std::string mAuthUsername;
+	std::string mAuthPassword;
+	bool mAuthOK;
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password)
+	{
+		mAuthOK = false;
+
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "auth_request");
+		message.setValue("url", in_url);
+		message.setValue("realm", in_realm);
+		message.setValueBoolean("blocking_request", true);
+				
+		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
+		sendMessage(message);
+		
+		if(mAuthOK)
+		{
+			out_username = mAuthUsername;
+			out_password = mAuthPassword;
+		}
+		
+		return mAuthOK;
+	}
+	
+	void authResponse(LLPluginMessage &message)
+	{
+		mAuthOK = message.getValueBoolean("ok");
+		if(mAuthOK)
+		{
+			mAuthUsername = message.getValue("username");
+			mAuthPassword = message.getValue("password");
+		}
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	// virtual
+	void onLinkHovered(const EventType& event)
+	{
+		if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "link_hovered");
+			message.setValue("link", event.getEventUri());
+			message.setValue("title", event.getStringValue());
+			message.setValue("text", event.getStringValue2());
+			sendMessage(message);
+		}
+	}
+	
+	LLQtWebKit::EKeyboardModifier decodeModifiers(std::string &modifiers)
+	{
+		int result = 0;
+		
+		if(modifiers.find("shift") != std::string::npos)
+			result |= LLQtWebKit::KM_MODIFIER_SHIFT;
+
+		if(modifiers.find("alt") != std::string::npos)
+			result |= LLQtWebKit::KM_MODIFIER_ALT;
+		
+		if(modifiers.find("control") != std::string::npos)
+			result |= LLQtWebKit::KM_MODIFIER_CONTROL;
+		
+		if(modifiers.find("meta") != std::string::npos)
+			result |= LLQtWebKit::KM_MODIFIER_META;
+		
+		return (LLQtWebKit::EKeyboardModifier)result;
+	}
+	
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void deserializeKeyboardData( LLSD native_key_data, uint32_t& native_scan_code, uint32_t& native_virtual_key, uint32_t& native_modifiers )
+	{
+		native_scan_code = 0;
+		native_virtual_key = 0;
+		native_modifiers = 0;
+		
+		if( native_key_data.isMap() )
+		{
+#if LL_DARWIN
+			native_scan_code = (uint32_t)(native_key_data["char_code"].asInteger());
+			native_virtual_key = (uint32_t)(native_key_data["key_code"].asInteger());
+			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
+#elif LL_WINDOWS
+			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
+			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
+			// TODO: I don't think we need to do anything with native modifiers here -- please verify
+#elif LL_LINUX
+			native_scan_code = (uint32_t)(native_key_data["scan_code"].asInteger());
+			native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
+			native_modifiers = (uint32_t)(native_key_data["modifiers"].asInteger());
+#else
+			// Add other platforms here as needed
+#endif
+		};
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void keyEvent(LLQtWebKit::EKeyEvent key_event, int key, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
+	{
+		// The incoming values for 'key' will be the ones from indra_constants.h
+		std::string utf8_text;
+		
+		if(key < KEY_SPECIAL)
+		{
+			// Low-ascii characters need to get passed through.
+			utf8_text = (char)key;
+		}
+		
+		// Any special-case handling we want to do for particular keys...
+		switch((KEY)key)
+		{
+			// ASCII codes for some standard keys
+			case LLQtWebKit::KEY_BACKSPACE:		utf8_text = (char)8;		break;
+			case LLQtWebKit::KEY_TAB:			utf8_text = (char)9;		break;
+			case LLQtWebKit::KEY_RETURN:		utf8_text = (char)13;		break;
+			case LLQtWebKit::KEY_PAD_RETURN:	utf8_text = (char)13;		break;
+			case LLQtWebKit::KEY_ESCAPE:		utf8_text = (char)27;		break;
+			
+			default:  
+			break;
+		}
+		
+//		std::cerr << "key event " << (int)key_event << ", native_key_data = " << native_key_data << std::endl;
+		
+		uint32_t native_scan_code = 0;
+		uint32_t native_virtual_key = 0;
+		uint32_t native_modifiers = 0;
+		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
+		
+		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, key_event, (uint32_t)key, utf8_text.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
+
+		checkEditState();
+	};
+
+	////////////////////////////////////////////////////////////////////////////////
+	//
+	void unicodeInput( const std::string &utf8str, LLQtWebKit::EKeyboardModifier modifiers, LLSD native_key_data = LLSD::emptyMap())
+	{		
+		uint32_t key = LLQtWebKit::KEY_NONE;
+		
+//		std::cerr << "unicode input, native_key_data = " << native_key_data << std::endl;
+		
+		if(utf8str.size() == 1)
+		{
+			// The only way a utf8 string can be one byte long is if it's actually a single 7-bit ascii character.
+			// In this case, use it as the key value.
+			key = utf8str[0];
+		}
+
+		uint32_t native_scan_code = 0;
+		uint32_t native_virtual_key = 0;
+		uint32_t native_modifiers = 0;
+		deserializeKeyboardData( native_key_data, native_scan_code, native_virtual_key, native_modifiers );
+		
+		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_DOWN, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
+		LLQtWebKit::getInstance()->keyboardEvent( mBrowserWindowId, LLQtWebKit::KE_KEY_UP, (uint32_t)key, utf8str.c_str(), modifiers, native_scan_code, native_virtual_key, native_modifiers);
+
+		checkEditState();
+	};
+	
+	void checkEditState(void)
+	{
+		bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT);
+		bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY);
+		bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE);
+					
+		if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste))
+		{
+			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state");
+			
+			if(can_cut != mCanCut)
+			{
+				mCanCut = can_cut;
+				message.setValueBoolean("cut", can_cut);
+			}
+
+			if(can_copy != mCanCopy)
+			{
+				mCanCopy = can_copy;
+				message.setValueBoolean("copy", can_copy);
+			}
+
+			if(can_paste != mCanPaste)
+			{
+				mCanPaste = can_paste;
+				message.setValueBoolean("paste", can_paste);
+			}
+			
+			sendMessage(message);
+			
+		}
+	}
+	
+	std::string mPickedFile;
+	
+	std::string blockingPickFile(void)
+	{
+		mPickedFile.clear();
+		
+		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file");
+		message.setValueBoolean("blocking_request", true);
+		
+		// The "blocking_request" key in the message means this sendMessage call will block until a response is received.
+		sendMessage(message);
+		
+		return mPickedFile;
+	}
+
+	void onPickFileResponse(const std::string &file)
+	{
+		mPickedFile = file;
+	}
+
+};
+
+MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) :
+	MediaPluginBase(host_send_func, host_user_data)
+{
+//	std::cerr << "MediaPluginWebKit constructor" << std::endl;
+
+	mBrowserWindowId = 0;
+	mInitState = INIT_STATE_UNINITIALIZED;
+	mNeedsUpdate = true;
+	mCanCut = false;
+	mCanCopy = false;
+	mCanPaste = false;
+	mLastMouseX = 0;
+	mLastMouseY = 0;
+	mFirstFocus = true;
+	mBackgroundR = 0.0f;
+	mBackgroundG = 0.0f;
+	mBackgroundB = 0.0f;
+
+	mHostLanguage = "en";		// default to english
+	mJavascriptEnabled = true;	// default to on
+	mPluginsEnabled = true;		// default to on
+	mEnableMediaPluginDebugging = false;
+	mUserAgent = "LLPluginMedia Web Browser";
+}
+
+MediaPluginWebKit::~MediaPluginWebKit()
+{
+	// unhook observer
+	LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
+
+	// clean up
+	LLQtWebKit::getInstance()->reset();
+
+//	std::cerr << "MediaPluginWebKit destructor" << std::endl;
+}
+
+void MediaPluginWebKit::receiveMessage(const char *message_string)
+{
+//	std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl;
+	LLPluginMessage message_in;
+	
+	if(message_in.parse(message_string) >= 0)
+	{
+		std::string message_class = message_in.getClass();
+		std::string message_name = message_in.getName();
+		if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE)
+		{
+			if(message_name == "init")
+			{
+				LLPluginMessage message("base", "init_response");
+				LLSD versions = LLSD::emptyMap();
+				versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION;
+				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION;
+				versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION;
+				message.setValueLLSD("versions", versions);
+
+				std::string plugin_version = "Webkit media plugin, Webkit version ";
+				plugin_version += LLQtWebKit::getInstance()->getVersion();
+				message.setValue("plugin_version", plugin_version);
+				sendMessage(message);
+			}
+			else if(message_name == "idle")
+			{
+				// no response is necessary here.
+				F64 time = message_in.getValueReal("time");
+				
+				// Convert time to milliseconds for update()
+				update((int)(time * 1000.0f));
+			}
+			else if(message_name == "cleanup")
+			{
+				// DTOR most likely won't be called but the recent change to the way this process
+				// is (not) killed means we see this message and can do what we need to here.
+				// Note: this cleanup is ultimately what writes cookies to the disk
+				LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this );
+				LLQtWebKit::getInstance()->reset();
+			}
+			else if(message_name == "shm_added")
+			{
+				SharedSegmentInfo info;
+				info.mAddress = message_in.getValuePointer("address");
+				info.mSize = (size_t)message_in.getValueS32("size");
+				std::string name = message_in.getValue("name");
+				
+//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name 
+//					<< ", size: " << info.mSize 
+//					<< ", address: " << info.mAddress 
+//					<< std::endl;
+
+				mSharedSegments.insert(SharedSegmentMap::value_type(name, info));
+			
+			}
+			else if(message_name == "shm_remove")
+			{
+				std::string name = message_in.getValue("name");
+				
+//				std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl;
+
+				SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+				if(iter != mSharedSegments.end())
+				{
+					if(mPixels == iter->second.mAddress)
+					{
+						// This is the currently active pixel buffer.  Make sure we stop drawing to it.
+						mPixels = NULL;
+						mTextureSegmentName.clear();
+					}
+					mSharedSegments.erase(iter);
+				}
+				else
+				{
+//					std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl;
+				}
+
+				// Send the response so it can be cleaned up.
+				LLPluginMessage message("base", "shm_remove_response");
+				message.setValue("name", name);
+				sendMessage(message);
+			}
+			else
+			{
+//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl;
+			}
+		}
+		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
+		{
+			if(message_name == "set_volume")
+			{
+				F32 volume = message_in.getValueReal("volume");
+				setVolume(volume);
+			}
+		}
+		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
+		{
+			if(message_name == "init")
+			{
+				mTarget = message_in.getValue("target");
+				
+				// This is the media init message -- all necessary data for initialization should have been received.
+				if(initBrowser())
+				{
+					
+					// Plugin gets to decide the texture parameters to use.
+					mDepth = 4;
+
+					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params");
+					message.setValueS32("default_width", 1024);
+					message.setValueS32("default_height", 1024);
+					message.setValueS32("depth", mDepth);
+					message.setValueU32("internalformat", GL_RGBA);
+	#if LL_QTWEBKIT_USES_PIXMAPS
+					message.setValueU32("format", GL_BGRA_EXT); // I hope this isn't system-dependant... is it?  If so, we'll have to check the root window's pixel layout or something... yuck.
+	#else
+					message.setValueU32("format", GL_RGBA);
+	#endif // LL_QTWEBKIT_USES_PIXMAPS
+					message.setValueU32("type", GL_UNSIGNED_BYTE);
+					message.setValueBoolean("coords_opengl", true);
+					sendMessage(message);
+				}
+				else
+				{
+					// if initialization failed, we're done.
+					mDeleteMe = true;
+				}
+
+			}
+			else if(message_name == "set_user_data_path")
+			{
+				std::string user_data_path = message_in.getValue("path"); // n.b. always has trailing platform-specific dir-delimiter
+				mProfileDir = user_data_path + "browser_profile";
+
+				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
+			}
+			else if(message_name == "set_language_code")
+			{
+				mHostLanguage = message_in.getValue("language");
+
+				// FIXME: Should we do anything with this if it comes in after the browser has been initialized?
+			}
+			else if(message_name == "plugins_enabled")
+			{
+				mPluginsEnabled = message_in.getValueBoolean("enable");
+			}
+			else if(message_name == "javascript_enabled")
+			{
+				mJavascriptEnabled = message_in.getValueBoolean("enable");
+			}
+			else if(message_name == "size_change")
+			{
+				std::string name = message_in.getValue("name");
+				S32 width = message_in.getValueS32("width");
+				S32 height = message_in.getValueS32("height");
+				S32 texture_width = message_in.getValueS32("texture_width");
+				S32 texture_height = message_in.getValueS32("texture_height");
+				mBackgroundR = message_in.getValueReal("background_r");
+				mBackgroundG = message_in.getValueReal("background_g");
+				mBackgroundB = message_in.getValueReal("background_b");
+//				mBackgroundA = message_in.setValueReal("background_a");		// Ignore any alpha
+								
+				if(!name.empty())
+				{
+					// Find the shared memory region with this name
+					SharedSegmentMap::iterator iter = mSharedSegments.find(name);
+					if(iter != mSharedSegments.end())
+					{
+						mPixels = (unsigned char*)iter->second.mAddress;
+						mWidth = width;
+						mHeight = height;
+
+						if(initBrowserWindow())
+						{
+
+							// size changed so tell the browser
+							LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight );
+							
+	//						std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight 
+	//								<< ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl;
+									
+							S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); 
+							
+							// The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response.
+							if(real_width <= texture_width)
+							{
+								texture_width = real_width;
+							}
+							else
+							{
+								// This won't work -- it'll be bigger than the allocated memory.  This is a fatal error.
+	//							std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl;
+								mDeleteMe = true;
+								return;
+							}
+						}
+						else
+						{
+							// Setting up the browser window failed.  This is a fatal error.
+							mDeleteMe = true;
+						}
+
+						
+						mTextureWidth = texture_width;
+						mTextureHeight = texture_height;
+						
+					};
+				};
+
+				LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response");
+				message.setValue("name", name);
+				message.setValueS32("width", width);
+				message.setValueS32("height", height);
+				message.setValueS32("texture_width", texture_width);
+				message.setValueS32("texture_height", texture_height);
+				sendMessage(message);
+
+			}
+			else if(message_name == "load_uri")
+			{
+				std::string uri = message_in.getValue("uri");
+
+//				std::cout << "loading URI: " << uri << std::endl;
+				
+				if(!uri.empty())
+				{
+					if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE)
+					{
+						LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri );
+					}
+					else
+					{
+						mInitialNavigateURL = uri;
+					}
+				}
+			}
+			else if(message_name == "mouse_event")
+			{
+				std::string event = message_in.getValue("event");
+				S32 button = message_in.getValueS32("button");
+				mLastMouseX = message_in.getValueS32("x");
+				mLastMouseY = message_in.getValueS32("y");
+				std::string modifiers = message_in.getValue("modifiers");
+				
+				// Treat unknown mouse events as mouse-moves.
+				LLQtWebKit::EMouseEvent mouse_event = LLQtWebKit::ME_MOUSE_MOVE;
+				if(event == "down")
+				{
+					mouse_event = LLQtWebKit::ME_MOUSE_DOWN;
+				}
+				else if(event == "up")
+				{
+					mouse_event = LLQtWebKit::ME_MOUSE_UP;
+				}
+				else if(event == "double_click")
+				{
+					mouse_event = LLQtWebKit::ME_MOUSE_DOUBLE_CLICK;
+				}
+				
+				LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, mouse_event, button, mLastMouseX, mLastMouseY, decodeModifiers(modifiers));
+				checkEditState();
+			}
+			else if(message_name == "scroll_event")
+			{
+				S32 x = message_in.getValueS32("x");
+				S32 y = message_in.getValueS32("y");
+				std::string modifiers = message_in.getValue("modifiers");
+				
+				// Incoming scroll events are adjusted so that 1 detent is approximately 1 unit.
+				// Qt expects 1 detent to be 120 units.
+				// It also seems that our y scroll direction is inverted vs. what Qt expects.
+				
+				x *= 120;
+				y *= -120;
+				
+				LLQtWebKit::getInstance()->scrollWheelEvent(mBrowserWindowId, mLastMouseX, mLastMouseY, x, y, decodeModifiers(modifiers));
+			}
+			else if(message_name == "key_event")
+			{
+				std::string event = message_in.getValue("event");
+				S32 key = message_in.getValueS32("key");
+				std::string modifiers = message_in.getValue("modifiers");
+				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
+				
+				// Treat unknown events as key-up for safety.
+				LLQtWebKit::EKeyEvent key_event = LLQtWebKit::KE_KEY_UP;
+				if(event == "down")
+				{
+					key_event = LLQtWebKit::KE_KEY_DOWN;
+				}
+				else if(event == "repeat")
+				{
+					key_event = LLQtWebKit::KE_KEY_REPEAT;
+				}
+				
+				keyEvent(key_event, key, decodeModifiers(modifiers), native_key_data);
+			}
+			else if(message_name == "text_event")
+			{
+				std::string text = message_in.getValue("text");
+				std::string modifiers = message_in.getValue("modifiers");
+				LLSD native_key_data = message_in.getValueLLSD("native_key_data");
+				
+				unicodeInput(text, decodeModifiers(modifiers), native_key_data);
+			}
+			if(message_name == "edit_cut")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT );
+				checkEditState();
+			}
+			if(message_name == "edit_copy")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY );
+				checkEditState();
+			}
+			if(message_name == "edit_paste")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE );
+				checkEditState();
+			}
+			if(message_name == "pick_file_response")
+			{
+				onPickFileResponse(message_in.getValue("file"));
+			}
+			if(message_name == "auth_response")
+			{
+				authResponse(message_in);
+			}
+			else
+			if(message_name == "enable_media_plugin_debugging")
+			{
+				mEnableMediaPluginDebugging = message_in.getValueBoolean( "enable" );
+			}
+
+			else
+			if(message_name == "js_enable_object")
+			{
+#if LLQTWEBKIT_API_VERSION >= 9
+				bool enable = message_in.getValueBoolean( "enable" );
+				LLQtWebKit::getInstance()->setSLObjectEnabled( enable );
+#endif
+			}
+			else
+			if(message_name == "js_agent_location")
+			{
+#if LLQTWEBKIT_API_VERSION >= 9
+				F32 x = message_in.getValueReal("x");
+				F32 y = message_in.getValueReal("y");
+				F32 z = message_in.getValueReal("z");
+				LLQtWebKit::getInstance()->setAgentLocation( x, y, z );
+				LLQtWebKit::getInstance()->emitLocation();
+#endif
+			}
+			else
+			if(message_name == "js_agent_global_location")
+			{
+#if LLQTWEBKIT_API_VERSION >= 9
+				F32 x = message_in.getValueReal("x");
+				F32 y = message_in.getValueReal("y");
+				F32 z = message_in.getValueReal("z");
+				LLQtWebKit::getInstance()->setAgentGlobalLocation( x, y, z );
+				LLQtWebKit::getInstance()->emitLocation();
+#endif
+			}
+			else			
+			if(message_name == "js_agent_orientation")
+			{
+#if LLQTWEBKIT_API_VERSION >= 9
+				F32 angle = message_in.getValueReal("angle");
+				LLQtWebKit::getInstance()->setAgentOrientation( angle );
+				LLQtWebKit::getInstance()->emitLocation();
+#endif
+			}
+			else
+			if(message_name == "js_agent_region")
+			{
+#if LLQTWEBKIT_API_VERSION >= 9
+				const std::string& region = message_in.getValue("region");
+				LLQtWebKit::getInstance()->setAgentRegion( region );
+				LLQtWebKit::getInstance()->emitLocation();
+#endif
+			}
+			else
+				if(message_name == "js_agent_maturity")
+				{
+#if LLQTWEBKIT_API_VERSION >= 9
+					const std::string& maturity = message_in.getValue("maturity");
+					LLQtWebKit::getInstance()->setAgentMaturity( maturity );
+					LLQtWebKit::getInstance()->emitMaturity();
+#endif
+				}
+			else
+			if(message_name == "js_agent_language")
+			{
+#if LLQTWEBKIT_API_VERSION >= 9
+				const std::string& language = message_in.getValue("language");
+				LLQtWebKit::getInstance()->setAgentLanguage( language );
+				LLQtWebKit::getInstance()->emitLanguage();
+#endif
+			}
+			else
+			{
+//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl;
+			}
+		}
+		else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
+		{
+			if(message_name == "focus")
+			{
+				bool val = message_in.getValueBoolean("focused");
+				LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val );
+				
+				if(mFirstFocus && val)
+				{
+					// On the first focus, post a tab key event.  This fixes a problem with initial focus.
+					std::string empty;
+					keyEvent(LLQtWebKit::KE_KEY_DOWN, KEY_TAB, decodeModifiers(empty));
+					keyEvent(LLQtWebKit::KE_KEY_UP, KEY_TAB, decodeModifiers(empty));
+					mFirstFocus = false;
+				}
+			}
+			else if(message_name == "clear_cache")
+			{
+				LLQtWebKit::getInstance()->clearCache();
+			}
+			else if(message_name == "clear_cookies")
+			{
+				LLQtWebKit::getInstance()->clearAllCookies();
+			}
+			else if(message_name == "enable_cookies")
+			{
+				mCookiesEnabled = message_in.getValueBoolean("enable");
+				LLQtWebKit::getInstance()->enableCookies( mCookiesEnabled );
+			}
+			else if(message_name == "enable_plugins")
+			{
+				mPluginsEnabled = message_in.getValueBoolean("enable");
+				LLQtWebKit::getInstance()->enablePlugins( mPluginsEnabled );
+			}
+			else if(message_name == "enable_javascript")
+			{
+				mJavascriptEnabled = message_in.getValueBoolean("enable");
+				//LLQtWebKit::getInstance()->enableJavascript( mJavascriptEnabled );
+			}
+			else if(message_name == "set_cookies")
+			{
+				LLQtWebKit::getInstance()->setCookies(message_in.getValue("cookies"));
+			}
+			else if(message_name == "proxy_setup")
+			{
+				bool val = message_in.getValueBoolean("enable");
+				std::string host = message_in.getValue("host");
+				int port = message_in.getValueS32("port");
+				LLQtWebKit::getInstance()->enableProxy( val, host, port );
+			}
+			else if(message_name == "browse_stop")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP );
+			}
+			else if(message_name == "browse_reload")
+			{
+				// foo = message_in.getValueBoolean("ignore_cache");
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD );
+			}
+			else if(message_name == "browse_forward")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD );
+			}
+			else if(message_name == "browse_back")
+			{
+				LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK );
+			}
+			else if(message_name == "set_status_redirect")
+			{
+				int code = message_in.getValueS32("code");
+				std::string url = message_in.getValue("url");
+				if ( 404 == code )	// browser lib only supports 404 right now
+				{
+#if LLQTWEBKIT_API_VERSION < 8
+				 	LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url );
+#endif
+				};
+			}
+			else if(message_name == "set_user_agent")
+			{
+				mUserAgent = message_in.getValue("user_agent");
+				LLQtWebKit::getInstance()->setBrowserAgentId( mUserAgent );
+			}
+			else if(message_name == "show_web_inspector")
+			{
+#if LLQTWEBKIT_API_VERSION >= 10
+				bool val = message_in.getValueBoolean("show");
+				LLQtWebKit::getInstance()->showWebInspector( val );
+#else
+				llwarns << "Ignoring showWebInspector message (llqtwebkit version is too old)." << llendl;
+#endif
+			}
+			else if(message_name == "ignore_ssl_cert_errors")
+			{
+#if LLQTWEBKIT_API_VERSION >= 3
+				LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( message_in.getValueBoolean("ignore") );
+#else
+				llwarns << "Ignoring ignore_ssl_cert_errors message (llqtwebkit version is too old)." << llendl;
+#endif
+			}
+			else if(message_name == "add_certificate_file_path")
+			{
+#if LLQTWEBKIT_API_VERSION >= 6
+				LLQtWebKit::getInstance()->setCAFile( message_in.getValue("path") );
+#else
+				llwarns << "Ignoring add_certificate_file_path message (llqtwebkit version is too old)." << llendl;
+#endif
+			}
+			else if(message_name == "init_history")
+			{
+				// Initialize browser history
+				LLSD history = message_in.getValueLLSD("history");
+				// First, clear the URL history
+				LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId);
+				// Then, add the history items in order
+				LLSD::array_iterator iter_history = history.beginArray();
+				LLSD::array_iterator end_history = history.endArray();
+				for(; iter_history != end_history; ++iter_history)
+				{
+					std::string url = (*iter_history).asString();
+					if(! url.empty()) {
+						LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url);
+					}
+				}
+			}
+			else if(message_name == "proxy_window_opened")
+			{
+				std::string target = message_in.getValue("target");
+				std::string uuid = message_in.getValue("uuid");
+				LLQtWebKit::getInstance()->proxyWindowOpened(mBrowserWindowId, target, uuid);
+			}
+			else if(message_name == "proxy_window_closed")
+			{
+				std::string uuid = message_in.getValue("uuid");
+				LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid);
+			}
+			else
+			{
+//				std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl;
+			};
+		}
+		else
+		{
+//			std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl;
+		};
+	}
+}
+
+void MediaPluginWebKit::setVolume(F32 volume)
+{
+	mVolumeCatcher.setVolume(volume);
+}
+
+int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data)
+{
+	MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data);
+	*plugin_send_func = MediaPluginWebKit::staticReceiveMessage;
+	*plugin_user_data = (void*)self;
+
+	return 0;
+}
+
+
diff --git a/indra/newview/app_settings/CA.pem b/indra/newview/app_settings/CA.pem
index 6140842a7f743a92b985c4ae645123b725c56807..a16b4225e50248063beffe76816815d15db876d9 100644
--- a/indra/newview/app_settings/CA.pem
+++ b/indra/newview/app_settings/CA.pem
@@ -4587,38 +4587,6 @@ zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy
 wy39FCqQmbkHzJ8=
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-MIIFijCCA3KgAwIBAgIQDHbanJEMTiye/hXQWJM8TDANBgkqhkiG9w0BAQUFADBf
-MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp
-Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww
-HhcNMDcwNTE2MTcxOTM2WhcNMjUwMzMxMTgxOTIxWjBfMQswCQYDVQQGEwJOTDES
-MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg
-MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B
-8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY
-tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl
-HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj
-zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU
-JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM
-ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv
-a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p
-K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi
-puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT
-yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO
-owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
-HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC
-jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy
-fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo
-Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo
-M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM
-Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed
-2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH
-/M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl
-nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE
-O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU
-9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9
-j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
 MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO
 TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh
 dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 43aa67e9497c8277207161f4ddbdf7c534838d79..6ebb0162a471473e6033f069601b0b04c2e3fc7d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -25,7 +25,7 @@
       <key>Type</key>
       <string>S32</string>
       <key>Value</key>
-      <real>300</real>
+      <real>0</real>
     </map>
     <key>AdminMenu</key>
     <map>
@@ -1981,6 +1981,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>DebugShowPrivateMem</key>
+    <map>
+      <key>Comment</key>
+      <string>Show Private Mem Info</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>DebugShowRenderInfo</key>
     <map>
       <key>Comment</key>
@@ -5459,6 +5470,17 @@
       <key>Value</key>
       <real>48.0</real>
     </map>
+    <key>MaxHeapSize</key>
+    <map>
+      <key>Comment</key>
+      <string>Maximum heap size (GB)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>1.6</real>
+    </map>
     <key>MaxSelectDistance</key>
     <map>
       <key>Comment</key>
@@ -5481,6 +5503,17 @@
       <key>Value</key>
       <real>60.0</real>
     </map>
+  <key>MediaPluginDebugging</key>
+  <map>
+    <key>Comment</key>
+    <string>Turn on debugging messages that may help diagnosing media issues (WARNING: May reduce performance).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
   <key>MediaControlFadeTime</key>
   <map>
     <key>Comment</key>
@@ -5580,6 +5613,17 @@
     <key>Value</key>
     <integer>1</integer>
   </map>
+  <key>MemoryFailurePreventionEnabled</key>
+  <map>
+    <key>Comment</key>
+    <string>If set, the viewer will quit to avoid crash when memory failure happens</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
   <key>MemoryLogFrequency</key>
         <map>
         <key>Comment</key>
@@ -5591,6 +5635,17 @@
         <key>Value</key>
             <real>600.0</real>
         </map>
+    <key>MemoryPrivatePoolEnabled</key>
+    <map>
+      <key>Comment</key>
+      <string>Enable the private memory pool management</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>MemProfiling</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 1388d9aee010e87806b0efdccf6488be97cd2e1d..a0af94ba778b15857766aabed6a9d147d26ec609 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -2285,7 +2285,9 @@ void LLAppearanceMgr::autopopulateOutfits()
 void LLAppearanceMgr::onFirstFullyVisible()
 {
 	gAgentAvatarp->debugAvatarVisible();
-	autopopulateOutfits();
+	// The auto-populate is failing at the point of generating outfits
+	// folders, so don't do the library copy until that is resolved.
+	// autopopulateOutfits();
 }
 
 bool LLAppearanceMgr::updateBaseOutfit()
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 6a808b5daf0aa7e94bb08040116acd95b03d2fa2..7e597fe5dc6267238c1d2d789f9c57cd94875b0c 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -686,7 +686,7 @@ LLAppViewer::~LLAppViewer()
 }
 
 bool LLAppViewer::init()
-{
+{	
 	//
 	// Start of the application
 	//
@@ -719,6 +719,11 @@ bool LLAppViewer::init()
 
 	LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ;
 
+	//set the max heap size.
+	initMaxHeapSize() ;
+
+	LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled")) ;
+
 	// write Google Breakpad minidump files to our log directory
 	std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
 	logdir += gDirUtilp->getDirDelimiter();
@@ -1088,9 +1093,97 @@ bool LLAppViewer::init()
 
 	LLAgentLanguage::init();
 
+	return true;
+}
 
+void LLAppViewer::initMaxHeapSize()
+{
+	//set the max heap size.
+	//here is some info regarding to the max heap size:
+	//------------------------------------------------------------------------------------------
+	// OS       | setting | SL address bits | max manageable memory space | max heap size
+	// Win 32   | default | 32-bit          | 2GB                         | < 1.7GB
+	// Win 32   | /3G     | 32-bit          | 3GB                         | < 1.7GB or 2.7GB
+	//Linux 32  | default | 32-bit          | 3GB                         | < 2.7GB
+	//Linux 32  |HUGEMEM  | 32-bit          | 4GB                         | < 3.7GB
+	//64-bit OS |default  | 32-bit          | 4GB                         | < 3.7GB
+	//64-bit OS |default  | 64-bit          | N/A (> 4GB)                 | N/A (> 4GB)
+	//------------------------------------------------------------------------------------------
+	//currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB.
+
+	//F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ;
+	F32 max_heap_size_gb = gSavedSettings.getF32("MaxHeapSize") ;
+	BOOL enable_mem_failure_prevention = (BOOL)gSavedSettings.getBOOL("MemoryFailurePreventionEnabled") ;
+
+	LLMemory::initMaxHeapSizeGB(max_heap_size_gb, enable_mem_failure_prevention) ;
+}
 
-	return true;
+void LLAppViewer::checkMemory()
+{
+	const static F32 MEMORY_CHECK_INTERVAL = 1.0f ; //second
+	//const static F32 MAX_QUIT_WAIT_TIME = 30.0f ; //seconds
+	const static U32 MAX_SIZE_CHECKED_MEMORY_BLOCK = 64 * 1024 * 1024 ; //64 MB
+	//static F32 force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ;
+	static void* last_reserved_address = NULL ;
+
+	if(MEMORY_CHECK_INTERVAL > mMemCheckTimer.getElapsedTimeF32())
+	{
+		return ;
+	}
+	mMemCheckTimer.reset() ;
+
+	if(gGLManager.mDebugGPU)
+	{
+		//update the availability of memory
+		LLMemory::updateMemoryInfo() ;
+	}
+
+	//check the virtual address space fragmentation
+	if(!last_reserved_address)
+	{
+		last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ;
+	}
+	else
+	{
+		last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ;
+		if(!last_reserved_address) //failed, try once more
+		{
+			last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ;
+		}
+	}
+
+	S32 is_low = !last_reserved_address || LLMemory::isMemoryPoolLow() ;
+
+	//if(is_low < 0) //to force quit
+	//{
+	//	if(force_quit_timer > MAX_QUIT_WAIT_TIME) //just hit the limit for the first time
+	//	{
+	//		//send out the notification to tell the viewer is about to quit in 30 seconds.
+	//		LLNotification::Params params("ForceQuitDueToLowMemory");
+	//		LLNotifications::instance().add(params);
+
+	//		force_quit_timer = MAX_QUIT_WAIT_TIME - MEMORY_CHECK_INTERVAL ;
+	//	}
+	//	else
+	//	{
+	//		force_quit_timer -= MEMORY_CHECK_INTERVAL ;
+	//		if(force_quit_timer < 0.f)
+	//		{
+	//			forceQuit() ; //quit
+	//		}
+	//	}
+	//}
+	//else
+	//{
+	//	force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ;
+	//}
+
+	LLPipeline::throttleNewMemoryAllocation(!is_low ? FALSE : TRUE) ;		
+	
+	if(is_low)
+	{
+		LLMemory::logMemoryInfo() ;
+	}
 }
 
 static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages");
@@ -1118,7 +1211,7 @@ bool LLAppViewer::mainLoop()
 	//-------------------------------------------
 
 	// Create IO Pump to use for HTTP Requests.
-	gServicePump = new LLPumpIO(gAPRPoolp);
+	gServicePump = new LLPumpIO;
 	LLHTTPClient::setPump(*gServicePump);
 	LLCurl::setCAFile(gDirUtilp->getCAFile());
 
@@ -1128,7 +1221,6 @@ bool LLAppViewer::mainLoop()
 	LLVoiceClient::getInstance()->init(gServicePump);
 	LLTimer frameTimer,idleTimer;
 	LLTimer debugTime;
-	LLFrameTimer memCheckTimer;
 	LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
 	joystick->setNeedsReset(true);
 
@@ -1139,7 +1231,9 @@ bool LLAppViewer::mainLoop()
     // point of posting.
     LLSD newFrame;
 
-	const F32 memory_check_interval = 1.0f ; //second
+	//LLPrivateMemoryPoolTester::getInstance()->run(false) ;
+	//LLPrivateMemoryPoolTester::getInstance()->run(true) ;
+	//LLPrivateMemoryPoolTester::destroy() ;
 
 	// Handle messages
 	while (!LLApp::isExiting())
@@ -1150,18 +1244,8 @@ bool LLAppViewer::mainLoop()
 		llclearcallstacks;
 
 		//check memory availability information
-		{
-			if(memory_check_interval < memCheckTimer.getElapsedTimeF32())
-			{
-				memCheckTimer.reset() ;
-
-				//update the availability of memory
-				LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ;
-			}
-			llcallstacks << "Available physical mem(KB): " << mAvailPhysicalMemInKB << llcallstacksendl ;
-			llcallstacks << "Available virtual mem(KB): " << mAvailVirtualMemInKB << llcallstacksendl ;
-		}
-
+		checkMemory() ;
+		
 		try
 		{
 			pingMainloopTimeout("Main:MiscNativeWindowEvents");
@@ -1325,7 +1409,7 @@ bool LLAppViewer::mainLoop()
 				idleTimer.reset();
 				bool is_slow = (frameTimer.getElapsedTimeF64() > FRAME_SLOW_THRESHOLD) ;
 				S32 total_work_pending = 0;
-				S32 total_io_pending = 0;				
+				S32 total_io_pending = 0;	
 				while(!is_slow)//do not unpause threads if the frame rates are very low.
 				{
 					S32 work_pending = 0;
@@ -1393,15 +1477,7 @@ bool LLAppViewer::mainLoop()
 		}
 		catch(std::bad_alloc)
 		{			
-			{
-				llinfos << "Availabe physical memory(KB) at the beginning of the frame: " << mAvailPhysicalMemInKB << llendl ;
-				llinfos << "Availabe virtual memory(KB) at the beginning of the frame: " << mAvailVirtualMemInKB << llendl ;
-
-				LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ;
-
-				llinfos << "Current availabe physical memory(KB): " << mAvailPhysicalMemInKB << llendl ;
-				llinfos << "Current availabe virtual memory(KB): " << mAvailVirtualMemInKB << llendl ;
-			}
+			LLMemory::logMemoryInfo(TRUE) ;
 
 			//stop memory leaking simulation
 			LLFloaterMemLeak* mem_leak_instance =
@@ -1494,16 +1570,16 @@ bool LLAppViewer::cleanup()
 	}
 
 	// *TODO - generalize this and move DSO wrangling to a helper class -brad
-	std::set<struct apr_dso_handle_t *>::const_iterator i;
-	for(i = mPlugins.begin(); i != mPlugins.end(); ++i)
+	for(std::map<apr_dso_handle_t*, boost::shared_ptr<LLAPRPool> >::iterator plugin = mPlugins.begin();
+		plugin != mPlugins.end(); ++plugin)
 	{
 		int (*ll_plugin_stop_func)(void) = NULL;
-		apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, *i, "ll_plugin_stop");
+		apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, plugin->first, "ll_plugin_stop");
 		ll_plugin_stop_func();
 
-		rv = apr_dso_unload(*i);
+		rv = apr_dso_unload(plugin->first);
 	}
-	mPlugins.clear();
+	mPlugins.clear();	// Forget handles and destroy all memory pools.
 
 	//flag all elements as needing to be destroyed immediately
 	// to ensure shutdown order
@@ -1887,6 +1963,9 @@ bool LLAppViewer::cleanup()
 
 	LLMainLoopRepeater::instance().stop();
 
+	//release all private memory pools.
+	LLPrivateMemoryPoolManager::destroyClass() ;
+
 	ll_close_fail_log();
 
 	MEM_TRACK_RELEASE
@@ -1938,7 +2017,7 @@ bool LLAppViewer::initThreads()
 
 	if (LLFastTimer::sLog || LLFastTimer::sMetricLog)
 	{
-		LLFastTimer::sLogLock = new LLMutex(NULL);
+		LLFastTimer::sLogLock = new LLMutex;
 		mFastTimerLogThread = new LLFastTimerLogThread(LLFastTimer::sLogName);
 		mFastTimerLogThread->start();
 	}
@@ -3186,8 +3265,7 @@ void LLAppViewer::handleViewerCrash()
 		else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME);
 		llinfos << "Creating crash marker file " << crash_file_name << llendl;
 		
-		LLAPRFile crash_file ;
-		crash_file.open(crash_file_name, LL_APR_W);
+		LLAPRFile crash_file(crash_file_name, LL_APR_W);
 		if (crash_file.getFileHandle())
 		{
 			LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL;
@@ -3251,11 +3329,10 @@ bool LLAppViewer::anotherInstanceRunning()
 	LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
 
 	//Freeze case checks
-	if (LLAPRFile::isExist(marker_file, NULL, LL_APR_RB))
+	if (LLAPRFile::isExist(marker_file, LL_APR_RB))
 	{
 		// File exists, try opening with write permissions
-		LLAPRFile outfile ;
-		outfile.open(marker_file, LL_APR_WB);
+		LLAPRFile outfile(marker_file, LL_APR_WB);
 		apr_file_t* fMarker = outfile.getFileHandle() ; 
 		if (!fMarker)
 		{
@@ -3294,25 +3371,25 @@ void LLAppViewer::initMarkerFile()
 	std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
 	std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
 
-	if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning())
+	if (LLAPRFile::isExist(mMarkerFileName, LL_APR_RB) && !anotherInstanceRunning())
 	{
 		gLastExecEvent = LAST_EXEC_FROZE;
 		LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;
 	}    
-	if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB))
+	if(LLAPRFile::isExist(logout_marker_file, LL_APR_RB))
 	{
 		gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
 		LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
 		LLAPRFile::remove(logout_marker_file);
 	}
-	if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB))
+	if(LLAPRFile::isExist(llerror_marker_file, LL_APR_RB))
 	{
 		if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
 		else gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
 		LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
 		LLAPRFile::remove(llerror_marker_file);
 	}
-	if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB))
+	if(LLAPRFile::isExist(error_marker_file, LL_APR_RB))
 	{
 		if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
 		else gLastExecEvent = LAST_EXEC_OTHER_CRASH;
@@ -3328,7 +3405,7 @@ void LLAppViewer::initMarkerFile()
 	
 	// Create the marker file for this execution & lock it
 	apr_status_t s;
-	s = mMarkerFile.open(mMarkerFileName, LL_APR_W, TRUE);	
+	s = mMarkerFile.open(mMarkerFileName, LL_APR_W, LLAPRFile::long_lived);
 
 	if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
 	{
@@ -4586,8 +4663,7 @@ void LLAppViewer::sendLogoutRequest()
 		gLogoutInProgress = TRUE;
 		mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
 		
-		LLAPRFile outfile ;
-		outfile.open(mLogoutMarkerFileName, LL_APR_W);
+		LLAPRFile outfile(mLogoutMarkerFileName, LL_APR_W);
 		mLogoutMarkerFile =  outfile.getFileHandle() ;
 		if (mLogoutMarkerFile)
 		{
@@ -5039,14 +5115,15 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)
 	}
 #endif // LL_WINDOWS
 
-	apr_dso_handle_t * eventhost_dso_handle = NULL;
-	apr_pool_t * eventhost_dso_memory_pool = NULL;
+	boost::shared_ptr<LLAPRPool> eventhost_dso_memory_pool_ptr(new LLAPRPool);
+	LLAPRPool& eventhost_dso_memory_pool(*eventhost_dso_memory_pool_ptr);
+	apr_dso_handle_t* eventhost_dso_handle = NULL;
 
 	//attempt to load the shared library
-	apr_pool_create(&eventhost_dso_memory_pool, NULL);
+	eventhost_dso_memory_pool.create();
 	apr_status_t rv = apr_dso_load(&eventhost_dso_handle,
 		dso_path.c_str(),
-		eventhost_dso_memory_pool);
+		eventhost_dso_memory_pool());
 	llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));
 	llassert_always(eventhost_dso_handle != NULL);
 
@@ -5066,7 +5143,8 @@ void LLAppViewer::loadEventHostModule(S32 listen_port)
 		llerrs << "problem loading eventhost plugin, status: " << status << llendl;
 	}
 
-	mPlugins.insert(eventhost_dso_handle);
+	// Store the handle and link it to the pool that was used to allocate it.
+	mPlugins[eventhost_dso_handle] = eventhost_dso_memory_pool_ptr;
 }
 
 void LLAppViewer::launchUpdater()
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 32115e0e7b9418386f32e26e32c9453d6c2e6376..168aaf5d947ece222eac412d4a7706f647481e39 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -170,7 +170,7 @@ class LLAppViewer : public LLApp
 	
 	// mute/unmute the system's master audio
 	virtual void setMasterSystemAudioMute(bool mute);
-	virtual bool getMasterSystemAudioMute();
+	virtual bool getMasterSystemAudioMute();	
 
 	// Metrics policy helper statics.
 	static void metricsUpdateRegion(U64 region_handle);
@@ -193,11 +193,12 @@ class LLAppViewer : public LLApp
 
 private:
 
+	void initMaxHeapSize();
 	bool initThreads(); // Initialize viewer threads, return false on failure.
 	bool initConfiguration(); // Initialize settings from the command line/config file.
 	void initUpdater(); // Initialize the updater service.
 	bool initCache(); // Initialize local client cache.
-
+	void checkMemory() ;
 
 	// We have switched locations of both Mac and Windows cache, make sure
 	// files migrate and old cache is cleared out.
@@ -269,10 +270,9 @@ class LLAppViewer : public LLApp
 
     LLAllocator mAlloc;
 
-	std::set<struct apr_dso_handle_t*> mPlugins;
+	std::map<apr_dso_handle_t*, boost::shared_ptr<LLAPRPool> > mPlugins;
 
-	U32 mAvailPhysicalMemInKB ;
-	U32 mAvailVirtualMemInKB ;
+	LLFrameTimer mMemCheckTimer;
 	
 	boost::scoped_ptr<LLUpdaterService> mUpdater;
 
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 48d02dfeaade77a3b13729edbb1ab2925af61897..db11462fcbd292c4c1f82258938a48b53f2b2b77 100644
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -111,6 +111,7 @@ int main( int argc, char **argv )
 	}
 	delete viewer_app_ptr;
 	viewer_app_ptr = NULL;
+
 	return 0;
 }
 
diff --git a/indra/newview/llappviewerlinux_api_dbus.cpp b/indra/newview/llappviewerlinux_api_dbus.cpp
index 32e7e0a83d5b10d350bcfceefa47d5478a5bd9c5..1ae469dfcfde79ffcf9ad423038e454ea387c60e 100644
--- a/indra/newview/llappviewerlinux_api_dbus.cpp
+++ b/indra/newview/llappviewerlinux_api_dbus.cpp
@@ -27,11 +27,11 @@
 #if LL_DBUS_ENABLED
 
 #include "linden_common.h"
+#include "llaprpool.h"
 
 extern "C" {
 #include <dbus/dbus-glib.h>
 
-#include "apr_pools.h"
 #include "apr_dso.h"
 }
 
@@ -44,7 +44,7 @@ extern "C" {
 #undef LL_DBUS_SYM
 
 static bool sSymsGrabbed = false;
-static apr_pool_t *sSymDBUSDSOMemoryPool = NULL;
+static LLAPRPool sSymDBUSDSOMemoryPool;
 static apr_dso_handle_t *sSymDBUSDSOHandleG = NULL;
 
 bool grab_dbus_syms(std::string dbus_dso_name)
@@ -63,11 +63,11 @@ bool grab_dbus_syms(std::string dbus_dso_name)
 #define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##DBUSSYM, sSymDBUSDSOHandle, #DBUSSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #DBUSSYM); if (REQUIRED) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #DBUSSYM, (void*)ll##DBUSSYM);}while(0)
 
 	//attempt to load the shared library
-	apr_pool_create(&sSymDBUSDSOMemoryPool, NULL);
+	sSymDBUSDSOMemoryPool.create();
   
 	if ( APR_SUCCESS == (rv = apr_dso_load(&sSymDBUSDSOHandle,
 					       dbus_dso_name.c_str(),
-					       sSymDBUSDSOMemoryPool) ))
+					       sSymDBUSDSOMemoryPool()) ))
 	{
 		INFOMSG("Found DSO: %s", dbus_dso_name.c_str());
 
@@ -109,11 +109,7 @@ void ungrab_dbus_syms()
 		sSymDBUSDSOHandleG = NULL;
 	}
 	
-	if ( sSymDBUSDSOMemoryPool )
-	{
-		apr_pool_destroy(sSymDBUSDSOMemoryPool);
-		sSymDBUSDSOMemoryPool = NULL;
-	}
+	sSymDBUSDSOMemoryPool.destroy();
 	
 	// NULL-out all of the symbols we'd grabbed
 #define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) do{ll##DBUSSYM = NULL;}while(0)
diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp
index c2916717bd415f80fa6243c4780ec117229f145e..8929c0c1a4ceb023c0c91a37cf27939e2f1aba2f 100644
--- a/indra/newview/llappviewermacosx.cpp
+++ b/indra/newview/llappviewermacosx.cpp
@@ -113,6 +113,7 @@ int main( int argc, char **argv )
 	}
 	delete viewer_app_ptr;
 	viewer_app_ptr = NULL;
+
 	return 0;
 }
 
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index f781d5f3ff96274388f40bc2a12bfcebc53ba944..fb9958ee9dd52affbea8ee0538be67a76037105e 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -40,6 +40,7 @@
 #include "llvertexbuffer.h"
 #include "llviewerdisplay.h"
 #include "llrender.h"
+#include "pipeline.h"
 
 // static
 LLViewerDynamicTexture::instance_list_t LLViewerDynamicTexture::sInstances[ LLViewerDynamicTexture::ORDER_COUNT ];
@@ -201,7 +202,7 @@ void LLViewerDynamicTexture::postRender(BOOL success)
 BOOL LLViewerDynamicTexture::updateAllInstances()
 {
 	sNumRenders = 0;
-	if (gGLManager.mIsDisabled)
+	if (gGLManager.mIsDisabled || LLPipeline::sMemAllocationThrottled)
 	{
 		return TRUE;
 	}
diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp
index 1f334815d6a1e42c56232e051d6f6169cf4758a2..9f0218a95e34b463af7712ba2495ac57e1b92d8f 100644
--- a/indra/newview/llfloateranimpreview.cpp
+++ b/indra/newview/llfloateranimpreview.cpp
@@ -223,8 +223,7 @@ BOOL LLFloaterAnimPreview::postBuild()
 		// now load bvh file
 		S32 file_size;
 		
-		LLAPRFile infile ;
-		infile.open(mFilenameAndPath, LL_APR_RB, NULL, &file_size);
+		LLAPRFile infile(mFilenameAndPath, LL_APR_RB, &file_size);
 		
 		if (!infile.getFileHandle())
 		{
diff --git a/indra/newview/llfloatermemleak.cpp b/indra/newview/llfloatermemleak.cpp
index 58931d112e954ddbb86255c25b8ee09f2890c442..9edfe1e3546d8b31ec3c559fe07286b572a972a4 100644
--- a/indra/newview/llfloatermemleak.cpp
+++ b/indra/newview/llfloatermemleak.cpp
@@ -90,6 +90,11 @@ LLFloaterMemLeak::~LLFloaterMemLeak()
 
 void LLFloaterMemLeak::release()
 {
+	if(mLeakedMem.empty())
+	{
+		return ;
+	}
+
 	for(S32 i = 0 ; i < (S32)mLeakedMem.size() ; i++)
 	{
 		delete[] mLeakedMem[i] ;
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index ef846ec42e0a46c2467bd49a8283daedd91cb591..2510f43aa71799855e394b3d405082489bf53e6b 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -367,7 +367,7 @@ mCalculateBtn(NULL)
 	mLastMouseX = 0;
 	mLastMouseY = 0;
 	mGLName = 0;
-	mStatusLock = new LLMutex(NULL);
+	mStatusLock = new LLMutex();
 	mModelPreview = NULL;
 
 	mLODMode[LLModel::LOD_HIGH] = 0;
@@ -2878,7 +2878,7 @@ LLColor4 LLModelLoader::getDaeColor(daeElement* element)
 //-----------------------------------------------------------------------------
 
 LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
-: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL)
+: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex()
 , mPelvisZOffset( 0.0f )
 , mLegacyRigValid( false )
 , mRigValidJointUpload( false )
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index ec162e00ebf731e4af0f032635aae77149ba8495..e4bd2049fa22a09013ea2fb5741d4286d8805730 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -181,6 +181,7 @@ LLFolderView::Params::Params()
 // Default constructor
 LLFolderView::LLFolderView(const Params& p)
 :	LLFolderViewFolder(p),
+	mRunningHeight(0),
 	mScrollContainer( NULL ),
 	mPopupMenuHandle(),
 	mAllowMultiSelect(p.allow_multiselect),
@@ -479,6 +480,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen
 		target_height = running_height;
 	}
 
+	mRunningHeight = running_height;
 	LLRect scroll_rect = mScrollContainer->getContentWindowRect();
 	reshape( llmax(scroll_rect.getWidth(), total_width), running_height );
 
@@ -524,10 +526,11 @@ void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent)
 	LLRect scroll_rect;
 	if (mScrollContainer)
 	{
+		LLView::reshape(width, height, called_from_parent);
 		scroll_rect = mScrollContainer->getContentWindowRect();
 	}
 	width = llmax(mMinWidth, scroll_rect.getWidth());
-	height = llmax(height, scroll_rect.getHeight());
+	height = llmax(mRunningHeight, scroll_rect.getHeight());
 
 	// restrict width with scroll container's width
 	if (mUseEllipses)
@@ -1915,9 +1918,9 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 	if (!handled)
 	{
 		if (getListener()->getUUID().notNull())
-		{
-			LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
-		}
+	{
+		LLFolderViewFolder::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
+	}
 		else
 		{
 			if (!mFolders.empty())
diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h
index 705a76a7b4e361e162fb2dd173c808157a0159af..8af01e9102b8667e386527a1e59ef207b9a59e7d 100644
--- a/indra/newview/llfolderview.h
+++ b/indra/newview/llfolderview.h
@@ -314,6 +314,7 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	signal_t						mReshapeSignal;
 	S32								mSignalSelectCallback;
 	S32								mMinWidth;
+	S32								mRunningHeight;
 	std::map<LLUUID, LLFolderViewItem*> mItemMap;
 	BOOL							mDragAndDropThisFrame;
 	
diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp
index 5c020e6d982eb7060b857a800f36b4d050f87f25..d73048a28b101b9fdf6a0044f27c6f173ce400c7 100644
--- a/indra/newview/llmainlooprepeater.cpp
+++ b/indra/newview/llmainlooprepeater.cpp
@@ -46,7 +46,7 @@ void LLMainLoopRepeater::start(void)
 {
 	if(mQueue != 0) return;
 
-	mQueue = new LLThreadSafeQueue<LLSD>(gAPRPoolp, 1024);
+	mQueue = new LLThreadSafeQueue<LLSD>(1024);
 	mMainLoopConnection = LLEventPumps::instance().
 		obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1));
 	mRepeaterConnection = LLEventPumps::instance().
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index 1eb786f433d873008c1f34e628c7bec12fb0c0e7..5bbef78dd4d8aa50fd511e6d93547d752e1f386b 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -319,6 +319,11 @@ BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )
 
 	if (mContextMenu)
 	{
+		// hide/show debugging options
+		bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging");
+		mContextMenu->setItemVisible("open_webinspector", media_plugin_debugging_enabled );
+		mContextMenu->setItemVisible("debug_separator", media_plugin_debugging_enabled );
+
 		mContextMenu->show(x, y);
 		LLMenuGL::showPopup(this, mContextMenu, x, y);
 	}
@@ -385,12 +390,22 @@ void LLMediaCtrl::onFocusLost()
 //
 BOOL LLMediaCtrl::postBuild ()
 {
+	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar;
+	registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this));
+
 	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(
 		"menu_media_ctrl.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());
 	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2));
+
 	return TRUE;
 }
 
+void LLMediaCtrl::onOpenWebInspector()
+{
+	if (mMediaSource && mMediaSource->hasMedia())
+		mMediaSource->getMediaPlugin()->showWebInspector( true );
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 //
 BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask )
@@ -1065,6 +1080,12 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
 			mHoverTextChanged = true;
 		};
 		break;
+
+		case MEDIA_EVENT_DEBUG_MESSAGE:
+		{
+			LL_INFOS("media") << self->getDebugMessageText() << LL_ENDL; 
+		};
+		break;
 	};
 
 	// chain all events to any potential observers of this object.
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 0e4a5b1d65cb80d5bc6eda9f090855ee2962ae10..3c0436e27a45e336bef5590229c3650a41839777 100644
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -166,6 +166,9 @@ class LLMediaCtrl :
 		// Incoming media event dispatcher
 		virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event);
 
+		// right click debugging item
+		void onOpenWebInspector();
+
 		LLUUID getTextureID() {return mMediaTextureID;}
 
 	protected:
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index afed306a28fa343b593453d0b8dc3c1c883b11f4..fc594841e314c807c0ff14701eaf5ee1588ccc43 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -445,12 +445,12 @@ class LLWholeModelUploadResponder: public LLCurl::Responder
 };
 
 LLMeshRepoThread::LLMeshRepoThread()
-: LLThread("mesh repo", NULL) 
+: LLThread("mesh repo") 
 { 
 	mWaiting = false;
-	mMutex = new LLMutex(NULL);
-	mHeaderMutex = new LLMutex(NULL);
-	mSignal = new LLCondition(NULL);
+	mMutex = new LLMutex();
+	mHeaderMutex = new LLMutex();
+	mSignal = new LLCondition();
 }
 
 LLMeshRepoThread::~LLMeshRepoThread()
@@ -1199,7 +1199,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,
 	mUploadTextures = upload_textures;
 	mUploadSkin = upload_skin;
 	mUploadJoints = upload_joints;
-	mMutex = new LLMutex(NULL);
+	mMutex = new LLMutex();
 	mCurlRequest = NULL;
 	mPendingUploads = 0;
 	mFinished = false;
@@ -2029,7 +2029,7 @@ LLMeshRepository::LLMeshRepository()
 
 void LLMeshRepository::init()
 {
-	mMeshMutex = new LLMutex(NULL);
+	mMeshMutex = new LLMutex();
 	
 	LLConvexDecomposition::getInstance()->initSystem();
 
@@ -2852,8 +2852,8 @@ LLPhysicsDecomp::LLPhysicsDecomp()
 	mQuitting = false;
 	mDone = false;
 
-	mSignal = new LLCondition(NULL);
-	mMutex = new LLMutex(NULL);
+	mSignal = new LLCondition();
+	mMutex = new LLMutex();
 }
 
 LLPhysicsDecomp::~LLPhysicsDecomp()
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index bef809f3a71749423ad6e8f6c0c28cc16401f13c..db7d836799c4d61d040437c2cfb217c185f82f4d 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -154,6 +154,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	}
 	updateLocationCombo(false);
 
+	LLUICtrl& mode_combo = getChildRef<LLUICtrl>("mode_combo");
+	mode_combo.setValue(gSavedSettings.getString("SessionSettingsFile"));
+	mode_combo.setCommitCallback(boost::bind(&LLPanelLogin::onModeChange, this, getChild<LLUICtrl>("mode_combo")->getValue(), _2));
+
 	LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
 	server_choice_combo->setCommitCallback(onSelectServer, NULL);
 	server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1));
@@ -1021,6 +1025,32 @@ void LLPanelLogin::updateLoginPanelLinks()
 	sInstance->getChildView("forgot_password_text")->setVisible( system_grid);
 }
 
+void LLPanelLogin::onModeChange(const LLSD& original_value, const LLSD& new_value)
+{
+	if (original_value.asString() != new_value.asString())
+	{
+		LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&LLPanelLogin::onModeChangeConfirm, this, original_value, new_value, _1, _2));
+	}
+}
+
+void LLPanelLogin::onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response)
+{
+	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+	switch (option)
+	{
+	case 0:
+		gSavedSettings.getControl("SessionSettingsFile")->set(new_value);
+		LLAppViewer::instance()->requestQuit();
+		break;
+	case 1:
+		// revert to original value
+		getChild<LLUICtrl>("mode_combo")->setValue(original_value);
+		break;
+	default:
+		break;
+	}
+}
+
 std::string canonicalize_username(const std::string& name)
 {
 	std::string cname = name;
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index 4078eedc774030fb78ce8ba2d69ceeb49bbc40e4..be9de884d14b1cd0168c8051997a687470d465d8 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -87,6 +87,8 @@ class LLPanelLogin:
 	void reshapeBrowser();
 	void addFavoritesToStartLocation();
 	void addUsersWithFavoritesToUsername();
+	void onModeChange(const LLSD& original_value, const LLSD& new_value);
+	void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response);
 	static void onClickConnect(void*);
 	static void onClickNewAccount(void*);
 	static void onClickVersion(void*);
@@ -97,7 +99,6 @@ class LLPanelLogin:
 	static void onServerComboLostFocus(LLFocusableElement*);
 	static void updateServerCombo();
 	static void updateStartSLURL();
-	
 	static void updateLoginPanelLinks();
 
 private:
diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp
index 4cf1df165555ce3098f91a3c64902d5e3ce3e479..a853726deaae2a9c8453c23f0ea98dc7f0fcf43b 100644
--- a/indra/newview/llslurl.cpp
+++ b/indra/newview/llslurl.cpp
@@ -273,11 +273,11 @@ LLSLURL::LLSLURL(const std::string& slurl)
 			mRegion = LLURI::unescape(path_array[0].asString());
 			path_array.erase(0);
 			
-			// parse the x, y, z
-			if(path_array.size() >= 3)
+			// parse the x, y, and optionally z
+			if(path_array.size() >= 2)
 			{	
 			  
-			  mPosition = LLVector3(path_array);
+			  mPosition = LLVector3(path_array); // this construction handles LLSD without all components (values default to 0.f)
 			  if((F32(mPosition[VX]) < 0.f) || 
                              (mPosition[VX] > REGION_WIDTH_METERS) ||
 			     (F32(mPosition[VY]) < 0.f) || 
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index 1b8be7a5b23805be39b9b9e530ecbadf52055fe1..0a008858437b210df76862dc477e863ac48db98f 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -162,6 +162,8 @@ BOOL LLStatusBar::handleRightMouseDown(S32 x, S32 y, MASK mask)
 
 BOOL LLStatusBar::postBuild()
 {
+	LLControlVariablePtr mode_control = gSavedSettings.getControl("SessionSettingsFile");
+
 	gMenuBarView->setRightMouseDownCallback(boost::bind(&show_navbar_context_menu, _1, _2, _3));
 
 	mTextTime = getChild<LLTextBox>("TimeText" );
@@ -233,9 +235,40 @@ BOOL LLStatusBar::postBuild()
 
 	mScriptOut = getChildView("scriptout");
 
+	LLUICtrl& mode_combo = getChildRef<LLUICtrl>("mode_combo");
+	mode_combo.setValue(gSavedSettings.getString("SessionSettingsFile"));
+	mode_combo.setCommitCallback(boost::bind(&LLStatusBar::onModeChange, this, getChild<LLUICtrl>("mode_combo")->getValue(), _2));
+
+
 	return TRUE;
 }
 
+void LLStatusBar::onModeChange(const LLSD& original_value, const LLSD& new_value)
+{
+	if (original_value.asString() != new_value.asString())
+	{
+		LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&LLStatusBar::onModeChangeConfirm, this, original_value, new_value, _1, _2));
+	}
+}
+
+void LLStatusBar::onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response)
+{
+	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+	switch (option)
+	{
+	case 0:
+		gSavedSettings.getControl("SessionSettingsFile")->set(new_value);
+		LLAppViewer::instance()->requestQuit();
+		break;
+	case 1:
+		// revert to original value
+		getChild<LLUICtrl>("mode_combo")->setValue(original_value);
+		break;
+	default:
+		break;
+	}
+}
+
 // Per-frame updates of visibility
 void LLStatusBar::refresh()
 {
diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h
index 4ea3183d1820a4c606bbadb45e78ff64923bdd66..e1e1f5459b9b24931ccd7f94da96355313695dc8 100644
--- a/indra/newview/llstatusbar.h
+++ b/indra/newview/llstatusbar.h
@@ -92,6 +92,8 @@ class LLStatusBar
 	void onMouseEnterVolume();
 	void onMouseEnterNearbyMedia();
 	void onClickScreen(S32 x, S32 y);
+	void onModeChange(const LLSD& original_value, const LLSD& new_value);
+	void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response);
 
 	static void onClickMediaToggle(void* data);
 	static void onClickBalance(void* data);
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 9b417307fd574ee6eede09278f3c7301a4b19490..87b6304f9ddf250efdd5ac7a1a7b82f6290279f0 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -113,7 +113,7 @@ class LLTextureCacheWorker : public LLWorkerClass
 	~LLTextureCacheWorker()
 	{
 		llassert_always(!haveWork());
-		delete[] mReadData;
+		FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
 	}
 
 	// override this interface
@@ -176,7 +176,7 @@ class LLTextureCacheLocalFileWorker : public LLTextureCacheWorker
 
 bool LLTextureCacheLocalFileWorker::doRead()
 {
-	S32 local_size = LLAPRFile::size(mFileName, mCache->getLocalAPRFilePool());
+	S32 local_size = LLAPRFile::size(mFileName);
 
 	if (local_size > 0 && mFileName.size() > 4)
 	{
@@ -215,7 +215,7 @@ bool LLTextureCacheLocalFileWorker::doRead()
 			mDataSize = 0;
 			return true;
 		}
-		mReadData = new U8[mDataSize];
+		mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize);
 		mBytesRead = -1;
 		mBytesToRead = mDataSize;
 		setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
@@ -233,7 +233,7 @@ bool LLTextureCacheLocalFileWorker::doRead()
 // 						<< " Bytes: " << mDataSize << " Offset: " << mOffset
 // 						<< " / " << mDataSize << llendl;
 				mDataSize = 0; // failed
-				delete[] mReadData;
+				FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
 				mReadData = NULL;
 			}
 			return true;
@@ -248,9 +248,9 @@ bool LLTextureCacheLocalFileWorker::doRead()
 	{
 		mDataSize = local_size;
 	}
-	mReadData = new U8[mDataSize];
+	mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize);
 	
-	S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());	
+	S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize);
 
 	if (bytes_read != mDataSize)
 	{
@@ -258,7 +258,7 @@ bool LLTextureCacheLocalFileWorker::doRead()
 // 				<< " Bytes: " << mDataSize << " Offset: " << mOffset
 // 				<< " / " << mDataSize << llendl;
 		mDataSize = 0;
-		delete[] mReadData;
+		FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
 		mReadData = NULL;
 	}
 	else
@@ -331,7 +331,7 @@ bool LLTextureCacheRemoteWorker::doRead()
 		// Is it a JPEG2000 file? 
 		{
 			local_filename = filename + ".j2c";
-			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
+			local_size = LLAPRFile::size(local_filename);
 			if (local_size > 0)
 			{
 				mImageFormat = IMG_CODEC_J2C;
@@ -341,7 +341,7 @@ bool LLTextureCacheRemoteWorker::doRead()
 		if (local_size == 0)
 		{
 			local_filename = filename + ".jpg";
-			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
+			local_size = LLAPRFile::size(local_filename);
 			if (local_size > 0)
 			{
 				mImageFormat = IMG_CODEC_JPEG;
@@ -352,7 +352,7 @@ bool LLTextureCacheRemoteWorker::doRead()
 		if (local_size == 0)
 		{
 			local_filename = filename + ".tga";
-			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
+			local_size = LLAPRFile::size(local_filename);
 			if (local_size > 0)
 			{
 				mImageFormat = IMG_CODEC_TGA;
@@ -377,16 +377,15 @@ bool LLTextureCacheRemoteWorker::doRead()
 			mDataSize = local_size;
 		}
 		// Allocate read buffer
-		mReadData = new U8[mDataSize];
-		S32 bytes_read = LLAPRFile::readEx(local_filename, 
-											 mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());
+		mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize);
+		S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize);
 		if (bytes_read != mDataSize)
 		{
  			llwarns << "Error reading file from local cache: " << local_filename
  					<< " Bytes: " << mDataSize << " Offset: " << mOffset
  					<< " / " << mDataSize << llendl;
 			mDataSize = 0;
-			delete[] mReadData;
+			FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
 			mReadData = NULL;
 		}
 		else
@@ -429,15 +428,14 @@ bool LLTextureCacheRemoteWorker::doRead()
 		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
 		size = llmin(size, mDataSize);
 		// Allocate the read buffer
-		mReadData = new U8[size];
-		S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, 
-											 mReadData, offset, size, mCache->getLocalAPRFilePool());
+		mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), size);
+		S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, mReadData, offset, size);
 		if (bytes_read != size)
 		{
 			llwarns << "LLTextureCacheWorker: "  << mID
 					<< " incorrect number of bytes read from header: " << bytes_read
 					<< " / " << size << llendl;
-			delete[] mReadData;
+			FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
 			mReadData = NULL;
 			mDataSize = -1; // failed
 			done = true;
@@ -457,7 +455,7 @@ bool LLTextureCacheRemoteWorker::doRead()
 	if (!done && (mState == BODY))
 	{
 		std::string filename = mCache->getTextureFileName(mID);
-		S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool());
+		S32 filesize = LLAPRFile::size(filename);
 
 		if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset)
 		{
@@ -467,7 +465,7 @@ bool LLTextureCacheRemoteWorker::doRead()
 			S32 data_offset, file_size, file_offset;
 			
 			// Reserve the whole data buffer first
-			U8* data = new U8[mDataSize];
+			U8* data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize);
 
 			// Set the data file pointers taking the read offset into account. 2 cases:
 			if (mOffset < TEXTURE_CACHE_ENTRY_SIZE)
@@ -480,7 +478,7 @@ bool LLTextureCacheRemoteWorker::doRead()
 				// Copy the raw data we've been holding from the header cache into the new sized buffer
 				llassert_always(mReadData);
 				memcpy(data, mReadData, data_offset);
-				delete[] mReadData;
+				FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
 				mReadData = NULL;
 			}
 			else
@@ -499,14 +497,13 @@ bool LLTextureCacheRemoteWorker::doRead()
 			// Read the data at last
 			S32 bytes_read = LLAPRFile::readEx(filename, 
 											 mReadData + data_offset,
-											 file_offset, file_size,
-											 mCache->getLocalAPRFilePool());
+											 file_offset, file_size);
 			if (bytes_read != file_size)
 			{
 				llwarns << "LLTextureCacheWorker: "  << mID
 						<< " incorrect number of bytes read from body: " << bytes_read
 						<< " / " << file_size << llendl;
-				delete[] mReadData;
+				FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
 				mReadData = NULL;
 				mDataSize = -1; // failed
 				done = true;
@@ -598,16 +595,16 @@ bool LLTextureCacheRemoteWorker::doWrite()
 		{
 			// We need to write a full record in the header cache so, if the amount of data is smaller
 			// than a record, we need to transfer the data to a buffer padded with 0 and write that
-			U8* padBuffer = new U8[TEXTURE_CACHE_ENTRY_SIZE];
+			U8* padBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), TEXTURE_CACHE_ENTRY_SIZE);
 			memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE);		// Init with zeros
 			memcpy(padBuffer, mWriteData, mDataSize);			// Copy the write buffer
-			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool());
-			delete [] padBuffer;
+			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size);
+			FREE_MEM(LLImageBase::getPrivatePool(), padBuffer);
 		}
 		else
 		{
 			// Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file
-			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool());
+			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size);
 		}
 
 		if (bytes_written <= 0)
@@ -642,8 +639,7 @@ bool LLTextureCacheRemoteWorker::doWrite()
 // 			llinfos << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << llendl;
 			S32 bytes_written = LLAPRFile::writeEx(	filename, 
 													mWriteData + TEXTURE_CACHE_ENTRY_SIZE,
-													0, file_size,
-													mCache->getLocalAPRFilePool());
+													0, file_size);
 			if (bytes_written <= 0)
 			{
 				llwarns << "LLTextureCacheWorker: "  << mID
@@ -698,7 +694,7 @@ void LLTextureCacheWorker::finishWork(S32 param, bool completed)
 			}
 			else
 			{
-				delete[] mReadData;
+				FREE_MEM(LLImageBase::getPrivatePool(), mReadData);
 				mReadData = NULL;
 			}
 		}
@@ -740,9 +736,6 @@ void LLTextureCacheWorker::endWork(S32 param, bool aborted)
 
 LLTextureCache::LLTextureCache(bool threaded)
 	: LLWorkerThread("TextureCache", threaded),
-	  mWorkersMutex(NULL),
-	  mHeaderMutex(NULL),
-	  mListMutex(NULL),
 	  mHeaderAPRFile(NULL),
 	  mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called.
 	  mTexturesSizeTotal(0),
@@ -846,7 +839,7 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id)
 	// Is it a JPEG2000 file? 
 	{
 		local_filename = filename + ".j2c";
-		local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
+		local_size = LLAPRFile::size(local_filename);
 		if (local_size > 0)
 		{
 			return TRUE ;
@@ -856,7 +849,7 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id)
 	// If not, is it a jpeg file?		
 	{
 		local_filename = filename + ".jpg";
-		local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
+		local_size = LLAPRFile::size(local_filename);
 		if (local_size > 0)
 		{
 			return TRUE ;
@@ -866,7 +859,7 @@ BOOL LLTextureCache::isInLocal(const LLUUID& id)
 	// Hmm... What about a targa file? (used for UI texture mostly)		
 	{
 		local_filename = filename + ".tga";
-		local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
+		local_size = LLAPRFile::size(local_filename);
 		if (local_size > 0)
 		{
 			return TRUE ;
@@ -912,10 +905,10 @@ void LLTextureCache::purgeCache(ELLPath location)
 		if(LLFile::isdir(mTexturesDirName))
 		{
 			std::string file_name = gDirUtilp->getExpandedFilename(location, entries_filename);
-			LLAPRFile::remove(file_name, getLocalAPRFilePool());
+			LLAPRFile::remove(file_name);
 
 			file_name = gDirUtilp->getExpandedFilename(location, cache_filename);
-			LLAPRFile::remove(file_name, getLocalAPRFilePool());
+			LLAPRFile::remove(file_name);
 
 			purgeAllTextures(true);
 		}
@@ -991,7 +984,9 @@ LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset)
 {
 	llassert_always(mHeaderAPRFile == NULL);
 	apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY;
-	mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, getLocalAPRFilePool());
+	// All code calling openHeaderEntriesFile, immediately calls closeHeaderEntriesFile,
+	// so this file is very short-lived.
+	mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags);
 	if(offset > 0)
 	{
 		mHeaderAPRFile->seek(APR_SET, offset);
@@ -1014,10 +1009,9 @@ void LLTextureCache::readEntriesHeader()
 {
 	// mHeaderEntriesInfo initializes to default values so safe not to read it
 	llassert_always(mHeaderAPRFile == NULL);
-	if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool()))
+	if (LLAPRFile::isExist(mHeaderEntriesFileName))
 	{
-		LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
-						  getLocalAPRFilePool());
+		LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
 	}
 	else //create an empty entries header.
 	{
@@ -1032,8 +1026,7 @@ void LLTextureCache::writeEntriesHeader()
 	llassert_always(mHeaderAPRFile == NULL);
 	if (!mReadOnly)
 	{
-		LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
-						   getLocalAPRFilePool());
+		LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
 	}
 }
 
@@ -1622,7 +1615,7 @@ void LLTextureCache::purgeTextures(bool validate)
 			if (uuididx == validate_idx)
 			{
  				LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL;
-				S32 bodysize = LLAPRFile::size(filename, getLocalAPRFilePool());
+				S32 bodysize = LLAPRFile::size(filename);
 				if (bodysize != entries[idx].mBodySize)
 				{
 					LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize
@@ -1857,7 +1850,7 @@ void LLTextureCache::removeCachedTexture(const LLUUID& id)
 		mTexturesSizeMap.erase(id);
 	}
 	mHeaderIDMap.erase(id);
-	LLAPRFile::remove(getTextureFileName(id), getLocalAPRFilePool());		
+	LLAPRFile::remove(getTextureFileName(id));		
 }
 
 //called after mHeaderMutex is locked.
@@ -1869,7 +1862,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename)
 	{
 		if (entry.mBodySize == 0)	// Always attempt to remove when mBodySize > 0.
 		{
-		  if (LLAPRFile::isExist(filename, getLocalAPRFilePool()))		// Sanity check. Shouldn't exist when body size is 0.
+		  if (LLAPRFile::isExist(filename))		// Sanity check. Shouldn't exist when body size is 0.
 		  {
 			  LL_WARNS("TextureCache") << "Entry has body size of zero but file " << filename << " exists. Deleting this file, too." << LL_ENDL;
 		  }
@@ -1890,7 +1883,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename)
 
 	if (file_maybe_exists)
 	{
-		LLAPRFile::remove(filename, getLocalAPRFilePool());		
+		LLAPRFile::remove(filename);
 	}
 }
 
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index 64e3a2658c38565f1b8f32253fdb50621ed90773..79f5ba58358329f1231efdfd732751c4a5e4bf59 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -142,9 +142,6 @@ class LLTextureCache : public LLWorkerThread
 	std::string getTextureFileName(const LLUUID& id);
 	void addCompleted(Responder* responder, bool success);
 	
-protected:
-	//void setFileAPRPool(apr_pool_t* pool) { mFileAPRPool = pool ; }
-
 private:
 	void setDirNames(ELLPath location);
 	void readHeaderCache();
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 18c3a3b87ddf6ef917c86fc2107d112e46bbf026..e9be45ffd0cfef841ddf5d2c5232a6cae60226a3 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -674,7 +674,6 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	  mRetryAttempt(0),
 	  mActiveCount(0),
 	  mGetStatus(0),
-	  mWorkMutex(NULL),
 	  mFirstPacket(0),
 	  mLastPacket(-1),
 	  mTotalPackets(0),
@@ -817,7 +816,7 @@ void LLTextureFetchWorker::setImagePriority(F32 priority)
 
 void LLTextureFetchWorker::resetFormattedData()
 {
-	delete[] mBuffer;
+	FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
 	mBuffer = NULL;
 	mBufferSize = 0;
 	if (mFormattedImage.notNull())
@@ -888,7 +887,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		mSentRequest = UNSENT;
 		mDecoded  = FALSE;
 		mWritten  = FALSE;
-		delete[] mBuffer;
+		FREE_MEM(LLImageBase::getPrivatePool(), mBuffer);
 		mBuffer = NULL;
 		mBufferSize = 0;
 		mHaveAllData = FALSE;
@@ -1284,7 +1283,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			llassert_always(mBufferSize == cur_size + mRequestedSize);
 			if(!mBufferSize)//no data received.
 			{
-				delete[] mBuffer; 
+				FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); 
 				mBuffer = NULL;
 
 				//abort.
@@ -1312,7 +1311,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 				mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded.
 			}
 			
-			U8* buffer = new U8[mBufferSize];
+			U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mBufferSize);
 			if (cur_size > 0)
 			{
 				memcpy(buffer, mFormattedImage->getData(), cur_size);
@@ -1321,7 +1320,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			// NOTE: setData releases current data and owns new data (buffer)
 			mFormattedImage->setData(buffer, mBufferSize);
 			// delete temp data
-			delete[] mBuffer; // Note: not 'buffer' (assigned in setData())
+			FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); // Note: not 'buffer' (assigned in setData())
 			mBuffer = NULL;
 			mBufferSize = 0;
 			mLoadedDiscard = mRequestedDiscard;
@@ -1618,7 +1617,7 @@ bool LLTextureFetchWorker::processSimulatorPackets()
 			if (buffer_size > cur_size)
 			{
 				/// We have new data
-				U8* buffer = new U8[buffer_size];
+				U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), buffer_size);
 				S32 offset = 0;
 				if (cur_size > 0 && mFirstPacket > 0)
 				{
@@ -1670,7 +1669,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
 		if (data_size > 0)
 		{
 			// *TODO: set the formatted image data here directly to avoid the copy
-			mBuffer = new U8[data_size];
+			mBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), data_size);
 			buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
 			mBufferSize += data_size;
 			if (data_size < mRequestedSize && mRequestedDiscard == 0)
@@ -1816,8 +1815,6 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 	  mDebugPause(FALSE),
 	  mPacketCount(0),
 	  mBadPacketCount(0),
-	  mQueueMutex(getAPRPool()),
-	  mNetworkQueueMutex(getAPRPool()),
 	  mTextureCache(cache),
 	  mImageDecodeThread(imagedecodethread),
 	  mTextureBandwidth(0),
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 39053fe9e4b2889545f93311b363666c6add65b2..6142ee0dd661edc04998e9769d670c03d8d1c402 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -202,6 +202,7 @@ void display_stats()
 		gMemoryAllocated = LLMemory::getCurrentRSS();
 		U32 memory = (U32)(gMemoryAllocated / (1024*1024));
 		llinfos << llformat("MEMORY: %d MB", memory) << llendl;
+		LLMemory::logMemoryInfo() ;
 		gRecentMemoryTime.reset();
 	}
 }
@@ -692,7 +693,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				glh::matrix4f mod = glh_get_current_modelview();
 				glViewport(0,0,512,512);
 				LLVOAvatar::updateFreezeCounter() ;
-				LLVOAvatar::updateImpostors();
+
+				if(!LLPipeline::sMemAllocationThrottled)
+				{		
+					LLVOAvatar::updateImpostors();
+				}
 
 				glh_set_current_projection(proj);
 				glh_set_current_modelview(mod);
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 384f7cd61d32423c005156e7f87b54db3fc6a332..31b22119cbcf60a8f5377bf53badeb8353755b73 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1776,6 +1776,7 @@ void LLViewerMediaImpl::createMediaSource()
 			LL_WARNS("Media") << "Failed to initialize media for mime type " << mMimeType << LL_ENDL;
 		}
 	}
+
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -1880,7 +1881,10 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 			// collect 'javascript enabled' setting from prefs and send to embedded browser
 			bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" );
 			media_source->setJavascriptEnabled( javascript_enabled );
-			
+		
+			bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging");
+			media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled );
+
 			media_source->setTarget(target);
 			
 			const std::string plugin_dir = gDirUtilp->getLLPluginDir();
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index b9293b3b3105f8c9a1ebaef7e2752b97df21728a..8139f7deda420d6d63ee616d306b634a5164409c 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -149,7 +149,7 @@ void LLFilePickerThread::run()
 //static
 void LLFilePickerThread::initClass()
 {
-	sMutex = new LLMutex(NULL);
+	sMutex = new LLMutex();
 }
 
 //static
@@ -816,8 +816,7 @@ LLUUID upload_new_resource(
 		uuid = tid.makeAssetID(gAgent.getSecureSessionID());
 		// copy this file into the vfs for upload
 		S32 file_size;
-		LLAPRFile infile ;
-		infile.open(filename, LL_APR_RB, NULL, &file_size);
+		LLAPRFile infile(filename, LL_APR_RB, &file_size);
 		if (infile.getFileHandle())
 		{
 			LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE);
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp
index dfa35edef46b505135f8f792cb79a23f6722b992..90fbc41daa8f38477b50ff77981ac8277045eb60 100644
--- a/indra/newview/llviewerparcelmedia.cpp
+++ b/indra/newview/llviewerparcelmedia.cpp
@@ -485,6 +485,12 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
 {
 	switch(event)
 	{
+		case MEDIA_EVENT_DEBUG_MESSAGE:
+		{
+			// LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_DEBUG_MESSAGE " << LL_ENDL;
+		};
+		break;
+
 		case MEDIA_EVENT_CONTENT_UPDATED:
 		{
 			// LL_DEBUGS("Media") <<  "Media event:  MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL;
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 70509f9a9f409dbb59a0b848d6ef18e3b7f4ef89..280337be0f73086905810f72437f5abd62039613 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -3109,9 +3109,16 @@ void LLViewerLODTexture::processTextureStats()
 	{
 		mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel) ;
 	}
+	else if(LLPipeline::sMemAllocationThrottled)//release memory of large textures by decrease their resolutions.
+	{
+		if(scaleDown())
+		{
+			mDesiredDiscardLevel = mCachedRawDiscardLevel ;
+		}
+	}
 }
 
-void LLViewerLODTexture::scaleDown()
+bool LLViewerLODTexture::scaleDown()
 {
 	if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel())
 	{		
@@ -3122,7 +3129,10 @@ void LLViewerLODTexture::scaleDown()
 		{
 			tester->setStablizingTime() ;
 		}
+
+		return true ;
 	}
+	return false ;
 }
 //----------------------------------------------------------------------------------------------
 //end of LLViewerLODTexture
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index de528927b46fbe56a243fd07aafb4db7c1756907..a4a5ae0a5b7364a3ecfda4cd299812a5ba597a75 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -597,7 +597,7 @@ class LLViewerLODTexture : public LLViewerFetchedTexture
 
 private:
 	void init(bool firstinit) ;
-	void scaleDown() ;		
+	bool scaleDown() ;		
 
 private:
 	F32 mDiscardVirtualSize;		// Virtual size used to calculate desired discard	
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 8d4f9b346f1a019da2795f89d4850844ad7db742..5893259d964bcc17116c95dda20706800884624a 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -662,6 +662,17 @@ class LLDebugText
 			addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3]));
 			ypos += y_inc;
 		}
+
+		if (gSavedSettings.getBOOL("DebugShowPrivateMem"))
+		{
+			LLPrivateMemoryPoolManager::getInstance()->updateStatistics() ;
+			addText(xpos, ypos, llformat("Total Reserved(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024));
+			ypos += y_inc;
+
+			addText(xpos, ypos, llformat("Total Allocated(KB): %d", LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024));
+			ypos += y_inc;
+		}
+
 		// only display these messages if we are actually rendering beacons at this moment
 		if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons"))
 		{
@@ -1630,6 +1641,7 @@ LLViewerWindow::LLViewerWindow(
 	}
 	LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable"));
 	LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ;
+	gGL.init() ;
 
 	if (LLFeatureManager::getInstance()->isSafe()
 		|| (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
@@ -2026,15 +2038,17 @@ void LLViewerWindow::shutdownGL()
 	llinfos << "All textures and llimagegl images are destroyed!" << llendl ;
 
 	llinfos << "Cleaning up select manager" << llendl;
-	LLSelectMgr::getInstance()->cleanup();
-
-	LLVertexBuffer::cleanupClass();
+	LLSelectMgr::getInstance()->cleanup();	
 
 	llinfos << "Stopping GL during shutdown" << llendl;
 	stopGL(FALSE);
 	stop_glerror();
 
 	gGL.shutdown();
+
+	LLVertexBuffer::cleanupClass();
+
+	llinfos << "LLVertexBuffer cleaned." << llendl ;
 }
 
 // shutdownViews() and shutdownGL() need to be called first
@@ -4148,6 +4162,19 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 	{
 		return FALSE;
 	}
+	//check if there is enough memory for the snapshot image
+	if(LLPipeline::sMemAllocationThrottled)
+	{
+		return FALSE ; //snapshot taking is disabled due to memory restriction.
+	}
+	if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K
+	{
+		if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3))
+		{
+			llwarns << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << llendl ;
+			return FALSE ; //there is no enough memory for taking this snapshot.
+		}
+	}
 
 	// PRE SNAPSHOT
 	gDisplaySwapBuffers = FALSE;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 79468462221f8ba3ef4507ba44393d9bb1e6d559..7c6a815defc53facb45602cf4473b5a1a366556c 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -7506,8 +7506,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
 // static
 void LLVOAvatar::dumpArchetypeXML( void* )
 {
-	LLAPRFile outfile;
-	outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB );
+	LLAPRFile outfile(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER, "new archetype.xml"), LL_APR_WB);
 	apr_file_t* file = outfile.getFileHandle() ;
 	if (!file)
 	{
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 6d457434b5f1cabedc4aa973e9e7d6ac198c2374..baf01ec06617478425e448ac2ed3acf92c4c5475 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -268,7 +268,6 @@ LLVOCache::LLVOCache():
 	mCacheSize(1)
 {
 	mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled");
-	mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
 }
 
 LLVOCache::~LLVOCache()
@@ -278,7 +277,6 @@ LLVOCache::~LLVOCache()
 		writeCacheHeader();
 		clearCacheInMemory();
 	}
-	delete mLocalAPRFilePoolp;
 }
 
 void LLVOCache::setDirNames(ELLPath location)
@@ -435,7 +433,7 @@ void LLVOCache::removeFromCache(HeaderEntryInfo* entry)
 
 	std::string filename;
 	getObjectCacheFilename(entry->mHandle, filename);
-	LLAPRFile::remove(filename, mLocalAPRFilePoolp);
+	LLAPRFile::remove(filename);
 	entry->mTime = INVALID_TIME ;
 	updateEntry(entry) ; //update the head file.
 }
@@ -452,9 +450,9 @@ void LLVOCache::readCacheHeader()
 	clearCacheInMemory();	
 
 	bool success = true ;
-	if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp))
+	if (LLAPRFile::isExist(mHeaderFileName))
 	{
-		LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);		
+		LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY);		
 		
 		//read the meta element
 		success = check_read(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
@@ -539,7 +537,7 @@ void LLVOCache::writeCacheHeader()
 
 	bool success = true ;
 	{
-		LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+		LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY);
 
 		//write the meta element
 		success = check_write(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
@@ -577,7 +575,7 @@ void LLVOCache::writeCacheHeader()
 
 BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
 {
-	LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+	LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY);
 	apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
 
 	return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
@@ -603,7 +601,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 	{
 		std::string filename;
 		getObjectCacheFilename(handle, filename);
-		LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
+		LLAPRFile apr_file(filename, APR_READ|APR_BINARY);
 	
 		LLUUID cache_id ;
 		success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ;
@@ -726,7 +724,7 @@ 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);
 	
 		success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ;
 
@@ -751,4 +749,3 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
 
 	return ;
 }
-
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 14e3b4c79355a94b23827c9b29be224c13a085e7..13651c67799c1591ef01c9f36cc61932ba76bad5 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -142,7 +142,6 @@ class LLVOCache
 	U32                  mNumEntries;
 	std::string          mHeaderFileName ;
 	std::string          mObjectCacheDirName;
-	LLVolatileAPRPool*   mLocalAPRFilePoolp ; 	
 	header_entry_queue_t mHeaderEntryQueue;
 	handle_entry_map_t   mHandleEntryMap;	
 
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 0db0010688369ee1f21417d407b42888b99148c1..8b942fbc6a10d53d5a79bae778eb4448fdc89ae3 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -942,7 +942,7 @@ void LLVivoxVoiceClient::stateMachine()
 
 				if(!mSocket)
 				{
-					mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);	
+					mSocket = LLSocket::create(LLSocket::STREAM_TCP);	
 				}
 				
 				mConnected = mSocket->blockingConnect(mDaemonHost);
diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp
index 4f582fc2dbd7d6f534cba1d3256ba42a4640730c..64ca94b5678779c7ff37d6272e635fe1e19cba08 100644
--- a/indra/newview/llwatchdog.cpp
+++ b/indra/newview/llwatchdog.cpp
@@ -178,8 +178,8 @@ void LLWatchdog::init(killer_event_callback func)
 	mKillerCallback = func;
 	if(!mSuspectsAccessMutex && !mTimer)
 	{
-		mSuspectsAccessMutex = new LLMutex(NULL);
-		mTimer = new LLWatchdogTimerThread();
+		mSuspectsAccessMutex = new LLMutex;
+		mTimer = new LLWatchdogTimerThread;
 		mTimer->setSleepTime(WATCHDOG_SLEEP_TIME_USEC / 1000);
 		mLastClockCount = LLTimer::getTotalTime();
 
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 4a6ec7fdbbed5f8e88cc7c073e532497e40013fc..a7ae456f3ce76923d8da794595e505afd7b462f3 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -127,6 +127,12 @@ void LLWorld::destroyClass()
 		LLVOCache::getInstance()->destroyClass() ;
 	}
 	LLViewerPartSim::getInstance()->destroyClass();
+
+	mDefaultWaterTexturep = NULL ;
+	for (S32 i = 0; i < 8; i++)
+	{
+		mEdgeWaterObjects[i] = NULL;
+	}
 }
 
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 7a264041383d22d55f95797727443f1aed7ba7c1..a50f66f2829d46690f2475c5a562f0d8a3ec224c 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -103,6 +103,7 @@
 #include "llmutelist.h"
 #include "lltoolpie.h"
 #include "llcurl.h"
+#include "llnotifications.h"
 
 
 void check_stack_depth(S32 stack_depth)
@@ -317,6 +318,7 @@ BOOL	LLPipeline::sRenderFrameTest = FALSE;
 BOOL	LLPipeline::sRenderAttachedLights = TRUE;
 BOOL	LLPipeline::sRenderAttachedParticles = TRUE;
 BOOL	LLPipeline::sRenderDeferred = FALSE;
+BOOL    LLPipeline::sMemAllocationThrottled = FALSE;
 S32		LLPipeline::sVisibleLightCount = 0;
 F32		LLPipeline::sMinRenderSize = 0.f;
 
@@ -561,6 +563,24 @@ void LLPipeline::destroyGL()
 
 static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
 
+//static
+void LLPipeline::throttleNewMemoryAllocation(BOOL disable)
+{
+	if(sMemAllocationThrottled != disable)
+	{
+		sMemAllocationThrottled = disable ;
+
+		if(sMemAllocationThrottled)
+		{
+			//send out notification
+			LLNotification::Params params("LowMemory");
+			LLNotifications::instance().add(params);
+
+			//release some memory.
+		}
+	}
+}
+
 void LLPipeline::resizeScreenTexture()
 {
 	LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE);
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 28e6526acd960dc761e6cc3644798f736e6945d0..3f0640221e0367f818c9a321f7b0ad8ff192e873 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -362,6 +362,8 @@ class LLPipeline
 	static void updateRenderDeferred();
 	static void refreshRenderDeferred();
 
+	static void throttleNewMemoryAllocation(BOOL disable);
+
 	void addDebugBlip(const LLVector3& position, const LLColor4& color);
 
 private:
@@ -517,8 +519,9 @@ class LLPipeline
 	static BOOL				sRenderAttachedLights;
 	static BOOL				sRenderAttachedParticles;
 	static BOOL				sRenderDeferred;
+	static BOOL             sMemAllocationThrottled;
 	static S32				sVisibleLightCount;
-	static F32				sMinRenderSize;
+	static F32				sMinRenderSize;	
 
 	//screen texture
 	U32 					mScreenWidth;
diff --git a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml
index c39c26f25f5278cc53619923df540bd565eedace..960da4bd7a22894f79da0e9c4aa704298db2447e 100644
--- a/indra/newview/skins/default/xui/en/menu_media_ctrl.xml
+++ b/indra/newview/skins/default/xui/en/menu_media_ctrl.xml
@@ -28,4 +28,16 @@
     <menu_item_call.on_enable
      function="Edit.EnablePaste" />
   </menu_item_call>
+  <menu_item_separator
+   layout="topleft"
+   name="debug_separator"
+   visible="false" />
+  <menu_item_call
+   label="Open Web Inspector"
+   layout="topleft"
+   name="open_webinspector"
+   visible="false">
+    <menu_item_call.on_click
+     function="Open.WebInspector" />
+  </menu_item_call>
 </context_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index b08e3abb71fee7651437283dc5b493fe4f0400bb..36ebe737532a017b0868ab7701db08ddc357a774 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2133,6 +2133,16 @@
                function="ToggleControl"
                parameter="DebugShowMemory" />
             </menu_item_check>
+	     <menu_item_check
+               label="Show Private Mem Info"
+               name="Show Private Mem Info">
+              <menu_item_check.on_check
+               function="CheckControl"
+               parameter="DebugShowPrivateMem" />
+              <menu_item_check.on_click
+               function="ToggleControl"
+               parameter="DebugShowPrivateMem" />
+            </menu_item_check>
 
             <menu_item_separator/>
 
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 251fce2333a22f3395b7393e14f9c12ec152b58d..99ab56d10a84c3dade51169ac15a215c0ac0034c 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -7147,6 +7147,20 @@ Click and drag anywhere on the world to rotate your view
     <tag>funds</tag>
   </notification>
 
+   <notification
+   icon="alertmodal.tga"
+   name="LowMemory"
+   type="alertmodal">
+    Your memory pool is low. Some functions of SL are disabled to avoid crash. Please close other applications. Restart SL if this persists.
+  </notification>
+
+  <notification
+     icon="alertmodal.tga"
+     name="ForceQuitDueToLowMemory"
+     type="alertmodal">
+    SL will quit in 30 seconds due to out of memory.
+  </notification>
+
   <notification
   name="PopupAttempt"
   icon="Popup_Caution"
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 83f1bff91f5c5d6d33cbf6b95e3cec43d3afc2e9..983f93cb036545e84185dd5c6b2bc5578777bf19 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -117,17 +117,33 @@ label="Remember password"
   name="connect_btn"
   top="35"
   width="90" />
-  <!-- Utf code in label is a filled up-pointing triangle -->
-  <menu_button
-  left_pad="5"
-  top="35"
-  width="80"
+  <text
+  follows="left|bottom"
+  font="SansSerifSmall"
+  height="15"
+  left_pad="10"
+  name="mode_selection_text"
+  top="20"
+  width="130">
+    Mode:
+  </text>
+  <combo_box
+    follows="left|bottom"
   height="23"
-  label="Mode &#9650;"
-  name="mode_menu"  
+    max_chars="128"
   tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
-  menu_filename="menu_mode_change.xml"
-    />
+    top_pad="0"
+    name="mode_combo"
+    width="110">
+    <combo_box.item
+      label="Basic"
+      name="Basic"
+      value="settings_minimal.xml" />
+    <combo_box.item
+      label="Advanced"
+      name="Advanced"
+      value="" />
+  </combo_box>
   <text
   follows="left|bottom"
   font="SansSerifSmall"
diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
index 8a7bd53054b60293cb4ae0a5c094d27ea651e56b..9749b6fdd46cd3a042906f3e55395975b3782db7 100644
--- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
@@ -97,7 +97,7 @@
 	     mouse_opaque="false"
 	     name="location_combo"
 	     top_delta="0"
-	     width="266">
+	     width="226">
          <combo_list
          mouse_wheel_opaque="true"/>
 	     <!-- *TODO: Delete.  Let the location_input use the correct art sizes.
@@ -137,7 +137,7 @@
 	     name="search_combo_box"
 	     tool_tip="Search"
 	     top_delta="0"
-	     width="200" >
+	     width="244" >
          <combo_editor
           label="Search [SECOND_LIFE]"
           name="search_combo_editor"/>
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 f25a73da38a6e699f21781ed8a615c90baf59751..c780cf26968b288c4cf5acebcd56e50d468815f4 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="-315"
+    left="-355"
     width="95"
     top="1"
     follows="right|top" 
@@ -77,20 +77,28 @@
      top="0"
      width="55" />
   </panel>
-  <!-- UTF 9660 code in label below is a down-pointing filled-in triangle -->
-  <menu_button
-     follows="right|top"    
-    image_color="0 0 0 0"
-    hover_glow_amount="0"
+  <combo_box
+    follows="right|top"   
+    drop_down_button.pad_left="10" 
     left_pad="5"
-    top="2"
-    width="55"
-    height="18"
-    label="Mode &#9660;"
+    top="0"
+    width="120"
+    height="20"
+    pad_left="5"
+    name="mode_combo"
     tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
-    menu_filename="menu_mode_change.xml"
-    />
+    >
+    <combo_box.item
+      label="Basic Mode"
+      name="Basic"
+      value="settings_minimal.xml" />
+    <combo_box.item
+      label="Advanced Mode"
+      name="Advanced"
+      value="" />
+  </combo_box>
     <text
+      left_pad="5"
      type="string"
      font="SansSerifSmall"
      text_readonly_color="TimeTextColor"
@@ -99,10 +107,9 @@
      height="16"
      top="5"
      layout="topleft"
-     left_pad="5"
      name="TimeText"
      tool_tip="Current time (Pacific)"
-     width="90">
+     width="75">
         24:00 AM PST
     </text>
     <button
diff --git a/indra/newview/skins/default/xui/en/widgets/combo_box.xml b/indra/newview/skins/default/xui/en/widgets/combo_box.xml
index d1f68a9ef9aaac3578ee47240573787d3f1c9f4a..82d620d1e6b57f6f9a6430b7c660e1d7cdee82ba 100644
--- a/indra/newview/skins/default/xui/en/widgets/combo_box.xml
+++ b/indra/newview/skins/default/xui/en/widgets/combo_box.xml
@@ -16,6 +16,9 @@
                               font="SansSerifSmall"
                               scale_image="true"
                               pad_right="24"
+                              halign="left"
+                              tab_stop="true"
+                              follows="all"
                               image_unselected="DropDown_Off"
                               image_selected="DropDown_On"
                               image_pressed="DropDown_Press" 
diff --git a/indra/newview/skins/minimal/xui/en/main_view.xml b/indra/newview/skins/minimal/xui/en/main_view.xml
index ec2683880a30fafc8f40d5b6d5fcf9ecd4151bb7..0ce6cbc98456ff6b1d93d83d6c88a2a6b524abe2 100644
--- a/indra/newview/skins/minimal/xui/en/main_view.xml
+++ b/indra/newview/skins/minimal/xui/en/main_view.xml
@@ -187,9 +187,9 @@
        name="status_bar_container"
        tab_stop="false"
        height="30"
-       left="-120"
+       left="-160"
        top="0"
-       width="120"
+       width="160"
        visible="false"/>
   <panel follows="top|bottom"
          height="500"
diff --git a/indra/newview/skins/minimal/xui/en/panel_login.xml b/indra/newview/skins/minimal/xui/en/panel_login.xml
index d89a0c6be16f0dde4d728281dfd62d743103d01e..40d2df78e13a91ff2ee27515fe2038ec32b87b89 100644
--- a/indra/newview/skins/minimal/xui/en/panel_login.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_login.xml
@@ -118,16 +118,33 @@ label="Remember password"
   name="connect_btn"
   top="35"
   width="90" />
-  <menu_button
-left_pad="10"
-top="35"
-width="80"
-height="23"
-label="Mode â–²"
-name="mode_menu"
-tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
-menu_filename="menu_mode_change.xml"
-    />
+  <text
+  follows="left|bottom"
+  font="SansSerifSmall"
+  height="15"
+  left_pad="10"
+  name="mode_selection_text"
+  top="20"
+  width="130">
+    Mode:
+  </text>
+  <combo_box
+  follows="left|bottom"
+  height="23"
+  max_chars="128"
+  tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
+  top_pad="0"
+  name="mode_combo"
+  width="110">
+    <combo_box.item
+      label="Basic"
+      name="Basic"
+      value="settings_minimal.xml" />
+    <combo_box.item
+      label="Advanced"
+      name="Advanced"
+      value="" />
+  </combo_box>
 </layout_panel>
 <layout_panel
 tab_stop="false"
diff --git a/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml b/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml
index e50911b8d2187558df98b76e58b7627cd2eaba89..73a85642741f4fb28e580c3bb867bb0cb9161753 100644
--- a/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml
@@ -63,7 +63,7 @@ width="31" />
      mouse_opaque="false"
      name="location_combo"
      top_delta="0"
-     width="390">
+     width="325">
     </location_input>
     <icon follows="right"
           height="20"
diff --git a/indra/newview/skins/minimal/xui/en/panel_status_bar.xml b/indra/newview/skins/minimal/xui/en/panel_status_bar.xml
index 42e6f30d4827bf28a2b92dc1ba26ac2f7f0c1e79..fdd6b5d6ec5cdd25c957ae2f9e7195b6efe03c2d 100644
--- a/indra/newview/skins/minimal/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/minimal/xui/en/panel_status_bar.xml
@@ -12,7 +12,7 @@
  name="status"
  top="19"
  tab_stop="false"
- width="120">
+ width="185">
     <panel.string
      name="packet_loss_tooltip">
         Packet Loss
@@ -33,18 +33,27 @@
      name="buycurrencylabel">
         L$ [AMT]
     </panel.string>
-  <menu_button
-     follows="right|top"    
-    image_color="0 0 0 0"
-    hover_glow_amount="0"
-    left="5"
-    top="7"
-    width="55"  
-    height="18"
-    label="Mode â–¼"
-    tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
-    menu_filename="menu_mode_change.xml"
-    />
+  <combo_box
+   follows="right|top"
+   left_pad="5"
+   drop_down_button.pad_left="10"
+   left="0"
+   top="5"
+   pad_left="5"
+   width="120"
+   height="23"
+   name="mode_combo"
+   tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
+    >
+    <combo_box.item
+      label="Basic Mode"
+      name="Basic"
+      value="settings_minimal.xml" />
+    <combo_box.item
+      label="Advanced Mode"
+      name="Advanced"
+      value="" />
+  </combo_box>
      <button
      follows="right|top"
      height="16"
@@ -53,7 +62,7 @@
      image_pressed="Pause_Press"
      image_pressed_selected="Play_Press"
      is_toggle="true"
-     left="65"
+     left_pad="5"
      top="7"
      name="media_toggle_btn"
      tool_tip="Start/Stop All Media (Music, Video, Web pages)"
diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp
index acc6e814bc7a196d1f071cc6c79d4a15b9f68123..102294959a35ee15c9bcc75174144d6cd8b1fa03 100644
--- a/indra/newview/tests/llworldmap_test.cpp
+++ b/indra/newview/tests/llworldmap_test.cpp
@@ -27,7 +27,6 @@
 
 // Dependencies
 #include "linden_common.h"
-#include "llapr.h"
 #include "llsingleton.h"
 #include "lltrans.h"
 #include "lluistring.h"
diff --git a/indra/test/lltemplatemessagebuilder_tut.cpp b/indra/test/lltemplatemessagebuilder_tut.cpp
index 09beb53869d4afcefa164840ebdfb6cc3b210b5a..532f26ee6086a3d56bbed28b2099dcd0f08b5f0c 100644
--- a/indra/test/lltemplatemessagebuilder_tut.cpp
+++ b/indra/test/lltemplatemessagebuilder_tut.cpp
@@ -29,7 +29,6 @@
 #include "linden_common.h"
 #include "lltut.h"
 
-#include "llapr.h"
 #include "llmessagetemplate.h"
 #include "llquaternion.h"
 #include "lltemplatemessagebuilder.h"
@@ -53,7 +52,6 @@ namespace tut
 			static bool init = false;
 			if(! init)
 			{
-				ll_init_apr();
 				const F32 circuit_heartbeat_interval=5;
 				const F32 circuit_timeout=100;
 
diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp
index d971b334752dc1c99e5c7bc80d62f84430a62a10..9a6ccd4d6819cb8935af4e52cc987bb4ac40998d 100644
--- a/indra/test/message_tut.cpp
+++ b/indra/test/message_tut.cpp
@@ -29,7 +29,6 @@
 #include "linden_common.h"
 #include "lltut.h"
 
-#include "llapr.h"
 #include "llmessageconfig.h"
 #include "llsdserialize.h"
 #include "llversionserver.h"
@@ -62,7 +61,6 @@ namespace tut
 			static bool init = false;
 			if(!init)
 			{
-				ll_init_apr();
 				//init_prehash_data();
 				init = true;
 			}
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index ffdb0cb976a311f79a8233ddc4fa7409f139473e..45e8aef99a972b8be9e726c6f4d66ac521d17fcb 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -37,8 +37,8 @@
 #include "linden_common.h"
 #include "llerrorcontrol.h"
 #include "lltut.h"
+#include "llaprpool.h"
 
-#include "apr_pools.h"
 #include "apr_getopt.h"
 
 // the CTYPE_WORKAROUND is needed for linux dev stations that don't
@@ -349,17 +349,12 @@ int main(int argc, char **argv)
 	ctype_workaround();
 #endif
 
-	apr_initialize();
-	apr_pool_t* pool = NULL;
-	if(APR_SUCCESS != apr_pool_create(&pool, NULL))
-	{
-		std::cerr << "Unable to initialize pool" << std::endl;
-		return 1;
-	}
+	LLAPRPool pool;
+	pool.create();
 	apr_getopt_t* os = NULL;
-	if(APR_SUCCESS != apr_getopt_init(&os, pool, argc, argv))
+	if(APR_SUCCESS != apr_getopt_init(&os, pool(), argc, argv))
 	{
-		std::cerr << "Unable to  pool" << std::endl;
+		std::cerr << "Unable to initialize the arguments for parsing by apr_getopt()." << std::endl;
 		return 1;
 	}
 
@@ -477,8 +472,6 @@ int main(int argc, char **argv)
 		s.close();
 	}
 
-	apr_terminate();
-
 	int retval = (success ? 0 : 1);
 	return retval;
 
diff --git a/indra/test_apps/llplugintest/llmediaplugintest.cpp b/indra/test_apps/llplugintest/llmediaplugintest.cpp
index 884b00f0ccba6f96325047e51614638ffa24eb9d..d5ee09c5bc3a35f41c7593b01bacdff72b08c181 100644
--- a/indra/test_apps/llplugintest/llmediaplugintest.cpp
+++ b/indra/test_apps/llplugintest/llmediaplugintest.cpp
@@ -27,7 +27,6 @@
 #include "linden_common.h"
 #include "indra_constants.h"
 
-#include "llapr.h"
 #include "llerrorcontrol.h"
 
 #include <math.h>
@@ -186,9 +185,6 @@ LLMediaPluginTest::LLMediaPluginTest( int app_window, int window_width, int wind
 		std::cout << "Unable to read bookmarks from file: " << bookmarks_filename << std::endl;
 	};
 
-	// initialize linden lab APR module
-	ll_init_apr();
-
 	// Set up llerror logging
 	{
 		LLError::initForApplication(".");
diff --git a/indra/viewer_components/updater/llupdateinstaller.cpp b/indra/viewer_components/updater/llupdateinstaller.cpp
index c7b70c2de8e91fcd8deec2075c3a66f9df8f8675..24ba00ad8e6db18c3a29ede865cbff8d68e480a1 100644
--- a/indra/viewer_components/updater/llupdateinstaller.cpp
+++ b/indra/viewer_components/updater/llupdateinstaller.cpp
@@ -26,6 +26,7 @@
 #include "linden_common.h"
 #include <apr_file_io.h>
 #include "llapr.h"
+#include "llscopedvolatileaprpool.h"
 #include "llprocesslauncher.h"
 #include "llupdateinstaller.h"
 #include "lldir.h" 
@@ -45,7 +46,8 @@ namespace {
 	{
 		std::string scriptFile = gDirUtilp->getBaseFileName(path);
 		std::string newPath = gDirUtilp->getExpandedFilename(LL_PATH_TEMP, scriptFile);
-		apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, gAPRPoolp);
+		LLScopedVolatileAPRPool pool;
+		apr_status_t status = apr_file_copy(path.c_str(), newPath.c_str(), APR_FILE_SOURCE_PERMS, pool);
 		if(status != APR_SUCCESS) throw RelocateError();
 		
 		return newPath;