From 6cc6f816780e64c5fb1e17a22fb5e473e75efe69 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 23 Jul 2010 22:07:15 -0700
Subject: first pass ui rendering performance improvements

---
 indra/llrender/llfontfreetype.cpp |   6 +-
 indra/llrender/llfontfreetype.h   |   4 +-
 indra/llrender/llfontgl.cpp       | 195 ++++++++++++++++++++++----------------
 indra/llrender/llfontgl.h         |   4 +-
 indra/llrender/llrender.cpp       |  97 +++++++++++++++----
 indra/llrender/llrender.h         |   8 +-
 indra/llui/lllocalcliprect.cpp    |  42 ++------
 indra/llui/lllocalcliprect.h      |  26 ++++-
 indra/llui/lltextbase.cpp         |  15 ++-
 9 files changed, 242 insertions(+), 155 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index a86bbbffff..0a16b5120a 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -259,10 +259,10 @@ F32 LLFontFreetype::getXAdvance(llwchar wch) const
 	}
 	else
 	{
-		gi = get_if_there(mCharGlyphInfoMap, (llwchar)0, (LLFontGlyphInfo*)NULL);
-		if (gi)
+		char_glyph_info_map_t::iterator found_it = mCharGlyphInfoMap.find((llwchar)0);
+		if (found_it != mCharGlyphInfoMap.end())
 		{
-			return gi->mXAdvance;
+			return found_it->second->mXAdvance;
 		}
 	}
 
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
index f60d09316d..4b4a0bb189 100644
--- a/indra/llrender/llfontfreetype.h
+++ b/indra/llrender/llfontfreetype.h
@@ -33,7 +33,7 @@
 #ifndef LL_LLFONTFREETYPE_H
 #define LL_LLFONTFREETYPE_H
 
-#include <map>
+#include <boost/unordered_map.hpp>
 #include "llpointer.h"
 #include "llstl.h"
 
@@ -170,7 +170,7 @@ private:
 
 	BOOL mValid;
 
-	typedef std::map<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
+	typedef boost::unordered_map<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
 	mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap
 
 	mutable LLPointer<LLFontBitmapCache> mFontBitmapCachep;
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 6eb5e0eff4..c0297eae3e 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -181,12 +181,17 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 
 	gGL.loadUIIdentity();
 	
-	gGL.translateUI(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
+	//gGL.translateUI(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
 
 	// this code snaps the text origin to a pixel grid to start with
-	F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
-	F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
-	gGL.translateUI(-pixel_offset_x, -pixel_offset_y, 0.f);
+	//F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
+	//F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
+	//gGL.translateUI(-pixel_offset_x, -pixel_offset_y, 0.f);
+
+	LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY));
+	// snap the text origin to a pixel grid to start with
+	origin.mV[VX] -= llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
+	origin.mV[VY] -= llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
 
 	LLFastTimer t(FTM_RENDER_FONTS);
 
@@ -210,8 +215,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
  	// Not guaranteed to be set correctly
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 	
-	cur_x = ((F32)x * sScaleX);
-	cur_y = ((F32)y * sScaleY);
+	cur_x = ((F32)x * sScaleX) + origin.mV[VX];
+	cur_y = ((F32)y * sScaleY) + origin.mV[VY];
 
 	// Offset y by vertical alignment.
 	switch (valign)
@@ -276,6 +281,12 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 
 	const LLFontGlyphInfo* next_glyph = NULL;
 
+	const S32 GLYPH_BATCH_SIZE = 30;
+	LLVector3 vertices[GLYPH_BATCH_SIZE * 4];
+	LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
+	LLColor4U colors[GLYPH_BATCH_SIZE * 4];
+
+	S32 glyph_count = 0;
 	for (i = begin_offset; i < begin_offset + length; i++)
 	{
 		llwchar wch = wstr[i];
@@ -313,7 +324,18 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 				    llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
 				    llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
 		
-		drawGlyph(screen_rect, uv_rect, color, style_to_add, shadow, drop_shadow_strength);
+		if (glyph_count >= GLYPH_BATCH_SIZE)
+		{
+			gGL.begin(LLRender::QUADS);
+			{
+				gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
+			}
+			gGL.end();
+
+			glyph_count = 0;
+		}
+
+		drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, color, style_to_add, shadow, drop_shadow_strength);
 
 		chars_drawn++;
 		cur_x += fgi->mXAdvance;
@@ -338,11 +360,19 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 		cur_render_y = cur_y;
 	}
 
+	gGL.begin(LLRender::QUADS);
+	{
+		gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
+	}
+	gGL.end();
+
+
 	if (right_x)
 	{
 		*right_x = cur_x / sScaleX;
 	}
 
+	//FIXME: add underline as glyph?
 	if (style_to_add & UNDERLINE)
 	{
 		F32 descender = mFontFreetype->getDescenderHeight();
@@ -1091,95 +1121,96 @@ LLFontGL &LLFontGL::operator=(const LLFontGL &source)
 	return *this;
 }
 
-void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const
+void LLFontGL::renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const
 {
-	gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
-	gGL.vertex2f(llfont_round_x(screen_rect.mRight), 
-				llfont_round_y(screen_rect.mTop));
-
-	gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
-	gGL.vertex2f(llfont_round_x(screen_rect.mLeft), 
-				llfont_round_y(screen_rect.mTop));
-
-	gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
-	gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), 
-				llfont_round_y(screen_rect.mBottom));
-
-	gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
-	gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt), 
-				llfont_round_y(screen_rect.mBottom));
+	S32 index = 0;
+
+	vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mRight), llfont_round_y(screen_rect.mTop), 0.f);
+	uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
+	colors_out[index] = color;
+	index++;
+
+	vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mLeft), llfont_round_y(screen_rect.mTop), 0.f);
+	uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
+	colors_out[index] = color;
+	index++;
+
+	vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mLeft), llfont_round_y(screen_rect.mBottom), 0.f);
+	uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
+	colors_out[index] = color;
+	index++;
+
+	vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mRight), llfont_round_y(screen_rect.mBottom), 0.f);
+	uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
+	colors_out[index] = color;
 }
 
-void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
+//FIXME: do colors out as well
+void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
 {
 	F32 slant_offset;
 	slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f);
 
-	gGL.begin(LLRender::QUADS);
+	//FIXME: bold and drop shadow are mutually exclusive only for convenience
+	//Allow both when we need them.
+	if (style & BOLD)
 	{
-		//FIXME: bold and drop shadow are mutually exclusive only for convenience
-		//Allow both when we need them.
-		if (style & BOLD)
+		for (S32 pass = 0; pass < 2; pass++)
 		{
-			gGL.color4fv(color.mV);
-			for (S32 pass = 0; pass < 2; pass++)
-			{
-				LLRectf screen_rect_offset = screen_rect;
+			LLRectf screen_rect_offset = screen_rect;
 
-				screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
-				renderQuad(screen_rect_offset, uv_rect, slant_offset);
-			}
+			screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
+			renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, color, slant_offset);
+			glyph_count++;
 		}
-		else if (shadow == DROP_SHADOW_SOFT)
+	}
+	else if (shadow == DROP_SHADOW_SOFT)
+	{
+		LLColor4U shadow_color = LLFontGL::sShadowColor;
+		shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH;
+		for (S32 pass = 0; pass < 5; pass++)
 		{
-			LLColor4 shadow_color = LLFontGL::sShadowColor;
-			shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH;
-			gGL.color4fv(shadow_color.mV);
-			for (S32 pass = 0; pass < 5; pass++)
-			{
-				LLRectf screen_rect_offset = screen_rect;
+			LLRectf screen_rect_offset = screen_rect;
 
-				switch(pass)
-				{
-				case 0:
-					screen_rect_offset.translate(-1.f, -1.f);
-					break;
-				case 1:
-					screen_rect_offset.translate(1.f, -1.f);
-					break;
-				case 2:
-					screen_rect_offset.translate(1.f, 1.f);
-					break;
-				case 3:
-					screen_rect_offset.translate(-1.f, 1.f);
-					break;
-				case 4:
-					screen_rect_offset.translate(0, -2.f);
-					break;
-				}
-			
-				renderQuad(screen_rect_offset, uv_rect, slant_offset);
+			switch(pass)
+			{
+			case 0:
+				screen_rect_offset.translate(-1.f, -1.f);
+				break;
+			case 1:
+				screen_rect_offset.translate(1.f, -1.f);
+				break;
+			case 2:
+				screen_rect_offset.translate(1.f, 1.f);
+				break;
+			case 3:
+				screen_rect_offset.translate(-1.f, 1.f);
+				break;
+			case 4:
+				screen_rect_offset.translate(0, -2.f);
+				break;
 			}
-			gGL.color4fv(color.mV);
-			renderQuad(screen_rect, uv_rect, slant_offset);
-		}
-		else if (shadow == DROP_SHADOW)
-		{
-			LLColor4 shadow_color = LLFontGL::sShadowColor;
-			shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
-			gGL.color4fv(shadow_color.mV);
-			LLRectf screen_rect_shadow = screen_rect;
-			screen_rect_shadow.translate(1.f, -1.f);
-			renderQuad(screen_rect_shadow, uv_rect, slant_offset);
-			gGL.color4fv(color.mV);
-			renderQuad(screen_rect, uv_rect, slant_offset);
-		}
-		else // normal rendering
-		{
-			gGL.color4fv(color.mV);
-			renderQuad(screen_rect, uv_rect, slant_offset);
+		
+			renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, shadow_color, slant_offset);
+			glyph_count++;
 		}
-
+		renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
+		glyph_count++;
+	}
+	else if (shadow == DROP_SHADOW)
+	{
+		LLColor4 shadow_color = LLFontGL::sShadowColor;
+		shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
+		LLRectf screen_rect_shadow = screen_rect;
+		screen_rect_shadow.translate(1.f, -1.f);
+		renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_shadow, uv_rect, shadow_color, slant_offset);
+		glyph_count++;
+		renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
+		glyph_count++;
+	}
+	else // normal rendering
+	{
+		renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
+		glyph_count++;
 	}
-	gGL.end();
 }
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index f29ac5165c..8bc45fbf74 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -217,8 +217,8 @@ private:
 	LLFontDescriptor mFontDescriptor;
 	LLPointer<LLFontFreetype> mFontFreetype;
 
-	void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const;
-	void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const;
+	void renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const;
+	void drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const;
 
 	// Registry holds all instantiated fonts.
 	static LLFontRegistry* sFontRegistry;
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 5597b23c69..64238b2008 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -851,9 +851,9 @@ void LLRender::translateUI(F32 x, F32 y, F32 z)
 		llerrs << "Need to push a UI translation frame before offsetting" << llendl;
 	}
 
-	mUIOffset.front().mV[0] += x;
-	mUIOffset.front().mV[1] += y;
-	mUIOffset.front().mV[2] += z;
+	mUIOffset.back().mV[0] += x;
+	mUIOffset.back().mV[1] += y;
+	mUIOffset.back().mV[2] += z;
 }
 
 void LLRender::scaleUI(F32 x, F32 y, F32 z)
@@ -863,27 +863,27 @@ void LLRender::scaleUI(F32 x, F32 y, F32 z)
 		llerrs << "Need to push a UI transformation frame before scaling." << llendl;
 	}
 
-	mUIScale.front().scaleVec(LLVector3(x,y,z));
+	mUIScale.back().scaleVec(LLVector3(x,y,z));
 }
 
 void LLRender::pushUIMatrix()
 {
 	if (mUIOffset.empty())
 	{
-		mUIOffset.push_front(LLVector3(0,0,0));
+		mUIOffset.push_back(LLVector3(0,0,0));
 	}
 	else
 	{
-		mUIOffset.push_front(mUIOffset.front());
+		mUIOffset.push_back(mUIOffset.back());
 	}
 	
 	if (mUIScale.empty())
 	{
-		mUIScale.push_front(LLVector3(1,1,1));
+		mUIScale.push_back(LLVector3(1,1,1));
 	}
 	else
 	{
-		mUIScale.push_front(mUIScale.front());
+		mUIScale.push_back(mUIScale.back());
 	}
 }
 
@@ -893,8 +893,8 @@ void LLRender::popUIMatrix()
 	{
 		llerrs << "UI offset stack blown." << llendl;
 	}
-	mUIOffset.pop_front();
-	mUIScale.pop_front();
+	mUIOffset.pop_back();
+	mUIScale.pop_back();
 }
 
 LLVector3 LLRender::getUITranslation()
@@ -903,7 +903,7 @@ LLVector3 LLRender::getUITranslation()
 	{
 		llerrs << "UI offset stack empty." << llendl;
 	}
-	return mUIOffset.front();
+	return mUIOffset.back();
 }
 
 LLVector3 LLRender::getUIScale()
@@ -912,7 +912,7 @@ LLVector3 LLRender::getUIScale()
 	{
 		llerrs << "UI scale stack empty." << llendl;
 	}
-	return mUIScale.front();
+	return mUIScale.back();
 }
 
 
@@ -922,8 +922,8 @@ void LLRender::loadUIIdentity()
 	{
 		llerrs << "Need to push UI translation frame before clearing offset." << llendl;
 	}
-	mUIOffset.front().setVec(0,0,0);
-	mUIScale.front().setVec(1,1,1);
+	mUIOffset.back().setVec(0,0,0);
+	mUIScale.back().setVec(1,1,1);
 }
 
 void LLRender::setColorMask(bool writeColor, bool writeAlpha)
@@ -1210,18 +1210,79 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
 	}
 	else
 	{
-		LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.front()).scaledVec(mUIScale.front());
+		LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back());
 		mVerticesp[mCount] = vert;
 	}
 
 	mCount++;
-	if (mCount < 4096)
+	mVerticesp[mCount] = mVerticesp[mCount-1];
+	mColorsp[mCount] = mColorsp[mCount-1];
+	mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+}
+
+void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
+{
+	if (mCount + vert_count > 4094)
 	{
-		mVerticesp[mCount] = mVerticesp[mCount-1];
-		mColorsp[mCount] = mColorsp[mCount-1];
+		//	llwarns << "GL immediate mode overflow.  Some geometry not drawn." << llendl;
+		return;
+	}
+
+	for (S32 i = 0; i < vert_count; i++)
+	{
+		mVerticesp[mCount] = verts[i];
+
+		mCount++;
 		mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+		mColorsp[mCount] = mColorsp[mCount-1];
 	}
+
+	mVerticesp[mCount] = mVerticesp[mCount-1];
 }
+
+void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count)
+{
+	if (mCount + vert_count > 4094)
+	{
+		//	llwarns << "GL immediate mode overflow.  Some geometry not drawn." << llendl;
+		return;
+	}
+
+	for (S32 i = 0; i < vert_count; i++)
+	{
+		mVerticesp[mCount] = verts[i];
+		mTexcoordsp[mCount] = uvs[i];
+
+		mCount++;
+		mColorsp[mCount] = mColorsp[mCount-1];
+	}
+
+	mVerticesp[mCount] = mVerticesp[mCount-1];
+	mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+}
+
+void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count)
+{
+	if (mCount + vert_count > 4094)
+	{
+		//	llwarns << "GL immediate mode overflow.  Some geometry not drawn." << llendl;
+		return;
+	}
+
+	for (S32 i = 0; i < vert_count; i++)
+	{
+		mVerticesp[mCount] = verts[i];
+		mTexcoordsp[mCount] = uvs[i];
+		mColorsp[mCount] = colors[i];
+
+		mCount++;
+	}
+
+	mVerticesp[mCount] = mVerticesp[mCount-1];
+	mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+	mColorsp[mCount] = mColorsp[mCount-1];
+}
+
 void LLRender::vertex2i(const GLint& x, const GLint& y)
 {
 	vertex3f((GLfloat) x, (GLfloat) y, 0);	
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index f6c87aa1db..0fa503182e 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -317,6 +317,10 @@ public:
 	void color3fv(const GLfloat* c);
 	void color4ubv(const GLubyte* c);
 
+	void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count);
+	void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count);
+	void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
+
 	void setColorMask(bool writeColor, bool writeAlpha);
 	void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha);
 	void setSceneBlendType(eBlendType type);
@@ -373,8 +377,8 @@ private:
 
 	F32				mMaxAnisotropy;
 
-	std::list<LLVector3> mUIOffset;
-	std::list<LLVector3> mUIScale;
+	std::vector<LLVector3> mUIOffset;
+	std::vector<LLVector3> mUIScale;
 
 };
 
diff --git a/indra/llui/lllocalcliprect.cpp b/indra/llui/lllocalcliprect.cpp
index 43c21e250c..55329f64e4 100644
--- a/indra/llui/lllocalcliprect.cpp
+++ b/indra/llui/lllocalcliprect.cpp
@@ -33,33 +33,8 @@
 #include "lllocalcliprect.h"
 
 #include "llfontgl.h"
-#include "llgl.h"
 #include "llui.h"
 
-#include <stack>
-
-//---------------------------------------------------------------------------
-// LLScreenClipRect
-// implementation class in screen space
-//---------------------------------------------------------------------------
-class LLScreenClipRect
-{
-public:
-	LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE);
-	virtual ~LLScreenClipRect();
-
-private:
-	static void pushClipRect(const LLRect& rect);
-	static void popClipRect();
-	static void updateScissorRegion();
-
-private:
-	LLGLState		mScissorState;
-	BOOL			mEnabled;
-
-	static std::stack<LLRect> sClipRectStack;
-};
-
 /*static*/ std::stack<LLRect> LLScreenClipRect::sClipRectStack;
 
 
@@ -131,16 +106,11 @@ void LLScreenClipRect::updateScissorRegion()
 // LLLocalClipRect
 //---------------------------------------------------------------------------
 LLLocalClipRect::LLLocalClipRect(const LLRect& rect, BOOL enabled /* = TRUE */)
-{
-	LLRect screen(rect.mLeft + LLFontGL::sCurOrigin.mX, 
-		rect.mTop + LLFontGL::sCurOrigin.mY, 
-		rect.mRight + LLFontGL::sCurOrigin.mX, 
-		rect.mBottom + LLFontGL::sCurOrigin.mY);
-	mScreenClipRect = new LLScreenClipRect(screen, enabled);
-}
+:	LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX, 
+					rect.mTop + LLFontGL::sCurOrigin.mY, 
+					rect.mRight + LLFontGL::sCurOrigin.mX, 
+					rect.mBottom + LLFontGL::sCurOrigin.mY), enabled)
+{}
 
 LLLocalClipRect::~LLLocalClipRect()
-{
-	delete mScreenClipRect;
-	mScreenClipRect = NULL;
-}
+{}
diff --git a/indra/llui/lllocalcliprect.h b/indra/llui/lllocalcliprect.h
index cd0c55ca72..36413f1496 100644
--- a/indra/llui/lllocalcliprect.h
+++ b/indra/llui/lllocalcliprect.h
@@ -31,7 +31,9 @@
 #ifndef LLLOCALCLIPRECT_H
 #define LLLOCALCLIPRECT_H
 
+#include "llgl.h"
 #include "llrect.h"		// can't forward declare, it's templated
+#include <stack>
 
 // Clip rendering to a specific rectangle using GL scissor
 // Just create one of these on the stack:
@@ -39,15 +41,29 @@
 //     LLLocalClipRect(rect);
 //     draw();
 // }
-class LLLocalClipRect
+class LLScreenClipRect
 {
 public:
-	LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE);
-	~LLLocalClipRect();
+	LLScreenClipRect(const LLRect& rect, BOOL enabled = TRUE);
+	virtual ~LLScreenClipRect();
+
+private:
+	static void pushClipRect(const LLRect& rect);
+	static void popClipRect();
+	static void updateScissorRegion();
 
 private:
-	// implementation class
-	class LLScreenClipRect* mScreenClipRect;
+	LLGLState		mScissorState;
+	BOOL			mEnabled;
+
+	static std::stack<LLRect> sClipRectStack;
+};
+
+class LLLocalClipRect : public LLScreenClipRect
+{
+public:
+	LLLocalClipRect(const LLRect& rect, BOOL enabled = TRUE);
+	~LLLocalClipRect();
 };
 
 #endif
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 617c496d6a..0587b3f48d 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -1012,22 +1012,25 @@ void LLTextBase::draw()
 	if (mBGVisible)
 	{
 		// clip background rect against extents, if we support scrolling
-		LLLocalClipRect clip(doc_rect, mScroller != NULL);
-
+		LLRect bg_rect = mVisibleTextRect;
+		if (mScroller)
+		{
+			bg_rect.intersectWith(doc_rect);
+		}
 		LLColor4 bg_color = mReadOnly 
 							? mReadOnlyBgColor.get()
 							: hasFocus() 
 								? mFocusBgColor.get() 
 								: mWriteableBgColor.get();
-		gl_rect_2d(mVisibleTextRect, bg_color, TRUE);
+		gl_rect_2d(doc_rect, bg_color, TRUE);
 	}
 
 	// draw document view
 	LLUICtrl::draw();
 
 	{
-		// only clip if we support scrolling (mScroller != NULL)
-		LLLocalClipRect clip(doc_rect, mScroller != NULL);
+		// only clip if we support scrolling or have word wrap turned off
+		LLLocalClipRect clip(doc_rect, !getWordWrap() || mScroller != NULL);
 		drawSelectionBackground();
 		drawText();
 		drawCursor();
@@ -1495,6 +1498,7 @@ LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)
 	// when there are no segments, we return the end iterator, which must be checked by caller
 	if (mSegments.size() <= 1) { return mSegments.begin(); }
 
+	//FIXME: avoid operator new somehow (without running into refcount problems)
 	segment_set_t::iterator it = mSegments.upper_bound(new LLIndexSegment(index));
 	return it;
 }
@@ -2269,6 +2273,7 @@ void LLTextBase::updateRects()
 	// allow horizontal scrolling?
 	// if so, use entire width of text contents
 	// otherwise, stop at width of mVisibleTextRect
+	//FIXME: consider use of getWordWrap() instead
 	doc_rect.mRight = mScroller 
 		? llmax(mVisibleTextRect.getWidth(), mTextBoundingRect.mRight)
 		: mVisibleTextRect.getWidth();
-- 
cgit v1.2.3