diff --git a/doc/contributions.txt b/doc/contributions.txt
index 62210f08f4d7c6c911c897f9929dad62472d4f10..236112334391e167ed8a7563476533103b1fea73 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -18,6 +18,7 @@ Alissa Sabre
 	VWR-171
 	VWR-177
 	VWR-213
+	VWR-250
 	VWR-251
 	VWR-286
 	VWR-414
@@ -55,6 +56,7 @@ Catherine Pfeffer
 Dale Glass
 	VWR-120
 	VWR-560
+	VWR-2502
 	VWR-1358
 	VWR-2041
 Drewan Keats
@@ -91,6 +93,8 @@ Feep Larsson
 	VWR-1314
 Fremont Cunningham
 	VWR-1147
+Gudmund Shepherd
+	VWR-1873
 Gigs Taggart
 	SVC-493
 	VWR-38
@@ -106,6 +110,7 @@ Gigs Taggart
 	VWR-1434
 	VWR-1987
 	VWR-2065
+	VWR-2502
 Ginko Bayliss
 	VWR-4
 Grazer Kline
@@ -216,7 +221,9 @@ Nicholaz Beresford
 	VWR-1872
 	VWR-1968
 	VWR-2046
+	VWR-2142
 	VWR-2152
+	VWR-2614
 Nounouch Hapmouche
 	VWR-238
 Paul Churchill
diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py
index 2408fab96f1cbfa41ec2c08d497cbfd7672269b6..a73fc6c29305379ff78f56c2a1313f6f6395fc63 100644
--- a/indra/lib/python/indra/util/llmanifest.py
+++ b/indra/lib/python/indra/util/llmanifest.py
@@ -28,6 +28,7 @@
 """
 
 import commands
+import errno
 import filecmp
 import fnmatch
 import getopt
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 6dab598341fbbea874007f094c2e74820b1ecb40..9895a684b2a98347f4e059928810214ce3a9db4f 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -239,6 +239,84 @@ LLWString utf16str_to_wstring(const llutf16string &utf16str)
 	return utf16str_to_wstring(utf16str, len);
 }
 
+// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
+S32 utf16str_wstring_length(const llutf16string &utf16str, const S32 utf16_len)
+{
+	S32 surrogate_pairs = 0;
+	// ... craziness to make gcc happy (llutf16string.c_str() is tweaked on linux):
+	const U16 *const utf16_chars = &(*(utf16str.begin()));
+	S32 i = 0;
+	while (i < utf16_len)
+	{
+		const U16 c = utf16_chars[i++];
+		if (c >= 0xD800 && c <= 0xDBFF)		// See http://en.wikipedia.org/wiki/UTF-16
+		{   // Have first byte of a surrogate pair
+			if (i >= utf16_len)
+			{
+				break;
+			}
+			const U16 d = utf16_chars[i];
+			if (d >= 0xDC00 && d <= 0xDFFF)
+			{   // Have valid second byte of a surrogate pair
+				surrogate_pairs++;
+				i++;
+			}
+		}
+	}
+	return utf16_len - surrogate_pairs;
+}
+
+// Length in utf16string (UTF-16) of wlen wchars beginning at woffset.
+S32 wstring_utf16_length(const LLWString &wstr, const S32 woffset, const S32 wlen)
+{
+	const S32 end = llmin((S32)wstr.length(), woffset + wlen);
+	if (end < woffset)
+	{
+		return 0;
+	}
+	else
+	{
+		S32 length = end - woffset;
+		for (S32 i = woffset; i < end; i++)
+		{
+			if (wstr[i] >= 0x10000)
+			{
+				length++;
+			}
+		}
+		return length;
+	}
+}
+
+// Given a wstring and an offset in it, returns the length as wstring (i.e.,
+// number of llwchars) of the longest substring that starts at the offset
+// and whose equivalent utf-16 string does not exceeds the given utf16_length.
+S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, const S32 woffset, const S32 utf16_length, BOOL *unaligned)
+{
+	const S32 end = wstr.length();
+	BOOL u = FALSE;
+	S32 n = woffset + utf16_length;
+	S32 i = woffset;
+	while (i < end)
+	{
+		if (wstr[i] >= 0x10000)
+		{
+			--n;
+		}
+		if (i >= n)
+		{
+			u = (i > n);
+			break;
+		}
+		i++;
+	}
+	if (unaligned)
+	{
+		*unaligned = u;
+	}
+	return i - woffset;
+}
+
 S32 wchar_utf8_length(const llwchar wc)
 {
 	if (wc < 0x80)
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 70f7d5483efdd4970b4bf2ea613c82bb2e1edef7..ec4ff335c993bb6169b45491939b377fb3636847 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -433,6 +433,15 @@ S32 wchar_utf8_length(const llwchar wc);
 
 std::string utf8str_tolower(const std::string& utf8str);
 
+// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
+S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len);
+
+// Length in utf16string (UTF-16) of wlen wchars beginning at woffset.
+S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen);
+
+// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.)
+S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL);
+
 /**
  * @brief Properly truncate a utf8 string to a maximum byte count.
  * 
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 4dea08505dd11873b8614fb3a85cdceabbcb0bdf..7c8fe86d2b2efda9e7df701b819ec516dac6b26d 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -86,7 +86,7 @@ const S32 SCULPT_REZ_2 = 8;
 const S32 SCULPT_REZ_3 = 16;
 const S32 SCULPT_REZ_4 = 32;
 
-const F32 SCULPT_MIN_AREA = 0.005f;
+const F32 SCULPT_MIN_AREA = 0.002f;
 
 BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
 {    
@@ -1834,9 +1834,9 @@ inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b)
 {
 	// maps RGB values to vector values [0..255] -> [-0.5..0.5]
 	LLVector3 value;
-	value.mV[VX] = r / 256.f - 0.5f;
-	value.mV[VY] = g / 256.f - 0.5f;
-	value.mV[VZ] = b / 256.f - 0.5f;
+	value.mV[VX] = r / 255.f - 0.5f;
+	value.mV[VY] = g / 255.f - 0.5f;
+	value.mV[VZ] = b / 255.f - 0.5f;
 
 	return value;
 }
diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp
index e80bc8cce8f8c1749b72948015acd3c936fbc33f..ff4f8a2e660ed7d294005228efe83fb1dac73a3a 100644
--- a/indra/llmessage/lltransfermanager.cpp
+++ b/indra/llmessage/lltransfermanager.cpp
@@ -106,10 +106,15 @@ void LLTransferManager::cleanup()
 
 void LLTransferManager::updateTransfers()
 {
-	host_tc_map::iterator iter;
-	for (iter = mTransferConnections.begin(); iter != mTransferConnections.end(); iter++)
+	host_tc_map::iterator iter,cur;
+
+	iter = mTransferConnections.begin();
+
+	while (iter !=mTransferConnections.end())
 	{
-		iter->second->updateTransfers();
+		cur = iter;
+		iter++;
+		cur->second->updateTransfers();
 	}
 }
 
@@ -571,7 +576,6 @@ void LLTransferManager::processTransferAbort(LLMessageSystem *msgp, void **)
 	msgp->getUUID("TransferInfo", "TransferID", transfer_id);
 	msgp->getS32("TransferInfo", "ChannelType", (S32 &)channel_type);
 
-
 	// See if it's a target that we're trying to abort
 	// Find the transfer associated with this packet.
 	LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type);
@@ -651,10 +655,14 @@ LLTransferConnection::~LLTransferConnection()
 void LLTransferConnection::updateTransfers()
 {
 	// Do stuff for source transfers (basically, send data out).
-	tsc_iter iter;
-	for (iter = mTransferSourceChannels.begin(); iter != mTransferSourceChannels.end(); iter++)
+	tsc_iter iter, cur;
+	iter = mTransferSourceChannels.begin();
+
+	while (iter !=mTransferSourceChannels.end())
 	{
-		(*iter)->updateTransfers();
+		cur = iter;
+		iter++;
+		(*cur)->updateTransfers();
 	}
 
 	// Do stuff for target transfers
@@ -768,14 +776,16 @@ void LLTransferSourceChannel::updateTransfers()
 		return;
 	}
 
-	LLPriQueueMap<LLTransferSource *>::pqm_iter iter;
-
+	LLPriQueueMap<LLTransferSource *>::pqm_iter iter, next;
 
 	BOOL done = FALSE;
 	for (iter = mTransferSources.mMap.begin(); (iter != mTransferSources.mMap.end()) && !done;)
 	{
 		//llinfos << "LLTransferSourceChannel::updateTransfers()" << llendl;
-		// Do stuff.
+		// Do stuff. 
+		next = iter;
+		next++;
+
 		LLTransferSource *tsp = iter->second;
 		U8 *datap = NULL;
 		S32 data_size = 0;
@@ -793,11 +803,12 @@ void LLTransferSourceChannel::updateTransfers()
 			// We don't have any data, but we're not done, just go on.
 			// This will presumably be used for streaming or async transfers that
 			// are stalled waiting for data from another source.
-			iter++;
+			iter=next;
 			continue;
 		}
 
 		LLUUID *cb_uuid = new LLUUID(tsp->getID());
+		LLUUID transaction_id = tsp->getID();
 
 		// Send the data now, even if it's an error.
 		// The status code will tell the other end what to do.
@@ -822,7 +833,17 @@ void LLTransferSourceChannel::updateTransfers()
 			delete[] datap;
 			datap = NULL;
 		}
-		
+
+		if (findTransferSource(transaction_id) == NULL)
+		{
+			//Warning!  In the case of an aborted transfer, the sendReliable call above calls 
+			//AbortTransfer which in turn calls deleteTransfer which means that somewhere way 
+			//down the chain our current iter can get invalidated resulting in an infrequent
+			//sim crash.  This check gets us to a valid transfer source in this event.
+			iter=next;
+			continue;
+		}
+
 		// Update the packet counter
 		tsp->setLastPacketID(packet_id);
 
@@ -839,7 +860,8 @@ void LLTransferSourceChannel::updateTransfers()
 			tsp->completionCallback(status);
 			delete tsp;
 			
-			mTransferSources.mMap.erase(iter++);
+			mTransferSources.mMap.erase(iter);
+			iter = next;
 			break;
 		default:
 			llerrs << "Unknown transfer error code!" << llendl;
@@ -876,23 +898,20 @@ LLTransferSource *LLTransferSourceChannel::findTransferSource(const LLUUID &tran
 
 BOOL LLTransferSourceChannel::deleteTransfer(LLTransferSource *tsp)
 {
+
 	LLPriQueueMap<LLTransferSource *>::pqm_iter iter;
 	for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++)
 	{
 		if (iter->second == tsp)
 		{
-			break;
+			delete tsp;
+			mTransferSources.mMap.erase(iter);
+			return TRUE;
 		}
 	}
 
-	if (iter == mTransferSources.mMap.end())
-	{
-		llerrs << "Unable to find transfer source to delete!" << llendl;
-		return FALSE;
-	}
-	mTransferSources.mMap.erase(iter);
-	delete tsp;
-	return TRUE;
+	llerrs << "Unable to find transfer source to delete!" << llendl;
+	return FALSE;
 }
 
 
@@ -1000,18 +1019,14 @@ BOOL LLTransferTargetChannel::deleteTransfer(LLTransferTarget *ttp)
 	{
 		if (*iter == ttp)
 		{
-			break;
+			delete ttp;
+			mTransferTargets.erase(iter);
+			return TRUE;
 		}
 	}
 
-	if (iter == mTransferTargets.end())
-	{
-		llerrs << "Unable to find transfer target to delete!" << llendl;
-		return FALSE;
-	}
-	mTransferTargets.erase(iter);
-	delete ttp;
-	return TRUE;
+	llerrs << "Unable to find transfer target to delete!" << llendl;
+	return FALSE;
 }
 
 
@@ -1072,7 +1087,7 @@ void LLTransferSource::sendTransferStatus(LLTSCode status)
 void LLTransferSource::abortTransfer()
 {
 	// Send a message down, call the completion callback
-	llinfos << "Aborting transfer " << getID() << " to " << mChannelp->getHost() << llendl;
+	llinfos << "LLTransferSource::Aborting transfer " << getID() << " to " << mChannelp->getHost() << llendl;
 	gMessageSystem->newMessage("TransferAbort");
 	gMessageSystem->nextBlock("TransferInfo");
 	gMessageSystem->addUUID("TransferID", getID());
@@ -1204,7 +1219,7 @@ LLTransferTarget::~LLTransferTarget()
 void LLTransferTarget::abortTransfer()
 {
 	// Send a message up, call the completion callback
-	llinfos << "Aborting transfer " << getID() << " from " << mChannelp->getHost() << llendl;
+	llinfos << "LLTransferTarget::Aborting transfer " << getID() << " from " << mChannelp->getHost() << llendl;
 	gMessageSystem->newMessage("TransferAbort");
 	gMessageSystem->nextBlock("TransferInfo");
 	gMessageSystem->addUUID("TransferID", getID());
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index b41879380fafdcd929d9d6e0223f929738a601fc..77bca8f803173ed378678e3851fa7d3463799f6a 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -41,6 +41,7 @@
 #include "llvolumemgr.h"
 #include "llstring.h"
 #include "lldatapacker.h"
+#include "llsdutil.h"
 
 /**
  * exported constants
@@ -1795,6 +1796,47 @@ void LLLightParams::copy(const LLNetworkData& data)
 	mFalloff = param->mFalloff;
 }
 
+LLSD LLLightParams::asLLSD() const
+{
+	LLSD sd;
+	
+	sd["color"] = ll_sd_from_color4(getColor());
+	sd["radius"] = getRadius();
+	sd["falloff"] = getFalloff();
+	sd["cutoff"] = getCutoff();
+		
+	return sd;
+}
+
+bool LLLightParams::fromLLSD(LLSD& sd)
+{
+	const char *w;
+	w = "color";
+	if (sd.has(w))
+	{
+		setColor( ll_color4_from_sd(sd["color"]) );
+	} else goto fail;
+	w = "radius";
+	if (sd.has(w))
+	{
+		setRadius( (F32)sd[w].asReal() );
+	} else goto fail;
+	w = "falloff";
+	if (sd.has(w))
+	{
+		setFalloff( (F32)sd[w].asReal() );
+	} else goto fail;
+	w = "cutoff";
+	if (sd.has(w))
+	{
+		setCutoff( (F32)sd[w].asReal() );
+	} else goto fail;
+	
+	return true;
+ fail:
+	return false;
+}
+
 //============================================================================
 
 LLFlexibleObjectData::LLFlexibleObjectData()
@@ -1876,6 +1918,59 @@ void LLFlexibleObjectData::copy(const LLNetworkData& data)
 	//mRenderingCollisionSphere = flex_data->mRenderingCollisionSphere;
 }
 
+LLSD LLFlexibleObjectData::asLLSD() const
+{
+	LLSD sd;
+
+	sd["air_friction"] = getAirFriction();
+	sd["gravity"] = getGravity();
+	sd["simulate_lod"] = getSimulateLOD();
+	sd["tension"] = getTension();
+	sd["user_force"] = getUserForce().getValue();
+	sd["wind_sensitivity"] = getWindSensitivity();
+	
+	return sd;
+}
+
+bool LLFlexibleObjectData::fromLLSD(LLSD& sd)
+{
+	const char *w;
+	w = "air_friction";
+	if (sd.has(w))
+	{
+		setAirFriction( (F32)sd[w].asReal() );
+	} else goto fail;
+	w = "gravity";
+	if (sd.has(w))
+	{
+		setGravity( (F32)sd[w].asReal() );
+	} else goto fail;
+	w = "simulate_lod";
+	if (sd.has(w))
+	{
+		setSimulateLOD( sd[w].asInteger() );
+	} else goto fail;
+	w = "tension";
+	if (sd.has(w))
+	{
+		setTension( (F32)sd[w].asReal() );
+	} else goto fail;
+	w = "user_force";
+	if (sd.has(w))
+	{
+		LLVector3 user_force = ll_vector3_from_sd(sd[w], 0);
+		setUserForce( user_force );
+	} else goto fail;
+	w = "wind_sensitivity";
+	if (sd.has(w))
+	{
+		setWindSensitivity( (F32)sd[w].asReal() );
+	} else goto fail;
+	
+	return true;
+ fail:
+	return false;
+}
 
 //============================================================================
 
@@ -1927,3 +2022,34 @@ void LLSculptParams::copy(const LLNetworkData& data)
 	mSculptType = param->mSculptType;
 }
 
+
+
+LLSD LLSculptParams::asLLSD() const
+{
+	LLSD sd;
+	
+	sd["texture"] = mSculptTexture;
+	sd["type"] = mSculptType;
+		
+	return sd;
+}
+
+bool LLSculptParams::fromLLSD(LLSD& sd)
+{
+	const char *w;
+	w = "texture";
+	if (sd.has(w))
+	{
+		setSculptTexture( sd[w] );
+	} else goto fail;
+	w = "type";
+	if (sd.has(w))
+	{
+		setSculptType( (U8)sd[w].asInteger() );
+	} else goto fail;
+	
+	return true;
+ fail:
+	return false;
+}
+
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 53b17bc2efa8bcb28662f20ab37313ab457c1400..eef58341e7639cffbc89f1e4e4f5fecc1e9def6c 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -141,7 +141,13 @@ class LLLightParams : public LLNetworkData
 	/*virtual*/ BOOL unpack(LLDataPacker &dp);
 	/*virtual*/ bool operator==(const LLNetworkData& data) const;
 	/*virtual*/ void copy(const LLNetworkData& data);
+	// LLSD implementations here are provided by Eddy Stryker.
+	// NOTE: there are currently unused in protocols
+	LLSD asLLSD() const;
+	operator LLSD() const { return asLLSD(); }
+	bool fromLLSD(LLSD& sd);
 
+	
 	void setColor(const LLColor4& color)	{ mColor = color; mColor.clamp(); }
 	void setRadius(F32 radius)				{ mRadius = llclamp(radius, LIGHT_MIN_RADIUS, LIGHT_MAX_RADIUS); }
 	void setFalloff(F32 falloff)			{ mFalloff = llclamp(falloff, LIGHT_MIN_FALLOFF, LIGHT_MAX_FALLOFF); }
@@ -229,6 +235,9 @@ class LLFlexibleObjectData : public LLNetworkData
 	BOOL unpack(LLDataPacker &dp);
 	bool operator==(const LLNetworkData& data) const;
 	void copy(const LLNetworkData& data);
+	LLSD asLLSD() const;
+	operator LLSD() const { return asLLSD(); }
+	bool fromLLSD(LLSD& sd);
 };// end of attributes structure
 
 
@@ -245,6 +254,9 @@ class LLSculptParams : public LLNetworkData
 	/*virtual*/ BOOL unpack(LLDataPacker &dp);
 	/*virtual*/ bool operator==(const LLNetworkData& data) const;
 	/*virtual*/ void copy(const LLNetworkData& data);
+	LLSD asLLSD() const;
+	operator LLSD() const { return asLLSD(); }
+	bool fromLLSD(LLSD& sd);
 
 	void setSculptTexture(const LLUUID& id) { mSculptTexture = id; }
 	LLUUID getSculptTexture()               { return mSculptTexture; }
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index 420970a38aeca9097d5d8d5158570cc3cc02f89d..3c7cd17b925fb545958d57669539ce46aadb0809 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -72,6 +72,15 @@ const S32   SCROLL_INCREMENT_DEL = 4;	// make space for baskspacing
 const F32   AUTO_SCROLL_TIME = 0.05f;
 const F32	LABEL_HPAD = 5.f;
 
+const F32	PREEDIT_MARKER_BRIGHTNESS = 0.4f;
+const S32	PREEDIT_MARKER_GAP = 1;
+const S32	PREEDIT_MARKER_POSITION = 2;
+const S32	PREEDIT_MARKER_THICKNESS = 1;
+const F32	PREEDIT_STANDOUT_BRIGHTNESS = 0.6f;
+const S32	PREEDIT_STANDOUT_GAP = 1;
+const S32	PREEDIT_STANDOUT_POSITION = 2;
+const S32	PREEDIT_STANDOUT_THICKNESS = 2;
+
 // This is a friend class of and is only used by LLLineEditor
 class LLLineEditorRollback
 {
@@ -127,7 +136,6 @@ LLLineEditor::LLLineEditor(const LLString& name, const LLRect& rect,
 						   S32 border_thickness)
 	:
 		LLUICtrl( name, rect, TRUE, commit_callback, userdata, FOLLOWS_TOP | FOLLOWS_LEFT ),
-		mMaxLengthChars(max_length_bytes),
 		mMaxLengthBytes(max_length_bytes),
 		mCursorPos( 0 ),
 		mScrollHPos( 0 ),
@@ -223,12 +231,19 @@ LLString LLLineEditor::getWidgetTag() const
 	return LL_LINE_EDITOR_TAG;
 }
 
-void LLLineEditor::onFocusLost()
+void LLLineEditor::onFocusReceived()
 {
-	// Need to notify early when loosing focus.
-	getWindow()->allowLanguageTextInput(FALSE);
+	LLUICtrl::onFocusReceived();
+	updateAllowingLanguageInput();
+}
 
-	LLUICtrl::onFocusLost();
+void LLLineEditor::onFocusLost()
+{
+	// The call to updateAllowLanguageInput()
+	// when loosing the keyboard focus *may*
+	// indirectly invoke handleUnicodeCharHere(), 
+	// so it must be called before onCommit.
+	updateAllowingLanguageInput();
 
 	if( mCommitOnFocusLost && mText.getString() != mPrevText) 
 	{
@@ -241,6 +256,8 @@ void LLLineEditor::onFocusLost()
 	}
 
 	getWindow()->showCursorFromMouseMove();
+
+	LLUICtrl::onFocusLost();
 }
 
 void LLLineEditor::onCommit()
@@ -301,6 +318,7 @@ void LLLineEditor::setEnabled(BOOL enabled)
 {
 	mReadOnly = !enabled;
 	setTabStop(!mReadOnly);
+	updateAllowingLanguageInput();
 }
 
 
@@ -308,7 +326,6 @@ void LLLineEditor::setMaxTextLength(S32 max_text_length)
 {
 	S32 max_len = llmax(0, max_text_length);
 	mMaxLengthBytes = max_len;
-	mMaxLengthChars = max_len;
 } 
 
 void LLLineEditor::setBorderWidth(S32 left, S32 right)
@@ -337,13 +354,13 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
 	BOOL allSelected = (len > 0) && (( mSelectionStart == 0 && mSelectionEnd == len ) 
 		|| ( mSelectionStart == len && mSelectionEnd == 0 ));
 
+	// Do safe truncation so we don't split multi-byte characters
 	LLString truncated_utf8 = new_text;
 	if (truncated_utf8.size() > (U32)mMaxLengthBytes)
-	{
-		utf8str_truncate(truncated_utf8, mMaxLengthBytes);
+	{	
+		truncated_utf8 = utf8str_truncate(new_text, mMaxLengthBytes);
 	}
 	mText.assign(truncated_utf8);
-	mText.truncate(mMaxLengthChars);
 
 	if (allSelected)
 	{
@@ -735,17 +752,12 @@ void LLLineEditor::addChar(const llwchar uni_char)
 		mText.erase(getCursor(), 1);
 	}
 
-	S32 length_chars = mText.length();
-	S32 cur_bytes = mText.getString().size();;
+	S32 cur_bytes = mText.getString().size();
 	S32 new_bytes = wchar_utf8_length(new_c);
 
 	BOOL allow_char = TRUE;
 
-	// Inserting character
-	if (length_chars == mMaxLengthChars)
-	{
-		allow_char = FALSE;
-	}
+	// Check byte length limit
 	if ((new_bytes + cur_bytes) > mMaxLengthBytes)
 	{
 		allow_char = FALSE;
@@ -794,6 +806,12 @@ void LLLineEditor::setSelection(S32 start, S32 end)
 	setCursor(start);
 }
 
+void LLLineEditor::setDrawAsterixes(BOOL b)
+{
+	mDrawAsterixes = b;
+	updateAllowingLanguageInput();
+}
+
 S32 LLLineEditor::prevWordPos(S32 cursorPos) const
 {
 	const LLWString& wtext = mText.getWString();
@@ -1022,13 +1040,11 @@ void LLLineEditor::paste()
 
 			// Insert the string
 
-			//check to see that the size isn't going to be larger than the
-			//max number of characters or bytes
+			// Check to see that the size isn't going to be larger than the max number of bytes
 			U32 available_bytes = mMaxLengthBytes - wstring_utf8_length(mText);
-			size_t available_chars = mMaxLengthChars - mText.length();
 
 			if ( available_bytes < (U32) wstring_utf8_length(clean_string) )
-			{
+			{	// Doesn't all fit
 				llwchar current_symbol = clean_string[0];
 				U32 wchars_that_fit = 0;
 				U32 total_bytes = wchar_utf8_length(current_symbol);
@@ -1043,20 +1059,13 @@ void LLLineEditor::paste()
 					current_symbol = clean_string[++wchars_that_fit];
 					total_bytes += wchar_utf8_length(current_symbol);
 				}
-
+				// Truncate the clean string at the limit of what will fit
 				clean_string = clean_string.substr(0, wchars_that_fit);
 				reportBadKeystroke();
 			}
-			else if (available_chars < clean_string.length())
-			{
-				// We can't insert all the characters.  Insert as many as possible
-				// but make a noise to alert the user. JC
-				clean_string = clean_string.substr(0, available_chars);
-				reportBadKeystroke();
-			}
 
 			mText.insert(getCursor(), clean_string);
-			setCursor(llmin(mMaxLengthChars, getCursor() + (S32)clean_string.length()));
+			setCursor( getCursor() + (S32)clean_string.length() );
 			deselect();
 
 			// Validate new string and rollback the if needed.
@@ -1523,6 +1532,41 @@ void LLLineEditor::draw()
 	}
 	LLColor4 label_color = mTentativeFgColor;
 
+	if (hasPreeditString())
+	{
+		// Draw preedit markers.  This needs to be before drawing letters.
+		for (U32 i = 0; i < mPreeditStandouts.size(); i++)
+		{
+			const S32 preedit_left = mPreeditPositions[i];
+			const S32 preedit_right = mPreeditPositions[i + 1];
+			if (preedit_right > mScrollHPos)
+			{
+				S32 preedit_pixels_left = findPixelNearestPos(llmax(preedit_left, mScrollHPos) - getCursor());
+				S32 preedit_pixels_right = llmin(findPixelNearestPos(preedit_right - getCursor()), background.mRight);
+				if (preedit_pixels_left >= background.mRight)
+				{
+					break;
+				}
+				if (mPreeditStandouts[i])
+				{
+					gl_rect_2d(preedit_pixels_left + PREEDIT_STANDOUT_GAP,
+						background.mBottom + PREEDIT_STANDOUT_POSITION,
+						preedit_pixels_right - PREEDIT_STANDOUT_GAP - 1,
+						background.mBottom + PREEDIT_STANDOUT_POSITION - PREEDIT_STANDOUT_THICKNESS,
+						(text_color * PREEDIT_STANDOUT_BRIGHTNESS + bg_color * (1 - PREEDIT_STANDOUT_BRIGHTNESS)).setAlpha(1.0f));
+				}
+				else
+				{
+					gl_rect_2d(preedit_pixels_left + PREEDIT_MARKER_GAP,
+						background.mBottom + PREEDIT_MARKER_POSITION,
+						preedit_pixels_right - PREEDIT_MARKER_GAP - 1,
+						background.mBottom + PREEDIT_MARKER_POSITION - PREEDIT_MARKER_THICKNESS,
+						(text_color * PREEDIT_MARKER_BRIGHTNESS + bg_color * (1 - PREEDIT_MARKER_BRIGHTNESS)).setAlpha(1.0f));
+				}
+			}
+		}
+	}
+
 	S32 rendered_text = 0;
 	F32 rendered_pixels_right = (F32)mMinHPixels;
 	F32 text_bottom = (F32)background.mBottom + (F32)UI_LINEEDITOR_V_PAD;
@@ -1677,7 +1721,7 @@ void LLLineEditor::draw()
 
 
 // Returns the local screen space X coordinate associated with the text cursor position.
-S32 LLLineEditor::findPixelNearestPos(const S32 cursor_offset)
+S32 LLLineEditor::findPixelNearestPos(const S32 cursor_offset) const
 {
 	S32 dpos = getCursor() - mScrollHPos + cursor_offset;
 	S32 result = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos, dpos) + mMinHPixels;
@@ -1715,7 +1759,7 @@ void LLLineEditor::setFocus( BOOL new_state )
 
 	if (!new_state)
 	{
-		getWindow()->allowLanguageTextInput(FALSE);
+		getWindow()->allowLanguageTextInput(this, FALSE);
 	}
 
 
@@ -1757,7 +1801,7 @@ void LLLineEditor::setFocus( BOOL new_state )
 		// fine on 1.15.0.2, since all prevalidate func reject any
 		// non-ASCII characters.  I'm not sure on future versions,
 		// however.
-		getWindow()->allowLanguageTextInput(mPrevalidateFunc == NULL);
+		getWindow()->allowLanguageTextInput(this, mPrevalidateFunc == NULL);
 	}
 }
 
@@ -1776,6 +1820,12 @@ void LLLineEditor::setRect(const LLRect& rect)
 	}
 }
 
+void LLLineEditor::setPrevalidate(BOOL (*func)(const LLWString &))
+{
+	mPrevalidateFunc = func;
+	updateAllowingLanguageInput();
+}
+
 // Limits what characters can be used to [1234567890.-] with [-] only valid in the first position.
 // Does NOT ensure that the string is a well-formed number--that's the job of post-validation--for
 // the simple reasons that intermediate states may be invalid even if the final result is valid.
@@ -2336,6 +2386,239 @@ BOOL LLLineEditor::setLabelArg( const LLString& key, const LLStringExplicit& tex
 	return TRUE;
 }
 
+
+void LLLineEditor::updateAllowingLanguageInput()
+{
+	// Allow Language Text Input only when this LineEditor has
+	// no prevalidate function attached (as long as other criteria
+	// common to LLTextEditor).  This criterion works
+	// fine on 1.15.0.2, since all prevalidate func reject any
+	// non-ASCII characters.  I'm not sure on future versions,
+	// however...
+	if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL)
+	{
+		getWindow()->allowLanguageTextInput(this, TRUE);
+	}
+	else
+	{
+		getWindow()->allowLanguageTextInput(this, FALSE);
+	}
+}
+
+BOOL LLLineEditor::hasPreeditString() const
+{
+	return (mPreeditPositions.size() > 1);
+}
+
+void LLLineEditor::resetPreedit()
+{
+	if (hasPreeditString())
+	{
+		const S32 preedit_pos = mPreeditPositions.front();
+		mText.erase(preedit_pos, mPreeditPositions.back() - preedit_pos);
+		mText.insert(preedit_pos, mPreeditOverwrittenWString);
+		setCursor(preedit_pos);
+		
+		mPreeditWString.clear();
+		mPreeditOverwrittenWString.clear();
+		mPreeditPositions.clear();
+
+		mKeystrokeTimer.reset();
+		if (mKeystrokeCallback)
+		{
+			mKeystrokeCallback(this, mCallbackUserData);
+		}
+	}
+}
+
+void LLLineEditor::updatePreedit(const LLWString &preedit_string,
+		const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position)
+{
+	// Just in case.
+	if (mReadOnly)
+	{
+		return;
+	}
+
+	if (hasSelection())
+	{
+		if (hasPreeditString())
+		{
+			llwarns << "Preedit and selection!" << llendl;
+			deselect();
+		}
+		else
+		{
+			deleteSelection();
+		}
+	}
+
+	S32 insert_preedit_at = getCursor();
+	if (hasPreeditString())
+	{
+		insert_preedit_at = mPreeditPositions.front();
+		//mText.replace(insert_preedit_at, mPreeditPositions.back() - insert_preedit_at, mPreeditOverwrittenWString);
+		mText.erase(insert_preedit_at, mPreeditPositions.back() - insert_preedit_at);
+		mText.insert(insert_preedit_at, mPreeditOverwrittenWString);
+	}
+
+	mPreeditWString = preedit_string;
+	mPreeditPositions.resize(preedit_segment_lengths.size() + 1);
+	S32 position = insert_preedit_at;
+	for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++)
+	{
+		mPreeditPositions[i] = position;
+		position += preedit_segment_lengths[i];
+	}
+	mPreeditPositions.back() = position;
+	if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode())
+	{
+		mPreeditOverwrittenWString.assign( LLWString( mText, insert_preedit_at, mPreeditWString.length() ) );
+		mText.erase(insert_preedit_at, mPreeditWString.length());
+	}
+	else
+	{
+		mPreeditOverwrittenWString.clear();
+	}
+	mText.insert(insert_preedit_at, mPreeditWString);
+
+	mPreeditStandouts = preedit_standouts;
+
+	setCursor(position);
+	setCursor(mPreeditPositions.front() + caret_position);
+
+	// Update of the preedit should be caused by some key strokes.
+	mKeystrokeTimer.reset();
+	if( mKeystrokeCallback )
+	{
+		mKeystrokeCallback( this, mCallbackUserData );
+	}
+}
+
+BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const
+{
+	if (control)
+	{
+		LLRect control_rect_screen;
+		localRectToScreen(mRect, &control_rect_screen);
+		LLUI::screenRectToGL(control_rect_screen, control);
+	}
+
+	S32 preedit_left_column, preedit_right_column;
+	if (hasPreeditString())
+	{
+		preedit_left_column = mPreeditPositions.front();
+		preedit_right_column = mPreeditPositions.back();
+	}
+	else
+	{
+		preedit_left_column = preedit_right_column = getCursor();
+	}
+	if (preedit_right_column < mScrollHPos)
+	{
+		// This should not occure...
+		return FALSE;
+	}
+
+	const S32 query = (query_offset >= 0 ? preedit_left_column + query_offset : getCursor());
+	if (query < mScrollHPos || query < preedit_left_column || query > preedit_right_column)
+	{
+		return FALSE;
+	}
+
+	if (coord)
+	{
+		S32 query_local = findPixelNearestPos(query - getCursor());
+		S32 query_screen_x, query_screen_y;
+		localPointToScreen(query_local, mRect.getHeight() / 2, &query_screen_x, &query_screen_y);
+		LLUI::screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY);
+	}
+
+	if (bounds)
+	{
+		S32 preedit_left_local = findPixelNearestPos(llmax(preedit_left_column, mScrollHPos) - getCursor());
+		S32 preedit_right_local = llmin(findPixelNearestPos(preedit_right_column - getCursor()), mRect.getWidth() - mBorderThickness);
+		if (preedit_left_local > preedit_right_local)
+		{
+			// Is this condition possible?
+			preedit_right_local = preedit_left_local;
+		}
+
+		LLRect preedit_rect_local(preedit_left_local, mRect.getHeight(), preedit_right_local, 0);
+		LLRect preedit_rect_screen;
+		localRectToScreen(preedit_rect_local, &preedit_rect_screen);
+		LLUI::screenRectToGL(preedit_rect_screen, bounds);
+	}
+
+	return TRUE;
+}
+
+void LLLineEditor::getPreeditRange(S32 *position, S32 *length) const
+{
+	if (hasPreeditString())
+	{
+		*position = mPreeditPositions.front();
+		*length = mPreeditPositions.back() - mPreeditPositions.front();
+	}
+	else
+	{
+		*position = mCursorPos;
+		*length = 0;
+	}
+}
+
+void LLLineEditor::getSelectionRange(S32 *position, S32 *length) const
+{
+	if (hasSelection())
+	{
+		*position = llmin(mSelectionStart, mSelectionEnd);
+		*length = llabs(mSelectionStart - mSelectionEnd);
+	}
+	else
+	{
+		*position = mCursorPos;
+		*length = 0;
+	}
+}
+
+void LLLineEditor::markAsPreedit(S32 position, S32 length)
+{
+	deselect();
+	setCursor(position);
+	if (hasPreeditString())
+	{
+		llwarns << "markAsPreedit invoked when hasPreeditString is true." << llendl;
+	}
+	mPreeditWString.assign( LLWString( mText.getWString(), position, length ) );
+	if (length > 0)
+	{
+		mPreeditPositions.resize(2);
+		mPreeditPositions[0] = position;
+		mPreeditPositions[1] = position + length;
+		mPreeditStandouts.resize(1);
+		mPreeditStandouts[0] = FALSE;
+	}
+	else
+	{
+		mPreeditPositions.clear();
+		mPreeditStandouts.clear();
+	}
+	if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode())
+	{
+		mPreeditOverwrittenWString = mPreeditWString;
+	}
+	else
+	{
+		mPreeditOverwrittenWString.clear();
+	}
+}
+
+S32 LLLineEditor::getPreeditFontSize() const
+{
+	return llround(mGLFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
+}
+
+
 LLSearchEditor::LLSearchEditor(const LLString& name, 
 		const LLRect& rect,
 		S32 max_length_bytes,
diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h
index f1b9fbe33ee278bda25da7ebfdf15d60f56341d8..a019353856ae3afb037ab8ea79187d8192e27cff 100644
--- a/indra/llui/lllineeditor.h
+++ b/indra/llui/lllineeditor.h
@@ -53,6 +53,8 @@
 #include "lluistring.h"
 #include "llviewborder.h"
 
+#include "llpreeditor.h"
+
 class LLFontGL;
 class LLLineEditorRollback;
 class LLButton;
@@ -63,7 +65,7 @@ typedef BOOL (*LLLinePrevalidateFunc)(const LLWString &wstr);
 // Classes
 //
 class LLLineEditor
-: public LLUICtrl, public LLEditMenuHandler
+: public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor
 {
 	friend class LLLineEditorRollback;
 
@@ -120,6 +122,7 @@ class LLLineEditor
 	// view overrides
 	virtual void	draw();
 	virtual void	reshape(S32 width,S32 height,BOOL called_from_parent=TRUE);
+	virtual void	onFocusReceived();
 	virtual void	onFocusLost();
 	virtual void	setEnabled(BOOL enabled);
 
@@ -146,7 +149,7 @@ class LLLineEditor
 	const LLWString& getWText() const	{ return mText.getWString(); }
 	S32				getLength() const	{ return mText.length(); }
 
-	S32				getCursor()		{ return mCursorPos; }
+	S32				getCursor()	const	{ return mCursorPos; }
 	void			setCursor( S32 pos );
 	void			setCursorToEnd();
 
@@ -177,13 +180,13 @@ class LLLineEditor
 	void			setIgnoreTab(BOOL b)			{ mIgnoreTab = b; }
 	void			setPassDelete(BOOL b)			{ mPassDelete = b; }
 
-	void			setDrawAsterixes(BOOL b)		{ mDrawAsterixes = b; }
+	void			setDrawAsterixes(BOOL b);
 
 	// get the cursor position of the beginning/end of the prev/next word in the text
 	S32				prevWordPos(S32 cursorPos) const;
 	S32				nextWordPos(S32 cursorPos) const;
 
-	BOOL			hasSelection() { return (mSelectionStart != mSelectionEnd); }
+	BOOL			hasSelection() const { return (mSelectionStart != mSelectionEnd); }
 	void			startSelection();
 	void			endSelection();
 	void			extendSelection(S32 new_cursor_pos);
@@ -199,7 +202,7 @@ class LLLineEditor
 
 	static BOOL		isPartOfWord(llwchar c);
 	// Prevalidation controls which keystrokes can affect the editor
-	void			setPrevalidate( BOOL (*func)(const LLWString &) ) { mPrevalidateFunc = func; }
+	void			setPrevalidate( BOOL (*func)(const LLWString &) );
 	static BOOL		prevalidateFloat(const LLWString &str );
 	static BOOL		prevalidateInt(const LLWString &str );
 	static BOOL		prevalidatePositiveS32(const LLWString &str);
@@ -221,7 +224,7 @@ class LLLineEditor
 	void			addChar(const llwchar c);
 	void			setCursorAtLocalPos(S32 local_mouse_x);
 
-	S32				findPixelNearestPos(S32 cursor_offset = 0);
+	S32				findPixelNearestPos(S32 cursor_offset = 0) const;
 	void			reportBadKeystroke();
 
 	BOOL			handleSpecialKey(KEY key, MASK mask);
@@ -229,6 +232,19 @@ class LLLineEditor
 	BOOL			handleControlKey(KEY key, MASK mask);
 	S32				handleCommitKey(KEY key, MASK mask);
 
+protected:
+	void			updateAllowingLanguageInput();
+	BOOL			hasPreeditString() const;
+	// Implementation (overrides) of LLPreeditor
+	virtual void	resetPreedit();
+	virtual void	updatePreedit(const LLWString &preedit_string,
+						const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position);
+	virtual void	markAsPreedit(S32 position, S32 length);
+	virtual void	getPreeditRange(S32 *position, S32 *length) const;
+	virtual void	getSelectionRange(S32 *position, S32 *length) const;
+	virtual BOOL	getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const;
+	virtual S32		getPreeditFontSize() const;
+
 protected:
 	LLUIString		mText;					// The string being edited.
 	LLString		mPrevText;				// Saved string for 'ESC' revert
@@ -241,8 +257,7 @@ class LLLineEditor
 
 	LLViewBorder* mBorder;
 	const LLFontGL*	mGLFont;
-	S32			mMaxLengthChars;			// Max number of characters
-	S32			mMaxLengthBytes;			// Max length of the UTF8 string.
+	S32			mMaxLengthBytes;			// Max length of the UTF8 string in bytes
 	S32			mCursorPos;					// I-beam is just after the mCursorPos-th character.
 	S32			mScrollHPos;				// Horizontal offset from the start of mText.  Used for scrolling.
 	LLFrameTimer mScrollTimer;
@@ -288,6 +303,11 @@ class LLLineEditor
 	BOOL		mPassDelete;
 
 	BOOL		mReadOnly;
+
+	LLWString	mPreeditWString;
+	LLWString	mPreeditOverwrittenWString;
+	std::vector<S32> mPreeditPositions;
+	LLPreeditor::standouts_t mPreeditStandouts;
 };
 
 
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index d150f8954ef262d365b79a77ceabd6ae26bd9fb6..46f9f515d7176e2dd59456c6fa968b65ceab738a 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -632,7 +632,7 @@ class LLMenuItemSeparatorGL : public LLMenuItemGL
 };
 
 LLMenuItemSeparatorGL::LLMenuItemSeparatorGL( const LLString &name ) :
-	LLMenuItemGL( SEPARATOR_NAME, SEPARATOR_LABEL )
+	LLMenuItemGL( name, SEPARATOR_LABEL )
 {
 }
 
@@ -2832,7 +2832,7 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa
 	while(1)
 	{
 		// skip separators and disabled items
-		if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getName() != SEPARATOR_NAME)
+		if ((*next_item_iter)->getEnabled() && (*next_item_iter)->getType() != SEPARATOR_NAME)
 		{
 			if (cur_item)
 			{
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index efd42455e5b836c31098c722badc4f8879aa0d5e..8bd7b1509fca2688a3084146d35d1412a75b42dd 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -174,7 +174,7 @@ BOOL LLTextBox::handleHover(S32 x, S32 y, MASK mask)
 		mHasHover = TRUE; // This should be set every frame during a hover.
 		return TRUE;
 	}
-	return FALSE;
+	return LLView::handleHover(x,y,mask);
 }
 
 void LLTextBox::setText(const LLStringExplicit& text)
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index d08997c3eddae18421f3e0287e534fc453512323..5c8b7c7281835c5592598b9f451b8a5f265f5b8e 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -79,6 +79,15 @@ const F32	CURSOR_FLASH_DELAY = 1.0f;  // in seconds
 const S32	CURSOR_THICKNESS = 2;
 const S32	SPACES_PER_TAB = 4;
 
+const F32	PREEDIT_MARKER_BRIGHTNESS = 0.4f;
+const S32	PREEDIT_MARKER_GAP = 1;
+const S32	PREEDIT_MARKER_POSITION = 2;
+const S32	PREEDIT_MARKER_THICKNESS = 1;
+const F32	PREEDIT_STANDOUT_BRIGHTNESS = 0.6f;
+const S32	PREEDIT_STANDOUT_GAP = 1;
+const S32	PREEDIT_STANDOUT_POSITION = 2;
+const S32	PREEDIT_STANDOUT_THICKNESS = 2;
+
 LLColor4 LLTextEditor::mLinkColor = LLColor4::blue;
 void (* LLTextEditor::mURLcallback)(const char*)              = NULL;
 bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&)   = NULL;
@@ -274,14 +283,14 @@ class LLTextCmdRemove : public LLTextCmd
 LLTextEditor::LLTextEditor(	
 	const LLString& name, 
 	const LLRect& rect, 
-	S32 max_length, 
+	S32 max_length,						// In bytes
 	const LLString &default_text, 
 	const LLFontGL* font,
 	BOOL allow_embedded_items)
 	:	
 	LLUICtrl( name, rect, TRUE, NULL, NULL, FOLLOWS_TOP | FOLLOWS_LEFT ),
 	mTextIsUpToDate(TRUE),
-	mMaxTextLength( max_length ),
+	mMaxTextByteLength( max_length ),
 	mBaseDocIsPristine(TRUE),
 	mPristineCmd( NULL ),
 	mLastCmd( NULL ),
@@ -510,13 +519,27 @@ BOOL LLTextEditor::isPartOfWord(llwchar c) { return (c == '_') || isalnum(c); }
 
 
 
-void LLTextEditor::truncate()
+BOOL LLTextEditor::truncate()
 {
-	if (mWText.size() > (size_t)mMaxTextLength)
-	{
-		LLWString::truncate(mWText, mMaxTextLength);
-		mTextIsUpToDate = FALSE;
+	BOOL did_truncate = FALSE;
+
+	// First rough check - if we're less than 1/4th the size, we're OK
+	if (mWText.size() >= (size_t) (mMaxTextByteLength / 4))
+	{	
+		// Have to check actual byte size
+		S32 utf8_byte_size = wstring_utf8_length( mWText );
+		if ( utf8_byte_size > mMaxTextByteLength )
+		{
+			// Truncate safely in UTF-8
+			std::string temp_utf8_text = wstring_to_utf8str( mWText );
+			temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength );
+			mWText = utf8str_to_wstring( temp_utf8_text );
+			mTextIsUpToDate = FALSE;
+			did_truncate = TRUE;
+		}
 	}
+
+	return did_truncate;
 }
 
 void LLTextEditor::setText(const LLStringExplicit &utf8str)
@@ -750,12 +773,12 @@ S32 LLTextEditor::nextWordPos(S32 cursorPos) const
 	return cursorPos;
 }
 
-S32 LLTextEditor::getLineCount()
+S32 LLTextEditor::getLineCount() const
 {
 	return mLineStartList.size();
 }
 
-S32 LLTextEditor::getLineStart( S32 line )
+S32 LLTextEditor::getLineStart( S32 line ) const
 {
 	S32 num_lines = getLineCount();
 	if (num_lines == 0)
@@ -1604,7 +1627,7 @@ void LLTextEditor::removeChar()
 // Add a single character to the text
 S32 LLTextEditor::addChar(S32 pos, llwchar wc)
 {
-	if ((S32)mWText.length() == mMaxTextLength)
+	if ( (wstring_utf8_length( mWText ) + wchar_utf8_length( wc ))  >= mMaxTextByteLength)
 	{
 		make_ui_sound("UISndBadKeystroke");
 		return 0;
@@ -2490,11 +2513,16 @@ void LLTextEditor::redo()
 	}
 }
 
+void LLTextEditor::onFocusReceived()
+{
+	LLUICtrl::onFocusReceived();
+	updateAllowingLanguageInput();
+}
 
 // virtual, from LLView
 void LLTextEditor::onFocusLost()
 {
-	getWindow()->allowLanguageTextInput(FALSE);
+	updateAllowingLanguageInput();
 
 	// Route menu back to the default
  	if( gEditMenuHandler == this )
@@ -2521,6 +2549,7 @@ void LLTextEditor::setEnabled(BOOL enabled)
 	{
 		mReadOnly = read_only;
 		updateSegments();
+		updateAllowingLanguageInput();
 	}
 }
 
@@ -2825,6 +2854,100 @@ void LLTextEditor::drawCursor()
 	}
 }
 
+void LLTextEditor::drawPreeditMarker()
+{
+	if (!hasPreeditString())
+	{
+		return;
+	}
+
+	const llwchar *text = mWText.c_str();
+	const S32 text_len = getLength();
+	const S32 num_lines = getLineCount();
+
+	S32 cur_line = mScrollbar->getDocPos();
+	if (cur_line >= num_lines)
+	{
+		return;
+	}
+		
+	const S32 line_height = llround( mGLFont->getLineHeight() );
+
+	S32 line_start = getLineStart(cur_line);
+	S32 line_y = mTextRect.mTop - line_height;
+	while((mTextRect.mBottom <= line_y) && (num_lines > cur_line))
+	{
+		S32 next_start = -1;
+		S32 line_end = text_len;
+
+		if ((cur_line + 1) < num_lines)
+		{
+			next_start = getLineStart(cur_line + 1);
+			line_end = next_start;
+		}
+		if ( text[line_end-1] == '\n' )
+		{
+			--line_end;
+		}
+
+		// Does this line contain preedits?
+		if (line_start >= mPreeditPositions.back())
+		{
+			// We have passed the preedits.
+			break;
+		}
+		if (line_end > mPreeditPositions.front())
+		{
+			for (U32 i = 0; i < mPreeditStandouts.size(); i++)
+			{
+				S32 left = mPreeditPositions[i];
+				S32 right = mPreeditPositions[i + 1];
+				if (right <= line_start || left >= line_end)
+				{
+					continue;
+				}
+
+				S32 preedit_left = mTextRect.mLeft;
+				if (left > line_start)
+				{
+					preedit_left += mGLFont->getWidth(text, line_start, left - line_start, mAllowEmbeddedItems);
+				}
+				S32 preedit_right = mTextRect.mLeft;
+				if (right < line_end)
+				{
+					preedit_right += mGLFont->getWidth(text, line_start, right - line_start, mAllowEmbeddedItems);
+				}
+				else
+				{
+					preedit_right += mGLFont->getWidth(text, line_start, line_end - line_start, mAllowEmbeddedItems);
+				}
+
+				if (mPreeditStandouts[i])
+				{
+					gl_rect_2d(preedit_left + PREEDIT_STANDOUT_GAP,
+							line_y + PREEDIT_STANDOUT_POSITION,
+							preedit_right - PREEDIT_STANDOUT_GAP - 1,
+							line_y + PREEDIT_STANDOUT_POSITION - PREEDIT_STANDOUT_THICKNESS,
+							(mCursorColor * PREEDIT_STANDOUT_BRIGHTNESS + mWriteableBgColor * (1 - PREEDIT_STANDOUT_BRIGHTNESS)).setAlpha(1.0f));
+				}
+				else
+				{
+					gl_rect_2d(preedit_left + PREEDIT_MARKER_GAP,
+							line_y + PREEDIT_MARKER_POSITION,
+							preedit_right - PREEDIT_MARKER_GAP - 1,
+							line_y + PREEDIT_MARKER_POSITION - PREEDIT_MARKER_THICKNESS,
+							(mCursorColor * PREEDIT_MARKER_BRIGHTNESS + mWriteableBgColor * (1 - PREEDIT_MARKER_BRIGHTNESS)).setAlpha(1.0f));
+				}
+			}
+		}
+
+		// move down one line
+		line_y -= line_height;
+		line_start = next_start;
+		cur_line++;
+	}
+}
+
 
 void LLTextEditor::drawText()
 {
@@ -3025,6 +3148,7 @@ void LLTextEditor::draw()
 
 			drawBackground();
 			drawSelectionBackground();
+			drawPreeditMarker();
 			drawText();
 			drawCursor();
 
@@ -3067,10 +3191,10 @@ void LLTextEditor::setFocus( BOOL new_state )
 	// Don't change anything if the focus state didn't change
 	if (new_state == old_state) return;
 
-	// Notify early if we are loosing focus.
+	// Notify early if we are losing focus.
 	if (!new_state)
 	{
-		getWindow()->allowLanguageTextInput(FALSE);
+		getWindow()->allowLanguageTextInput(this, FALSE);
 	}
 
 	LLUICtrl::setFocus( new_state );
@@ -3093,12 +3217,6 @@ void LLTextEditor::setFocus( BOOL new_state )
 
 		endSelection();
 	}
-
-	// Notify late if we are gaining focus.
-	if (new_state && !mReadOnly)
-	{
-		getWindow()->allowLanguageTextInput(TRUE);
-	}
 }
 
 BOOL LLTextEditor::acceptsTextInput() const
@@ -3540,22 +3658,20 @@ void LLTextEditor::removeTextFromEnd(S32 num_chars)
 
 S32 LLTextEditor::insertStringNoUndo(const S32 pos, const LLWString &wstr)
 {
-	S32 len = mWText.length();
-	S32 s_len = wstr.length();
-	S32 new_len = len + s_len;
-	if( new_len > mMaxTextLength )
-	{
-		new_len = mMaxTextLength;
+	S32 old_len = mWText.length();		// length() returns character length
+	S32 insert_len = wstr.length();
 
+	mWText.insert(pos, wstr);
+	mTextIsUpToDate = FALSE;
+
+	if ( truncate() )
+	{
 		// The user's not getting everything he's hoping for
 		make_ui_sound("UISndBadKeystroke");
+		insert_len = mWText.length() - old_len;
 	}
 
-	mWText.insert(pos, wstr);
-	mTextIsUpToDate = FALSE;
-	truncate();
-
-	return new_len - len;
+	return insert_len;
 }
 
 S32 LLTextEditor::removeStringNoUndo(S32 pos, S32 length)
@@ -3920,7 +4036,7 @@ BOOL LLTextEditor::importBuffer(const LLString& buffer )
 		return FALSE;
 	}
 
-	if( text_len > mMaxTextLength )
+	if( text_len > mMaxTextByteLength )
 	{
 		llwarns << "Invalid Linden text length: " << text_len << llendl;
 		return FALSE;
@@ -4281,3 +4397,262 @@ BOOL LLTextEditor::findHTML(const LLString &line, S32 *begin, S32 *end)
 	}
 	return matched;
 }
+
+
+
+void LLTextEditor::updateAllowingLanguageInput()
+{
+	if (hasFocus() && !mReadOnly)
+	{
+		getWindow()->allowLanguageTextInput(this, TRUE);
+	}
+	else
+	{
+		getWindow()->allowLanguageTextInput(this, FALSE);
+	}
+}
+
+// Preedit is managed off the undo/redo command stack.
+
+BOOL LLTextEditor::hasPreeditString() const
+{
+	return (mPreeditPositions.size() > 1);
+}
+
+void LLTextEditor::resetPreedit()
+{
+	if (hasPreeditString())
+	{
+		mCursorPos = mPreeditPositions.front();
+		removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos);
+		insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString);
+
+		mPreeditWString.clear();
+		mPreeditOverwrittenWString.clear();
+		mPreeditPositions.clear();
+
+		updateLineStartList();
+		setCursorPos(mCursorPos);
+		// updateScrollFromCursor();
+	}
+}
+
+void LLTextEditor::updatePreedit(const LLWString &preedit_string,
+		const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position)
+{
+	// Just in case.
+	if (mReadOnly)
+	{
+		return;
+	}
+
+	if (hasSelection())
+	{
+		if (hasPreeditString())
+		{
+			llwarns << "Preedit and selection!" << llendl;
+			deselect();
+		}
+		else
+		{
+			deleteSelection(TRUE);
+		}
+	}
+
+	getWindow()->hideCursorUntilMouseMove();
+
+	S32 insert_preedit_at = mCursorPos;
+	if (hasPreeditString())
+	{
+		insert_preedit_at = mPreeditPositions.front();
+		removeStringNoUndo(insert_preedit_at, mPreeditPositions.back() - insert_preedit_at);
+		insertStringNoUndo(insert_preedit_at, mPreeditOverwrittenWString);
+	}
+
+	mPreeditWString = preedit_string;
+	mPreeditPositions.resize(preedit_segment_lengths.size() + 1);
+	S32 position = insert_preedit_at;
+	for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++)
+	{
+		mPreeditPositions[i] = position;
+		position += preedit_segment_lengths[i];
+	}
+	mPreeditPositions.back() = position;
+
+	if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode())
+	{
+		mPreeditOverwrittenWString = getWSubString(insert_preedit_at, mPreeditWString.length());
+		removeStringNoUndo(insert_preedit_at, mPreeditWString.length());
+	}
+	else
+	{
+		mPreeditOverwrittenWString.clear();
+	}
+	insertStringNoUndo(insert_preedit_at, mPreeditWString);
+
+	mPreeditStandouts = preedit_standouts;
+
+	updateLineStartList();
+	setCursorPos(insert_preedit_at + caret_position);
+	// updateScrollFromCursor();
+
+	// Update of the preedit should be caused by some key strokes.
+	mKeystrokeTimer.reset();
+}
+
+BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const
+{
+	if (control)
+	{
+		LLRect control_rect_screen;
+		localRectToScreen(mTextRect, &control_rect_screen);
+		LLUI::screenRectToGL(control_rect_screen, control);
+	}
+
+	S32 preedit_left_position, preedit_right_position;
+	if (hasPreeditString())
+	{
+		preedit_left_position = mPreeditPositions.front();
+		preedit_right_position = mPreeditPositions.back();
+	}
+	else
+	{
+		preedit_left_position = preedit_right_position = mCursorPos;
+	}
+
+	const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos);
+	if (query < preedit_left_position || query > preedit_right_position)
+	{
+		return FALSE;
+	}
+
+	const S32 first_visible_line = mScrollbar->getDocPos();
+	if (query < getLineStart(first_visible_line))
+	{
+		return FALSE;
+	}
+
+	S32 current_line = first_visible_line;
+	S32 current_line_start, current_line_end;
+	for (;;)
+	{
+		current_line_start = getLineStart(current_line);
+		current_line_end = getLineStart(current_line + 1);
+		if (query >= current_line_start && query < current_line_end)
+		{
+			break;
+		}
+		if (current_line_start == current_line_end)
+		{
+			// We have reached on the last line.  The query position must be here.
+			break;
+		}
+		current_line++;
+	}
+
+	const llwchar * const text = mWText.c_str();
+	const S32 line_height = llround(mGLFont->getLineHeight());
+
+	if (coord)
+	{
+		const S32 query_x = mTextRect.mLeft + mGLFont->getWidth(text, current_line_start, query - current_line_start, mAllowEmbeddedItems);
+		const S32 query_y = mTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2;
+		S32 query_screen_x, query_screen_y;
+		localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y);
+		LLUI::screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY);
+	}
+
+	if (bounds)
+	{
+		S32 preedit_left = mTextRect.mLeft;
+		if (preedit_left_position > current_line_start)
+		{
+			preedit_left += mGLFont->getWidth(text, current_line_start, preedit_left_position - current_line_start, mAllowEmbeddedItems);
+		}
+
+		S32 preedit_right = mTextRect.mLeft;
+		if (preedit_right_position < current_line_end)
+		{
+			preedit_right += mGLFont->getWidth(text, current_line_start, preedit_right_position - current_line_start, mAllowEmbeddedItems);
+		}
+		else
+		{
+			preedit_right += mGLFont->getWidth(text, current_line_start, current_line_end - current_line_start, mAllowEmbeddedItems);
+		}
+
+		const S32 preedit_top = mTextRect.mTop - (current_line - first_visible_line) * line_height;
+		const S32 preedit_bottom = preedit_top - line_height;
+
+		const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom);
+		LLRect preedit_rect_screen;
+		localRectToScreen(preedit_rect_local, &preedit_rect_screen);
+		LLUI::screenRectToGL(preedit_rect_screen, bounds);
+	}
+
+	return TRUE;
+}
+
+void LLTextEditor::getSelectionRange(S32 *position, S32 *length) const
+{
+	if (hasSelection())
+	{
+		*position = llmin(mSelectionStart, mSelectionEnd);
+		*length = llabs(mSelectionStart - mSelectionEnd);
+	}
+	else
+	{
+		*position = mCursorPos;
+		*length = 0;
+	}
+}
+
+void LLTextEditor::getPreeditRange(S32 *position, S32 *length) const
+{
+	if (hasPreeditString())
+	{
+		*position = mPreeditPositions.front();
+		*length = mPreeditPositions.back() - mPreeditPositions.front();
+	}
+	else
+	{
+		*position = mCursorPos;
+		*length = 0;
+	}
+}
+
+void LLTextEditor::markAsPreedit(S32 position, S32 length)
+{
+	deselect();
+	setCursorPos(position);
+	if (hasPreeditString())
+	{
+		llwarns << "markAsPreedit invoked when hasPreeditString is true." << llendl;
+	}
+	mPreeditWString = LLWString( mWText, position, length );
+	if (length > 0)
+	{
+		mPreeditPositions.resize(2);
+		mPreeditPositions[0] = position;
+		mPreeditPositions[1] = position + length;
+		mPreeditStandouts.resize(1);
+		mPreeditStandouts[0] = FALSE;
+	}
+	else
+	{
+		mPreeditPositions.clear();
+		mPreeditStandouts.clear();
+	}
+	if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode())
+	{
+		mPreeditOverwrittenWString = mPreeditWString;
+	}
+	else
+	{
+		mPreeditOverwrittenWString.clear();
+	}
+}
+
+S32 LLTextEditor::getPreeditFontSize() const
+{
+	return llround(mGLFont->getLineHeight() * LLUI::sGLScaleFactor.mV[VY]);
+}
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index d38accca8f9f3d50f185c19a2bb2f7f8cd75fc5b..7049de7b89692dcb09b44ae8340f513a5c4b76fe 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -43,6 +43,8 @@
 #include "lleditmenuhandler.h"
 #include "lldarray.h"
 
+#include "llpreeditor.h"
+
 class LLFontGL;
 class LLScrollbar;
 class LLViewBorder;
@@ -64,7 +66,7 @@ const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1;
 class LLTextSegment;
 class LLTextCmd;
 
-class LLTextEditor : public LLUICtrl, LLEditMenuHandler
+class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor
 {
 	friend class LLTextCmd;
 public:
@@ -104,6 +106,7 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 	// view overrides
 	virtual void	reshape(S32 width, S32 height, BOOL called_from_parent);
 	virtual void	draw();
+	virtual void	onFocusReceived();
 	virtual void	onFocusLost();
 	virtual void	setEnabled(BOOL enabled);
 
@@ -234,7 +237,8 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 	void			setText(const LLStringExplicit &utf8str);
 	void			setWText(const LLWString &wtext);
 	
-	S32				getMaxLength() const 			{ return mMaxTextLength; }
+	// Returns byte length limit
+	S32				getMaxLength() const 			{ return mMaxTextByteLength; }
 
 	// Change cursor
 	void			startOfLine();
@@ -259,6 +263,7 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 	void			drawCursor();
 	void			drawText();
 	void			drawClippedSegment(const LLWString &wtext, S32 seg_start, S32 seg_end, F32 x, F32 y, S32 selection_left, S32 selection_right, const LLStyle& color, F32* right_x);
+	void			drawPreeditMarker();
 
 	void			updateLineStartList(S32 startpos = 0);
 	void			updateScrollFromCursor();
@@ -267,7 +272,7 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 	void			pruneSegments();
 
 	void 			assignEmbedded(const LLString &s);
-	void 			truncate();
+	BOOL 			truncate();				// Returns true if truncation occurs
 	
 	static BOOL		isPartOfWord(llwchar c);
 
@@ -291,7 +296,7 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 	BOOL			handleControlKey(const KEY key, const MASK mask);
 	BOOL			handleEditKey(const KEY key, const MASK mask);
 
-	BOOL			hasSelection() { return (mSelectionStart !=mSelectionEnd); }
+	BOOL			hasSelection() const		{ return (mSelectionStart !=mSelectionEnd); }
 	BOOL			selectionContainsLineBreaks();
 	void			startSelection();
 	void			endSelection();
@@ -300,8 +305,8 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 	S32				prevWordPos(S32 cursorPos) const;
 	S32				nextWordPos(S32 cursorPos) const;
 
-	S32 			getLineCount();
-	S32 			getLineStart( S32 line );
+	S32 			getLineCount() const;
+	S32 			getLineStart( S32 line ) const;
 	void			getLineAndOffset(S32 pos, S32* linep, S32* offsetp);
 	S32				getPos(S32 line, S32 offset);
 
@@ -338,6 +343,20 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 	S32 			removeStringNoUndo(S32 pos, S32 length);
 	S32				overwriteCharNoUndo(S32 pos, llwchar wc);
 	
+protected:
+	void			updateAllowingLanguageInput();
+	BOOL			hasPreeditString() const;
+
+	// Overrides LLPreeditor
+	virtual void	resetPreedit();
+	virtual void	updatePreedit(const LLWString &preedit_string,
+						const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position);
+	virtual void	markAsPreedit(S32 position, S32 length);
+	virtual void	getPreeditRange(S32 *position, S32 *length) const;
+	virtual void	getSelectionRange(S32 *position, S32 *length) const;
+	virtual BOOL	getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const;
+	virtual S32		getPreeditFontSize() const;
+
 public:
 	LLKeywords		mKeywords;
 	static LLColor4 mLinkColor;
@@ -349,7 +368,7 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 	mutable LLString mUTF8Text;
 	mutable BOOL	mTextIsUpToDate;
 	
-	S32				mMaxTextLength;		// Maximum length mText is allowed to be
+	S32				mMaxTextByteLength;		// Maximum length mText is allowed to be in bytes
 
 	const LLFontGL*	mGLFont;
 
@@ -439,6 +458,11 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler
 
 	BOOL			mParseHTML;
 	LLString		mHTML;
+
+	LLWString			mPreeditWString;
+	LLWString			mPreeditOverwrittenWString;
+	std::vector<S32> 	mPreeditPositions;
+	std::vector<BOOL> 	mPreeditStandouts;
 };
 
 class LLTextSegment
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 7af0d726cb6631999f3d912aa16894b2a3019be5..00a230dff3cd77b41b57eb8b874259fd3294fe54 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -1695,6 +1695,34 @@ LLVector2 LLUI::getWindowSize()
 	return LLVector2(window_rect.mX / sGLScaleFactor.mV[VX], window_rect.mY / sGLScaleFactor.mV[VY]);
 }
 
+//static
+void LLUI::screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y)
+{
+	*gl_x = llround((F32)screen_x * sGLScaleFactor.mV[VX]);
+	*gl_y = llround((F32)screen_y * sGLScaleFactor.mV[VY]);
+}
+
+//static
+void LLUI::glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y)
+{
+	*screen_x = llround((F32)gl_x / sGLScaleFactor.mV[VX]);
+	*screen_y = llround((F32)gl_y / sGLScaleFactor.mV[VY]);
+}
+
+//static
+void LLUI::screenRectToGL(const LLRect& screen, LLRect *gl)
+{
+	screenPointToGL(screen.mLeft, screen.mTop, &gl->mLeft, &gl->mTop);
+	screenPointToGL(screen.mRight, screen.mBottom, &gl->mRight, &gl->mBottom);
+}
+
+//static
+void LLUI::glRectToScreen(const LLRect& gl, LLRect *screen)
+{
+	glPointToScreen(gl.mLeft, gl.mTop, &screen->mLeft, &screen->mTop);
+	glPointToScreen(gl.mRight, gl.mBottom, &screen->mRight, &screen->mBottom);
+}
+
 //static
 LLUUID			LLUI::findAssetUUIDByName(const LLString	&asset_name)
 {
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index b78b046a8c8e58465587f4395afc5b728061b67a..b98f4d5de221a4f2efef98168f40c1cae1aa62aa 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -174,6 +174,10 @@ class LLUI
 	static void setLineWidth(F32 width);
 	static LLUUID findAssetUUIDByName(const LLString&	name);
 	static LLVector2 getWindowSize();
+	static void screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y);
+	static void glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y);
+	static void screenRectToGL(const LLRect& screen, LLRect *gl);
+	static void glRectToScreen(const LLRect& gl, LLRect *screen);
 	static void setHtmlHelp(LLHtmlHelp* html_help);
 
 private:
diff --git a/indra/llwindow/llpreeditor.h b/indra/llwindow/llpreeditor.h
new file mode 100644
index 0000000000000000000000000000000000000000..63e64ab781cef183705509e917cd9c3ad16e4d60
--- /dev/null
+++ b/indra/llwindow/llpreeditor.h
@@ -0,0 +1,81 @@
+/** 
+ * @file llpreeditor.h
+ * @brief abstract class that defines interface for components to feedback preedits to users.
+ *
+ * Copyright (c) 2000-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#ifndef LL_PREEDITOR
+#define LL_PREEDITOR
+
+class LLPreeditor
+{
+public:
+
+	typedef std::vector<S32> segment_lengths_t;
+	typedef std::vector<BOOL> standouts_t;
+	
+	// We don't delete against LLPreeditor, but compilers complain without this...
+	
+	virtual ~LLPreeditor() {};
+
+	// Discard any preedit info. on this preeditor.
+	
+	virtual void resetPreedit() = 0;
+
+	// Update the preedit feedback using specified details.
+	// Existing preedit is discarded and replaced with the new one.  (I.e., updatePreedit is not cumulative.) 
+	// All arguments are IN.
+	// preedit_count is the number of elements in arrays preedit_list and preedit_standouts.
+	// preedit list is an array of preedit texts (clauses.)
+	// preedit_standouts indicates whether each preedit text should be shown as standout clause.
+	// caret_position is the preedit-local position of text editing caret, in # of llwchar.
+	
+	virtual void updatePreedit(const LLWString &preedit_string,
+						const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) = 0;
+
+	// Turn the specified sub-contents into an active preedit.
+	// Both position and length are IN and count with UTF-32 (llwchar) characters.
+	// This method primarily facilitates reconversion.
+
+	virtual void markAsPreedit(S32 position, S32 length) = 0;
+
+	// Get the position and the length of the active preedit in the contents.
+	// Both position and length are OUT and count with UTF-32 (llwchar) characters.
+	// When this preeditor has no active preedit, position receives
+	// the caret position, and length receives 0.
+
+	virtual void getPreeditRange(S32 *position, S32 *length) const = 0;
+
+	// Get the position and the length of the current selection in the contents.
+	// Both position and length are OUT and count with UTF-32 (llwchar) characters.
+	// When this preeditor has no selection, position receives
+	// the caret position, and length receives 0.
+
+	virtual void getSelectionRange(S32 *position, S32 *length) const = 0;
+
+	// Get the locations where the preedit and related UI elements are displayed.
+	// Locations are relative to the app window and measured in GL coordinate space (before scaling.)
+	// query_position is IN argument, and other three are OUT.
+
+	virtual BOOL getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const = 0;
+
+	// Get the size (height) of the current font used in this preeditor.
+
+	virtual S32 getPreeditFontSize() const = 0;
+
+	// Get the contents of this preeditor as a LLWString.  If there is an active preedit,
+	// the returned LLWString contains it.
+
+	virtual const LLWString & getWText() const = 0;
+
+	// Handle a UTF-32 char on this preeditor, i.e., add the character
+	// to the contents.
+	// This is a back door of the method of same name of LLWindowCallback.
+	// called_from_parent should be set to FALSE if calling through LLPreeditor.
+
+	virtual BOOL handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent) = 0;
+};
+
+#endif
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 4db2c8105f937d9fbf8cc560c009a6f831d4fac3..9a3542d3fbb822864554d14e92a2320b5348b44b 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -81,6 +81,8 @@ class LLSplashScreen;
 
 class LLWindow;
 
+class LLPreeditor;
+
 class LLWindowCallbacks
 {
 public:
@@ -222,8 +224,10 @@ class LLWindow
 	virtual void *getPlatformWindow() = 0;
 	
 	// control platform's Language Text Input mechanisms.
-	virtual void allowLanguageTextInput( BOOL b ) {};
+	virtual void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) {}
 	virtual void setLanguageTextInput( const LLCoordGL & pos ) {};
+	virtual void updateLanguageTextInputArea() {}
+	virtual void interruptLanguageTextInput() {}
 
 protected:
 	LLWindow(BOOL fullscreen, U32 flags);
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 2724cb56e43a36767eae0b54b428b4af44b938ed..943b98e9d59bd7b3c54f20a9095b5a15f96c1781 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -48,6 +48,7 @@
 #include "indra_constants.h"
 
 #include "llwindowmacosx-objc.h"
+#include "llpreeditor.h"
 
 extern BOOL gDebugWindowProc;
 
@@ -172,8 +173,22 @@ static EventTypeSpec WindowHandlerEventList[] =
 	{ kEventClassKeyboard, kEventRawKeyModifiersChanged },
 
 	// Text input events
-	{ kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }
-
+	{ kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
+	{ kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
+	{ kEventClassTextInput, kEventTextInputOffsetToPos },
+	{ kEventClassTextInput, kEventTextInputPosToOffset },
+	{ kEventClassTextInput, kEventTextInputShowHideBottomWindow },
+	{ kEventClassTextInput, kEventTextInputGetSelectedText },
+	{ kEventClassTextInput, kEventTextInputFilterText },
+
+	// TSM Document Access events (advanced input method support)
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument }
 };
 
 static EventTypeSpec GlobalHandlerEventList[] =
@@ -195,7 +210,22 @@ static EventTypeSpec GlobalHandlerEventList[] =
 	{ kEventClassKeyboard, kEventRawKeyModifiersChanged },
 
 	// Text input events
-	{ kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }
+	{ kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
+	{ kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
+	{ kEventClassTextInput, kEventTextInputOffsetToPos },
+	{ kEventClassTextInput, kEventTextInputPosToOffset },
+	{ kEventClassTextInput, kEventTextInputShowHideBottomWindow },
+	{ kEventClassTextInput, kEventTextInputGetSelectedText },
+	{ kEventClassTextInput, kEventTextInputFilterText },
+
+	// TSM Document Access events (advanced input method support)
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument },
+	{ kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument }
 };
 
 static EventTypeSpec CommandHandlerEventList[] =
@@ -246,6 +276,7 @@ LLWindowMacOSX::LLWindowMacOSX(char *title, char *name, S32 x, S32 y, S32 width,
 	mLanguageTextInputAllowed = FALSE;
 	mTSMScriptCode = 0;
 	mTSMLangCode = 0;
+	mPreeditor = NULL;
 	
 	// For reasons that aren't clear to me, LLTimers seem to be created in the "started" state.
 	// Since the started state of this one is used to track whether the NMRec has been installed, it wants to start out in the "stopped" state.
@@ -497,15 +528,16 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
 			mTSMDocument = NULL;
 		}
 		static InterfaceTypeList types = { kUnicodeDocument };
-		OSErr err = NewTSMDocument(1, types, &mTSMDocument, 0);
+		err = NewTSMDocument(1, types, &mTSMDocument, 0);
 		if (err != noErr)
 		{
 			llwarns << "createContext: couldn't create a TSMDocument (" << err << ")" << llendl;
 		}
 		if (mTSMDocument)
 		{
-			UseInputWindow(mTSMDocument, TRUE);
 			ActivateTSMDocument(mTSMDocument);
+			UseInputWindow(mTSMDocument, FALSE);
+			allowLanguageTextInput(NULL, FALSE);
 		}
 	}
 
@@ -1949,6 +1981,141 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 		{
 			switch (evtKind)
 			{
+			case kEventTextInputUpdateActiveInputArea:
+				{
+					EventParamType param_type;
+
+					long fix_len;
+					UInt32 text_len;
+					if (mPreeditor
+						&& (result = GetEventParameter(event, kEventParamTextInputSendFixLen,
+										typeLongInteger, &param_type, sizeof(fix_len), NULL, &fix_len)) == noErr
+						&& typeLongInteger == param_type 
+						&& (result = GetEventParameter(event, kEventParamTextInputSendText,
+										typeUnicodeText, &param_type, 0, &text_len, NULL)) == noErr
+						&& typeUnicodeText == param_type)
+					{
+						// Handle an optional (but essential to facilitate TSMDA) ReplaceRange param.
+						CFRange range;
+						if (GetEventParameter(event, kEventParamTextInputSendReplaceRange,
+								typeCFRange, &param_type, sizeof(range), NULL, &range) == noErr
+							&& typeCFRange == param_type)
+						{
+							// Although the spec. is unclear, replace range should
+							// not present when there is an active preedit.  We just
+							// ignore the case.  markAsPreedit will detect the case and warn it.
+							const LLWString & text = mPreeditor->getWText();
+							const S32 location = wstring_wstring_length_from_utf16_length(text, 0, range.location);
+							const S32 length = wstring_wstring_length_from_utf16_length(text, location, range.length);
+							mPreeditor->markAsPreedit(location, length);
+						}
+						mPreeditor->resetPreedit();
+						
+						// Receive the text from input method.
+						U16 *const text = new U16[text_len / sizeof(U16)];
+						GetEventParameter(event, kEventParamTextInputSendText, typeUnicodeText, NULL, text_len, NULL, text);
+						if (fix_len < 0)
+						{
+							// Do we still need this?  Seems obsolete...
+							fix_len = text_len;
+						}
+						const LLWString fix_string
+								= utf16str_to_wstring(llutf16string(text, fix_len / sizeof(U16)));
+						const LLWString preedit_string
+								= utf16str_to_wstring(llutf16string(text + fix_len / sizeof(U16), (text_len - fix_len) / sizeof(U16)));
+						delete[] text;
+
+						// Handle fixed (comitted) string.
+						if (fix_string.length() > 0)
+						{
+							for (LLWString::const_iterator i = fix_string.begin(); i != fix_string.end(); i++)
+							{
+								mPreeditor->handleUnicodeCharHere(*i, FALSE);
+							}
+						}
+
+						// Receive the segment info and caret position.
+						LLPreeditor::segment_lengths_t preedit_segment_lengths;
+						LLPreeditor::standouts_t preedit_standouts;
+						S32 caret_position = preedit_string.length();
+						UInt32 text_range_array_size;
+						if (GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray,
+								&param_type, 0, &text_range_array_size, NULL) == noErr
+							&& typeTextRangeArray == param_type
+							&& text_range_array_size > sizeof(TextRangeArray))
+						{
+							// TextRangeArray is a variable-length struct.
+							TextRangeArray * const text_range_array = (TextRangeArray *) new char[text_range_array_size];
+							GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray,
+									NULL, text_range_array_size, NULL, text_range_array);
+
+							// WARNING: We assume ranges are in ascending order, 
+							// although the condition is undocumented.  It seems
+							// OK to assume this.  I also assumed
+							// the ranges are contiguous in previous versions, but I
+							// have heard a rumore that older versions os ATOK may 
+							// return ranges with some _gap_.  I don't know whether
+							// it is true, but I'm preparing my code for the case.
+
+							const S32 ranges = text_range_array->fNumOfRanges;
+							preedit_segment_lengths.reserve(ranges);
+							preedit_standouts.reserve(ranges);
+
+							S32 last_bytes = 0;
+							S32 last_utf32 = 0;
+							for (S32 i = 0; i < ranges; i++)
+							{
+								const TextRange &range = text_range_array->fRange[i];
+								if (range.fStart > last_bytes)
+								{
+									const S32 length_utf16 = (range.fStart - last_bytes) / sizeof(U16);
+									const S32 length_utf32 = wstring_wstring_length_from_utf16_length(preedit_string, last_utf32, length_utf16);
+									preedit_segment_lengths.push_back(length_utf32);
+									preedit_standouts.push_back(FALSE);
+									last_utf32 += length_utf32;
+								}
+								if (range.fEnd > range.fStart)
+								{
+									const S32 length_utf16 = (range.fEnd - range.fStart) / sizeof(U16);
+									const S32 length_utf32 = wstring_wstring_length_from_utf16_length(preedit_string, last_utf32, length_utf16);
+									preedit_segment_lengths.push_back(length_utf32);
+									preedit_standouts.push_back(
+										kTSMHiliteSelectedRawText == range.fHiliteStyle
+										|| kTSMHiliteSelectedConvertedText ==  range.fHiliteStyle
+										|| kTSMHiliteSelectedText == range.fHiliteStyle);
+									last_utf32 += length_utf32;
+								}
+								if (kTSMHiliteCaretPosition == range.fHiliteStyle)
+								{
+									caret_position = last_utf32;
+								}
+								last_bytes = range.fEnd;
+							}
+							if (preedit_string.length() > last_utf32)
+							{
+								preedit_segment_lengths.push_back(preedit_string.length() - last_utf32);
+								preedit_standouts.push_back(FALSE);
+							}
+
+							delete[] (char *) text_range_array;
+						}
+
+						// Handle preedit string.
+						if (preedit_string.length() > 0)
+						{
+							if (preedit_segment_lengths.size() == 0)
+							{
+								preedit_segment_lengths.push_back(preedit_string.length());
+								preedit_standouts.push_back(FALSE);
+							}
+							mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position);
+						}
+
+						result = noErr;
+					}
+				}
+				break;
+				
 			case kEventTextInputUnicodeForKeyEvent:
 				{
 					UInt32 modifiers = 0;
@@ -2021,6 +2188,63 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 					result = err;
 				}
 				break;
+				
+			case kEventTextInputOffsetToPos:
+				{
+					EventParamType param_type;
+					long offset;
+					if (mPreeditor
+						&& GetEventParameter(event, kEventParamTextInputSendTextOffset, typeLongInteger,
+								&param_type, sizeof(offset), NULL, &offset) == noErr
+						&& typeLongInteger == param_type)
+					{
+						S32 preedit, preedit_length;
+						mPreeditor->getPreeditRange(&preedit, &preedit_length);
+						const LLWString & text = mPreeditor->getWText();
+						 
+						LLCoordGL caret_coord;
+						LLRect preedit_bounds;
+						if (0 <= offset
+							&& mPreeditor->getPreeditLocation(wstring_wstring_length_from_utf16_length(text, preedit, offset / sizeof(U16)),
+															  &caret_coord, &preedit_bounds, NULL))
+						{
+							LLCoordGL caret_base_coord(caret_coord.mX, preedit_bounds.mBottom);
+							LLCoordScreen caret_base_coord_screen;
+							convertCoords(caret_base_coord, &caret_base_coord_screen);
+							Point qd_point;
+							qd_point.h = caret_base_coord_screen.mX;
+							qd_point.v = caret_base_coord_screen.mY;
+							SetEventParameter(event, kEventParamTextInputReplyPoint, typeQDPoint, sizeof(qd_point), &qd_point);
+							
+							short line_height = (short) preedit_bounds.getHeight();
+							SetEventParameter(event, kEventParamTextInputReplyLineHeight, typeShortInteger, sizeof(line_height), &line_height);
+							
+							result = noErr;
+						}
+						else
+						{
+							result = errOffsetInvalid;
+						}
+					}
+				}
+				break;
+
+			case kEventTextInputGetSelectedText:
+				{
+					if (mPreeditor)
+					{
+						S32 selection, selection_length;
+						mPreeditor->getSelectionRange(&selection, &selection_length);
+						if (selection_length)
+						{
+							const LLWString text = mPreeditor->getWText().substr(selection, selection_length);
+							const llutf16string text_utf16 = wstring_to_utf16str(text);
+							result = SetEventParameter(event, kEventParamTextInputReplyText, typeUnicodeText,
+										text_utf16.length() * sizeof(U16), text_utf16.c_str());
+						}
+					}
+				}
+				break;
 			}
 		}
 		break;
@@ -2194,6 +2418,13 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 				switch (evtKind)
 				{
 				case kEventMouseDown:
+					if (mLanguageTextInputAllowed)
+					{
+						// We need to interrupt before handling mouse events,
+						// so that the fixed string from IM are delivered to
+						// the currently focused UI component.
+						interruptLanguageTextInput();
+					}
 					switch(button)
 					{
 					case kEventMouseButtonPrimary:
@@ -2287,6 +2518,10 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 			mCallbacks->handleFocus(this);
 			break;
 		case kEventWindowDeactivated:
+			if (mTSMDocument)
+			{
+				DeactivateTSMDocument(mTSMDocument);
+			}
 			mCallbacks->handleFocusLost(this);
 			break;
 		case kEventWindowBoundsChanging:
@@ -2359,6 +2594,109 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
 			//					BringToFront(mWindow);
 			//					result = noErr;
 			break;
+		
+		}
+		break;
+
+	case kEventClassTSMDocumentAccess:
+		if (mPreeditor)
+		{
+			switch(evtKind)
+			{		
+
+			case kEventTSMDocumentAccessGetLength:
+				{
+					// Return the number of UTF-16 units in the text, excluding those for preedit.
+
+					S32 preedit, preedit_length;
+					mPreeditor->getPreeditRange(&preedit, &preedit_length);
+					const LLWString & text = mPreeditor->getWText();
+					const CFIndex length = wstring_utf16_length(text, 0, preedit)
+						+ wstring_utf16_length(text, preedit + preedit_length, text.length());
+					result = SetEventParameter(event, kEventParamTSMDocAccessCharacterCount, typeCFIndex, sizeof(length), &length);
+				}
+				break;
+
+			case kEventTSMDocumentAccessGetSelectedRange:
+				{
+					// Return the selected range, excluding preedit.
+					// In our preeditor, preedit and selection are exclusive, so,
+					// when it has a preedit, there is no selection and the 
+					// insertion point is on the preedit that corrupses into the
+					// beginning of the preedit when the preedit was removed.
+
+					S32 preedit, preedit_length;
+					mPreeditor->getPreeditRange(&preedit, &preedit_length);
+					const LLWString & text = mPreeditor->getWText();
+					
+					CFRange range;
+					if (preedit_length)
+					{
+						range.location = wstring_utf16_length(text, 0, preedit);
+						range.length = 0;
+					}
+					else
+					{
+						S32 selection, selection_length;
+						mPreeditor->getSelectionRange(&selection, &selection_length);
+						range.location = wstring_utf16_length(text, 0, selection);
+						range.length = wstring_utf16_length(text, selection, selection_length);
+					}
+
+					result = SetEventParameter(event, kEventParamTSMDocAccessReplyCharacterRange, typeCFRange, sizeof(range), &range);
+				}
+				break;
+
+			case kEventTSMDocumentAccessGetCharacters:
+				{
+					UniChar *target_pointer;
+					CFRange range;
+					EventParamType param_type;
+					if ((result = GetEventParameter(event, kEventParamTSMDocAccessSendCharacterRange,
+										typeCFRange, &param_type, sizeof(range), NULL, &range)) == noErr
+						&& typeCFRange == param_type
+						&& (result = GetEventParameter(event, kEventParamTSMDocAccessSendCharactersPtr,
+										typePtr, &param_type, sizeof(target_pointer), NULL, &target_pointer)) == noErr
+						&& typePtr == param_type)
+					{
+						S32 preedit, preedit_length;
+						mPreeditor->getPreeditRange(&preedit, &preedit_length);
+						const LLWString & text = mPreeditor->getWText();
+
+						// The GetCharacters event of TSMDA has a fundamental flaw;
+						// An input method need to decide the starting offset and length
+						// *before* it actually see the contents, so it is impossible
+						// to guarantee the character-aligned access.  The event reply
+						// has no way to indicate a condition something like "Request
+						// was not fulfilled due to unaligned access.  Please retry."
+						// Any error sent back to the input method stops use of TSMDA
+						// entirely during the session...
+						// We need to simulate very strictly the behaviour as if the
+						// underlying *text engine* holds the contents in UTF-16.
+						// I guess this is the reason why Apple repeats saying "all
+						// text handling application should use UTF-16."  They are
+						// trying to _fix_ the flaw by changing the appliations...
+						// ... or, domination of UTF-16 in the industry may be a part
+						// of the company vision, and Apple is trying to force third
+						// party developers to obey their vision.  Remember that use
+						// of 16 bits per _a_character_ was one of the very fundamental
+						// Unicode design policy on its early days (during late 80s)
+						// and the original Unicode design was by two Apple employees...
+
+						const llutf16string text_utf16
+							= wstring_to_utf16str(text, preedit)
+							+ wstring_to_utf16str(text.substr(preedit + preedit_length));
+
+						llassert_always(sizeof(U16) == sizeof(UniChar));
+						llassert(0 <= range.location && 0 <= range.length && range.location + range.length <= text_utf16.length());
+						memcpy(target_pointer, text_utf16.c_str() + range.location, range.length * sizeof(UniChar));
+
+						// Note that result has already been set above.
+					}					
+				}
+				break;
+
+			}
 		}
 		break;
 	}
@@ -2995,10 +3333,34 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key)
 	return int_value; // otherwise return the long value
 }
 
-void LLWindowMacOSX::allowLanguageTextInput(BOOL b)
+void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
 {
 	ScriptLanguageRecord script_language;
 
+	if (preeditor != mPreeditor && !b)
+	{
+		// This condition may occur by a call to
+		// setEnabled(BOOL) against LLTextEditor or LLLineEditor
+		// when the control is not focused.
+		// We need to silently ignore the case so that
+		// the language input status of the focused control
+		// is not disturbed.
+		return;
+	}
+
+	// Take care of old and new preeditors.
+	if (preeditor != mPreeditor || !b)
+	{
+		// We need to interrupt before updating mPreeditor,
+		// so that the fix string from input method goes to
+		// the old preeditor.
+		if (mLanguageTextInputAllowed)
+		{
+			interruptLanguageTextInput();
+		}
+		mPreeditor = (b ? preeditor : NULL);
+	}
+
 	if (b == mLanguageTextInputAllowed)
 	{
 		return;
@@ -3028,4 +3390,12 @@ void LLWindowMacOSX::allowLanguageTextInput(BOOL b)
 	}
 }
 
+void LLWindowMacOSX::interruptLanguageTextInput()
+{
+	if (mTSMDocument)
+	{
+		FixTSMDocument(mTSMDocument);
+	}
+}
+
 #endif // LL_DARWIN
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index ee3019bd2184e4f03ea2b4b3265d3c5bc15ed82b..2a4cf973088f4f474b788a8ce09191f84069e7ba 100644
--- a/indra/llwindow/llwindowmacosx.h
+++ b/indra/llwindow/llwindowmacosx.h
@@ -111,8 +111,10 @@ class LLWindowMacOSX : public LLWindow
 	/*virtual*/ void *getPlatformWindow();
 	/*virtual*/ void bringToFront() {};
 	
-	/*virtual*/ void allowLanguageTextInput(BOOL b);
-	
+	/*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b);
+	/*virtual*/ void updateLanguageTextInputArea(const LLCoordGL& caret, const LLRect& bounds);
+	/*virtual*/ void interruptLanguageTextInput();
+
 protected:
 	LLWindowMacOSX(
 		char *title, char *name, int x, int y, int width, int height, U32 flags,
@@ -193,6 +195,7 @@ class LLWindowMacOSX : public LLWindow
 	BOOL		mLanguageTextInputAllowed;
 	ScriptCode	mTSMScriptCode;
 	LangCode	mTSMLangCode;
+	LLPreeditor*	mPreeditor;
 
 	friend class LLWindowManager;
 };
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index e5fd0f7360809f66c2f6b178e435a008bfaa8ba8..4e4bed64859ca20829a46cd7364a17aefacb435c 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -57,6 +57,8 @@
 
 #include "indra_constants.h"
 
+#include "llpreeditor.h"
+
 // culled from winuser.h
 #ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */
 const S32	WM_MOUSEWHEEL = 0x020A;
@@ -112,6 +114,7 @@ class LLWinImm
 public:
 	// Wrappers for IMM API.
 	static BOOL		isIME(HKL hkl);															
+	static HWND		getDefaultIMEWnd(HWND hwnd);
 	static HIMC		getContext(HWND hwnd);													
 	static BOOL		releaseContext(HWND hwnd, HIMC himc);
 	static BOOL		getOpenStatus(HIMC himc);												
@@ -120,6 +123,11 @@ class LLWinImm
 	static BOOL		setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence);		
 	static BOOL		getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);					
 	static BOOL		setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);					
+	static LONG		getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length);
+	static BOOL		setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength);
+	static BOOL		setCompositionFont(HIMC himc, LPLOGFONTW logfont);
+	static BOOL		setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form);
+	static BOOL		notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value);
 
 private:
 	LLWinImm();
@@ -128,6 +136,7 @@ class LLWinImm
 private:
 	// Pointers to IMM API.
 	BOOL	 	(WINAPI *mImmIsIME)(HKL);
+	HWND		(WINAPI *mImmGetDefaultIMEWnd)(HWND);
 	HIMC		(WINAPI *mImmGetContext)(HWND);
 	BOOL		(WINAPI *mImmReleaseContext)(HWND, HIMC);
 	BOOL		(WINAPI *mImmGetOpenStatus)(HIMC);
@@ -136,6 +145,11 @@ class LLWinImm
 	BOOL		(WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD);
 	BOOL		(WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
 	BOOL		(WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
+	LONG		(WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
+	BOOL		(WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD);
+	BOOL		(WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW);
+	BOOL		(WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM);
+	BOOL		(WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
 
 private:
 	HMODULE		mHImmDll;
@@ -155,6 +169,7 @@ LLWinImm::LLWinImm() : mHImmDll(NULL)
 	if (mHImmDll != NULL)
 	{
 		mImmIsIME               = (BOOL (WINAPI *)(HKL))                    GetProcAddress(mHImmDll, "ImmIsIME");
+		mImmGetDefaultIMEWnd	= (HWND (WINAPI *)(HWND))					GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd");
 		mImmGetContext          = (HIMC (WINAPI *)(HWND))                   GetProcAddress(mHImmDll, "ImmGetContext");
 		mImmReleaseContext      = (BOOL (WINAPI *)(HWND, HIMC))             GetProcAddress(mHImmDll, "ImmReleaseContext");
 		mImmGetOpenStatus       = (BOOL (WINAPI *)(HIMC))                   GetProcAddress(mHImmDll, "ImmGetOpenStatus");
@@ -163,8 +178,14 @@ LLWinImm::LLWinImm() : mHImmDll(NULL)
 		mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD))     GetProcAddress(mHImmDll, "ImmSetConversionStatus");
 		mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmGetCompositionWindow");
 		mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmSetCompositionWindow");
+		mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD))					GetProcAddress(mHImmDll, "ImmGetCompositionStringW");
+		mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD))	GetProcAddress(mHImmDll, "ImmSetCompositionStringW");
+		mImmSetCompositionFont  = (BOOL (WINAPI *)(HIMC, LPLOGFONTW))		GetProcAddress(mHImmDll, "ImmSetCompositionFontW");
+		mImmSetCandidateWindow  = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM))  GetProcAddress(mHImmDll, "ImmSetCandidateWindow");
+		mImmNotifyIME			= (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD))	GetProcAddress(mHImmDll, "ImmNotifyIME");
 
 		if (mImmIsIME == NULL ||
+			mImmGetDefaultIMEWnd == NULL ||
 			mImmGetContext == NULL ||
 			mImmReleaseContext == NULL ||
 			mImmGetOpenStatus == NULL ||
@@ -172,7 +193,12 @@ LLWinImm::LLWinImm() : mHImmDll(NULL)
 			mImmGetConversionStatus == NULL ||
 			mImmSetConversionStatus == NULL ||
 			mImmGetCompostitionWindow == NULL ||
-			mImmSetCompostitionWindow == NULL)
+			mImmSetCompostitionWindow == NULL ||
+			mImmGetCompositionString == NULL ||
+			mImmSetCompositionString == NULL ||
+			mImmSetCompositionFont == NULL ||
+			mImmSetCandidateWindow == NULL ||
+			mImmNotifyIME == NULL)
 		{
 			// If any of the above API entires are not found, we can't use IMM API.  
 			// So, turn off the IMM support.  We should log some warning message in 
@@ -186,6 +212,7 @@ LLWinImm::LLWinImm() : mHImmDll(NULL)
 
 			// If we unload the library, make sure all the function pointers are cleared
 			mImmIsIME = NULL;
+			mImmGetDefaultIMEWnd = NULL;
 			mImmGetContext = NULL;
 			mImmReleaseContext = NULL;
 			mImmGetOpenStatus = NULL;
@@ -194,6 +221,11 @@ LLWinImm::LLWinImm() : mHImmDll(NULL)
 			mImmSetConversionStatus = NULL;
 			mImmGetCompostitionWindow = NULL;
 			mImmSetCompostitionWindow = NULL;
+			mImmGetCompositionString = NULL;
+			mImmSetCompositionString = NULL;
+			mImmSetCompositionFont = NULL;
+			mImmSetCandidateWindow = NULL;
+			mImmNotifyIME = NULL;
 		}
 	}
 }
@@ -272,6 +304,50 @@ BOOL		LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)
 }
 
 
+// static 
+LONG		LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length)					
+{ 
+	if ( sTheInstance.mImmGetCompositionString )
+		return sTheInstance.mImmGetCompositionString(himc, index, data, length);	
+	return FALSE;
+}
+
+
+// static 
+BOOL		LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength)					
+{ 
+	if ( sTheInstance.mImmSetCompositionString )
+		return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);	
+	return FALSE;
+}
+
+// static 
+BOOL		LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont)					
+{ 
+	if ( sTheInstance.mImmSetCompositionFont )
+		return sTheInstance.mImmSetCompositionFont(himc, pFont);	
+	return FALSE;
+}
+
+// static 
+BOOL		LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form)					
+{ 
+	if ( sTheInstance.mImmSetCandidateWindow )
+		return sTheInstance.mImmSetCandidateWindow(himc, form);	
+	return FALSE;
+}
+
+// static 
+BOOL		LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value)					
+{ 
+	if ( sTheInstance.mImmNotifyIME )
+		return sTheInstance.mImmNotifyIME(himc, action, index, value);	
+	return FALSE;
+}
+
+
+
+
 // ----------------------------------------------------------------------------------------
 LLWinImm::~LLWinImm()
 {
@@ -304,13 +380,14 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width,
 	mNativeAspectRatio = 0.f;
 	mMousePositionModified = FALSE;
 	mInputProcessingPaused = FALSE;
+	mPreeditor = NULL;
 
 	// Initialize the keyboard
 	gKeyboard = new LLKeyboardWin32();
 
 	// Initialize (boot strap) the Language text input management,
 	// based on the system's (user's) default settings.
-	allowLanguageTextInput(FALSE);
+	allowLanguageTextInput(mPreeditor, FALSE);
 
 	GLuint			pixel_format;
 	WNDCLASS		wc;
@@ -938,6 +1015,10 @@ LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width,
 	initCursors();
 	setCursor( UI_CURSOR_ARROW );
 
+	// Initialize (boot strap) the Language text input management,
+	// based on the system's (or user's) default settings.
+	allowLanguageTextInput(NULL, FALSE);
+
 	// Direct Input
 	HRESULT hr;
 
@@ -2035,6 +2116,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 				BOOL minimized = BOOL(HIWORD(w_param));
 
+				if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor)
+				{
+					window_imp->interruptLanguageTextInput();
+				}
+
 				// JC - I'm not sure why, but if we don't report that we handled the 
 				// WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work 
 				// properly when we run fullscreen.
@@ -2127,6 +2213,47 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 			// pass on to windows
 			break;
 
+		case WM_IME_SETCONTEXT:
+			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+			{
+				l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW;
+				// Invoke DefWinProc with the modified LPARAM.
+			}
+			break;
+
+		case WM_IME_STARTCOMPOSITION:
+			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+			{
+				window_imp->handleStartCompositionMessage();
+				return 0;
+			}
+			break;
+
+		case WM_IME_ENDCOMPOSITION:
+			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+			{
+				return 0;
+			}
+			break;
+
+		case WM_IME_COMPOSITION:
+			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+			{
+				window_imp->handleCompositionMessage(l_param);
+				return 0;
+			}
+			break;
+
+		case WM_IME_REQUEST:
+			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+			{
+				LRESULT result = 0;
+				if (window_imp->handleImeRequests(w_param, l_param, &result))
+				{
+					return result;
+				}
+			}
+			break;
 
 		case WM_CHAR:
 			// Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need
@@ -2154,6 +2281,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 
 		case WM_LBUTTONDOWN:
 			{
+				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+				{
+					window_imp->interruptLanguageTextInput();
+				}
+
 				// Because we move the cursor position in the app, we need to query
 				// to find out where the cursor at the time the event is handled.
 				// If we don't do this, many clicks could get buffered up, and if the
@@ -2236,6 +2368,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 		case WM_RBUTTONDBLCLK:
 		case WM_RBUTTONDOWN:
 			{
+				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+				{
+					window_imp->interruptLanguageTextInput();
+				}
+
 				// Because we move the cursor position in tllviewerhe app, we need to query
 				// to find out where the cursor at the time the event is handled.
 				// If we don't do this, many clicks could get buffered up, and if the
@@ -2287,6 +2424,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
 		case WM_MBUTTONDOWN:
 //		case WM_MBUTTONDBLCLK:
 			{
+				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
+				{
+					window_imp->interruptLanguageTextInput();
+				}
+
 				// Because we move the cursor position in tllviewerhe app, we need to query
 				// to find out where the cursor at the time the event is handled.
 				// If we don't do this, many clicks could get buffered up, and if the
@@ -3324,15 +3466,37 @@ void LLWindowWin32::focusClient()
 	SetFocus ( mWindowHandle );
 }
 
-void LLWindowWin32::allowLanguageTextInput(BOOL b)
+void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
 {
 	if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable())
 	{
 		return;
 	}
+
+	if (preeditor != mPreeditor && !b)
+	{
+		// This condition may occur with a call to
+		// setEnabled(BOOL) from LLTextEditor or LLLineEditor
+		// when the control is not focused.
+		// We need to silently ignore the case so that
+		// the language input status of the focused control
+		// is not disturbed.
+		return;
+	}
+
+	// Take care of old and new preeditors.
+	if (preeditor != mPreeditor || !b)
+	{
+		if (sLanguageTextInputAllowed)
+		{
+			interruptLanguageTextInput();
+		}
+		mPreeditor = (b ? preeditor : NULL);
+	}
+
 	sLanguageTextInputAllowed = b;
 
-	if (b)
+	if ( sLanguageTextInputAllowed )
 	{
 		// Allowing: Restore the previous IME status, so that the user has a feeling that the previous 
 		// text input continues naturally.  Be careful, however, the IME status is meaningful only during the user keeps 
@@ -3368,7 +3532,24 @@ void LLWindowWin32::allowLanguageTextInput(BOOL b)
 			LLWinImm::releaseContext(mWindowHandle, himc);
  		}
 	}
+}
 
+void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, 
+		CANDIDATEFORM *form)
+{
+	LLCoordWindow caret_coord, top_left, bottom_right;
+	convertCoords(caret, &caret_coord);
+	convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left);
+	convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right);
+
+	memset(form, 0, sizeof(CANDIDATEFORM));
+	form->dwStyle = CFS_EXCLUDE;
+	form->ptCurrentPos.x = caret_coord.mX;
+	form->ptCurrentPos.y = caret_coord.mY;
+	form->rcArea.left   = top_left.mX;
+	form->rcArea.top    = top_left.mY;
+	form->rcArea.right  = bottom_right.mX;
+	form->rcArea.bottom = bottom_right.mY;
 }
 
 
@@ -3416,4 +3597,455 @@ void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position )
 	}
 }
 
+
+void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control,
+		IMECHARPOSITION *char_position)
+{
+	LLCoordScreen caret_coord, top_left, bottom_right;
+	convertCoords(caret, &caret_coord);
+	convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left);
+	convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right);
+
+	char_position->pt.x = caret_coord.mX;
+	char_position->pt.y = top_left.mY;	// Windows wants the coordinate of upper left corner of a character...
+	char_position->cLineHeight = bottom_right.mY - top_left.mY;
+	char_position->rcDocument.left   = top_left.mX;
+	char_position->rcDocument.top    = top_left.mY;
+	char_position->rcDocument.right  = bottom_right.mX;
+	char_position->rcDocument.bottom = bottom_right.mY;
+}
+
+void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont)
+{
+	// Our font is a list of FreeType recognized font files that may
+	// not have a corresponding ones in Windows' fonts.  Hence, we
+	// can't simply tell Windows which font we are using.  We will
+	// notify a _standard_ font for a current input locale instead.
+	// We use a hard-coded knowledge about the Windows' standard
+	// configuration to do so...
+
+	memset(logfont, 0, sizeof(LOGFONT));
+
+	const WORD lang_id = LOWORD(GetKeyboardLayout(0));
+	switch (PRIMARYLANGID(lang_id))
+	{
+	case LANG_CHINESE:
+		// We need to identify one of two Chinese fonts.
+		switch (SUBLANGID(lang_id))
+		{
+		case SUBLANG_CHINESE_SIMPLIFIED:
+		case SUBLANG_CHINESE_SINGAPORE:
+			logfont->lfCharSet = GB2312_CHARSET;
+			lstrcpy(logfont->lfFaceName, TEXT("SimHei"));
+			break;
+		case SUBLANG_CHINESE_TRADITIONAL:
+		case SUBLANG_CHINESE_HONGKONG:
+		case SUBLANG_CHINESE_MACAU:
+		default:
+			logfont->lfCharSet = CHINESEBIG5_CHARSET;
+			lstrcpy(logfont->lfFaceName, TEXT("MingLiU"));
+			break;			
+		}
+		break;
+	case LANG_JAPANESE:
+		logfont->lfCharSet = SHIFTJIS_CHARSET;
+		lstrcpy(logfont->lfFaceName, TEXT("MS Gothic"));
+		break;		
+	case LANG_KOREAN:
+		logfont->lfCharSet = HANGUL_CHARSET;
+		lstrcpy(logfont->lfFaceName, TEXT("Gulim"));
+		break;
+	default:
+		logfont->lfCharSet = ANSI_CHARSET;
+		lstrcpy(logfont->lfFaceName, TEXT("Tahoma"));
+		break;
+	}
+							
+	logfont->lfHeight = mPreeditor->getPreeditFontSize();
+	logfont->lfWeight = FW_NORMAL;
+}	
+
+U32 LLWindowWin32::fillReconvertString(const LLWString &text,
+	S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string)
+{
+	const llutf16string text_utf16 = wstring_to_utf16str(text);
+	const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR);
+	if (reconvert_string && reconvert_string->dwSize >= required_size)
+	{
+		const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus);
+		const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length);
+
+		reconvert_string->dwVersion = 0;
+		reconvert_string->dwStrLen = text_utf16.length();
+		reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING);
+		reconvert_string->dwCompStrLen = focus_utf16_length;
+		reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR);
+		reconvert_string->dwTargetStrLen = 0;
+		reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR);
+
+		const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING));
+		memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR));
+	}
+	return required_size;
+}
+
+void LLWindowWin32::updateLanguageTextInputArea()
+{
+	if (!mPreeditor || !LLWinImm::isAvailable())
+	{
+		return;
+	}
+
+	LLCoordGL caret_coord;
+	LLRect preedit_bounds;
+	if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL))
+	{
+		mLanguageTextInputPointGL = caret_coord;
+		mLanguageTextInputAreaGL = preedit_bounds;
+
+		CANDIDATEFORM candidate_form;
+		fillCandidateForm(caret_coord, preedit_bounds, &candidate_form);
+
+		HIMC himc = LLWinImm::getContext(mWindowHandle);
+		// Win32 document says there may be up to 4 candidate windows.
+		// This magic number 4 appears only in the document, and
+		// there are no constant/macro for the value...
+		for (int i = 3; i >= 0; --i)
+		{
+			candidate_form.dwIndex = i;
+			LLWinImm::setCandidateWindow(himc, &candidate_form);
+		}
+		LLWinImm::releaseContext(mWindowHandle, himc);
+	}
+}
+
+void LLWindowWin32::interruptLanguageTextInput()
+{
+	if (mPreeditor)
+	{
+		if (LLWinImm::isAvailable())
+		{
+			HIMC himc = LLWinImm::getContext(mWindowHandle);
+			LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
+			LLWinImm::releaseContext(mWindowHandle, himc);
+		}
+		mPreeditor->resetPreedit();
+	}
+}
+
+void LLWindowWin32::handleStartCompositionMessage()
+{
+	// Let IME know the font to use in feedback UI.
+	LOGFONT logfont;
+	fillCompositionLogfont(&logfont);
+	HIMC himc = LLWinImm::getContext(mWindowHandle);
+	LLWinImm::setCompositionFont(himc, &logfont);
+	LLWinImm::releaseContext(mWindowHandle, himc);
+}
+
+// Handle WM_IME_COMPOSITION message.
+
+void LLWindowWin32::handleCompositionMessage(const U32 indexes)
+{
+	BOOL needs_update = FALSE;
+	LLWString result_string;
+	LLWString preedit_string;
+	S32 preedit_string_utf16_length = 0;
+	LLPreeditor::segment_lengths_t preedit_segment_lengths;
+	LLPreeditor::standouts_t preedit_standouts;
+
+	// Step I: Receive details of preedits from IME.
+
+	HIMC himc = LLWinImm::getContext(mWindowHandle);
+
+	if (indexes & GCS_RESULTSTR)
+	{
+		LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0);
+		if (size >= 0)
+		{
+			const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1];
+			size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size);
+			if (size > 0)
+			{
+				result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR)));
+			}
+			delete[] data;
+			needs_update = TRUE;
+		}
+	}
+	
+	if (indexes & GCS_COMPSTR)
+	{
+		LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0);
+		if (size >= 0)
+		{
+			const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1];
+			size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size);
+			if (size > 0)
+			{
+				preedit_string_utf16_length = size / sizeof(WCHAR);
+				preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR)));
+			}
+			delete[] data;
+			needs_update = TRUE;
+		}
+	}
+
+	if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0)
+	{
+		LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0);
+		if (size > 0)
+		{
+			const LPDWORD data = new DWORD[size / sizeof(DWORD)];
+			size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size);
+			if (size >= sizeof(DWORD) * 2
+				&& data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length)
+			{
+				preedit_segment_lengths.resize(size / sizeof(DWORD) - 1);
+				S32 offset = 0;
+				for (U32 i = 0; i < preedit_segment_lengths.size(); i++)
+				{
+					const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]);
+					preedit_segment_lengths[i] = length;
+					offset += length;
+				}
+			}
+			delete[] data;
+		}
+	}
+
+	if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1)
+	{
+		LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0);
+		if (size > 0)
+		{
+			const LPBYTE data = new BYTE[size / sizeof(BYTE)];
+			size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size);
+			if (size == preedit_string_utf16_length)
+			{
+				preedit_standouts.assign(preedit_segment_lengths.size(), FALSE);
+				S32 offset = 0;
+				for (U32 i = 0; i < preedit_segment_lengths.size(); i++)
+				{
+					if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset])
+					{
+						preedit_standouts[i] = TRUE;
+					}
+					offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]);
+				}
+			}
+			delete[] data;
+		}
+	}
+
+	S32 caret_position = preedit_string.length();
+	if (indexes & GCS_CURSORPOS)
+	{
+		const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0);
+		if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length)
+		{
+			caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16);
+		}
+	}
+
+	if (indexes == 0)
+	{
+		// I'm not sure this condition really happens, but
+		// Windows SDK document says it is an indication
+		// of "reset everything."
+		needs_update = TRUE;
+	}
+
+	LLWinImm::releaseContext(mWindowHandle, himc);
+
+	// Step II: Update the active preeditor.
+
+	if (needs_update)
+	{
+		mPreeditor->resetPreedit();
+
+		if (result_string.length() > 0)
+		{
+			for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++)
+			{
+				mPreeditor->handleUnicodeCharHere(*i, FALSE);
+			}
+		}
+
+		if (preedit_string.length() > 0)
+		{
+			if (preedit_segment_lengths.size() == 0)
+			{
+				preedit_segment_lengths.assign(1, preedit_string.length());
+			}
+			if (preedit_standouts.size() == 0)
+			{
+				preedit_standouts.assign(preedit_segment_lengths.size(), FALSE);
+			}
+			mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position);
+		}
+
+		// Some IME doesn't query char position after WM_IME_COMPOSITION,
+		// so we need to update them actively.
+		updateLanguageTextInputArea();
+	}
+}
+
+// Given a text and a focus range, find_context finds and returns a
+// surrounding context of the focused subtext.  A variable pointed
+// to by offset receives the offset in llwchars of the beginning of
+// the returned context string in the given wtext.
+
+static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset)
+{
+	static const S32 CONTEXT_EXCESS = 30;	// This value is by experiences.
+
+	const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS);
+	S32 end = focus + focus_length;
+	while (end < e && '\n' != wtext[end])
+	{
+		end++;
+	}
+
+	const S32 s = llmax(0, focus - CONTEXT_EXCESS);
+	S32 start = focus;
+	while (start > s && '\n' != wtext[start - 1])
+	{
+		--start;
+	}
+
+	*offset = start;
+	return wtext.substr(start, end - start);
+}
+
+// Handle WM_IME_REQUEST message.
+// If it handled the message, returns TRUE.  Otherwise, FALSE.
+// When it handled the message, the value to be returned from
+// the Window Procedure is set to *result.
+
+BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result)
+{
+	if ( mPreeditor )
+	{
+		switch (request)
+		{
+			case IMR_CANDIDATEWINDOW:		// http://msdn2.microsoft.com/en-us/library/ms776080.aspx
+			{
+				LLCoordGL caret_coord;
+				LLRect preedit_bounds;
+				mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL);
+				
+				CANDIDATEFORM *const form = (CANDIDATEFORM *)param;
+				DWORD const dwIndex = form->dwIndex;
+				fillCandidateForm(caret_coord, preedit_bounds, form);
+				form->dwIndex = dwIndex;
+
+				*result = 1;
+				return TRUE;
+			}
+			case IMR_QUERYCHARPOSITION:
+			{
+				IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param;
+
+				// char_position->dwCharPos counts in number of
+				// WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the
+				// number to getPreeditLocation.  
+
+				const LLWString & wtext = mPreeditor->getWText();
+				S32 preedit, preedit_length;
+				mPreeditor->getPreeditRange(&preedit, &preedit_length);
+				LLCoordGL caret_coord;
+				LLRect preedit_bounds, text_control;
+				const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos);
+
+				if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control))
+				{
+					llwarns << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << llendl;
+					return FALSE;
+				}
+				fillCharPosition(caret_coord, preedit_bounds, text_control, char_position);
+
+				*result = 1;
+				return TRUE;
+			}
+			case IMR_COMPOSITIONFONT:
+			{
+				fillCompositionLogfont((LOGFONT *)param);
+
+				*result = 1;
+				return TRUE;
+			}
+			case IMR_RECONVERTSTRING:
+			{
+				mPreeditor->resetPreedit();
+				const LLWString & wtext = mPreeditor->getWText();
+				S32 select, select_length;
+				mPreeditor->getSelectionRange(&select, &select_length);
+
+				S32 context_offset;
+				const LLWString context = find_context(wtext, select, select_length, &context_offset);
+
+				RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param;
+				const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string);
+				if (reconvert_string)
+				{
+					if (select_length == 0)
+					{
+						// Let the IME to decide the reconversion range, and
+						// adjust the reconvert_string structure accordingly.
+						HIMC himc = LLWinImm::getContext(mWindowHandle);
+						const BOOL adjusted = LLWinImm::setCompositionString(himc,
+									SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0);
+						LLWinImm::releaseContext(mWindowHandle, himc);
+						if (adjusted)
+						{
+							const llutf16string & text_utf16 = wstring_to_utf16str(context);
+							const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR);
+							const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen;
+							select = utf16str_wstring_length(text_utf16, new_preedit_start);
+							select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select;
+							select += context_offset;
+						}
+					}
+					mPreeditor->markAsPreedit(select, select_length);
+				}
+
+				*result = size;
+				return TRUE;
+			}
+			case IMR_CONFIRMRECONVERTSTRING:
+			{
+				*result = FALSE;
+				return TRUE;
+			}
+			case IMR_DOCUMENTFEED:
+			{
+				const LLWString & wtext = mPreeditor->getWText();
+				S32 preedit, preedit_length;
+				mPreeditor->getPreeditRange(&preedit, &preedit_length);
+				
+				S32 context_offset;
+				LLWString context = find_context(wtext, preedit, preedit_length, &context_offset);
+				preedit -= context_offset;
+				if (preedit_length)
+				{
+					// IMR_DOCUMENTFEED may be called when we have an active preedit.
+					// We should pass the context string *excluding* the preedit string.
+					// Otherwise, some IME are confused.
+					context.erase(preedit, preedit_length);
+				}
+				
+				RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param;
+				*result = fillReconvertString(context, preedit, 0, reconvert_string);
+				return TRUE;
+			}
+			default:
+				return FALSE;
+		}
+	}
+
+	return FALSE;
+}
+
+
 #endif // LL_WINDOWS
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 602e06600f25159cac347247aa669d59d7507097..9ad99b02016dd045ce9be4d2823009135faf2013 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -109,8 +109,10 @@ class LLWindowWin32 : public LLWindow
 	/*virtual*/ void bringToFront();
 	/*virtual*/ void focusClient();
 
-	/*virtual*/ void allowLanguageTextInput(BOOL b);
+	/*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b);
 	/*virtual*/ void setLanguageTextInput( const LLCoordGL & pos );
+	/*virtual*/ void updateLanguageTextInputArea();
+	/*virtual*/ void interruptLanguageTextInput();
 
 protected:
 	LLWindowWin32(
@@ -139,6 +141,14 @@ class LLWindowWin32 : public LLWindow
 
 	BOOL	shouldPostQuit() { return mPostQuit; }
 
+	void	fillCompositionForm(const LLRect& bounds, COMPOSITIONFORM *form);
+	void	fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, CANDIDATEFORM *form);
+	void	fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, IMECHARPOSITION *char_position);
+	void	fillCompositionLogfont(LOGFONT *logfont);
+	U32		fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string);
+	void	handleStartCompositionMessage();
+	void	handleCompositionMessage(U32 indexes);
+	BOOL	handleImeRequests(U32 request, U32 param, LRESULT *result);
 
 protected:
 	//
@@ -189,6 +199,10 @@ class LLWindowWin32 : public LLWindow
 	static DWORD	sWinIMEConversionMode;
 	static DWORD	sWinIMESentenceMode;
 	static LLCoordWindow sWinIMEWindowPosition;
+	LLCoordGL		mLanguageTextInputPointGL;
+	LLRect			mLanguageTextInputAreaGL;
+
+	LLPreeditor		*mPreeditor;
 
 	friend class LLWindowManager;
 };
diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp
index d5e806f6cb81a7ceea822d96a31ec529ebfd329e..a984b597e47ad893342735e66f5eec96be2c8a95 100644
--- a/indra/mac_updater/mac_updater.cpp
+++ b/indra/mac_updater/mac_updater.cpp
@@ -496,14 +496,13 @@ bool isDirWritable(FSRef &dir)
 	// This is kinda lame, but will pretty much always give the right answer.
 	
 	OSStatus err = noErr;
-	char temp[PATH_MAX];		/* Flawfinder: ignore */
+	char temp[PATH_MAX] = "";		/* Flawfinder: ignore */
 
 	err = FSRefMakePath(&dir, (UInt8*)temp, sizeof(temp));
 
 	if(err == noErr)
 	{
-		temp[0] = '\0';
-		strncat(temp, "/.test_XXXXXX", sizeof(temp) - 1);
+		strncat(temp, "/.test_XXXXXX", (sizeof(temp) - strlen(temp)) - 1);
 		
 		if(mkdtemp(temp) != NULL)
 		{
@@ -557,8 +556,8 @@ static std::string HFSUniStr255_to_utf8str(const HFSUniStr255* src)
 
 int restoreObject(const char* aside, const char* target, const char* path, const char* object)
 {
-	char source[PATH_MAX];		/* Flawfinder: ignore */
-	char dest[PATH_MAX];		/* Flawfinder: ignore */
+	char source[PATH_MAX] = "";		/* Flawfinder: ignore */
+	char dest[PATH_MAX] = "";		/* Flawfinder: ignore */
 	snprintf(source, sizeof(source), "%s/%s/%s", aside, path, object);		
 	snprintf(dest, sizeof(dest), "%s/%s", target, path);		
 	FSRef sourceRef;
@@ -592,7 +591,7 @@ int restoreObject(const char* aside, const char* target, const char* path, const
 // Replace any mention of "Second Life" with the product name.
 void filterFile(const char* filename)
 {
-	char temp[PATH_MAX];		/* Flawfinder: ignore */
+	char temp[PATH_MAX] = "";		/* Flawfinder: ignore */
 	// First copy the target's version, so we can run it through sed.
 	snprintf(temp, sizeof(temp), "cp '%s' '%s.tmp'", filename, filename);		
 	system(temp);		/* Flawfinder: ignore */
@@ -724,13 +723,13 @@ void *updatethreadproc(void*)
 {
 	char tempDir[PATH_MAX] = "";		/* Flawfinder: ignore */
 	FSRef tempDirRef;
-	char temp[PATH_MAX];	/* Flawfinder: ignore */
+	char temp[PATH_MAX] = "";	/* Flawfinder: ignore */
 	// *NOTE: This buffer length is used in a scanf() below.
 	char deviceNode[1024] = "";	/* Flawfinder: ignore */
 	FILE *downloadFile = NULL;
 	OSStatus err;
 	ProcessSerialNumber psn;
-	char target[PATH_MAX];		/* Flawfinder: ignore */
+	char target[PATH_MAX] = "";		/* Flawfinder: ignore */
 	FSRef targetRef;
 	FSRef targetParentRef;
 	FSVolumeRefNum targetVol;
@@ -907,14 +906,14 @@ void *updatethreadproc(void*)
 		if(err != noErr)
 			throw 0;
 		
-		temp[0] = '\0';
-		strncat(temp, "/SecondLifeUpdate_XXXXXX", sizeof(temp) - 1);
+		strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1);
 		if(mkdtemp(temp) == NULL)
 		{
 			throw 0;
 		}
 		
-		strcpy(tempDir, temp);		/* Flawfinder: ignore */
+		strncpy(tempDir, temp, sizeof(tempDir));
+		temp[sizeof(tempDir) - 1] = '\0';
 		
 		llinfos << "tempDir is " << tempDir << llendl;
 
diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt
index 066990bafa6c8fe446e499879f507d0c75f4e492..91d59a2c6b2224f602b3ae8532efa6b2a0ae3a72 100644
--- a/indra/newview/gpu_table.txt
+++ b/indra/newview/gpu_table.txt
@@ -49,6 +49,9 @@ ATI Radeon X1600				.*ATI.*Radeon X16.*						3
 ATI Radeon X1700				.*ATI.*Radeon X17.*						3
 ATI Radeon X1800				.*ATI.*Radeon X18.*						3
 ATI Radeon X1900				.*ATI.*Radeon X19.*						3
+ATI Radeon X2400				.*ATI.*Radeon X24.*						3
+ATI Radeon X2600				.*ATI.*Radeon X26.*						3
+ATI Radeon X2900				.*ATI.*Radeon X29.*						3
 ATI Radeon X300					.*ATI.*Radeon X3.*						2
 ATI Radeon X400					.*ATI.*Radeon X4.*						2
 ATI Radeon X500					.*ATI.*Radeon X5.*						2
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 63d1986deca0f8ff20f955064efe1f00b67fc4a5..ad934abfa75a07598c8ec55525385ee365193868 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1530,6 +1530,9 @@ bool LLAppViewer::cleanup()
 	delete gGlobalEconomy;
 	gGlobalEconomy = NULL;
 
+	delete gActiveChannelSpeakerMgr;
+	gActiveChannelSpeakerMgr = NULL;
+
 	delete gLocalSpeakerMgr;
 	gLocalSpeakerMgr = NULL;
 
@@ -3015,7 +3018,7 @@ const std::vector<std::string>& LLAppViewer::getLoginURIs() const
 	if (gLoginURIs.empty())
 	{
 		// not specified on the command line, use value from table
-		gLoginURIs = LLSRV::rewriteURI(gGridInfo[gGridChoice].mLoginURI);
+		gLoginURIs.push_back(gGridInfo[gGridChoice].mLoginURI);
 	}
 	return gLoginURIs;
 }
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 1bcd1e1ab4a75fafd85a1b5dd88f3f519e32656b..d957a3783ac9bd43b9ea390d5d193161ff0d6058 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -372,10 +372,14 @@ void LLFeatureManager::loadGPUClass()
 		
 		char* ex = strtok(expr, ".*");
 		char* rnd = (char*) renderer.c_str();
-		
+
 		while (ex != NULL && rnd != NULL)
 		{
 			rnd = strstr(rnd, ex);
+			if (rnd != NULL)
+			{
+				rnd += strlen(ex);
+			}
 			ex = strtok(NULL, ".*");
 		}
 		
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index 543dd94f3b5b3afef75d7ae7ae2014763b5f8e26..3b96a4ce5eb01b494d6bd8c4815c06011c79b5b9 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -1045,7 +1045,8 @@ BOOL LLPanelLandObjects::postBuild()
 	
 	mSelectedObjects = LLUICtrlFactory::getTextBoxByName(this, "selected_objects_text");
 	mCleanOtherObjectsTime = LLUICtrlFactory::getLineEditorByName(this, "clean other time");
-	mCleanOtherObjectsTime->setFocusLostCallback(onLostFocus);	
+	mCleanOtherObjectsTime->setFocusLostCallback(onLostFocus);
+	mCleanOtherObjectsTime->setCommitCallback(onCommitClean);
 	childSetPrevalidate("clean other time", LLLineEditor::prevalidateNonNegativeS32);
 	childSetUserData("clean other time", this);
 	
@@ -1817,6 +1818,12 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata)
 
 // static
 void LLPanelLandObjects::onLostFocus(LLUICtrl *caller, void* user_data)
+{
+	onCommitClean(caller, user_data);
+}
+
+// static
+void LLPanelLandObjects::onCommitClean(LLUICtrl *caller, void* user_data)
 {
 	LLPanelLandObjects	*lop = (LLPanelLandObjects *)user_data;
 	LLParcel* parcel = lop->mParcel->getParcel();
diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h
index 9be813f8fdf7230f2f4c83f3b52ec981d709453d..fa941caf787d8a1df9e47254d66ab25253b87654 100644
--- a/indra/newview/llfloaterland.h
+++ b/indra/newview/llfloaterland.h
@@ -258,7 +258,7 @@ class LLPanelLandObjects
 
 	static void onCommitList(LLUICtrl* ctrl, void* data);
 	static void onLostFocus(LLUICtrl* caller, void* user_data);
-	
+	static void onCommitClean(LLUICtrl* caller, void* user_data);
 	static void processParcelObjectOwnersReply(LLMessageSystem *msg, void **);
 	
 	virtual BOOL postBuild();
diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp
index 9bf1f785b001897bdb123578cf6893cd889258db..ffa1e13bf27b5167de57df0ef57db9ffb4d1d9b1 100644
--- a/indra/newview/llfloatersellland.cpp
+++ b/indra/newview/llfloatersellland.cpp
@@ -492,7 +492,14 @@ void LLFloaterSellLandUI::doSellLand(void *userdata)
 		args["[SALE_PRICE]"] = llformat("%d",sale_price);
 		args["[NAME]"] = authorizedBuyerName;
 
-		gViewerWindow->alertXml("ConfirmLandSaleChange", args, onConfirmSale, self);
+		if (sell_to_anyone)
+		{
+			gViewerWindow->alertXml("ConfirmLandSaleToAnyoneChange", args, onConfirmSale, self);
+		}
+		else
+		{
+			gViewerWindow->alertXml("ConfirmLandSaleChange", args, onConfirmSale, self);
+		}
 	}
 	else
 	{
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 353020d9c4bb50123522f4c6ed05489a6ede9964..4c03a1561990e1327b70496e4edbf9dd70f1760a 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -11,7 +11,7 @@
  * The source code in this file ("Source Code") is provided by Linden Lab
  * to you under the terms of the GNU General Public License, version 2.0
  * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * ("Other License"), formally executed by you and Linden Lab.	Terms of
  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  * online at http://secondlife.com/developers/opensource/gplv2
  * 
@@ -126,18 +126,18 @@ class LLMapInventoryObserver : public LLInventoryObserver
 {
 public:
 	LLMapInventoryObserver() {}
- 	virtual ~LLMapInventoryObserver() {}
-  	virtual void changed(U32 mask);
+	virtual ~LLMapInventoryObserver() {}
+	virtual void changed(U32 mask);
 };
   
 void LLMapInventoryObserver::changed(U32 mask)
 {
-  	// if there's a change we're interested in.
- 	if((mask & (LLInventoryObserver::CALLING_CARD | LLInventoryObserver::ADD |
- 				LLInventoryObserver::REMOVE)) != 0)
-  	{
- 		gFloaterWorldMap->inventoryChanged();
-  	}
+	// if there's a change we're interested in.
+	if((mask & (LLInventoryObserver::CALLING_CARD | LLInventoryObserver::ADD |
+				LLInventoryObserver::REMOVE)) != 0)
+	{
+		gFloaterWorldMap->inventoryChanged();
+	}
 }
 
 class LLMapFriendObserver : public LLFriendObserver
@@ -177,8 +177,8 @@ LLFloaterWorldMap::LLFloaterWorldMap()
 			  FALSE,	// drag on left
 			  TRUE,		// minimize
 			  TRUE),	// close
- 	mInventory(NULL),
- 	mInventoryObserver(NULL),
+	mInventory(NULL),
+	mInventoryObserver(NULL),
 	mFriendObserver(NULL),
 	mCompletingRegionName(""),
 	mWaitingForTracker(FALSE),
@@ -229,12 +229,18 @@ BOOL LLFloaterWorldMap::postBuild()
 	{
 		avatar_combo->selectFirstItem();
 		avatar_combo->setPrearrangeCallback( onAvatarComboPrearrange );
+		avatar_combo->setTextEntryCallback( onComboTextEntry );
 	}
 
 	childSetAction("DoSearch", onLocationCommit, this);
 
 	childSetFocusChangedCallback("location", updateSearchEnabled);
-	childSetKeystrokeCallback("location", (void (*)(LLLineEditor*,void*))updateSearchEnabled, NULL);
+
+	LLLineEditor *location_editor = LLUICtrlFactory::getLineEditorByName(this, "location");
+	if (location_editor)
+	{
+		location_editor->setKeystrokeCallback( onSearchTextEntry );
+	}
 	
 	childSetCommitCallback("search_results", onCommitSearchResult, this);
 	childSetDoubleClickCallback("search_results", onClickTeleportBtn);
@@ -249,6 +255,7 @@ BOOL LLFloaterWorldMap::postBuild()
 	{
 		landmark_combo->selectFirstItem();
 		landmark_combo->setPrearrangeCallback( onLandmarkComboPrearrange );
+		landmark_combo->setTextEntryCallback( onComboTextEntry );
 	}
 
 	childSetAction("Go Home", onGoHome, this);
@@ -284,9 +291,9 @@ LLFloaterWorldMap::~LLFloaterWorldMap()
 	// All cleaned up by LLView destructor
 	mTabs = NULL;
 
- 	// Inventory deletes all observers on shutdown
- 	mInventory = NULL;
- 	mInventoryObserver = NULL;
+	// Inventory deletes all observers on shutdown
+	mInventory = NULL;
+	mInventoryObserver = NULL;
 
 	// avatar tracker will delete this for us.
 	mFriendObserver = NULL;
@@ -509,7 +516,7 @@ void LLFloaterWorldMap::draw()
 	}
 
 	childSetEnabled("Teleport", (BOOL)tracking_status);
-// 	childSetEnabled("Clear", (BOOL)tracking_status);
+//	childSetEnabled("Clear", (BOOL)tracking_status);
 	childSetEnabled("Show Destination", (BOOL)tracking_status || gWorldMap->mIsTrackingUnknownLocation);
 	childSetEnabled("copy_slurl", (mSLURL.size() > 0) );
 
@@ -595,7 +602,7 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
 		if (combo) name = combo->getSimple();
 		mTrackedStatus = LLTracker::TRACKING_LANDMARK;
 		LLTracker::trackLandmark(mLandmarkAssetIDList.get( idx ),	// assetID
-								mLandmarkItemIDList.get( idx ),	// itemID
+								mLandmarkItemIDList.get( idx ), // itemID
 								name);			// name
 
 		if( asset_id != sHomeID )
@@ -605,7 +612,7 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id )
 		}
 
 		// We have to download both region info and landmark data, so set busy. JC
-// 		getWindow()->incBusyCount();
+//		getWindow()->incBusyCount();
 	}
 	else
 	{
@@ -1000,7 +1007,7 @@ void LLFloaterWorldMap::clearAvatarSelection(BOOL clear_ui)
 void LLFloaterWorldMap::adjustZoomSliderBounds()
 {
 	// World size in regions
-	S32 world_width_regions  = gWorldMap->getWorldWidth() / REGION_WIDTH_UNITS;
+	S32 world_width_regions	 = gWorldMap->getWorldWidth() / REGION_WIDTH_UNITS;
 	S32 world_height_regions = gWorldMap->getWorldHeight() / REGION_WIDTH_UNITS;
 
 	// Pad the world size a little bit, so we have a nice border on
@@ -1044,7 +1051,7 @@ void LLFloaterWorldMap::adjustZoomSliderBounds()
 // static
 void LLFloaterWorldMap::onPanBtn( void* userdata )
 {
-	if( !gFloaterWorldMap )	return;
+	if( !gFloaterWorldMap ) return;
 
 	EPanDirection direction = (EPanDirection)(intptr_t)userdata;
 
@@ -1055,7 +1062,7 @@ void LLFloaterWorldMap::onPanBtn( void* userdata )
 	case PAN_UP:	pan_y = -1;	break;
 	case PAN_DOWN:	pan_y = 1;	break;
 	case PAN_LEFT:	pan_x = 1;	break;
-	case PAN_RIGHT:	pan_x = -1;	break;
+	case PAN_RIGHT: pan_x = -1;	break;
 	default:		llassert(0);	return;
 	}
 
@@ -1095,6 +1102,21 @@ void LLFloaterWorldMap::onLandmarkComboPrearrange( LLUICtrl* ctrl, void* userdat
 
 }
 
+void LLFloaterWorldMap::onComboTextEntry( LLLineEditor* ctrl, void* userdata )
+{
+	// Reset the tracking whenever we start typing into any of the search fields,
+	// so that hitting <enter> does an auto-complete versus teleporting us to the
+	// previously selected landmark/friend.
+	LLTracker::clearFocus();
+}
+
+// static
+void LLFloaterWorldMap::onSearchTextEntry( LLLineEditor* ctrl, void* userdata )
+{
+	onComboTextEntry(ctrl, userdata);
+	updateSearchEnabled(ctrl, userdata);
+}
+
 // static 
 void LLFloaterWorldMap::onLandmarkComboCommit( LLUICtrl* ctrl, void* userdata )
 {
@@ -1260,7 +1282,7 @@ void LLFloaterWorldMap::onClearBtn(void* data)
 	self->mTrackedStatus = LLTracker::TRACKING_NOTHING;
 	LLTracker::stopTracking((void *)(intptr_t)TRUE);
 	gWorldMap->mIsTrackingUnknownLocation = FALSE;
-	self->mSLURL = "";  				// Clear the SLURL since it's invalid
+	self->mSLURL = "";				// Clear the SLURL since it's invalid
 	self->mSetToUserPosition = TRUE;	// Revert back to the current user position
 }
 
@@ -1329,7 +1351,7 @@ void LLFloaterWorldMap::centerOnTarget(BOOL animate)
 		else
 		{
 			// We've got the position finally, so we're no longer busy. JC
-// 			getWindow()->decBusyCount();
+//			getWindow()->decBusyCount();
 			pos_global = LLTracker::getTrackedPositionGlobal() - gAgent.getCameraPositionGlobal();
 		}
 	}
diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h
index b98bbbbe4455be1cf82aa39014f7c95b29d7c135..c069b4092932399364af873eb7c532e9da1ff9cc 100644
--- a/indra/newview/llfloaterworldmap.h
+++ b/indra/newview/llfloaterworldmap.h
@@ -10,7 +10,7 @@
  * The source code in this file ("Source Code") is provided by Linden Lab
  * to you under the terms of the GNU General Public License, version 2.0
  * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * ("Other License"), formally executed by you and Linden Lab.	Terms of
  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  * online at http://secondlife.com/developers/opensource/gplv2
  * 
@@ -90,16 +90,16 @@ class LLFloaterWorldMap : public LLFloater
 	void			trackLocation(const LLVector3d& pos);
 	void			trackEvent(const LLItemInfo &event_info);
 	void			trackGenericItem(const LLItemInfo &item);
-	void 			trackURL(const LLString& region_name, S32 x_coord, S32 y_coord, S32 z_coord);
+	void			trackURL(const LLString& region_name, S32 x_coord, S32 y_coord, S32 z_coord);
 
 	static const LLUUID& getHomeID() { return sHomeID; }
 
 	// A z_attenuation of 0.0f collapses the distance into the X-Y plane
-	F32 			getDistanceToDestination(const LLVector3d& pos_global, F32 z_attenuation = 0.5f) const;
+	F32			getDistanceToDestination(const LLVector3d& pos_global, F32 z_attenuation = 0.5f) const;
 
-	void 			clearLocationSelection(BOOL clear_ui = FALSE);
-	void 			clearAvatarSelection(BOOL clear_ui = FALSE);
-	void 			clearLandmarkSelection(BOOL clear_ui = FALSE);
+	void			clearLocationSelection(BOOL clear_ui = FALSE);
+	void			clearAvatarSelection(BOOL clear_ui = FALSE);
+	void			clearLandmarkSelection(BOOL clear_ui = FALSE);
 
 	// Adjust the maximally zoomed out limit of the zoom slider so you can
 	// see the whole world, plus a little.
@@ -118,12 +118,15 @@ class LLFloaterWorldMap : public LLFloater
 
 	static void		onLandmarkComboPrearrange( LLUICtrl* ctrl, void* data );
 	static void		onLandmarkComboCommit( LLUICtrl* ctrl, void* data );
-	
+
 	static void		onAvatarComboPrearrange( LLUICtrl* ctrl, void* data );
 	static void		onAvatarComboCommit( LLUICtrl* ctrl, void* data );
 
 	static void		onCommitBackground(void* data, bool from_click);
 
+	static void		onComboTextEntry( LLLineEditor* ctrl, void* data );
+	static void		onSearchTextEntry( LLLineEditor* ctrl, void* data );
+
 	static void		onClearBtn(void*);
 	static void		onFlyBtn(void*);
 	static void		onClickTeleportBtn(void*);
@@ -143,7 +146,7 @@ class LLFloaterWorldMap : public LLFloater
 	static void		onGoToLandmarkDialog(S32 option,void* userdata);
 	void			flyToLandmark();
 	void			teleportToLandmark();
-	void 			setLandmarkVisited();
+	void			setLandmarkVisited();
 
 	void			buildAvatarIDList();
 	void			flyToAvatar();
@@ -154,7 +157,7 @@ class LLFloaterWorldMap : public LLFloater
 	static void		onCommitLocation( LLUICtrl* ctrl, void* userdata );
 	static void		onCommitSearchResult( LLUICtrl* ctrl, void* userdata );
 
-	void 			cacheLandmarkPosition();
+	void			cacheLandmarkPosition();
 
 protected:
 	LLTabContainerCommon*	mTabs;
@@ -165,7 +168,7 @@ class LLFloaterWorldMap : public LLFloater
 
 	LLDynamicArray<LLUUID>	mLandmarkAssetIDList;
 	LLDynamicArray<LLUUID>	mLandmarkItemIDList;
-	BOOL 					mHasLandmarkPosition;
+	BOOL					mHasLandmarkPosition;
 
 	static const LLUUID	sHomeID;
 
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index eb9addcf5ce702891a36d8061c70e8b9293fddba..2577474e243583b951fa5ca81bbef801b12def7c 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -3681,7 +3681,7 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask, BOOL called_from_parent )
 	// SL-51858: Key presses are not being passed to the Popup menu.
 	// A proper fix is non-trivial so instead just close the menu.
 	LLMenuGL* menu = (LLMenuGL*)LLView::getViewByHandle(mPopupMenuHandle);
-	if (menu->isOpen())
+	if (menu && menu->isOpen())
 	{
 		LLMenuGL::sMenuContainer->hideMenus();
 	}
@@ -3921,6 +3921,14 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_pare
 	BOOL handled = FALSE;
 	if (gFocusMgr.childHasKeyboardFocus(getRoot()))
 	{
+		// SL-51858: Key presses are not being passed to the Popup menu.
+		// A proper fix is non-trivial so instead just close the menu.
+		LLMenuGL* menu = (LLMenuGL*)LLView::getViewByHandle(mPopupMenuHandle);
+		if (menu && menu->isOpen())
+		{
+			LLMenuGL::sMenuContainer->hideMenus();
+		}
+
 		//do text search
 		if (mSearchTimer.getElapsedTimeF32() > gSavedSettings.getF32("TypeAheadTimeout"))
 		{
diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp
index c213d268481e86cf05b025c165b426ab3bb46319..82a42a18b56ce4510725b0ed58129e8b58dd1916 100644
--- a/indra/newview/llgroupmgr.cpp
+++ b/indra/newview/llgroupmgr.cpp
@@ -867,6 +867,12 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data)
 				llinfos << "Received null group member data." << llendl;
 			}
 		}
+
+		//if group members are loaded while titles are missing, load the titles.
+		if(group_datap->mTitles.size() < 1)
+		{
+			gGroupMgr->sendGroupTitlesRequest(group_id);
+		}
 	}
 
 	if (group_datap->mMembers.size() ==  (U32)group_datap->mMemberCount)
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 12617efb673cf10a52a25395f60983aa7005805f..9c9b1ad2573d9d10c75dec82fc17d7917fe0c58f 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -2719,6 +2719,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 						  && (LLUUID::null != item->getCreatorUUID())
 						  && (item->getCreatorUUID() != gAgent.getID()));
 		BOOL user_online = (LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()));
+		items.push_back("Send Instant Message Separator");
 		items.push_back("Send Instant Message");
 		items.push_back("Offer Teleport...");
 		items.push_back("Conference Chat");
@@ -4294,21 +4295,24 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 		getClipboardEntries(true, items, disabled_items, flags);
 
 		items.push_back("Wearable Separator");
+		
 		items.push_back("Wearable Wear");
 		items.push_back("Wearable Edit");
+
+
 		if ((flags & FIRST_SELECTED_ITEM) == 0)
 		{
 			disabled_items.push_back("Wearable Edit");
 		}
-		/*menu.appendSeparator();
-		menu.append(new LLMenuItemCallGL("Wear",
-										 LLWearableBridge::onWearOnAvatar,
-										 LLWearableBridge::canWearOnAvatar,
-										 (void*)this));
-		menu.append(new LLMenuItemCallGL("Edit",
-										 LLWearableBridge::onEditOnAvatar,
-										 LLWearableBridge::canEditOnAvatar,
-										 (void*)this));*/
+		//menu.appendSeparator();
+		//menu.append(new LLMenuItemCallGL("Wear",
+		//								 LLWearableBridge::onWearOnAvatar,
+		//								 LLWearableBridge::canWearOnAvatar,
+		//								 (void*)this));
+		//menu.append(new LLMenuItemCallGL("Edit",
+		//								 LLWearableBridge::onEditOnAvatar,
+		//								 LLWearableBridge::canEditOnAvatar,
+		//								 (void*)this));
 
 		if( item && (item->getType() == LLAssetType::AT_CLOTHING) )
 		{
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 36e3f9a5e909efc54e667e976c7f32ca4808c1aa..2f5f154b772ea05cb23ab6afdede0ac21ca2d75f 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -2132,15 +2132,12 @@ void LLManipTranslate::renderTranslationHandles()
 				LLVector3 arrow_axis;
 				getManipAxis(first_object, which_arrow[face], arrow_axis);
 
-				if (fabs(angle_between(camera_axis, arrow_axis) - F_PI_BY_TWO) < F_PI_BY_TWO - HANDLE_HIDE_ANGLE)
-				{
-					renderArrow(which_arrow[face],
-								mManipPart,
-								(face >= 3) ? -mConeSize : mConeSize,
-								(face >= 3) ? -mArrowLengthMeters : mArrowLengthMeters,
-								mConeSize,
-								FALSE);
-				}
+				renderArrow(which_arrow[face],
+							mManipPart,
+							(face >= 3) ? -mConeSize : mConeSize,
+							(face >= 3) ? -mArrowLengthMeters : mArrowLengthMeters,
+							mConeSize,
+							FALSE);
 			}
 		}
 	}
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index f36e282ea0b8f5061e03e3254daed8ff4bc7ee9b..4d02af8faecb6c710c40a9c9d77f82ae723d4619 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -62,6 +62,8 @@
 #include "llviewergenericmessage.h"	// for gGenericDispatcher
 #include "llviewerwindow.h"
 #include "llworld.h" //for particle system banning
+#include "llviewerobject.h" 
+#include "llviewerobjectlist.h"
 
 LLMuteList* gMuteListp = NULL;
 
@@ -513,8 +515,21 @@ BOOL LLMuteList::saveToFile(const LLString& filename)
 
 BOOL LLMuteList::isMuted(const LLUUID& id, const LLString& name, U32 flags) const
 {
+	LLUUID id_to_check = id;
+	
+	// for objects, check for muting on their parent prim
+	LLViewerObject *objectp = gObjectList.findObject(id);
+	if ((objectp) && (!objectp->isAvatar()))
+	{
+		LLViewerObject *parentp = (LLViewerObject *)objectp->getParent();
+		if (parentp)
+		{
+			id_to_check = parentp->getID();
+		}
+	}
+	
 	// don't need name or type for lookup
-	LLMute mute(id);
+	LLMute mute(id_to_check);
 	mute_set_t::const_iterator mute_it = mMutes.find(mute);
 	if (mute_it != mMutes.end())
 	{
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 5b43497f03dae414fbfd1fffb5099e8684a3eb76..c090fd974978bc3c35cc80190d1d792615c8cbea 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -365,6 +365,7 @@ void LLPanelAvatarSecondLife::onDoubleClickGroup(void* data)
 	if(group_list)
 	{
 		LLScrollListItem* item = group_list->getFirstSelected();
+		
 		if(item && item->getUUID().notNull())
 		{
 			llinfos << "Show group info " << item->getUUID() << llendl;
@@ -1565,6 +1566,8 @@ void LLPanelAvatar::resetGroupList()
 				group_string += group_data.mName;
 
 				LLSD row;
+
+				row["id"] = id ;
 				row["columns"][0]["value"] = group_string;
 				row["columns"][0]["font"] = "SANSSERIF_SMALL";
 				row["columns"][0]["width"] = 0;
@@ -2010,8 +2013,7 @@ void LLPanelAvatar::processAvatarGroupsReply(LLMessageSystem *msg, void**)
 				LLString group_string;
 				if (group_id.notNull())
 				{
-					group_string.assign("Member of ");
-					group_string.append(group_name);
+					group_string.assign(group_name);
 				}
 				else
 				{
diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp
index 04fb54b0a7efd363c32d854c22a76e059eff84d0..7163a71bc3e392c6041dec9c5480e4dcf02141bc 100644
--- a/indra/newview/llpanelclassified.cpp
+++ b/indra/newview/llpanelclassified.cpp
@@ -808,17 +808,21 @@ void LLPanelClassified::confirmPublish(S32 option)
 	}
 
 	// Tell all the widgets to reset their dirty state since the ad was just saved
-	mSnapshotCtrl->resetDirty();
-	mNameEditor->resetDirty();
-	mDescEditor->resetDirty();
-	mLocationEditor->resetDirty();
+	if (mSnapshotCtrl)
+		mSnapshotCtrl->resetDirty();
+	if (mNameEditor)
+		mNameEditor->resetDirty();
+	if (mDescEditor)
+		mDescEditor->resetDirty();
+	if (mLocationEditor)
+		mLocationEditor->resetDirty();
 	mLocationChanged = false;
-	mCategoryCombo->resetDirty();
-	mMatureCheck->resetDirty();
+	if (mCategoryCombo)
+		mCategoryCombo->resetDirty();
+	if (mMatureCheck)
+		mMatureCheck->resetDirty();
 	if (mAutoRenewCheck)
-	{
 		mAutoRenewCheck->resetDirty();
-	}
 }
 
 // static
diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp
index e4f7d1e0b27ccf0e81c4ae3acb0031cf790ca930..660de69fb07aaabfaa14bf4e892c426f66b77dd9 100644
--- a/indra/newview/llpreview.cpp
+++ b/indra/newview/llpreview.cpp
@@ -66,12 +66,14 @@ LLPreview::LLPreview(const std::string& name) :
 	mUserResized(FALSE),
 	mCloseAfterSave(FALSE),
 	mAssetStatus(PREVIEW_ASSET_UNLOADED),
-	mItem(NULL)
+	mItem(NULL),
+	mDirty(TRUE)
 {
 	// don't add to instance list, since ItemID is null
 	mAuxItem = new LLInventoryItem; // (LLPointer is auto-deleted)
 	// don't necessarily steal focus on creation -- sometimes these guys pop up without user action
 	mAutoFocus = FALSE;
+	gInventory.addObserver(this);
 }
 
 LLPreview::LLPreview(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, const LLUUID& object_uuid, BOOL allow_resize, S32 min_width, S32 min_height, LLPointer<LLViewerInventoryItem> inv_item )
@@ -84,7 +86,8 @@ LLPreview::LLPreview(const std::string& name, const LLRect& rect, const std::str
 	mUserResized(FALSE),
 	mCloseAfterSave(FALSE),
 	mAssetStatus(PREVIEW_ASSET_UNLOADED),
-	mItem(inv_item)
+	mItem(inv_item),
+	mDirty(TRUE)
 {
 	mAuxItem = new LLInventoryItem;
 	// don't necessarily steal focus on creation -- sometimes these guys pop up without user action
@@ -94,7 +97,7 @@ LLPreview::LLPreview(const std::string& name, const LLRect& rect, const std::str
 	{
 		sInstances[mItemUUID] = this;
 	}
-
+	gInventory.addObserver(this);
 }
 
 LLPreview::~LLPreview()
@@ -118,6 +121,7 @@ LLPreview::~LLPreview()
 			}
 		}
 	}
+	gInventory.removeObserver(this);
 }
 
 void LLPreview::setItemID(const LLUUID& item_id)
@@ -215,6 +219,7 @@ void LLPreview::onCommit()
 		{
 			new_item->updateServer(FALSE);
 			gInventory.updateItem(new_item);
+			gInventory.notifyObservers();
 
 			// If the item is an attachment that is currently being worn,
 			// update the object itself.
@@ -238,6 +243,34 @@ void LLPreview::onCommit()
 	}
 }
 
+void LLPreview::changed(U32 mask)
+{
+	mDirty = TRUE;
+}
+
+void LLPreview::draw()
+{
+	LLFloater::draw();
+	if (mDirty)
+	{
+		mDirty = FALSE;
+		const LLViewerInventoryItem *item = getItem();
+		if (item)
+		{
+			refreshFromItem(item);
+		}
+	}
+}
+
+void LLPreview::refreshFromItem(const LLInventoryItem* item)
+{
+	setTitle(llformat("%s: %s",getTitleName(),item->getName().c_str()));
+	childSetText("desc",item->getDescription());
+
+	BOOL can_agent_manipulate = item->getPermissions().allowModifyBy(gAgent.getID());
+	childSetEnabled("desc",can_agent_manipulate);
+}
+
 // static 
 void LLPreview::onText(LLUICtrl*, void* userdata)
 {
diff --git a/indra/newview/llpreview.h b/indra/newview/llpreview.h
index ae986f5aaeab6225102d3f43e2b9131e11b55cd7..97cd2d5b073c7a266d88cb0d041a5e00af762a6a 100644
--- a/indra/newview/llpreview.h
+++ b/indra/newview/llpreview.h
@@ -38,6 +38,7 @@
 #include "lluuid.h"
 #include "llviewerinventory.h"
 #include "lltabcontainer.h"
+#include "llinventorymodel.h"
 #include <map>
 
 class LLLineEditor;
@@ -61,7 +62,7 @@ class LLMultiPreview : public LLMultiFloater
 	static std::map<LLUUID, LLViewHandle> sAutoOpenPreviewHandles;
 };
 
-class LLPreview : public LLFloater
+class LLPreview : public LLFloater, LLInventoryObserver
 {
 public:
 	typedef enum e_asset_status
@@ -116,6 +117,10 @@ class LLPreview : public LLFloater
 	void setNotecardInfo(const LLUUID& notecard_inv_id, const LLUUID& object_id)
 	{ mNotecardInventoryID = notecard_inv_id; mObjectID = object_id; }
 
+	// llview
+	virtual void draw();
+	void refreshFromItem(const LLInventoryItem* item);
+	
 protected:
 	virtual void onCommit();
 
@@ -124,7 +129,11 @@ class LLPreview : public LLFloater
 	static void onText(LLUICtrl*, void* userdata);
 	static void onRadio(LLUICtrl*, void* userdata);
 	
-
+	// for LLInventoryObserver 
+	virtual void changed(U32 mask);	
+	BOOL mDirty;
+	virtual const char *getTitleName() const { return "Preview"; }
+	
 protected:
 	LLUUID mItemUUID;
 	LLUUID	mSourceID;
diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h
index bb6ec759e4fcda5fc32a74c0b5d0bdcdc524f6c9..37cbd49725416309a2555fe266f42388758e4b1c 100644
--- a/indra/newview/llpreviewanim.h
+++ b/indra/newview/llpreviewanim.h
@@ -50,7 +50,8 @@ class LLPreviewAnim : public LLPreview
 
 protected:
 	virtual void onClose(bool app_quitting);
-
+	virtual const char *getTitleName() const { return "Animation"; }
+	
 	LLAnimPauseRequest	mPauseRequest;
 	LLUUID		mItemID;
 	LLString	mTitle;
diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h
index 5c84ee01889391da7a2077e9951638f30e7f540a..4dea34ba1c1b466060baceda374f412e05997ae4 100644
--- a/indra/newview/llpreviewgesture.h
+++ b/indra/newview/llpreviewgesture.h
@@ -137,6 +137,8 @@ class LLPreviewGesture : public LLPreview
 
 	static void onDonePreview(LLMultiGesture* gesture, void* data);
 
+	virtual const char *getTitleName() const { return "Gesture"; }
+
 protected:
 	// LLPreview contains mDescEditor
 	LLLineEditor*	mTriggerEditor;
diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp
index dc56494d7fbbc6ffa525f7a44c68c90bca409070..eef8c0d63633cc1fac54753f382934a65e135551 100644
--- a/indra/newview/llpreviewnotecard.cpp
+++ b/indra/newview/llpreviewnotecard.cpp
@@ -148,6 +148,10 @@ LLPreviewNotecard::LLPreviewNotecard(const std::string& name,
 	gAgent.changeCameraToDefault();
 }
 
+LLPreviewNotecard::~LLPreviewNotecard()
+{
+}
+
 BOOL LLPreviewNotecard::postBuild()
 {
 	LLViewerTextEditor *ed = (LLViewerTextEditor *)gUICtrlFactory->getTextEditorByName(this, "Notecard Editor");
@@ -213,7 +217,7 @@ BOOL LLPreviewNotecard::handleKeyHere(KEY key, MASK mask,
 			return TRUE;
 		}
 	}
-	return FALSE;
+	return LLPreview::handleKeyHere(key, mask, called_from_parent);
 }
 
 // virtual
diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h
index 9909284d5f8197df8d47d1a54496a6087464a43e..233246ceaaa9907371a57190d7cbf0d6c61381ee 100644
--- a/indra/newview/llpreviewnotecard.h
+++ b/indra/newview/llpreviewnotecard.h
@@ -54,7 +54,8 @@ class LLPreviewNotecard : public LLPreview
 					  const LLUUID& asset_id = LLUUID::null,
 					  BOOL show_keep_discard = FALSE,
 					  LLPointer<LLViewerInventoryItem> inv_item = NULL);
-
+	virtual ~LLPreviewNotecard();
+	
 	// llpreview	
 	virtual bool saveItem(LLPointer<LLInventoryItem>* itemptr);
 
@@ -102,6 +103,8 @@ class LLPreviewNotecard : public LLPreview
 
 	static void handleSaveChangesDialog(S32 option, void* userdata);
 
+	virtual const char *getTitleName() const { return "Note"; }
+
 protected:
 	LLViewerTextEditor* mEditor;
 	LLButton* mSaveBtn;
diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h
index 3dfeb2c3ac31909c9fe2a5afef2c8bb9dcbb5e7e..a9b36f397806856ad74ee0f5614a5b52ecc85770 100644
--- a/indra/newview/llpreviewscript.h
+++ b/indra/newview/llpreviewscript.h
@@ -128,6 +128,8 @@ class LLScriptEdCore : public LLPanel
 
 	static void onErrorList(LLUICtrl*, void* user_data);
 
+ 	virtual const char *getTitleName() const { return "Script"; }
+
 private:
 	LLString		mSampleText;
 	std::string		mHelpFile;
@@ -189,6 +191,8 @@ class LLPreviewLSL : public LLPreview
 
 
 protected:
+
+ 	virtual const char *getTitleName() const { return "Script"; }
 	LLScriptEdCore* mScriptEd;
 	// Can safely close only after both text and bytecode are uploaded
 	S32 mPendingUploads;
diff --git a/indra/newview/llpreviewsound.h b/indra/newview/llpreviewsound.h
index 74df017def7c6820f5dbdb444d0010cf0c0088e5..b56035f34e57e9a0c95fc5b8714dbf2a05c4c104 100644
--- a/indra/newview/llpreviewsound.h
+++ b/indra/newview/llpreviewsound.h
@@ -44,6 +44,9 @@ class LLPreviewSound : public LLPreview
 	static void playSound( void* userdata );
 	static void auditionSound( void* userdata );
 
+protected:
+	virtual const char *getTitleName() const { return "Sound"; }
+
 };
 
 #endif  // LL_LLPREVIEWSOUND_H
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index 4c8d4efb2576ae134f184671cee90a77300722d8..78d066f85f599eec601a10e154a6ebd708498ac8 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -286,7 +286,7 @@ void LLPreviewTexture::draw()
 						LLFontGL::DROP_SHADOW);
 				}
 			}
-		}
+		} 
 	}
 }
 
diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h
index b7850de92e15ea4a4811f5ec3aeadac3f571796f..8ed5210c469902dc0ccfef332b13ad8d3edccb84 100644
--- a/indra/newview/llpreviewtexture.h
+++ b/indra/newview/llpreviewtexture.h
@@ -80,6 +80,8 @@ class LLPreviewTexture : public LLPreview
 	void				init();
 	void				updateAspectRatio();
 
+	virtual const char *getTitleName() const { return "Texture"; }
+	
 protected:
 	LLUUID						mImageID;
 	LLPointer<LLViewerImage>		mImage;
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 3c29cfdbfc2c2af0cb2e9f1ec792bce24bc123b4..e2e076e364beedf6a238e9c6aeb39c366b18a9ef 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -3994,7 +3994,11 @@ void LLSelectMgr::sendListToRegions(const LLString& message_name,
 	switch(send_type)
 	{
 	  case SEND_ONLY_ROOTS:
-		getSelection()->applyToRootNodes(&pusheditable);
+		  if(message_name == "ObjectBuy")
+			getSelection()->applyToRootNodes(&pushroots);
+		  else
+			getSelection()->applyToRootNodes(&pusheditable);
+		  
 		break;
 	  case SEND_INDIVIDUALS:
 		getSelection()->applyToNodes(&pushall);
@@ -6062,23 +6066,19 @@ LLViewerObject* LLObjectSelection::getFirstDeleteableObject()
 		bool apply(LLSelectNode* node)
 		{
 			LLViewerObject* obj = node->getObject();
-			// you can delete an object if permissions allow it, you are
-			// the owner, you are an officer in the group that owns the
-			// object, or you are not the owner but it is on land you own
-			// or land owned by your group. (whew!)
+			// you can delete an object if you are the owner
+			// or you have permission to modify it.
 			if(    (obj->permModify()) 
 				|| (obj->permYouOwner())
 				|| (!obj->permAnyOwner())			// public
-				|| (obj->isOverAgentOwnedLand())
-				|| (obj->isOverGroupOwnedLand())
 				)
 			{
 				if( !obj->isAttachment() )
 				{
-					return TRUE;
+					return true;
 				}
 			}
-			return true;
+			return false;
 		}
 	} func;
 	LLSelectNode* node = getFirstNode(&func);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index c319ef97af9e8dbba0fd4af11ed81684140561a4..302291ab52bd458fecf40c871c373a8c7fbc6875 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -932,9 +932,15 @@ BOOL idle_startup()
 			gSavedSettings.setBOOL("UseDebugMenus", TRUE);
 			requested_options.push_back("god-connect");
 		}
-		LLAppViewer::instance()->getLoginURIs();
-		sAuthUris = LLAppViewer::instance()->getLoginURIs();
-
+		const std::vector<std::string>& uris = LLAppViewer::instance()->getLoginURIs();
+		std::vector<std::string>::const_iterator iter, end;
+		for (iter = uris.begin(), end = uris.end(); iter != end; ++iter)
+		{
+			std::vector<std::string> rewritten;
+			rewritten = LLSRV::rewriteURI(*iter);
+			sAuthUris.insert(sAuthUris.end(),
+							 rewritten.begin(), rewritten.end());
+		}
 		sAuthUriNum = 0;
 		auth_method = "login_to_simulator";
 		auth_desc = "Logging in.  ";
@@ -2161,7 +2167,7 @@ BOOL idle_startup()
 				else
 				{
 					args["[TYPE]"] = "home";
-					args["[HELP]"] = "\nYou may want to set a new home location.";
+					args["[HELP]"] = "You may want to set a new home location.";
 				}
 				gViewerWindow->alertXml("AvatarMoved", args);
 			}
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index 856943da6efe0081e1444445570813dccedd7667..4d49d33184a86f15e22a665a47a335686a226f66 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -375,7 +375,7 @@ void LLStatusBar::refresh()
 		x += buttonRect.getWidth();
 	}
 
-	BOOL have_voice = gVoiceClient->getAreaVoiceDisabled() ? FALSE : TRUE;
+	BOOL have_voice = parcel && parcel->getVoiceEnabled(); 
 	childSetVisible("status_voice", have_voice);
 	if (have_voice)
 	{
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index e6eca31cd0b600376f30d9c74d6925b66b068495..413b26309d280ed38d889ac46220d61fc44e2440 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1204,6 +1204,7 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,
 		// if the asset is already in the object's inventory 
 		// then it can always be added to a side.
 		// This saves some work if the task's inventory is already loaded
+		// and ensures that the texture item is only added once.
 		return TRUE;
 	}
 
@@ -1241,7 +1242,10 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,
 				return FALSE;
 			}
 		}
-		hit_obj->updateInventory(new_item, TASK_INVENTORY_ASSET_KEY, true);
+		// Add the texture item to the target object's inventory.
+		hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
+ 		// TODO: Check to see if adding the item was successful; if not, then
+		// we should return false here.
 	}
 	else if(!item->getPermissions().allowOperationBy(PERM_TRANSFER,
 													 gAgent.getID()))
@@ -1253,8 +1257,10 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj,
 		}
 		// *FIX: may want to make sure agent can paint hit_obj.
 
-		// make sure the object has the texture in it's inventory.
-		hit_obj->updateInventory(new_item, TASK_INVENTORY_ASSET_KEY, true);
+		// Add the texture item to the target object's inventory.
+		hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true);
+ 		// TODO: Check to see if adding the item was successful; if not, then
+		// we should return false here.
 	}
 	return TRUE;
 }
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index 4bab92269cdb7d7500fbd8081dd3673502b91001..594ecb5591bfd83d7f248c87ccf9b96ca649cfac 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -639,6 +639,10 @@ void LLTracker::stopTrackingLocation(BOOL clear_ui)
 	mTrackingLocationType = LOCATION_NOTHING;
 }
 
+void LLTracker::clearFocus()
+{
+	instance()->mTrackingStatus = TRACKING_NOTHING;
+}
 
 void LLTracker::drawMarker(const LLVector3d& pos_global, const LLColor4& color)
 {
diff --git a/indra/newview/lltracker.h b/indra/newview/lltracker.h
index c7e09d0d3dbb5b8e4f0bbbc5f53d45e4bdcf9ec1..5f7ad98fe51749e2c4279c65dcd949a2c1d218b0 100644
--- a/indra/newview/lltracker.h
+++ b/indra/newview/lltracker.h
@@ -82,7 +82,8 @@ class LLTracker
 	static ETrackingLocationType getTrackedLocationType() { return instance()->mTrackingLocationType; }
 	static BOOL isTracking(void*) { return (BOOL) instance()->mTrackingStatus; }
 	static void stopTracking(void*);
-
+	static void clearFocus();
+	
 	static const LLUUID& getTrackedLandmarkAssetID() { return instance()->mTrackedLandmarkAssetID; }
 	static const LLUUID& getTrackedLandmarkItemID()	 { return instance()->mTrackedLandmarkItemID; }
 
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 43e858917611764cd2eaae8a616f585b38548627..b5316d29e03515f2f460ed4edf356706a8936870 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -104,14 +104,9 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLViewerInventoryItem* other)
 }
 
 LLViewerInventoryItem::LLViewerInventoryItem(const LLInventoryItem *other) :
-	LLInventoryItem(other)
+	LLInventoryItem(other),
+	mIsComplete(TRUE)
 {
-	LLInventoryItem::copy(other);
-	if (!mIsComplete)
-	{
-		llwarns << "LLViewerInventoryItem copy constructor for incomplete item"
-			<< mUUID << llendl;
-	}
 }
 
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index b5f53e5d88a5fc638f832e4e1d9c16183e57e60d..7aa25266fed00db2d5418492e712f1b4ba018e29 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -6053,12 +6053,39 @@ BOOL object_selected_and_point_valid(void *user_data)
 		(selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL);
 }
 
+
+BOOL object_is_wearable()
+{
+	if (!object_selected_and_point_valid(NULL))
+	{
+		return FALSE;
+	}
+	if (sitting_on_selection())
+	{
+		return FALSE;
+	}
+	LLObjectSelectionHandle selection = gSelectMgr->getSelection();
+	for (LLObjectSelection::valid_root_iterator iter = gSelectMgr->getSelection()->valid_root_begin();
+		 iter != gSelectMgr->getSelection()->valid_root_end(); iter++)
+	{
+		LLSelectNode* node = *iter;		
+		if (node->mPermissions->getOwner() == gAgent.getID())
+		{
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
+
 // Also for seeing if object can be attached.  See above.
 class LLObjectEnableWear : public view_listener_t
 {
 	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
 	{
-		return object_selected_and_point_valid(NULL);
+		bool is_wearable = object_selected_and_point_valid(NULL);
+		gMenuHolder->findControl(userdata["control"].asString())->setValue(is_wearable);
+		return TRUE;
 	}
 };
 
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index f109ea417b8f8c76f8d4b9078780f2d273f5e542..fa92bfb217baeaed651132a251f578653476df43 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -131,6 +131,7 @@
 #include "pipeline.h"
 #include "llappviewer.h"
 #include "llfloaterworldmap.h"
+#include "llkeythrottle.h"
 #include "llviewerdisplay.h"
 #include "llkeythrottle.h"
 
@@ -4407,6 +4408,10 @@ void script_question_cb(S32 option, void* user_data)
 		notify_cautioned_script_question(cbdata, orig, allowed);
 	}
 
+	if ( option == 2 )
+	{
+		gMuteListp->add(LLMute(cbdata->mItemID, cbdata->mObjectName, LLMute::OBJECT));
+	}
 	delete cbdata;
 }
 
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index f0d6fd11c3814fdf9ffdbc52702d392dc6632730..b0d1d3daca637cd74db8bd3afb18ead22344defc 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -66,6 +66,7 @@
 #include "llworld.h"
 #include "lloverlaybar.h"
 #include "roles_constants.h"
+#include "llweb.h"
 
 const F32 PARCEL_COLLISION_DRAW_SECS = 1.f;
 
@@ -1720,6 +1721,10 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
 				std::string mediaUrl = std::string ( parcel->getMediaURL () );
 				LLString::trim(mediaUrl);
 
+				// clean spaces and whatnot 
+				mediaUrl = LLWeb::escapeURL(mediaUrl);
+
+				
 				// something changed
 				LLMediaEngine* me = LLMediaEngine::getInstance();
 				if (  ( me->getUrl () != mediaUrl )
@@ -1837,6 +1842,10 @@ void prepare_video(const LLParcel *parcel)
 	{
 		mediaUrl = std::string ( parcel->getMediaURL () );
 	}
+
+	// clean spaces and whatnot 
+	mediaUrl = LLWeb::escapeURL(mediaUrl);
+	
 	LLMediaEngine::getInstance ()->setUrl ( mediaUrl );
 	LLMediaEngine::getInstance ()->setImageUUID ( parcel->getMediaID () );
 	LLMediaEngine::getInstance ()->setAutoScaled ( parcel->getMediaAutoScale () ? TRUE : FALSE );  // (U8 instead of BOOL for future expansion)
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 49883eb8c61a45055b4eb5f49ee3bed9776d8058..a3611b227299880bd6f8036c0d8e259553ccc338 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2446,6 +2446,10 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
 			return TRUE;
 		}
 
+		//if quit from menu, turn off the Keyboardmode for the menu.
+		if(LLMenuGL::getKeyboardMode())
+			LLMenuGL::setKeyboardMode(FALSE);
+
 		// *TODO: get this to play well with mouselook and hidden
 		// cursor modes, etc, and re-enable.
 		//if (gFocusMgr.getMouseCapture())
diff --git a/indra/win_updater/updater.cpp b/indra/win_updater/updater.cpp
index e25383bfefde7aedccd3e810a1b1306ac9bfbf16..f849e4e9ada0024deed3ad70c701a5d45f737b22 100644
--- a/indra/win_updater/updater.cpp
+++ b/indra/win_updater/updater.cpp
@@ -41,6 +41,7 @@
 #define BUFSIZE 8192
 
 int  gTotalBytesRead = 0;
+DWORD gTotalBytes = -1;
 HWND gWindow = NULL;
 WCHAR gProgress[256];
 char* gUpdateURL;
@@ -129,6 +130,9 @@ int WINAPI get_url_into_file(WCHAR *uri, char *path, int *cancelled)
 		return success;
 	}
 
+	DWORD sizeof_total_bytes = sizeof(gTotalBytes);
+	HttpQueryInfo(hdownload, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &gTotalBytes, &sizeof_total_bytes, NULL);
+	
 	DWORD total_bytes = 0;
 	success = InternetQueryDataAvailable(hdownload, &total_bytes, 0, 0);
 	if (success == FALSE)
@@ -187,7 +191,11 @@ int WINAPI get_url_into_file(WCHAR *uri, char *path, int *cancelled)
 
 			gTotalBytesRead += int(bytes_read);
 
-			wsprintf(gProgress, L"Downloaded: %dK", gTotalBytesRead / 1024);
+			if (gTotalBytes != -1)
+				wsprintf(gProgress, L"Downloaded: %d%%", 100 * gTotalBytesRead / gTotalBytes);
+			else
+				wsprintf(gProgress, L"Downloaded: %dK", gTotalBytesRead / 1024);
+
 		}
 
 #if _DEBUG