llfontgl.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include <boost/tokenizer.hpp>
00035 
00036 #include "llfont.h"
00037 #include "llfontgl.h"
00038 #include "llgl.h"
00039 #include "v4color.h"
00040 #include "llstl.h"
00041 
00042 const S32 BOLD_OFFSET = 1;
00043 
00044 // static class members
00045 F32 LLFontGL::sVertDPI = 96.f;
00046 F32 LLFontGL::sHorizDPI = 96.f;
00047 F32 LLFontGL::sScaleX = 1.f;
00048 F32 LLFontGL::sScaleY = 1.f;
00049 LLString LLFontGL::sAppDir;
00050 
00051 LLFontGL* LLFontGL::sMonospace = NULL;
00052 LLFontGL* LLFontGL::sSansSerifSmall = NULL;
00053 LLFontGL* LLFontGL::sSansSerif = NULL;
00054 LLFontGL* LLFontGL::sSansSerifBig = NULL;
00055 LLFontGL* LLFontGL::sSansSerifHuge = NULL;
00056 LLFontGL* LLFontGL::sSansSerifBold = NULL;
00057 LLFontList*     LLFontGL::sSSFallback = NULL;
00058 LLFontList*     LLFontGL::sSSSmallFallback = NULL;
00059 LLFontList*     LLFontGL::sSSBigFallback = NULL;
00060 LLFontList*     LLFontGL::sSSHugeFallback = NULL;
00061 LLFontList*     LLFontGL::sSSBoldFallback = NULL;
00062 LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f);
00063 
00064 LLCoordFont LLFontGL::sCurOrigin;
00065 std::vector<LLCoordFont> LLFontGL::sOriginStack;
00066 
00067 LLFontGL*& gExtCharFont = LLFontGL::sSansSerif;
00068 
00069 const F32 EXT_X_BEARING = 1.f;
00070 const F32 EXT_Y_BEARING = 0.f;
00071 const F32 EXT_KERNING = 1.f;
00072 const F32 PIXEL_BORDER_THRESHOLD = 0.0001f;
00073 const F32 PIXEL_CORRECTION_DISTANCE = 0.01f;
00074 
00075 const F32 PAD_AMT = 0.5f;
00076 const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f;
00077 
00078 F32 llfont_round_x(F32 x)
00079 {
00080         //return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX;
00081         //return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY;
00082         return x;
00083 }
00084 
00085 F32 llfont_round_y(F32 y)
00086 {
00087         //return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY;
00088         //return llfloor(y+0.5f);
00089         return y;
00090 }
00091 
00092 // static
00093 U8 LLFontGL::getStyleFromString(const LLString &style)
00094 {
00095         S32 ret = 0;
00096         if (style.find("NORMAL") != style.npos)
00097         {
00098                 ret |= NORMAL;
00099         }
00100         if (style.find("BOLD") != style.npos)
00101         {
00102                 ret |= BOLD;
00103         }
00104         if (style.find("ITALIC") != style.npos)
00105         {
00106                 ret |= ITALIC;
00107         }
00108         if (style.find("UNDERLINE") != style.npos)
00109         {
00110                 ret |= UNDERLINE;
00111         }
00112         if (style.find("SHADOW") != style.npos)
00113         {
00114                 ret |= DROP_SHADOW;
00115         }
00116         if (style.find("SOFT_SHADOW") != style.npos)
00117         {
00118                 ret |= DROP_SHADOW_SOFT;
00119         }
00120         return ret;
00121 }
00122 
00123 LLFontGL::LLFontGL()
00124         : LLFont()
00125 {
00126         init();
00127         clearEmbeddedChars();
00128 }
00129 
00130 LLFontGL::LLFontGL(const LLFontGL &source)
00131 {
00132         llerrs << "Not implemented!" << llendl;
00133 }
00134 
00135 LLFontGL::~LLFontGL()
00136 {
00137         mImageGLp = NULL;
00138         mRawImageGLp = NULL;
00139         clearEmbeddedChars();
00140 }
00141 
00142 void LLFontGL::init()
00143 {
00144         if (mImageGLp.isNull())
00145         {
00146                 mImageGLp = new LLImageGL(FALSE);
00147                 //RN: use nearest mipmap filtering to obviate the need to do pixel-accurate positioning
00148                 mImageGLp->bind();
00149                 // we allow bilinear filtering to get sub-pixel positioning for drop shadows
00150                 //mImageGLp->setMipFilterNearest(TRUE, TRUE);
00151         }
00152         if (mRawImageGLp.isNull())
00153         {
00154                 mRawImageGLp = new LLImageRaw; // Note LLFontGL owns the image, not LLFont.
00155         }
00156         setRawImage( mRawImageGLp );  
00157 }
00158 
00159 void LLFontGL::reset()
00160 {
00161         init();
00162         resetBitmap();
00163 }
00164 
00165 // static 
00166 LLString LLFontGL::getFontPathSystem()
00167 {
00168         LLString system_path;
00169 
00170         // Try to figure out where the system's font files are stored.
00171         char *system_root = NULL;
00172 #if LL_WINDOWS
00173         system_root = getenv("SystemRoot");     /* Flawfinder: ignore */
00174         if (!system_root)
00175         {
00176                 llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl;
00177         }
00178 #endif
00179 
00180         if (system_root)
00181         {
00182                 system_path = llformat("%s/fonts/", system_root);
00183         }
00184         else
00185         {
00186 #if LL_WINDOWS
00187                 // HACK for windows 98/Me
00188                 system_path = "/WINDOWS/FONTS/";
00189 #elif LL_DARWIN
00190                 // HACK for Mac OS X
00191                 system_path = "/System/Library/Fonts/";
00192 #endif
00193         }
00194         return system_path;
00195 }
00196 
00197 
00198 // static 
00199 LLString LLFontGL::getFontPathLocal()
00200 {
00201         LLString local_path;
00202 
00203         // Backup files if we can't load from system fonts directory.
00204         // We could store this in an end-user writable directory to allow
00205         // end users to switch fonts.
00206         if (LLFontGL::sAppDir.length())
00207         {
00208                 // use specified application dir to look for fonts
00209                 local_path = LLFontGL::sAppDir + "/fonts/";
00210         }
00211         else
00212         {
00213                 // assume working directory is executable directory
00214                 local_path = "./fonts/";
00215         }
00216         return local_path;
00217 }
00218 
00219 //static
00220 bool LLFontGL::loadFaceFallback(LLFontList *fontlistp, const LLString& fontname, const F32 point_size)
00221 {
00222         LLString local_path = getFontPathLocal();
00223         LLString sys_path = getFontPathSystem();
00224         
00225         // The fontname string may contain multiple font file names separated by semicolons.
00226         // Break it apart and try loading each one, in order.
00227         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00228         boost::char_separator<char> sep(";");
00229         tokenizer tokens(fontname, sep);
00230         tokenizer::iterator token_iter;
00231 
00232         for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
00233         {
00234                 LLFont *fontp = new LLFont();
00235                 LLString font_path = local_path + *token_iter;
00236                 if (!fontp->loadFace(font_path.c_str(), point_size, sVertDPI, sHorizDPI, 2, TRUE))
00237                 {
00238                         font_path = sys_path + *token_iter;
00239                         if (!fontp->loadFace(font_path.c_str(), point_size, sVertDPI, sHorizDPI, 2, TRUE))
00240                         {
00241                                 llwarns << "Couldn't load font " << *token_iter << llendl;
00242                                 delete fontp;
00243                                 fontp = NULL;
00244                         }
00245                 }
00246                 
00247                 if(fontp)
00248                 {
00249                         fontlistp->addAtEnd(fontp);
00250                 }
00251         }
00252         
00253         // We want to return true if at least one fallback font loaded correctly.
00254         return (fontlistp->size() > 0);
00255 }
00256 
00257 //static
00258 bool LLFontGL::loadFace(LLFontGL *fontp, const LLString& fontname, const F32 point_size, LLFontList *fallback_fontp)
00259 {
00260         LLString local_path = getFontPathLocal();
00261         LLString font_path = local_path + fontname;
00262         if (!fontp->loadFace(font_path.c_str(), point_size, sVertDPI, sHorizDPI))
00263         {
00264                 LLString sys_path = getFontPathSystem();
00265                 font_path = sys_path + fontname;
00266                 if (!fontp->loadFace(font_path.c_str(), point_size, sVertDPI, sHorizDPI))
00267                 {
00268                         llwarns << "Couldn't load font " << fontname << llendl;
00269                         return false;
00270                 }
00271         }
00272 
00273         fontp->setFallbackFont(fallback_fontp);
00274         return true;
00275 }
00276 
00277 
00278 // static
00279 BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
00280                                                                 const LLString& monospace_file, F32 monospace_size,
00281                                                                 const LLString& sansserif_file,
00282                                                                 const LLString& sanserif_fallback_file, F32 ss_fallback_scale,
00283                                                                 F32 small_size, F32 medium_size, F32 big_size, F32 huge_size,
00284                                                                 const LLString& sansserif_bold_file, F32 bold_size,
00285                                                                 const LLString& app_dir)
00286 {
00287         BOOL failed = FALSE;
00288         sVertDPI = (F32)llfloor(screen_dpi * y_scale);
00289         sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
00290         sScaleX = x_scale;
00291         sScaleY = y_scale;
00292         sAppDir = app_dir;
00293 
00294         //
00295         // Monospace font
00296         //
00297 
00298         if (!sMonospace)
00299         {
00300                 sMonospace = new LLFontGL();
00301         }
00302         else
00303         {
00304                 sMonospace->reset();
00305         }
00306 
00307         failed |= !loadFace(sMonospace, monospace_file, monospace_size, NULL);
00308 
00309         //
00310         // Sans-serif fonts
00311         //
00312         if(!sSansSerifHuge)
00313         {
00314                 sSansSerifHuge = new LLFontGL();
00315         }
00316         else
00317         {
00318                 sSansSerifHuge->reset();
00319         }
00320 
00321         if (sSSHugeFallback)
00322         {
00323                 delete sSSHugeFallback;
00324         }
00325         sSSHugeFallback = new LLFontList();
00326         if (!loadFaceFallback(
00327                         sSSHugeFallback,
00328                         sanserif_fallback_file,
00329                         huge_size*ss_fallback_scale))
00330         {
00331                 delete sSSHugeFallback;
00332                 sSSHugeFallback = NULL;
00333         }
00334 
00335         failed |= !loadFace(sSansSerifHuge, sansserif_file, huge_size, sSSHugeFallback);
00336 
00337 
00338         if(!sSansSerifBig)
00339         {
00340                 sSansSerifBig = new LLFontGL();
00341         }
00342         else
00343         {
00344                 sSansSerifBig->reset();
00345         }
00346 
00347         if (sSSBigFallback)
00348         {
00349                 delete sSSBigFallback;
00350         }
00351         sSSBigFallback = new LLFontList();
00352         if (!loadFaceFallback(
00353                         sSSBigFallback,
00354                         sanserif_fallback_file,
00355                         big_size*ss_fallback_scale))
00356         {
00357                 delete sSSBigFallback;
00358                 sSSBigFallback = NULL;
00359         }
00360 
00361         failed |= !loadFace(sSansSerifBig, sansserif_file, big_size, sSSBigFallback);
00362 
00363 
00364         if(!sSansSerif)
00365         {
00366                 sSansSerif = new LLFontGL();
00367         }
00368         else
00369         {
00370                 sSansSerif->reset();
00371         }
00372 
00373         if (sSSFallback)
00374         {
00375                 delete sSSFallback;
00376         }
00377         sSSFallback = new LLFontList();
00378         if (!loadFaceFallback(
00379                         sSSFallback,
00380                         sanserif_fallback_file,
00381                         medium_size*ss_fallback_scale))
00382         {
00383                 delete sSSFallback;
00384                 sSSFallback = NULL;
00385         }
00386         failed |= !loadFace(sSansSerif, sansserif_file, medium_size, sSSFallback);
00387 
00388 
00389         if(!sSansSerifSmall)
00390         {
00391                 sSansSerifSmall = new LLFontGL();
00392         }
00393         else
00394         {
00395                 sSansSerifSmall->reset();
00396         }
00397 
00398         if(sSSSmallFallback)
00399         {
00400                 delete sSSSmallFallback;
00401         }
00402         sSSSmallFallback = new LLFontList();
00403         if (!loadFaceFallback(
00404                         sSSSmallFallback,
00405                         sanserif_fallback_file,
00406                         small_size*ss_fallback_scale))
00407         {
00408                 delete sSSSmallFallback;
00409                 sSSSmallFallback = NULL;
00410         }
00411         failed |= !loadFace(sSansSerifSmall, sansserif_file, small_size, sSSSmallFallback);
00412 
00413 
00414         //
00415         // Sans-serif bold
00416         //
00417         if(!sSansSerifBold)
00418         {
00419                 sSansSerifBold = new LLFontGL();
00420         }
00421         else
00422         {
00423                 sSansSerifBold->reset();
00424         }
00425 
00426         if (sSSBoldFallback)
00427         {
00428                 delete sSSBoldFallback;
00429         }
00430         sSSBoldFallback = new LLFontList();
00431         if (!loadFaceFallback(
00432                         sSSBoldFallback,
00433                         sanserif_fallback_file,
00434                         medium_size*ss_fallback_scale))
00435         {
00436                 delete sSSBoldFallback;
00437                 sSSBoldFallback = NULL;
00438         }
00439         failed |= !loadFace(sSansSerifBold, sansserif_bold_file, medium_size, sSSBoldFallback);
00440 
00441         return !failed;
00442 }
00443 
00444 
00445 
00446 // static
00447 void LLFontGL::destroyDefaultFonts()
00448 {
00449         delete sMonospace;
00450         sMonospace = NULL;
00451 
00452         delete sSansSerifHuge;
00453         sSansSerifHuge = NULL;
00454 
00455         delete sSansSerifBig;
00456         sSansSerifBig = NULL;
00457 
00458         delete sSansSerif;
00459         sSansSerif = NULL;
00460 
00461         delete sSansSerifSmall;
00462         sSansSerifSmall = NULL;
00463 
00464         delete sSansSerifBold;
00465         sSansSerifBold = NULL;
00466 
00467         delete sSSHugeFallback;
00468         sSSHugeFallback = NULL;
00469 
00470         delete sSSBigFallback;
00471         sSSBigFallback = NULL;
00472 
00473         delete sSSFallback;
00474         sSSFallback = NULL;
00475 
00476         delete sSSSmallFallback;
00477         sSSSmallFallback = NULL;
00478 
00479         delete sSSBoldFallback;
00480         sSSBoldFallback = NULL;
00481 }
00482 
00483 //static 
00484 void LLFontGL::destroyGL()
00485 {
00486         if (!sMonospace)
00487         {
00488                 // Already all destroyed.
00489                 return;
00490         }
00491         sMonospace->mImageGLp->destroyGLTexture();
00492         sSansSerifHuge->mImageGLp->destroyGLTexture();
00493         sSansSerifSmall->mImageGLp->destroyGLTexture();
00494         sSansSerif->mImageGLp->destroyGLTexture();
00495         sSansSerifBig->mImageGLp->destroyGLTexture();
00496         sSansSerifBold->mImageGLp->destroyGLTexture();
00497 }
00498 
00499 
00500 
00501 LLFontGL &LLFontGL::operator=(const LLFontGL &source)
00502 {
00503         llerrs << "Not implemented" << llendl;
00504         return *this;
00505 }
00506 
00507 BOOL LLFontGL::loadFace(const LLString& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi)
00508 {
00509         if (!LLFont::loadFace(filename, point_size, vert_dpi, horz_dpi, 2, FALSE))
00510         {
00511                 return FALSE;
00512         }
00513         mImageGLp->createGLTexture(0, mRawImageGLp);
00514         mImageGLp->bind();
00515         mImageGLp->setMipFilterNearest(TRUE, TRUE);
00516         return TRUE;
00517 }
00518 
00519 BOOL LLFontGL::addChar(const llwchar wch)
00520 {
00521         if (!LLFont::addChar(wch))
00522         {
00523                 return FALSE;
00524         }
00525 
00526         stop_glerror();
00527         mImageGLp->setSubImage(mRawImageGLp, 0, 0, mImageGLp->getWidth(), mImageGLp->getHeight());
00528         mImageGLp->bind();
00529         mImageGLp->setMipFilterNearest(TRUE, TRUE);
00530         stop_glerror();
00531         return TRUE;
00532 }
00533 
00534 
00535 S32 LLFontGL::renderUTF8(const LLString &text, const S32 offset, 
00536                                          const F32 x, const F32 y,
00537                                          const LLColor4 &color,
00538                                          const HAlign halign, const VAlign valign,
00539                                          U8 style,
00540                                          const S32 max_chars, const S32 max_pixels,
00541                                          F32* right_x,
00542                                          BOOL use_ellipses) const
00543 {
00544         LLWString wstr = utf8str_to_wstring(text);
00545         return render(wstr, offset, x, y, color, halign, valign, style, max_chars, max_pixels, right_x, use_ellipses);
00546 }
00547 
00548 S32 LLFontGL::render(const LLWString &wstr, 
00549                                          const S32 begin_offset,
00550                                          const F32 x, const F32 y,
00551                                          const LLColor4 &color,
00552                                          const HAlign halign, const VAlign valign,
00553                                          U8 style,
00554                                          const S32 max_chars, S32 max_pixels,
00555                                          F32* right_x,
00556                                          BOOL use_embedded,
00557                                          BOOL use_ellipses) const
00558 {
00559         LLGLEnable texture_2d(GL_TEXTURE_2D);
00560         
00561         if (wstr.empty())
00562         {
00563                 return 0;
00564         } 
00565 
00566         S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);
00567 
00568         // HACK for better bolding
00569         if (style & BOLD)
00570         {
00571                 if (this == LLFontGL::sSansSerif)
00572                 {
00573                         return LLFontGL::sSansSerifBold->render(
00574                                 wstr, begin_offset,
00575                                 x, y,
00576                                 color,
00577                                 halign, valign, 
00578                                 (style & ~BOLD),
00579                                 max_chars, max_pixels,
00580                                 right_x, use_embedded);
00581                 }
00582         }
00583 
00584         F32 drop_shadow_strength = 0.f;
00585         if (style & (DROP_SHADOW | DROP_SHADOW_SOFT))
00586         {
00587                 F32 luminance;
00588                 color.calcHSL(NULL, NULL, &luminance);
00589                 drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
00590                 if (luminance < 0.35f)
00591                 {
00592                         style = style & ~(DROP_SHADOW | DROP_SHADOW_SOFT);
00593                 }
00594         }
00595 
00596         glPushMatrix();
00597         glLoadIdentity();
00598         glTranslatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
00599         //glScalef(sScaleX, sScaleY, 1.0f);
00600         
00601         // avoid half pixels
00602         // RN: if we're going to this trouble, might as well snap to nearest pixel all the time
00603         // but the plan is to get rid of this so that fonts "just work"
00604         //F32 half_pixel_distance = llabs(fmodf(sCurOrigin.mX * sScaleX, 1.f) - 0.5f);
00605         //if (half_pixel_distance < PIXEL_BORDER_THRESHOLD)
00606         //{
00607                 glTranslatef(PIXEL_CORRECTION_DISTANCE*sScaleX, 0.f, 0.f);
00608         //}
00609 
00610         // this code would just snap to pixel grid, although it seems to introduce more jitter
00611         //F32 pixel_offset_x = llround(sCurOrigin.mX * sScaleX) - (sCurOrigin.mX * sScaleX);
00612         //F32 pixel_offset_y = llround(sCurOrigin.mY * sScaleY) - (sCurOrigin.mY * sScaleY);
00613         //glTranslatef(-pixel_offset_x, -pixel_offset_y, 0.f);
00614 
00615         // scale back to native pixel size
00616         //glScalef(1.f / sScaleX, 1.f / sScaleY, 1.f);
00617         //glScaled(1.0 / (F64) sScaleX, 1.0 / (F64) sScaleY, 1.0f);
00618         LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS);
00619 
00620         glColor4fv( color.mV );
00621 
00622         S32 chars_drawn = 0;
00623         S32 i;
00624         S32 length;
00625 
00626         if (-1 == max_chars)
00627         {
00628                 length = (S32)wstr.length() - begin_offset;
00629         }
00630         else
00631         {
00632                 length = llmin((S32)wstr.length() - begin_offset, max_chars );
00633         }
00634 
00635         F32 cur_x, cur_y, cur_render_x, cur_render_y;
00636 
00637         // Bind the font texture
00638         
00639         mImageGLp->bind(0);
00640         
00641         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Not guaranteed to be set correctly
00642         
00643         cur_x = ((F32)x * sScaleX);
00644         cur_y = ((F32)y * sScaleY);
00645 
00646         // Offset y by vertical alignment.
00647         switch (valign)
00648         {
00649         case TOP:
00650                 cur_y -= mAscender;
00651                 break;
00652         case BOTTOM:
00653                 cur_y += mDescender;
00654                 break;
00655         case VCENTER:
00656                 cur_y -= ((mAscender - mDescender)/2.f);
00657                 break;
00658         case BASELINE:
00659                 // Baseline, do nothing.
00660                 break;
00661         default:
00662                 break;
00663         }
00664 
00665         switch (halign)
00666         {
00667         case LEFT:
00668                 break;
00669         case RIGHT:
00670                 cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX));
00671                 break;
00672         case HCENTER:
00673             cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX)) / 2;
00674                 break;
00675         default:
00676                 break;
00677         }
00678 
00679         // Round properly.
00680         //cur_render_y = (F32)llfloor(cur_y/sScaleY + 0.5f)*sScaleY;
00681         //cur_render_x = (F32)llfloor(cur_x/sScaleX + 0.5f)*sScaleX;
00682         
00683         cur_render_y = cur_y;
00684         cur_render_x = cur_x;
00685 
00686         F32 start_x = cur_x;
00687 
00688         F32 inv_width = 1.f / mImageGLp->getWidth();
00689         F32 inv_height = 1.f / mImageGLp->getHeight();
00690 
00691         const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;
00692 
00693 
00694         BOOL draw_ellipses = FALSE;
00695         if (use_ellipses && halign == LEFT)
00696         {
00697                 // check for too long of a string
00698                 if (getWidthF32(wstr.c_str(), 0, max_chars) * sScaleX > scaled_max_pixels)
00699                 {
00700                         // use four dots for ellipsis width to generate padding
00701                         const LLWString dots(utf8str_to_wstring(LLString("....")));
00702                         scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
00703                         draw_ellipses = TRUE;
00704                 }
00705         }
00706 
00707 
00708         for (i = begin_offset; i < begin_offset + length; i++)
00709         {
00710                 llwchar wch = wstr[i];
00711 
00712                 // Handle embedded characters first, if they're enabled.
00713                 // Embedded characters are a hack for notecards
00714                 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
00715                 if (ext_data)
00716                 {
00717                         LLImageGL* ext_image = ext_data->mImage;
00718                         const LLWString& label = ext_data->mLabel;
00719 
00720                         F32 ext_height = (F32)ext_image->getHeight() * sScaleY;
00721 
00722                         F32 ext_width = (F32)ext_image->getWidth() * sScaleX;
00723                         F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width;
00724 
00725                         if (!label.empty())
00726                         {
00727                                 ext_advance += (EXT_X_BEARING + gExtCharFont->getWidthF32( label.c_str() )) * sScaleX;
00728                         }
00729 
00730                         if (start_x + scaled_max_pixels < cur_x + ext_advance)
00731                         {
00732                                 // Not enough room for this character.
00733                                 break;
00734                         }
00735 
00736                         ext_image->bind();
00737                         const F32 ext_x = cur_render_x + (EXT_X_BEARING * sScaleX);
00738                         const F32 ext_y = cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight);
00739 
00740                         LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
00741                         LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);
00742                         drawGlyph(screen_rect, uv_rect, LLColor4::white, style, drop_shadow_strength);
00743 
00744                         if (!label.empty())
00745                         {
00746                                 glPushMatrix();
00747                                 //glLoadIdentity();
00748                                 //glTranslatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
00749                                 //glScalef(sScaleX, sScaleY, 1.f);
00750                                 gExtCharFont->render(label, 0,
00751                                                                          /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX), 
00752                                                                          /*llfloor*/(cur_y / sScaleY),
00753                                                                          color,
00754                                                                          halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
00755                                                                          TRUE );
00756                                 glPopMatrix();
00757                         }
00758 
00759                         glColor4fv(color.mV);
00760 
00761                         chars_drawn++;
00762                         cur_x += ext_advance;
00763                         if (((i + 1) < length) && wstr[i+1])
00764                         {
00765                                 cur_x += EXT_KERNING * sScaleX;
00766                         }
00767                         cur_render_x = cur_x;
00768 
00769                         // Bind the font texture
00770                         mImageGLp->bind();
00771                 }
00772                 else
00773                 {
00774                         if (!hasGlyph(wch))
00775                         {
00776                                 (const_cast<LLFontGL*>(this))->addChar(wch);
00777                         }
00778 
00779                         const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
00780                         if (!fgi)
00781                         {
00782                                 llerrs << "Missing Glyph Info" << llendl;
00783                                 break;
00784                         }
00785                         if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
00786                         {
00787                                 // Not enough room for this character.
00788                                 break;
00789                         }
00790 
00791                         // Draw the text at the appropriate location
00792                         //Specify vertices and texture coordinates
00793                         LLRectf uv_rect((fgi->mXBitmapOffset - PAD_AMT) * inv_width,
00794                                                         (fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height,
00795                                                         (fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width,
00796                                                         (fgi->mYBitmapOffset - PAD_AMT) * inv_height);
00797                         LLRectf screen_rect(cur_render_x + (F32)fgi->mXBearing - PAD_AMT,
00798                                                                 cur_render_y + (F32)fgi->mYBearing + PAD_AMT,
00799                                                                 cur_render_x + (F32)fgi->mXBearing + (F32)fgi->mWidth + PAD_AMT,
00800                                                                 cur_render_y + (F32)fgi->mYBearing - (F32)fgi->mHeight - PAD_AMT);
00801 
00802                         drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength);
00803 
00804                         chars_drawn++;
00805                         cur_x += fgi->mXAdvance;
00806                         cur_y += fgi->mYAdvance;
00807 
00808                         llwchar next_char = wstr[i+1];
00809                         if (next_char && (next_char < LAST_CHARACTER))
00810                         {
00811                                 // Kern this puppy.
00812                                 if (!hasGlyph(next_char))
00813                                 {
00814                                         (const_cast<LLFontGL*>(this))->addChar(next_char);
00815                                 }
00816                                 cur_x += getXKerning(wch, next_char);
00817                         }
00818 
00819                         // Round after kerning.
00820                         // Must do this to cur_x, not just to cur_render_x, otherwise you
00821                         // will squish sub-pixel kerned characters too close together.
00822                         // For example, "CCCCC" looks bad.
00823                         cur_x = (F32)llfloor(cur_x + 0.5f);
00824                         //cur_y = (F32)llfloor(cur_y + 0.5f);
00825 
00826                         cur_render_x = cur_x;
00827                         cur_render_y = cur_y;
00828                 }
00829         }
00830 
00831         if (right_x)
00832         {
00833                 *right_x = cur_x / sScaleX;
00834         }
00835 
00836         if (style & UNDERLINE)
00837         {
00838                 LLGLSNoTexture no_texture;
00839                 glBegin(GL_LINES);
00840                 glVertex2f(start_x, cur_y - (mDescender));
00841                 glVertex2f(cur_x, cur_y - (mDescender));
00842                 glEnd();
00843         }
00844 
00845         // *FIX: get this working in all alignment cases, etc.
00846         if (draw_ellipses)
00847         {
00848                 // recursively render ellipses at end of string
00849                 // we've already reserved enough room
00850                 glPushMatrix();
00851                 //glLoadIdentity();
00852                 //glTranslatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
00853                 //glScalef(sScaleX, sScaleY, 1.f);
00854                 renderUTF8("...", 
00855                                 0,
00856                                 cur_x / sScaleX, (F32)y,
00857                                 color,
00858                                 LEFT, valign,
00859                                 style,
00860                                 S32_MAX, max_pixels,
00861                                 right_x,
00862                                 FALSE); 
00863                 glPopMatrix();
00864         }
00865 
00866         glPopMatrix();
00867 
00868         return chars_drawn;
00869 }
00870 
00871  
00872 LLImageGL *LLFontGL::getImageGL() const
00873 {
00874         return mImageGLp;
00875 }
00876 
00877 S32 LLFontGL::getWidth(const LLString& utf8text) const
00878 {
00879         LLWString wtext = utf8str_to_wstring(utf8text);
00880         return getWidth(wtext.c_str(), 0, S32_MAX);
00881 }
00882 
00883 S32 LLFontGL::getWidth(const llwchar* wchars) const
00884 {
00885         return getWidth(wchars, 0, S32_MAX);
00886 }
00887 
00888 S32 LLFontGL::getWidth(const LLString& utf8text, const S32 begin_offset, const S32 max_chars) const
00889 {
00890         LLWString wtext = utf8str_to_wstring(utf8text);
00891         return getWidth(wtext.c_str(), begin_offset, max_chars);
00892 }
00893 
00894 S32 LLFontGL::getWidth(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const
00895 {
00896         F32 width = getWidthF32(wchars, begin_offset, max_chars, use_embedded);
00897         return llround(width);
00898 }
00899 
00900 F32 LLFontGL::getWidthF32(const LLString& utf8text) const
00901 {
00902         LLWString wtext = utf8str_to_wstring(utf8text);
00903         return getWidthF32(wtext.c_str(), 0, S32_MAX);
00904 }
00905 
00906 F32 LLFontGL::getWidthF32(const llwchar* wchars) const
00907 {
00908         return getWidthF32(wchars, 0, S32_MAX);
00909 }
00910 
00911 F32 LLFontGL::getWidthF32(const LLString& utf8text, const S32 begin_offset, const S32 max_chars ) const
00912 {
00913         LLWString wtext = utf8str_to_wstring(utf8text);
00914         return getWidthF32(wtext.c_str(), begin_offset, max_chars);
00915 }
00916 
00917 F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const
00918 {
00919         const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;
00920 
00921         F32 cur_x = 0;
00922         const S32 max_index = begin_offset + max_chars;
00923         for (S32 i = begin_offset; i < max_index; i++)
00924         {
00925                 const llwchar wch = wchars[i];
00926                 if (wch == 0)
00927                 {
00928                         break; // done
00929                 }
00930                 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
00931                 if (ext_data)
00932                 {
00933                         // Handle crappy embedded hack
00934                         cur_x += getEmbeddedCharAdvance(ext_data);
00935 
00936                         if( ((i+1) < max_chars) && (i+1 < max_index))
00937                         {
00938                                 cur_x += EXT_KERNING * sScaleX;
00939                         }
00940                 }
00941                 else
00942                 {
00943                         cur_x += getXAdvance(wch);
00944                         llwchar next_char = wchars[i+1];
00945 
00946                         if (((i + 1) < max_chars) 
00947                                 && next_char 
00948                                 && (next_char < LAST_CHARACTER))
00949                         {
00950                                 // Kern this puppy.
00951                                 cur_x += getXKerning(wch, next_char);
00952                         }
00953                 }
00954                 // Round after kerning.
00955                 cur_x = (F32)llfloor(cur_x + 0.5f);
00956         }
00957 
00958         return cur_x / sScaleX;
00959 }
00960 
00961 
00962 
00963 // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
00964 S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars,
00965                                                            BOOL end_on_word_boundary, const BOOL use_embedded,
00966                                                            F32* drawn_pixels) const
00967 {
00968         if (!wchars || !wchars[0] || max_chars == 0)
00969         {
00970                 return 0;
00971         }
00972         
00973         llassert(max_pixels >= 0.f);
00974         llassert(max_chars >= 0);
00975         
00976         BOOL clip = FALSE;
00977         F32 cur_x = 0;
00978         F32 drawn_x = 0;
00979 
00980         S32 start_of_last_word = 0;
00981         BOOL in_word = FALSE;
00982 
00983         F32 scaled_max_pixels = (F32)llceil(max_pixels * sScaleX);
00984 
00985         S32 i;
00986         for (i=0; (i < max_chars); i++)
00987         {
00988                 llwchar wch = wchars[i];
00989 
00990                 if(wch == 0)
00991                 {
00992                         // Null terminator.  We're done.
00993                         break;
00994                 }
00995                         
00996                 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
00997                 if (ext_data)
00998                 {
00999                         if (in_word)
01000                         {
01001                                 in_word = FALSE;
01002                         }
01003                         else
01004                         {
01005                                 start_of_last_word = i;
01006                         }
01007                         cur_x += getEmbeddedCharAdvance(ext_data);
01008                         
01009                         if (scaled_max_pixels < cur_x)
01010                         {
01011                                 clip = TRUE;
01012                                 break;
01013                         }
01014                         
01015                         if (((i+1) < max_chars) && wchars[i+1])
01016                         {
01017                                 cur_x += EXT_KERNING * sScaleX;
01018                         }
01019 
01020                         if( scaled_max_pixels < cur_x )
01021                         {
01022                                 clip = TRUE;
01023                                 break;
01024                         }
01025                 }
01026                 else
01027                 {
01028                         if (in_word)
01029                         {
01030                                 if (iswspace(wch))
01031                                 {
01032                                         in_word = FALSE;
01033                                 }
01034                         }
01035                         else
01036                         {
01037                                 start_of_last_word = i;
01038                                 if (!iswspace(wch))
01039                                 {
01040                                         in_word = TRUE;
01041                                 }
01042                         }
01043 
01044                         cur_x += getXAdvance(wch);
01045                         
01046                         if (scaled_max_pixels < cur_x)
01047                         {
01048                                 clip = TRUE;
01049                                 break;
01050                         }
01051 
01052                         if (((i+1) < max_chars) && wchars[i+1])
01053                         {
01054                                 // Kern this puppy.
01055                                 cur_x += getXKerning(wch, wchars[i+1]);
01056                         }
01057                 }
01058                 // Round after kerning.
01059                 cur_x = (F32)llfloor(cur_x + 0.5f);
01060                 drawn_x = cur_x;
01061         }
01062 
01063         if( clip && end_on_word_boundary && (start_of_last_word != 0) )
01064         {
01065                 i = start_of_last_word;
01066         }
01067         if (drawn_pixels)
01068         {
01069                 *drawn_pixels = drawn_x;
01070         }
01071         return i;
01072 }
01073 
01074 
01075 S32     LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const
01076 {
01077         if (!wchars || !wchars[0] || max_chars == 0)
01078         {
01079                 return 0;
01080         }
01081         
01082         F32 total_width = 0.0;
01083         S32 drawable_chars = 0;
01084 
01085         F32 scaled_max_pixels = max_pixels * sScaleX;
01086 
01087         S32 start = llmin(start_pos, text_len - 1);
01088         for (S32 i = start; i >= 0; i--)
01089         {
01090                 llwchar wch = wchars[i];
01091 
01092                 const embedded_data_t* ext_data = getEmbeddedCharData(wch);
01093                 if (ext_data)
01094                 {
01095                         F32 char_width = getEmbeddedCharAdvance(ext_data);
01096 
01097                         if( scaled_max_pixels < (total_width + char_width) )
01098                         {
01099                                 break;
01100                         }
01101 
01102                         total_width += char_width;
01103 
01104                         drawable_chars++;
01105                         if( max_chars >= 0 && drawable_chars >= max_chars )
01106                         {
01107                                 break;
01108                         }
01109 
01110                         if ( i > 0 )
01111                         {
01112                                 total_width += EXT_KERNING * sScaleX;
01113                         }
01114 
01115                         // Round after kerning.
01116                         total_width = (F32)llfloor(total_width + 0.5f);
01117                 }
01118                 else
01119                 {
01120                         F32 char_width = getXAdvance(wch);
01121                         if( scaled_max_pixels < (total_width + char_width) )
01122                         {
01123                                 break;
01124                         }
01125 
01126                         total_width += char_width;
01127 
01128                         drawable_chars++;
01129                         if( max_chars >= 0 && drawable_chars >= max_chars )
01130                         {
01131                                 break;
01132                         }
01133 
01134                         if ( i > 0 )
01135                         {
01136                                 // Kerning
01137                                 total_width += getXKerning(wchars[i-1], wch);
01138                         }
01139 
01140                         // Round after kerning.
01141                         total_width = (F32)llfloor(total_width + 0.5f);
01142                 }
01143         }
01144 
01145         return text_len - drawable_chars;
01146 }
01147 
01148 
01149 S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const
01150 {
01151         if (!wchars || !wchars[0] || max_chars == 0)
01152         {
01153                 return 0;
01154         }
01155         
01156         F32 cur_x = 0;
01157         S32 pos = 0;
01158 
01159         target_x *= sScaleX;
01160 
01161         // max_chars is S32_MAX by default, so make sure we don't get overflow
01162         const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars);
01163 
01164         F32 scaled_max_pixels = max_pixels * sScaleX;
01165 
01166         for (S32 i = begin_offset; (i < max_index); i++)
01167         {
01168                 llwchar wch = wchars[i];
01169                 if (!wch)
01170                 {
01171                         break; // done
01172                 }
01173                 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
01174                 if (ext_data)
01175                 {
01176                         F32 ext_advance = getEmbeddedCharAdvance(ext_data);
01177 
01178                         if (round)
01179                         {
01180                                 // Note: if the mouse is on the left half of the character, the pick is to the character's left
01181                                 // If it's on the right half, the pick is to the right.
01182                                 if (target_x  < cur_x + ext_advance/2)
01183                                 {
01184                                         break;
01185                                 }
01186                         }
01187                         else
01188                         {
01189                                 if (target_x  < cur_x + ext_advance)
01190                                 {
01191                                         break;
01192                                 }
01193                         }
01194 
01195                         if (scaled_max_pixels < cur_x + ext_advance)
01196                         {
01197                                 break;
01198                         }
01199 
01200                         pos++;
01201                         cur_x += ext_advance;
01202 
01203                         if (((i + 1) < max_index)
01204                                 && (wchars[(i + 1)]))
01205                         {
01206                                 cur_x += EXT_KERNING * sScaleX;
01207                         }
01208                         // Round after kerning.
01209                         cur_x = (F32)llfloor(cur_x + 0.5f);
01210                 }
01211                 else
01212                 {
01213                         F32 char_width = getXAdvance(wch);
01214 
01215                         if (round)
01216                         {
01217                                 // Note: if the mouse is on the left half of the character, the pick is to the character's left
01218                                 // If it's on the right half, the pick is to the right.
01219                                 if (target_x  < cur_x + char_width*0.5f)
01220                                 {
01221                                         break;
01222                                 }
01223                         }
01224                         else if (target_x  < cur_x + char_width)
01225                         {
01226                                 break;
01227                         }
01228 
01229                         if (scaled_max_pixels < cur_x + char_width)
01230                         {
01231                                 break;
01232                         }
01233 
01234                         pos++;
01235                         cur_x += char_width;
01236 
01237                         if (((i + 1) < max_index)
01238                                 && (wchars[(i + 1)]))
01239                         {
01240                                 llwchar next_char = wchars[i + 1];
01241                                 // Kern this puppy.
01242                                 cur_x += getXKerning(wch, next_char);
01243                         }
01244 
01245                         // Round after kerning.
01246                         cur_x = (F32)llfloor(cur_x + 0.5f);
01247                 }
01248         }
01249 
01250         return pos;
01251 }
01252 
01253 
01254 const LLFontGL::embedded_data_t* LLFontGL::getEmbeddedCharData(const llwchar wch) const
01255 {
01256         // Handle crappy embedded hack
01257         embedded_map_t::const_iterator iter = mEmbeddedChars.find(wch);
01258         if (iter != mEmbeddedChars.end())
01259         {
01260                 return iter->second;
01261         }
01262         return NULL;
01263 }
01264 
01265 
01266 F32 LLFontGL::getEmbeddedCharAdvance(const embedded_data_t* ext_data) const
01267 {
01268         const LLWString& label = ext_data->mLabel;
01269         LLImageGL* ext_image = ext_data->mImage;
01270 
01271         F32 ext_width = (F32)ext_image->getWidth();
01272         if( !label.empty() )
01273         {
01274                 ext_width += (EXT_X_BEARING + gExtCharFont->getWidthF32(label.c_str())) * sScaleX;
01275         }
01276 
01277         return (EXT_X_BEARING * sScaleX) + ext_width;
01278 }
01279 
01280 
01281 void LLFontGL::clearEmbeddedChars()
01282 {
01283         for_each(mEmbeddedChars.begin(), mEmbeddedChars.end(), DeletePairedPointer());
01284         mEmbeddedChars.clear();
01285 }
01286 
01287 void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLString& label )
01288 {
01289         LLWString wlabel = utf8str_to_wstring(label);
01290         addEmbeddedChar(wc, image, wlabel);
01291 }
01292 
01293 void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& wlabel )
01294 {
01295         embedded_data_t* ext_data = new embedded_data_t(image, wlabel);
01296         mEmbeddedChars[wc] = ext_data;
01297 }
01298 
01299 void LLFontGL::removeEmbeddedChar( llwchar wc )
01300 {
01301         embedded_map_t::iterator iter = mEmbeddedChars.find(wc);
01302         if (iter != mEmbeddedChars.end())
01303         {
01304                 delete iter->second;
01305                 mEmbeddedChars.erase(wc);
01306         }
01307 }
01308 
01309 
01310 void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const
01311 {
01312         glTexCoord2f(uv_rect.mRight, uv_rect.mTop);
01313         glVertex2f(llfont_round_x(screen_rect.mRight), 
01314                                 llfont_round_y(screen_rect.mTop));
01315 
01316         glTexCoord2f(uv_rect.mLeft, uv_rect.mTop);
01317         glVertex2f(llfont_round_x(screen_rect.mLeft), 
01318                                 llfont_round_y(screen_rect.mTop));
01319 
01320         glTexCoord2f(uv_rect.mLeft, uv_rect.mBottom);
01321         glVertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), 
01322                                 llfont_round_y(screen_rect.mBottom));
01323 
01324         glTexCoord2f(uv_rect.mRight, uv_rect.mBottom);
01325         glVertex2f(llfont_round_x(screen_rect.mRight + slant_amt), 
01326                                 llfont_round_y(screen_rect.mBottom));
01327 }
01328 
01329 void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, F32 drop_shadow_strength) const
01330 {
01331         F32 slant_offset;
01332         slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f);
01333 
01334         glBegin(GL_QUADS);
01335         {
01336                 //FIXME: bold and drop shadow are mutually exclusive only for convenience
01337                 //Allow both when we need them.
01338                 if (style & BOLD)
01339                 {
01340                         glColor4fv(color.mV);
01341                         for (S32 pass = 0; pass < 2; pass++)
01342                         {
01343                                 LLRectf screen_rect_offset = screen_rect;
01344 
01345                                 screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
01346                                 renderQuad(screen_rect_offset, uv_rect, slant_offset);
01347                         }
01348                 }
01349                 else if (style & DROP_SHADOW_SOFT)
01350                 {
01351                         LLColor4 shadow_color = LLFontGL::sShadowColor;
01352                         shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH;
01353                         glColor4fv(shadow_color.mV);
01354                         for (S32 pass = 0; pass < 5; pass++)
01355                         {
01356                                 LLRectf screen_rect_offset = screen_rect;
01357 
01358                                 switch(pass)
01359                                 {
01360                                 case 0:
01361                                         screen_rect_offset.translate(-1.f, -1.f);
01362                                         break;
01363                                 case 1:
01364                                         screen_rect_offset.translate(1.f, -1.f);
01365                                         break;
01366                                 case 2:
01367                                         screen_rect_offset.translate(1.f, 1.f);
01368                                         break;
01369                                 case 3:
01370                                         screen_rect_offset.translate(-1.f, 1.f);
01371                                         break;
01372                                 case 4:
01373                                         screen_rect_offset.translate(0, -2.f);
01374                                         break;
01375                                 }
01376                         
01377                                 renderQuad(screen_rect_offset, uv_rect, slant_offset);
01378                         }
01379                         glColor4fv(color.mV);
01380                         renderQuad(screen_rect, uv_rect, slant_offset);
01381                 }
01382                 else if (style & DROP_SHADOW)
01383                 {
01384                         LLColor4 shadow_color = LLFontGL::sShadowColor;
01385                         shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
01386                         glColor4fv(shadow_color.mV);
01387                         LLRectf screen_rect_shadow = screen_rect;
01388                         screen_rect_shadow.translate(1.f, -1.f);
01389                         renderQuad(screen_rect_shadow, uv_rect, slant_offset);
01390                         glColor4fv(color.mV);
01391                         renderQuad(screen_rect, uv_rect, slant_offset);
01392                 }
01393                 else // normal rendering
01394                 {
01395                         glColor4fv(color.mV);
01396                         renderQuad(screen_rect, uv_rect, slant_offset);
01397                 }
01398 
01399         }
01400         glEnd();
01401 }
01402 
01403 // static
01404 LLString LLFontGL::nameFromFont(const LLFontGL* fontp)
01405 {
01406         if (fontp == sSansSerifHuge)
01407         {
01408                 return LLString("SansSerifHuge");
01409         }
01410         else if (fontp == sSansSerifSmall)
01411         {
01412                 return LLString("SansSerifSmall");
01413         }
01414         else if (fontp == sSansSerif)
01415         {
01416                 return LLString("SansSerif");
01417         }
01418         else if (fontp == sSansSerifBig)
01419         {
01420                 return LLString("SansSerifBig");
01421         }
01422         else if (fontp == sSansSerifBold)
01423         {
01424                 return LLString("SansSerifBold");
01425         }
01426         else if (fontp == sMonospace)
01427         {
01428                 return LLString("Monospace");
01429         }
01430         else
01431         {
01432                 return LLString();
01433         }
01434 }
01435 
01436 // static
01437 LLFontGL* LLFontGL::fontFromName(const LLString& font_name)
01438 {
01439         LLFontGL* gl_font = NULL;
01440         if (font_name == "SansSerifHuge")
01441         {
01442                 gl_font = LLFontGL::sSansSerifHuge;
01443         }
01444         else if (font_name == "SansSerifSmall")
01445         {
01446                 gl_font = LLFontGL::sSansSerifSmall;
01447         }
01448         else if (font_name == "SansSerif")
01449         {
01450                 gl_font = LLFontGL::sSansSerif;
01451         }
01452         else if (font_name == "SansSerifBig")
01453         {
01454                 gl_font = LLFontGL::sSansSerifBig;
01455         }
01456         else if (font_name == "SansSerifBold")
01457         {
01458                 gl_font = LLFontGL::sSansSerifBold;
01459         }
01460         else if (font_name == "Monospace")
01461         {
01462                 gl_font = LLFontGL::sMonospace;
01463         }
01464         return gl_font;
01465 }
01466 
01467 // static
01468 LLString LLFontGL::nameFromHAlign(LLFontGL::HAlign align)
01469 {
01470         if (align == LEFT)                      return LLString("left");
01471         else if (align == RIGHT)        return LLString("right");
01472         else if (align == HCENTER)      return LLString("center");
01473         else return LLString();
01474 }
01475 
01476 // static
01477 LLFontGL::HAlign LLFontGL::hAlignFromName(const LLString& name)
01478 {
01479         LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
01480         if (name == "left")
01481         {
01482                 gl_hfont_align = LLFontGL::LEFT;
01483         }
01484         else if (name == "right")
01485         {
01486                 gl_hfont_align = LLFontGL::RIGHT;
01487         }
01488         else if (name == "center")
01489         {
01490                 gl_hfont_align = LLFontGL::HCENTER;
01491         }
01492         //else leave left
01493         return gl_hfont_align;
01494 }
01495 
01496 // static
01497 LLString LLFontGL::nameFromVAlign(LLFontGL::VAlign align)
01498 {
01499         if (align == TOP)                       return LLString("top");
01500         else if (align == VCENTER)      return LLString("center");
01501         else if (align == BASELINE)     return LLString("baseline");
01502         else if (align == BOTTOM)       return LLString("bottom");
01503         else return LLString();
01504 }
01505 
01506 // static
01507 LLFontGL::VAlign LLFontGL::vAlignFromName(const LLString& name)
01508 {
01509         LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
01510         if (name == "top")
01511         {
01512                 gl_vfont_align = LLFontGL::TOP;
01513         }
01514         else if (name == "center")
01515         {
01516                 gl_vfont_align = LLFontGL::VCENTER;
01517         }
01518         else if (name == "baseline")
01519         {
01520                 gl_vfont_align = LLFontGL::BASELINE;
01521         }
01522         else if (name == "bottom")
01523         {
01524                 gl_vfont_align = LLFontGL::BOTTOM;
01525         }
01526         //else leave baseline
01527         return gl_vfont_align;
01528 }

Generated on Thu Jul 1 06:08:38 2010 for Second Life Viewer by  doxygen 1.4.7