PageRenderTime 128ms CodeModel.GetById 11ms app.highlight 107ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llrender/llfontgl.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1236 lines | 915 code | 187 blank | 134 comment | 168 complexity | 41f0ae47e53d507bc520923ee1d98e41 MD5 | raw file
   1/** 
   2 * @file llfontgl.cpp
   3 * @brief Wrapper around FreeType
   4 *
   5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "linden_common.h"
  28
  29#include "llfontgl.h"
  30
  31// Linden library includes
  32#include "llfontfreetype.h"
  33#include "llfontbitmapcache.h"
  34#include "llfontregistry.h"
  35#include "llgl.h"
  36#include "llimagegl.h"
  37#include "llrender.h"
  38#include "llstl.h"
  39#include "v4color.h"
  40#include "lltexture.h"
  41#include "lldir.h"
  42
  43// Third party library includes
  44#include <boost/tokenizer.hpp>
  45
  46const S32 BOLD_OFFSET = 1;
  47
  48// static class members
  49F32 LLFontGL::sVertDPI = 96.f;
  50F32 LLFontGL::sHorizDPI = 96.f;
  51F32 LLFontGL::sScaleX = 1.f;
  52F32 LLFontGL::sScaleY = 1.f;
  53BOOL LLFontGL::sDisplayFont = TRUE ;
  54std::string LLFontGL::sAppDir;
  55
  56LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f);
  57LLFontRegistry* LLFontGL::sFontRegistry = NULL;
  58
  59LLCoordFont LLFontGL::sCurOrigin;
  60std::vector<LLCoordFont> LLFontGL::sOriginStack;
  61
  62const F32 EXT_X_BEARING = 1.f;
  63const F32 EXT_Y_BEARING = 0.f;
  64const F32 EXT_KERNING = 1.f;
  65const F32 PIXEL_BORDER_THRESHOLD = 0.0001f;
  66const F32 PIXEL_CORRECTION_DISTANCE = 0.01f;
  67
  68const F32 PAD_UVY = 0.5f; // half of vertical padding between glyphs in the glyph texture
  69const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f;
  70
  71static F32 llfont_round_x(F32 x)
  72{
  73	//return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX;
  74	//return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY;
  75	return x;
  76}
  77
  78static F32 llfont_round_y(F32 y)
  79{
  80	//return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY;
  81	//return llfloor(y+0.5f);
  82	return y;
  83}
  84
  85LLFontGL::LLFontGL()
  86{
  87}
  88
  89LLFontGL::~LLFontGL()
  90{
  91}
  92
  93void LLFontGL::reset()
  94{
  95	mFontFreetype->reset(sVertDPI, sHorizDPI);
  96}
  97
  98void LLFontGL::destroyGL()
  99{
 100	mFontFreetype->destroyGL();
 101}
 102
 103BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback)
 104{
 105	if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
 106	{
 107		mFontFreetype = new LLFontFreetype;
 108	}
 109
 110	return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback);
 111}
 112
 113static LLFastTimer::DeclareTimer FTM_RENDER_FONTS("Fonts");
 114
 115S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
 116					 ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
 117{
 118	F32 x = rect.mLeft;
 119	F32 y = 0.f;
 120
 121	switch(valign)
 122	{
 123	case TOP:
 124		y = rect.mTop;
 125		break;
 126	case VCENTER:
 127		y = rect.getCenterY();
 128		break;
 129	case BASELINE:
 130	case BOTTOM:
 131		y = rect.mBottom;
 132		break;
 133	default:
 134		y = rect.mBottom;
 135		break;
 136	}
 137	return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses);
 138}
 139
 140
 141S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
 142					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
 143{
 144	LLFastTimer _(FTM_RENDER_FONTS);
 145
 146	if(!sDisplayFont) //do not display texts
 147	{
 148		return wstr.length() ;
 149	}
 150
 151	if (wstr.empty())
 152	{
 153		return 0;
 154	} 
 155
 156	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
 157
 158	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);
 159
 160	// determine which style flags need to be added programmatically by stripping off the
 161	// style bits that are drawn by the underlying Freetype font
 162	U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle();
 163
 164	F32 drop_shadow_strength = 0.f;
 165	if (shadow != NO_SHADOW)
 166	{
 167		F32 luminance;
 168		color.calcHSL(NULL, NULL, &luminance);
 169		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
 170		if (luminance < 0.35f)
 171		{
 172			shadow = NO_SHADOW;
 173		}
 174	}
 175
 176	gGL.pushUIMatrix();
 177
 178	gGL.loadUIIdentity();
 179	
 180	//gGL.translateUI(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
 181
 182	// this code snaps the text origin to a pixel grid to start with
 183	//F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
 184	//F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
 185	//gGL.translateUI(-pixel_offset_x, -pixel_offset_y, 0.f);
 186
 187	LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY));
 188	// snap the text origin to a pixel grid to start with
 189	origin.mV[VX] -= llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
 190	origin.mV[VY] -= llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
 191
 192	// Depth translation, so that floating text appears 'inworld'
 193	// and is correclty occluded.
 194	gGL.translatef(0.f,0.f,sCurOrigin.mZ);
 195
 196	S32 chars_drawn = 0;
 197	S32 i;
 198	S32 length;
 199
 200	if (-1 == max_chars)
 201	{
 202		length = (S32)wstr.length() - begin_offset;
 203	}
 204	else
 205	{
 206		length = llmin((S32)wstr.length() - begin_offset, max_chars );
 207	}
 208
 209	F32 cur_x, cur_y, cur_render_x, cur_render_y;
 210
 211 	// Not guaranteed to be set correctly
 212	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 213	
 214	cur_x = ((F32)x * sScaleX) + origin.mV[VX];
 215	cur_y = ((F32)y * sScaleY) + origin.mV[VY];
 216
 217	// Offset y by vertical alignment.
 218	switch (valign)
 219	{
 220	case TOP:
 221		cur_y -= mFontFreetype->getAscenderHeight();
 222		break;
 223	case BOTTOM:
 224		cur_y += mFontFreetype->getDescenderHeight();
 225		break;
 226	case VCENTER:
 227		cur_y -= (mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight()) / 2.f;
 228		break;
 229	case BASELINE:
 230		// Baseline, do nothing.
 231		break;
 232	default:
 233		break;
 234	}
 235
 236	switch (halign)
 237	{
 238	case LEFT:
 239		break;
 240	case RIGHT:
 241	  	cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX));
 242		break;
 243	case HCENTER:
 244	    cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2;
 245		break;
 246	default:
 247		break;
 248	}
 249
 250	cur_render_y = cur_y;
 251	cur_render_x = cur_x;
 252
 253	F32 start_x = llround(cur_x);
 254
 255	const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();
 256
 257	F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
 258	F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();
 259
 260	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
 261
 262
 263	BOOL draw_ellipses = FALSE;
 264	if (use_ellipses)
 265	{
 266		// check for too long of a string
 267		S32 string_width = llround(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX);
 268		if (string_width > scaled_max_pixels)
 269		{
 270			// use four dots for ellipsis width to generate padding
 271			const LLWString dots(utf8str_to_wstring(std::string("....")));
 272			scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
 273			draw_ellipses = TRUE;
 274		}
 275	}
 276
 277	const LLFontGlyphInfo* next_glyph = NULL;
 278
 279	const S32 GLYPH_BATCH_SIZE = 30;
 280	LLVector3 vertices[GLYPH_BATCH_SIZE * 4];
 281	LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
 282	LLColor4U colors[GLYPH_BATCH_SIZE * 4];
 283
 284	LLColor4U text_color(color);
 285
 286	S32 bitmap_num = -1;
 287	S32 glyph_count = 0;
 288	for (i = begin_offset; i < begin_offset + length; i++)
 289	{
 290		llwchar wch = wstr[i];
 291
 292		const LLFontGlyphInfo* fgi = next_glyph;
 293		next_glyph = NULL;
 294		if(!fgi)
 295		{
 296			fgi = mFontFreetype->getGlyphInfo(wch);
 297		}
 298		if (!fgi)
 299		{
 300			llerrs << "Missing Glyph Info" << llendl;
 301			break;
 302		}
 303		// Per-glyph bitmap texture.
 304		S32 next_bitmap_num = fgi->mBitmapNum;
 305		if (next_bitmap_num != bitmap_num)
 306		{
 307			// Actually draw the queued glyphs before switching their texture;
 308			// otherwise the queued glyphs will be taken from wrong textures.
 309			if (glyph_count > 0)
 310			{
 311				gGL.begin(LLRender::QUADS);
 312				{
 313					gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
 314				}
 315				gGL.end();
 316				glyph_count = 0;
 317			}
 318
 319			bitmap_num = next_bitmap_num;
 320			LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
 321			gGL.getTexUnit(0)->bind(font_image);
 322		}
 323	
 324		if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
 325		{
 326			// Not enough room for this character.
 327			break;
 328		}
 329
 330		// Draw the text at the appropriate location
 331		//Specify vertices and texture coordinates
 332		LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width,
 333				(fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height,
 334				(fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
 335				(fgi->mYBitmapOffset - PAD_UVY) * inv_height);
 336		// snap glyph origin to whole screen pixel
 337		LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing),
 338				    llround(cur_render_y + (F32)fgi->mYBearing),
 339				    llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
 340				    llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
 341		
 342		if (glyph_count >= GLYPH_BATCH_SIZE)
 343		{
 344			gGL.begin(LLRender::QUADS);
 345			{
 346				gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
 347			}
 348			gGL.end();
 349
 350			glyph_count = 0;
 351		}
 352
 353		drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength);
 354
 355		chars_drawn++;
 356		cur_x += fgi->mXAdvance;
 357		cur_y += fgi->mYAdvance;
 358
 359		llwchar next_char = wstr[i+1];
 360		if (next_char && (next_char < LAST_CHARACTER))
 361		{
 362			// Kern this puppy.
 363			next_glyph = mFontFreetype->getGlyphInfo(next_char);
 364			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
 365		}
 366
 367		// Round after kerning.
 368		// Must do this to cur_x, not just to cur_render_x, otherwise you
 369		// will squish sub-pixel kerned characters too close together.
 370		// For example, "CCCCC" looks bad.
 371		cur_x = (F32)llround(cur_x);
 372		//cur_y = (F32)llround(cur_y);
 373
 374		cur_render_x = cur_x;
 375		cur_render_y = cur_y;
 376	}
 377
 378	gGL.begin(LLRender::QUADS);
 379	{
 380		gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
 381	}
 382	gGL.end();
 383
 384
 385	if (right_x)
 386	{
 387		*right_x = (cur_x - origin.mV[VX]) / sScaleX;
 388	}
 389
 390	//FIXME: add underline as glyph?
 391	if (style_to_add & UNDERLINE)
 392	{
 393		F32 descender = mFontFreetype->getDescenderHeight();
 394
 395		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 396		gGL.begin(LLRender::LINES);
 397		gGL.vertex2f(start_x, cur_y - (descender));
 398		gGL.vertex2f(cur_x, cur_y - (descender));
 399		gGL.end();
 400	}
 401
 402	if (draw_ellipses)
 403	{
 404		
 405		// recursively render ellipses at end of string
 406		// we've already reserved enough room
 407		gGL.pushUIMatrix();
 408		renderUTF8(std::string("..."), 
 409				0,
 410				(cur_x - origin.mV[VX]) / sScaleX, (F32)y,
 411				color,
 412				LEFT, valign,
 413				style_to_add,
 414				shadow,
 415				S32_MAX, max_pixels,
 416				right_x,
 417				FALSE); 
 418		gGL.popUIMatrix();
 419	}
 420
 421	gGL.popUIMatrix();
 422
 423	return chars_drawn;
 424}
 425
 426S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const
 427{
 428	return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
 429}
 430
 431S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign,  VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels,  F32* right_x, BOOL use_ellipses) const
 432{
 433	return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses);
 434}
 435
 436S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const
 437{
 438	return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
 439}
 440
 441S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const
 442{
 443	return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE);
 444}
 445
 446// font metrics - override for LLFontFreetype that returns units of virtual pixels
 447F32 LLFontGL::getLineHeight() const
 448{ 
 449	return (F32)llround(mFontFreetype->getLineHeight() / sScaleY); 
 450}
 451
 452F32 LLFontGL::getAscenderHeight() const
 453{ 
 454	return (F32)llround(mFontFreetype->getAscenderHeight() / sScaleY); 
 455}
 456
 457F32 LLFontGL::getDescenderHeight() const
 458{ 
 459	return (F32)llround(mFontFreetype->getDescenderHeight() / sScaleY); 
 460}
 461
 462S32 LLFontGL::getWidth(const std::string& utf8text) const
 463{
 464	LLWString wtext = utf8str_to_wstring(utf8text);
 465	return getWidth(wtext.c_str(), 0, S32_MAX);
 466}
 467
 468S32 LLFontGL::getWidth(const llwchar* wchars) const
 469{
 470	return getWidth(wchars, 0, S32_MAX);
 471}
 472
 473S32 LLFontGL::getWidth(const std::string& utf8text, S32 begin_offset, S32 max_chars) const
 474{
 475	LLWString wtext = utf8str_to_wstring(utf8text);
 476	return getWidth(wtext.c_str(), begin_offset, max_chars);
 477}
 478
 479S32 LLFontGL::getWidth(const llwchar* wchars, S32 begin_offset, S32 max_chars) const
 480{
 481	F32 width = getWidthF32(wchars, begin_offset, max_chars);
 482	return llround(width);
 483}
 484
 485F32 LLFontGL::getWidthF32(const std::string& utf8text) const
 486{
 487	LLWString wtext = utf8str_to_wstring(utf8text);
 488	return getWidthF32(wtext.c_str(), 0, S32_MAX);
 489}
 490
 491F32 LLFontGL::getWidthF32(const llwchar* wchars) const
 492{
 493	return getWidthF32(wchars, 0, S32_MAX);
 494}
 495
 496F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max_chars ) const
 497{
 498	LLWString wtext = utf8str_to_wstring(utf8text);
 499	return getWidthF32(wtext.c_str(), begin_offset, max_chars);
 500}
 501
 502F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars) const
 503{
 504	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
 505
 506	F32 cur_x = 0;
 507	const S32 max_index = begin_offset + max_chars;
 508
 509	const LLFontGlyphInfo* next_glyph = NULL;
 510
 511	F32 width_padding = 0.f;
 512	for (S32 i = begin_offset; i < max_index && wchars[i] != 0; i++)
 513	{
 514		llwchar wch = wchars[i];
 515
 516		const LLFontGlyphInfo* fgi = next_glyph;
 517		next_glyph = NULL;
 518		if(!fgi)
 519		{
 520			fgi = mFontFreetype->getGlyphInfo(wch);
 521		}
 522
 523		F32 advance = mFontFreetype->getXAdvance(fgi);
 524
 525		// for the last character we want to measure the greater of its width and xadvance values
 526		// so keep track of the difference between these values for the each character we measure
 527		// so we can fix things up at the end
 528		width_padding = llmax(	0.f,											// always use positive padding amount
 529								width_padding - advance,						// previous padding left over after advance of current character
 530								(F32)(fgi->mWidth + fgi->mXBearing) - advance);	// difference between width of this character and advance to next character
 531
 532		cur_x += advance;
 533		llwchar next_char = wchars[i+1];
 534
 535		if (((i + 1) < begin_offset + max_chars) 
 536			&& next_char 
 537			&& (next_char < LAST_CHARACTER))
 538		{
 539			// Kern this puppy.
 540			next_glyph = mFontFreetype->getGlyphInfo(next_char);
 541			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
 542		}
 543		// Round after kerning.
 544		cur_x = (F32)llround(cur_x);
 545	}
 546
 547	// add in extra pixels for last character's width past its xadvance
 548	cur_x += width_padding;
 549
 550	return cur_x / sScaleX;
 551}
 552
 553// Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
 554S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary) const
 555{
 556	if (!wchars || !wchars[0] || max_chars == 0)
 557	{
 558		return 0;
 559	}
 560	
 561	llassert(max_pixels >= 0.f);
 562	llassert(max_chars >= 0);
 563	
 564	BOOL clip = FALSE;
 565	F32 cur_x = 0;
 566	F32 drawn_x = 0;
 567
 568	S32 start_of_last_word = 0;
 569	BOOL in_word = FALSE;
 570
 571	// avoid S32 overflow when max_pixels == S32_MAX by staying in floating point
 572	F32 scaled_max_pixels =	max_pixels * sScaleX;
 573	F32 width_padding = 0.f;
 574	
 575	LLFontGlyphInfo* next_glyph = NULL;
 576
 577	S32 i;
 578	for (i=0; (i < max_chars); i++)
 579	{
 580		llwchar wch = wchars[i];
 581
 582		if(wch == 0)
 583		{
 584			// Null terminator.  We're done.
 585			break;
 586		}
 587			
 588		if (in_word)
 589		{
 590			if (iswspace(wch))
 591			{
 592				if(wch !=(0x00A0))
 593				{
 594					in_word = FALSE;
 595				}
 596			}
 597			if (iswindividual(wch))
 598			{
 599				if (iswpunct(wchars[i+1]))
 600				{
 601					in_word=TRUE;
 602				}
 603				else
 604				{
 605					in_word=FALSE;
 606					start_of_last_word = i;
 607				}
 608			}
 609		}
 610		else
 611		{
 612			start_of_last_word = i;
 613			if (!iswspace(wch)||!iswindividual(wch))
 614			{
 615				in_word = TRUE;
 616			}
 617		}
 618		
 619		LLFontGlyphInfo* fgi = next_glyph;
 620		next_glyph = NULL;
 621		if(!fgi)
 622		{
 623			fgi = mFontFreetype->getGlyphInfo(wch);
 624		}
 625
 626		// account for glyphs that run beyond the starting point for the next glyphs
 627		width_padding = llmax(	0.f,													// always use positive padding amount
 628								width_padding - fgi->mXAdvance,							// previous padding left over after advance of current character
 629								(F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance);	// difference between width of this character and advance to next character
 630
 631		cur_x += fgi->mXAdvance;
 632		
 633		// clip if current character runs past scaled_max_pixels (using width_padding)
 634		if (scaled_max_pixels < cur_x + width_padding)
 635		{
 636			clip = TRUE;
 637			break;
 638		}
 639
 640		if (((i+1) < max_chars) && wchars[i+1])
 641		{
 642			// Kern this puppy.
 643			next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1]);
 644			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
 645		}
 646
 647		// Round after kerning.
 648		cur_x = llround(cur_x);
 649		drawn_x = cur_x;
 650	}
 651
 652	if( clip )
 653	{
 654		switch (end_on_word_boundary)
 655		{
 656		case ONLY_WORD_BOUNDARIES:
 657			i = start_of_last_word;
 658			break;
 659		case WORD_BOUNDARY_IF_POSSIBLE:
 660			if (start_of_last_word != 0)
 661			{
 662				i = start_of_last_word;
 663			}
 664			break;
 665		default:
 666		case ANYWHERE:
 667			// do nothing
 668			break;
 669		}
 670	}
 671	return i;
 672}
 673
 674S32	LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const
 675{
 676	if (!wchars || !wchars[0] || max_chars == 0)
 677	{
 678		return 0;
 679	}
 680	
 681	F32 total_width = 0.0;
 682	S32 drawable_chars = 0;
 683
 684	F32 scaled_max_pixels =	max_pixels * sScaleX;
 685
 686	S32 start = llmin(start_pos, text_len - 1);
 687	for (S32 i = start; i >= 0; i--)
 688	{
 689		llwchar wch = wchars[i];
 690
 691		const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch);
 692
 693		// last character uses character width, since the whole character needs to be visible
 694		// other characters just use advance
 695		F32 width = (i == start) 
 696			? (F32)(fgi->mWidth + fgi->mXBearing)  	// use actual width for last character
 697			: fgi->mXAdvance;						// use advance for all other characters										
 698
 699		if( scaled_max_pixels < (total_width + width) )
 700		{
 701			break;
 702		}
 703
 704		total_width += width;
 705		drawable_chars++;
 706
 707		if( max_chars >= 0 && drawable_chars >= max_chars )
 708		{
 709			break;
 710		}
 711
 712		if ( i > 0 )
 713		{
 714			// kerning
 715			total_width += mFontFreetype->getXKerning(wchars[i-1], wch);
 716		}
 717
 718		// Round after kerning.
 719		total_width = llround(total_width);
 720	}
 721
 722	if (drawable_chars == 0)
 723	{
 724		return start_pos; // just draw last character
 725	}
 726	else
 727	{
 728		// if only 1 character is drawable, we want to return start_pos as the first character to draw
 729		// if 2 are drawable, return start_pos and character before start_pos, etc.
 730		return start_pos + 1 - drawable_chars;
 731	}
 732	
 733}
 734
 735S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round) const
 736{
 737	if (!wchars || !wchars[0] || max_chars == 0)
 738	{
 739		return 0;
 740	}
 741	
 742	F32 cur_x = 0;
 743
 744	target_x *= sScaleX;
 745
 746	// max_chars is S32_MAX by default, so make sure we don't get overflow
 747	const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars - 1);
 748
 749	F32 scaled_max_pixels =	max_pixels * sScaleX;
 750	
 751	const LLFontGlyphInfo* next_glyph = NULL;
 752
 753	S32 pos;
 754	for (pos = begin_offset; pos < max_index; pos++)
 755	{
 756		llwchar wch = wchars[pos];
 757		if (!wch)
 758		{
 759			break; // done
 760		}
 761		
 762		const LLFontGlyphInfo* glyph = next_glyph;
 763		next_glyph = NULL;
 764		if(!glyph)
 765		{
 766			glyph = mFontFreetype->getGlyphInfo(wch);
 767		}
 768		
 769		F32 char_width = mFontFreetype->getXAdvance(glyph);
 770
 771		if (round)
 772		{
 773			// Note: if the mouse is on the left half of the character, the pick is to the character's left
 774			// If it's on the right half, the pick is to the right.
 775			if (target_x  < cur_x + char_width*0.5f)
 776			{
 777				break;
 778			}
 779		}
 780		else if (target_x  < cur_x + char_width)
 781		{
 782			break;
 783		}
 784
 785		if (scaled_max_pixels < cur_x + char_width)
 786		{
 787			break;
 788		}
 789
 790		cur_x += char_width;
 791
 792		if (((pos + 1) < max_index)
 793			&& (wchars[(pos + 1)]))
 794		{
 795			// Kern this puppy.
 796			next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1]);
 797			cur_x += mFontFreetype->getXKerning(glyph, next_glyph);
 798		}
 799
 800
 801		// Round after kerning.
 802		cur_x = llround(cur_x);
 803	}
 804
 805	return llmin(max_chars, pos - begin_offset);
 806}
 807
 808const LLFontDescriptor& LLFontGL::getFontDesc() const
 809{
 810	return mFontDescriptor;
 811}
 812
 813// static
 814void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector<std::string>& xui_paths, bool create_gl_textures)
 815{
 816	sVertDPI = (F32)llfloor(screen_dpi * y_scale);
 817	sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
 818	sScaleX = x_scale;
 819	sScaleY = y_scale;
 820	sAppDir = app_dir;
 821
 822	// Font registry init
 823	if (!sFontRegistry)
 824	{
 825		sFontRegistry = new LLFontRegistry(xui_paths, create_gl_textures);
 826		sFontRegistry->parseFontInfo("fonts.xml");
 827	}
 828	else
 829	{
 830		sFontRegistry->reset();
 831	}
 832}
 833
 834// Force standard fonts to get generated up front.
 835// This is primarily for error detection purposes.
 836// Don't do this during initClass because it can be slow and we want to get
 837// the viewer window on screen first. JC
 838// static
 839bool LLFontGL::loadDefaultFonts()
 840{
 841	bool succ = true;
 842	succ &= (NULL != getFontSansSerifSmall());
 843	succ &= (NULL != getFontSansSerif());
 844	succ &= (NULL != getFontSansSerifBig());
 845	succ &= (NULL != getFontSansSerifHuge());
 846	succ &= (NULL != getFontSansSerifBold());
 847	succ &= (NULL != getFontMonospace());
 848	succ &= (NULL != getFontExtChar());
 849	return succ;
 850}
 851
 852// static
 853void LLFontGL::destroyDefaultFonts()
 854{
 855	// Remove the actual fonts.
 856	delete sFontRegistry;
 857	sFontRegistry = NULL;
 858}
 859
 860//static 
 861void LLFontGL::destroyAllGL()
 862{
 863	if (sFontRegistry)
 864	{
 865		sFontRegistry->destroyGL();
 866	}
 867}
 868
 869// static
 870U8 LLFontGL::getStyleFromString(const std::string &style)
 871{
 872	S32 ret = 0;
 873	if (style.find("NORMAL") != style.npos)
 874	{
 875		ret |= NORMAL;
 876	}
 877	if (style.find("BOLD") != style.npos)
 878	{
 879		ret |= BOLD;
 880	}
 881	if (style.find("ITALIC") != style.npos)
 882	{
 883		ret |= ITALIC;
 884	}
 885	if (style.find("UNDERLINE") != style.npos)
 886	{
 887		ret |= UNDERLINE;
 888	}
 889	return ret;
 890}
 891
 892// static
 893std::string LLFontGL::getStringFromStyle(U8 style)
 894{
 895	std::string style_string;
 896	if (style & NORMAL)
 897	{
 898		style_string += "|NORMAL";
 899	}
 900	if (style & BOLD)
 901	{
 902		style_string += "|BOLD";
 903	}
 904	if (style & ITALIC)
 905	{
 906		style_string += "|ITALIC";
 907	}
 908	if (style & UNDERLINE)
 909	{
 910		style_string += "|UNDERLINE";
 911	}
 912	return style_string;
 913}
 914
 915// static
 916std::string LLFontGL::nameFromFont(const LLFontGL* fontp)
 917{
 918	return fontp->mFontDescriptor.getName();
 919}
 920
 921
 922// static
 923std::string LLFontGL::sizeFromFont(const LLFontGL* fontp)
 924{
 925	return fontp->mFontDescriptor.getSize();
 926}
 927
 928// static
 929std::string LLFontGL::nameFromHAlign(LLFontGL::HAlign align)
 930{
 931	if (align == LEFT)			return std::string("left");
 932	else if (align == RIGHT)	return std::string("right");
 933	else if (align == HCENTER)	return std::string("center");
 934	else return std::string();
 935}
 936
 937// static
 938LLFontGL::HAlign LLFontGL::hAlignFromName(const std::string& name)
 939{
 940	LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
 941	if (name == "left")
 942	{
 943		gl_hfont_align = LLFontGL::LEFT;
 944	}
 945	else if (name == "right")
 946	{
 947		gl_hfont_align = LLFontGL::RIGHT;
 948	}
 949	else if (name == "center")
 950	{
 951		gl_hfont_align = LLFontGL::HCENTER;
 952	}
 953	//else leave left
 954	return gl_hfont_align;
 955}
 956
 957// static
 958std::string LLFontGL::nameFromVAlign(LLFontGL::VAlign align)
 959{
 960	if (align == TOP)			return std::string("top");
 961	else if (align == VCENTER)	return std::string("center");
 962	else if (align == BASELINE)	return std::string("baseline");
 963	else if (align == BOTTOM)	return std::string("bottom");
 964	else return std::string();
 965}
 966
 967// static
 968LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
 969{
 970	LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
 971	if (name == "top")
 972	{
 973		gl_vfont_align = LLFontGL::TOP;
 974	}
 975	else if (name == "center")
 976	{
 977		gl_vfont_align = LLFontGL::VCENTER;
 978	}
 979	else if (name == "baseline")
 980	{
 981		gl_vfont_align = LLFontGL::BASELINE;
 982	}
 983	else if (name == "bottom")
 984	{
 985		gl_vfont_align = LLFontGL::BOTTOM;
 986	}
 987	//else leave baseline
 988	return gl_vfont_align;
 989}
 990
 991//static
 992LLFontGL* LLFontGL::getFontMonospace()
 993{
 994	static LLFontGL* fontp = getFont(LLFontDescriptor("Monospace","Monospace",0));
 995	return fontp;
 996}
 997
 998//static
 999LLFontGL* LLFontGL::getFontSansSerifSmall()
1000{
1001	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",0));
1002	return fontp;
1003}
1004
1005//static
1006LLFontGL* LLFontGL::getFontSansSerif()
1007{
1008	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",0));
1009	return fontp;
1010}
1011
1012//static
1013LLFontGL* LLFontGL::getFontSansSerifBig()
1014{
1015	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0));
1016	return fontp;
1017}
1018
1019//static 
1020LLFontGL* LLFontGL::getFontSansSerifHuge()
1021{
1022	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0));
1023	return fontp;
1024}
1025
1026//static 
1027LLFontGL* LLFontGL::getFontSansSerifBold()
1028{
1029	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",BOLD));
1030	return fontp;
1031}
1032
1033//static
1034LLFontGL* LLFontGL::getFontExtChar()
1035{
1036	return getFontSansSerif();
1037}
1038
1039//static 
1040LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc)
1041{
1042	return sFontRegistry->getFont(desc);
1043}
1044
1045//static
1046LLFontGL* LLFontGL::getFontByName(const std::string& name)
1047{
1048	// check for most common fonts first
1049	if (name == "SANSSERIF")
1050	{
1051		return getFontSansSerif();
1052	}
1053	else if (name == "SANSSERIF_SMALL")
1054	{
1055		return getFontSansSerifSmall();
1056	}
1057	else if (name == "SANSSERIF_BIG")
1058	{
1059		return getFontSansSerifBig();
1060	}
1061	else if (name == "SMALL" || name == "OCRA")
1062	{
1063		// *BUG: Should this be "MONOSPACE"?  Do we use "OCRA" anymore?
1064		// Does "SMALL" mean "SERIF"?
1065		return getFontMonospace();
1066	}
1067	else
1068	{
1069		return NULL;
1070	}
1071}
1072
1073//static
1074LLFontGL* LLFontGL::getFontDefault()
1075{
1076	return getFontSansSerif(); // Fallback to sans serif as default font
1077}
1078
1079
1080// static 
1081std::string LLFontGL::getFontPathSystem()
1082{
1083	std::string system_path;
1084
1085	// Try to figure out where the system's font files are stored.
1086	char *system_root = NULL;
1087#if LL_WINDOWS
1088	system_root = getenv("SystemRoot");	/* Flawfinder: ignore */
1089	if (!system_root)
1090	{
1091		llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl;
1092	}
1093#endif
1094
1095	if (system_root)
1096	{
1097		system_path = llformat("%s/fonts/", system_root);
1098	}
1099	else
1100	{
1101#if LL_WINDOWS
1102		// HACK for windows 98/Me
1103		system_path = "/WINDOWS/FONTS/";
1104#elif LL_DARWIN
1105		// HACK for Mac OS X
1106		system_path = "/System/Library/Fonts/";
1107#endif
1108	}
1109	return system_path;
1110}
1111
1112
1113// static 
1114std::string LLFontGL::getFontPathLocal()
1115{
1116	std::string local_path;
1117
1118	// Backup files if we can't load from system fonts directory.
1119	// We could store this in an end-user writable directory to allow
1120	// end users to switch fonts.
1121	if (LLFontGL::sAppDir.length())
1122	{
1123		// use specified application dir to look for fonts
1124		local_path = LLFontGL::sAppDir + "/fonts/";
1125	}
1126	else
1127	{
1128		// assume working directory is executable directory
1129		local_path = "./fonts/";
1130	}
1131	return local_path;
1132}
1133
1134LLFontGL::LLFontGL(const LLFontGL &source)
1135{
1136	llerrs << "Not implemented!" << llendl;
1137}
1138
1139LLFontGL &LLFontGL::operator=(const LLFontGL &source)
1140{
1141	llerrs << "Not implemented" << llendl;
1142	return *this;
1143}
1144
1145void 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
1146{
1147	S32 index = 0;
1148
1149	vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mRight), llfont_round_y(screen_rect.mTop), 0.f);
1150	uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
1151	colors_out[index] = color;
1152	index++;
1153
1154	vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mLeft), llfont_round_y(screen_rect.mTop), 0.f);
1155	uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
1156	colors_out[index] = color;
1157	index++;
1158
1159	vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mLeft), llfont_round_y(screen_rect.mBottom), 0.f);
1160	uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
1161	colors_out[index] = color;
1162	index++;
1163
1164	vertex_out[index] = LLVector3(llfont_round_x(screen_rect.mRight), llfont_round_y(screen_rect.mBottom), 0.f);
1165	uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
1166	colors_out[index] = color;
1167}
1168
1169void 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
1170{
1171	F32 slant_offset;
1172	slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f);
1173
1174	//FIXME: bold and drop shadow are mutually exclusive only for convenience
1175	//Allow both when we need them.
1176	if (style & BOLD)
1177	{
1178		for (S32 pass = 0; pass < 2; pass++)
1179		{
1180			LLRectf screen_rect_offset = screen_rect;
1181
1182			screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
1183			renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, color, slant_offset);
1184			glyph_count++;
1185		}
1186	}
1187	else if (shadow == DROP_SHADOW_SOFT)
1188	{
1189		LLColor4U shadow_color = LLFontGL::sShadowColor;
1190		shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH);
1191		for (S32 pass = 0; pass < 5; pass++)
1192		{
1193			LLRectf screen_rect_offset = screen_rect;
1194
1195			switch(pass)
1196			{
1197			case 0:
1198				screen_rect_offset.translate(-1.f, -1.f);
1199				break;
1200			case 1:
1201				screen_rect_offset.translate(1.f, -1.f);
1202				break;
1203			case 2:
1204				screen_rect_offset.translate(1.f, 1.f);
1205				break;
1206			case 3:
1207				screen_rect_offset.translate(-1.f, 1.f);
1208				break;
1209			case 4:
1210				screen_rect_offset.translate(0, -2.f);
1211				break;
1212			}
1213		
1214			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);
1215			glyph_count++;
1216		}
1217		renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
1218		glyph_count++;
1219	}
1220	else if (shadow == DROP_SHADOW)
1221	{
1222		LLColor4U shadow_color = LLFontGL::sShadowColor;
1223		shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength);
1224		LLRectf screen_rect_shadow = screen_rect;
1225		screen_rect_shadow.translate(1.f, -1.f);
1226		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);
1227		glyph_count++;
1228		renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
1229		glyph_count++;
1230	}
1231	else // normal rendering
1232	{
1233		renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
1234		glyph_count++;
1235	}
1236}