llfontgl.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:28k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llfontgl.cpp
  3.  * @brief Wrapper around FreeType
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #include "llfontgl.h"
  34. // Linden library includes
  35. #include "llfontfreetype.h"
  36. #include "llfontbitmapcache.h"
  37. #include "llfontregistry.h"
  38. #include "llgl.h"
  39. #include "llimagegl.h"
  40. #include "llrender.h"
  41. #include "llstl.h"
  42. #include "v4color.h"
  43. #include "lltexture.h"
  44. #include "lldir.h"
  45. // Third party library includes
  46. #include <boost/tokenizer.hpp>
  47. const S32 BOLD_OFFSET = 1;
  48. // static class members
  49. F32 LLFontGL::sVertDPI = 96.f;
  50. F32 LLFontGL::sHorizDPI = 96.f;
  51. F32 LLFontGL::sScaleX = 1.f;
  52. F32 LLFontGL::sScaleY = 1.f;
  53. BOOL LLFontGL::sDisplayFont = TRUE ;
  54. std::string LLFontGL::sAppDir;
  55. LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f);
  56. LLFontRegistry* LLFontGL::sFontRegistry = NULL;
  57. LLCoordFont LLFontGL::sCurOrigin;
  58. std::vector<LLCoordFont> LLFontGL::sOriginStack;
  59. const F32 EXT_X_BEARING = 1.f;
  60. const F32 EXT_Y_BEARING = 0.f;
  61. const F32 EXT_KERNING = 1.f;
  62. const F32 PIXEL_BORDER_THRESHOLD = 0.0001f;
  63. const F32 PIXEL_CORRECTION_DISTANCE = 0.01f;
  64. const F32 PAD_UVY = 0.5f; // half of vertical padding between glyphs in the glyph texture
  65. const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f;
  66. static F32 llfont_round_x(F32 x)
  67. {
  68. //return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX;
  69. //return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY;
  70. return x;
  71. }
  72. static F32 llfont_round_y(F32 y)
  73. {
  74. //return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY;
  75. //return llfloor(y+0.5f);
  76. return y;
  77. }
  78. LLFontGL::LLFontGL()
  79. {
  80. }
  81. LLFontGL::~LLFontGL()
  82. {
  83. }
  84. void LLFontGL::reset()
  85. {
  86. mFontFreetype->reset(sVertDPI, sHorizDPI);
  87. }
  88. void LLFontGL::destroyGL()
  89. {
  90. mFontFreetype->destroyGL();
  91. }
  92. BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback)
  93. {
  94. if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
  95. {
  96. mFontFreetype = new LLFontFreetype;
  97. }
  98. return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback);
  99. }
  100. static LLFastTimer::DeclareTimer FTM_RENDER_FONTS("Fonts");
  101. S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
  102.  ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
  103. {
  104. if(!sDisplayFont) //do not display texts
  105. {
  106. return wstr.length() ;
  107. }
  108. if (wstr.empty())
  109. {
  110. return 0;
  111. gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
  112. S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);
  113. // determine which style flags need to be added programmatically by stripping off the
  114. // style bits that are drawn by the underlying Freetype font
  115. U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle();
  116. F32 drop_shadow_strength = 0.f;
  117. if (shadow != NO_SHADOW)
  118. {
  119. F32 luminance;
  120. color.calcHSL(NULL, NULL, &luminance);
  121. drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
  122. if (luminance < 0.35f)
  123. {
  124. shadow = NO_SHADOW;
  125. }
  126. }
  127. gGL.pushMatrix();
  128. glLoadIdentity();
  129. gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
  130. // this code snaps the text origin to a pixel grid to start with
  131. F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
  132. F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
  133. gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f);
  134. LLFastTimer t(FTM_RENDER_FONTS);
  135. gGL.color4fv( color.mV );
  136. S32 chars_drawn = 0;
  137. S32 i;
  138. S32 length;
  139. if (-1 == max_chars)
  140. {
  141. length = (S32)wstr.length() - begin_offset;
  142. }
  143. else
  144. {
  145. length = llmin((S32)wstr.length() - begin_offset, max_chars );
  146. }
  147. F32 cur_x, cur_y, cur_render_x, cur_render_y;
  148.   // Not guaranteed to be set correctly
  149. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  150. cur_x = ((F32)x * sScaleX);
  151. cur_y = ((F32)y * sScaleY);
  152. // Offset y by vertical alignment.
  153. switch (valign)
  154. {
  155. case TOP:
  156. cur_y -= mFontFreetype->getAscenderHeight();
  157. break;
  158. case BOTTOM:
  159. cur_y += mFontFreetype->getDescenderHeight();
  160. break;
  161. case VCENTER:
  162. cur_y -= (mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight()) / 2.f;
  163. break;
  164. case BASELINE:
  165. // Baseline, do nothing.
  166. break;
  167. default:
  168. break;
  169. }
  170. switch (halign)
  171. {
  172. case LEFT:
  173. break;
  174. case RIGHT:
  175.    cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX));
  176. break;
  177. case HCENTER:
  178.     cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2;
  179. break;
  180. default:
  181. break;
  182. }
  183. cur_render_y = cur_y;
  184. cur_render_x = cur_x;
  185. F32 start_x = llround(cur_x);
  186. const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();
  187. F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
  188. F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();
  189. const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
  190. BOOL draw_ellipses = FALSE;
  191. if (use_ellipses)
  192. {
  193. // check for too long of a string
  194. S32 string_width = llround(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX);
  195. if (string_width > scaled_max_pixels)
  196. {
  197. // use four dots for ellipsis width to generate padding
  198. const LLWString dots(utf8str_to_wstring(std::string("....")));
  199. scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
  200. draw_ellipses = TRUE;
  201. }
  202. }
  203. // Remember last-used texture to avoid unnecesssary bind calls.
  204. LLImageGL *last_bound_texture = NULL;
  205. const LLFontGlyphInfo* next_glyph = NULL;
  206. for (i = begin_offset; i < begin_offset + length; i++)
  207. {
  208. llwchar wch = wstr[i];
  209. const LLFontGlyphInfo* fgi = next_glyph;
  210. next_glyph = NULL;
  211. if(!fgi)
  212. {
  213. fgi = mFontFreetype->getGlyphInfo(wch);
  214. }
  215. if (!fgi)
  216. {
  217. llerrs << "Missing Glyph Info" << llendl;
  218. break;
  219. }
  220. // Per-glyph bitmap texture.
  221. LLImageGL *image_gl = mFontFreetype->getFontBitmapCache()->getImageGL(fgi->mBitmapNum);
  222. if (last_bound_texture != image_gl)
  223. {
  224. gGL.getTexUnit(0)->bind(image_gl);
  225. last_bound_texture = image_gl;
  226. }
  227. if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
  228. {
  229. // Not enough room for this character.
  230. break;
  231. }
  232. // Draw the text at the appropriate location
  233. //Specify vertices and texture coordinates
  234. LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width,
  235. (fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height,
  236. (fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
  237. (fgi->mYBitmapOffset - PAD_UVY) * inv_height);
  238. // snap glyph origin to whole screen pixel
  239. LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing),
  240.     llround(cur_render_y + (F32)fgi->mYBearing),
  241.     llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
  242.     llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
  243. drawGlyph(screen_rect, uv_rect, color, style_to_add, shadow, drop_shadow_strength);
  244. chars_drawn++;
  245. cur_x += fgi->mXAdvance;
  246. cur_y += fgi->mYAdvance;
  247. llwchar next_char = wstr[i+1];
  248. if (next_char && (next_char < LAST_CHARACTER))
  249. {
  250. // Kern this puppy.
  251. next_glyph = mFontFreetype->getGlyphInfo(next_char);
  252. cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
  253. }
  254. // Round after kerning.
  255. // Must do this to cur_x, not just to cur_render_x, otherwise you
  256. // will squish sub-pixel kerned characters too close together.
  257. // For example, "CCCCC" looks bad.
  258. cur_x = (F32)llround(cur_x);
  259. //cur_y = (F32)llround(cur_y);
  260. cur_render_x = cur_x;
  261. cur_render_y = cur_y;
  262. }
  263. if (right_x)
  264. {
  265. *right_x = cur_x / sScaleX;
  266. }
  267. if (style_to_add & UNDERLINE)
  268. {
  269. F32 descender = mFontFreetype->getDescenderHeight();
  270. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  271. gGL.begin(LLRender::LINES);
  272. gGL.vertex2f(start_x, cur_y - (descender));
  273. gGL.vertex2f(cur_x, cur_y - (descender));
  274. gGL.end();
  275. }
  276. if (draw_ellipses)
  277. {
  278. // recursively render ellipses at end of string
  279. // we've already reserved enough room
  280. gGL.pushMatrix();
  281. //glLoadIdentity();
  282. //gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
  283. //glScalef(sScaleX, sScaleY, 1.f);
  284. renderUTF8(std::string("..."), 
  285. 0,
  286. cur_x / sScaleX, (F32)y,
  287. color,
  288. LEFT, valign,
  289. style_to_add,
  290. shadow,
  291. S32_MAX, max_pixels,
  292. right_x,
  293. FALSE); 
  294. gGL.popMatrix();
  295. }
  296. gGL.popMatrix();
  297. return chars_drawn;
  298. }
  299. S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const
  300. {
  301. return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
  302. }
  303. S32 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
  304. {
  305. return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses);
  306. }
  307. S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const
  308. {
  309. return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
  310. }
  311. S32 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
  312. {
  313. return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE);
  314. }
  315. // font metrics - override for LLFontFreetype that returns units of virtual pixels
  316. F32 LLFontGL::getLineHeight() const
  317. return (F32)llround(mFontFreetype->getLineHeight() / sScaleY); 
  318. }
  319. F32 LLFontGL::getAscenderHeight() const
  320. return (F32)llround(mFontFreetype->getAscenderHeight() / sScaleY); 
  321. }
  322. F32 LLFontGL::getDescenderHeight() const
  323. return (F32)llround(mFontFreetype->getDescenderHeight() / sScaleY); 
  324. }
  325. S32 LLFontGL::getWidth(const std::string& utf8text) const
  326. {
  327. LLWString wtext = utf8str_to_wstring(utf8text);
  328. return getWidth(wtext.c_str(), 0, S32_MAX);
  329. }
  330. S32 LLFontGL::getWidth(const llwchar* wchars) const
  331. {
  332. return getWidth(wchars, 0, S32_MAX);
  333. }
  334. S32 LLFontGL::getWidth(const std::string& utf8text, S32 begin_offset, S32 max_chars) const
  335. {
  336. LLWString wtext = utf8str_to_wstring(utf8text);
  337. return getWidth(wtext.c_str(), begin_offset, max_chars);
  338. }
  339. S32 LLFontGL::getWidth(const llwchar* wchars, S32 begin_offset, S32 max_chars) const
  340. {
  341. F32 width = getWidthF32(wchars, begin_offset, max_chars);
  342. return llround(width);
  343. }
  344. F32 LLFontGL::getWidthF32(const std::string& utf8text) const
  345. {
  346. LLWString wtext = utf8str_to_wstring(utf8text);
  347. return getWidthF32(wtext.c_str(), 0, S32_MAX);
  348. }
  349. F32 LLFontGL::getWidthF32(const llwchar* wchars) const
  350. {
  351. return getWidthF32(wchars, 0, S32_MAX);
  352. }
  353. F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max_chars ) const
  354. {
  355. LLWString wtext = utf8str_to_wstring(utf8text);
  356. return getWidthF32(wtext.c_str(), begin_offset, max_chars);
  357. }
  358. F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars) const
  359. {
  360. const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
  361. F32 cur_x = 0;
  362. const S32 max_index = begin_offset + max_chars;
  363. const LLFontGlyphInfo* next_glyph = NULL;
  364. F32 width_padding = 0.f;
  365. for (S32 i = begin_offset; i < max_index && wchars[i] != 0; i++)
  366. {
  367. llwchar wch = wchars[i];
  368. const LLFontGlyphInfo* fgi = next_glyph;
  369. next_glyph = NULL;
  370. if(!fgi)
  371. {
  372. fgi = mFontFreetype->getGlyphInfo(wch);
  373. }
  374. F32 advance = mFontFreetype->getXAdvance(fgi);
  375. // for the last character we want to measure the greater of its width and xadvance values
  376. // so keep track of the difference between these values for the each character we measure
  377. // so we can fix things up at the end
  378. width_padding = llmax( 0.f, // always use positive padding amount
  379. width_padding - advance, // previous padding left over after advance of current character
  380. (F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character
  381. cur_x += advance;
  382. llwchar next_char = wchars[i+1];
  383. if (((i + 1) < begin_offset + max_chars) 
  384. && next_char 
  385. && (next_char < LAST_CHARACTER))
  386. {
  387. // Kern this puppy.
  388. next_glyph = mFontFreetype->getGlyphInfo(next_char);
  389. cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
  390. }
  391. // Round after kerning.
  392. cur_x = (F32)llround(cur_x);
  393. }
  394. // add in extra pixels for last character's width past its xadvance
  395. cur_x += width_padding;
  396. return cur_x / sScaleX;
  397. }
  398. // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
  399. S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary) const
  400. {
  401. if (!wchars || !wchars[0] || max_chars == 0)
  402. {
  403. return 0;
  404. }
  405. llassert(max_pixels >= 0.f);
  406. llassert(max_chars >= 0);
  407. BOOL clip = FALSE;
  408. F32 cur_x = 0;
  409. F32 drawn_x = 0;
  410. S32 start_of_last_word = 0;
  411. BOOL in_word = FALSE;
  412. // avoid S32 overflow when max_pixels == S32_MAX by staying in floating point
  413. F32 scaled_max_pixels = ceil(max_pixels * sScaleX);
  414. F32 width_padding = 0.f;
  415. LLFontGlyphInfo* next_glyph = NULL;
  416. S32 i;
  417. for (i=0; (i < max_chars); i++)
  418. {
  419. llwchar wch = wchars[i];
  420. if(wch == 0)
  421. {
  422. // Null terminator.  We're done.
  423. break;
  424. }
  425. if (in_word)
  426. {
  427. if (iswspace(wch))
  428. {
  429. if(wch !=(0x00A0))
  430. {
  431. in_word = FALSE;
  432. }
  433. }
  434. if (iswindividual(wch))
  435. {
  436. if (iswpunct(wchars[i+1]))
  437. {
  438. in_word=TRUE;
  439. }
  440. else
  441. {
  442. in_word=FALSE;
  443. start_of_last_word = i;
  444. }
  445. }
  446. }
  447. else
  448. {
  449. start_of_last_word = i;
  450. if (!iswspace(wch)||!iswindividual(wch))
  451. {
  452. in_word = TRUE;
  453. }
  454. }
  455. LLFontGlyphInfo* fgi = next_glyph;
  456. next_glyph = NULL;
  457. if(!fgi)
  458. {
  459. fgi = mFontFreetype->getGlyphInfo(wch);
  460. }
  461. // account for glyphs that run beyond the starting point for the next glyphs
  462. width_padding = llmax( 0.f, // always use positive padding amount
  463. width_padding - fgi->mXAdvance, // previous padding left over after advance of current character
  464. (F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance); // difference between width of this character and advance to next character
  465. cur_x += fgi->mXAdvance;
  466. // clip if current character runs past scaled_max_pixels (using width_padding)
  467. if (scaled_max_pixels < cur_x + width_padding)
  468. {
  469. clip = TRUE;
  470. break;
  471. }
  472. if (((i+1) < max_chars) && wchars[i+1])
  473. {
  474. // Kern this puppy.
  475. next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1]);
  476. cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
  477. }
  478. // Round after kerning.
  479. cur_x = llround(cur_x);
  480. drawn_x = cur_x;
  481. }
  482. if( clip )
  483. {
  484. switch (end_on_word_boundary)
  485. {
  486. case ONLY_WORD_BOUNDARIES:
  487. i = start_of_last_word;
  488. break;
  489. case WORD_BOUNDARY_IF_POSSIBLE:
  490. if (start_of_last_word != 0)
  491. {
  492. i = start_of_last_word;
  493. }
  494. break;
  495. default:
  496. case ANYWHERE:
  497. // do nothing
  498. break;
  499. }
  500. }
  501. return i;
  502. }
  503. S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const
  504. {
  505. if (!wchars || !wchars[0] || max_chars == 0)
  506. {
  507. return 0;
  508. }
  509. F32 total_width = 0.0;
  510. S32 drawable_chars = 0;
  511. F32 scaled_max_pixels = max_pixels * sScaleX;
  512. S32 start = llmin(start_pos, text_len - 1);
  513. for (S32 i = start; i >= 0; i--)
  514. {
  515. llwchar wch = wchars[i];
  516. const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch);
  517. // last character uses character width, since the whole character needs to be visible
  518. // other characters just use advance
  519. F32 width = (i == start) 
  520. ? (F32)(fgi->mWidth + fgi->mXBearing)   // use actual width for last character
  521. : fgi->mXAdvance; // use advance for all other characters
  522. if( scaled_max_pixels < (total_width + width) )
  523. {
  524. break;
  525. }
  526. total_width += width;
  527. drawable_chars++;
  528. if( max_chars >= 0 && drawable_chars >= max_chars )
  529. {
  530. break;
  531. }
  532. if ( i > 0 )
  533. {
  534. // kerning
  535. total_width += mFontFreetype->getXKerning(wchars[i-1], wch);
  536. }
  537. // Round after kerning.
  538. total_width = llround(total_width);
  539. }
  540. if (drawable_chars == 0)
  541. {
  542. return start_pos; // just draw last character
  543. }
  544. else
  545. {
  546. // if only 1 character is drawable, we want to return start_pos as the first character to draw
  547. // if 2 are drawable, return start_pos and character before start_pos, etc.
  548. return start_pos + 1 - drawable_chars;
  549. }
  550. }
  551. S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round) const
  552. {
  553. if (!wchars || !wchars[0] || max_chars == 0)
  554. {
  555. return 0;
  556. }
  557. F32 cur_x = 0;
  558. target_x *= sScaleX;
  559. // max_chars is S32_MAX by default, so make sure we don't get overflow
  560. const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars);
  561. F32 scaled_max_pixels = max_pixels * sScaleX;
  562. const LLFontGlyphInfo* next_glyph = NULL;
  563. S32 pos;
  564. for (pos = begin_offset; pos < max_index; pos++)
  565. {
  566. llwchar wch = wchars[pos];
  567. if (!wch)
  568. {
  569. break; // done
  570. }
  571. const LLFontGlyphInfo* glyph = next_glyph;
  572. next_glyph = NULL;
  573. if(!glyph)
  574. {
  575. glyph = mFontFreetype->getGlyphInfo(wch);
  576. }
  577. F32 char_width = mFontFreetype->getXAdvance(glyph);
  578. if (round)
  579. {
  580. // Note: if the mouse is on the left half of the character, the pick is to the character's left
  581. // If it's on the right half, the pick is to the right.
  582. if (target_x  < cur_x + char_width*0.5f)
  583. {
  584. break;
  585. }
  586. }
  587. else if (target_x  < cur_x + char_width)
  588. {
  589. break;
  590. }
  591. if (scaled_max_pixels < cur_x + char_width)
  592. {
  593. break;
  594. }
  595. cur_x += char_width;
  596. if (((pos + 1) < max_index)
  597. && (wchars[(pos + 1)]))
  598. {
  599. // Kern this puppy.
  600. next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1]);
  601. cur_x += mFontFreetype->getXKerning(glyph, next_glyph);
  602. }
  603. // Round after kerning.
  604. cur_x = llround(cur_x);
  605. }
  606. return llmin(max_chars, pos - begin_offset);
  607. }
  608. const LLFontDescriptor& LLFontGL::getFontDesc() const
  609. {
  610. return mFontDescriptor;
  611. }
  612. // static
  613. void 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)
  614. {
  615. sVertDPI = (F32)llfloor(screen_dpi * y_scale);
  616. sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
  617. sScaleX = x_scale;
  618. sScaleY = y_scale;
  619. sAppDir = app_dir;
  620. // Font registry init
  621. if (!sFontRegistry)
  622. {
  623. sFontRegistry = new LLFontRegistry(xui_paths, create_gl_textures);
  624. sFontRegistry->parseFontInfo("fonts.xml");
  625. }
  626. else
  627. {
  628. sFontRegistry->reset();
  629. }
  630. }
  631. // Force standard fonts to get generated up front.
  632. // This is primarily for error detection purposes.
  633. // Don't do this during initClass because it can be slow and we want to get
  634. // the viewer window on screen first. JC
  635. // static
  636. bool LLFontGL::loadDefaultFonts()
  637. {
  638. bool succ = true;
  639. succ &= (NULL != getFontSansSerifSmall());
  640. succ &= (NULL != getFontSansSerif());
  641. succ &= (NULL != getFontSansSerifBig());
  642. succ &= (NULL != getFontSansSerifHuge());
  643. succ &= (NULL != getFontSansSerifBold());
  644. succ &= (NULL != getFontMonospace());
  645. succ &= (NULL != getFontExtChar());
  646. return succ;
  647. }
  648. // static
  649. void LLFontGL::destroyDefaultFonts()
  650. {
  651. // Remove the actual fonts.
  652. delete sFontRegistry;
  653. sFontRegistry = NULL;
  654. }
  655. //static 
  656. void LLFontGL::destroyAllGL()
  657. {
  658. if (sFontRegistry)
  659. {
  660. sFontRegistry->destroyGL();
  661. }
  662. }
  663. // static
  664. U8 LLFontGL::getStyleFromString(const std::string &style)
  665. {
  666. S32 ret = 0;
  667. if (style.find("NORMAL") != style.npos)
  668. {
  669. ret |= NORMAL;
  670. }
  671. if (style.find("BOLD") != style.npos)
  672. {
  673. ret |= BOLD;
  674. }
  675. if (style.find("ITALIC") != style.npos)
  676. {
  677. ret |= ITALIC;
  678. }
  679. if (style.find("UNDERLINE") != style.npos)
  680. {
  681. ret |= UNDERLINE;
  682. }
  683. return ret;
  684. }
  685. // static
  686. std::string LLFontGL::getStringFromStyle(U8 style)
  687. {
  688. std::string style_string;
  689. if (style & NORMAL)
  690. {
  691. style_string += "|NORMAL";
  692. }
  693. if (style & BOLD)
  694. {
  695. style_string += "|BOLD";
  696. }
  697. if (style & ITALIC)
  698. {
  699. style_string += "|ITALIC";
  700. }
  701. if (style & UNDERLINE)
  702. {
  703. style_string += "|UNDERLINE";
  704. }
  705. return style_string;
  706. }
  707. // static
  708. std::string LLFontGL::nameFromFont(const LLFontGL* fontp)
  709. {
  710. return fontp->mFontDescriptor.getName();
  711. }
  712. // static
  713. std::string LLFontGL::sizeFromFont(const LLFontGL* fontp)
  714. {
  715. return fontp->mFontDescriptor.getSize();
  716. }
  717. // static
  718. std::string LLFontGL::nameFromHAlign(LLFontGL::HAlign align)
  719. {
  720. if (align == LEFT) return std::string("left");
  721. else if (align == RIGHT) return std::string("right");
  722. else if (align == HCENTER) return std::string("center");
  723. else return std::string();
  724. }
  725. // static
  726. LLFontGL::HAlign LLFontGL::hAlignFromName(const std::string& name)
  727. {
  728. LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
  729. if (name == "left")
  730. {
  731. gl_hfont_align = LLFontGL::LEFT;
  732. }
  733. else if (name == "right")
  734. {
  735. gl_hfont_align = LLFontGL::RIGHT;
  736. }
  737. else if (name == "center")
  738. {
  739. gl_hfont_align = LLFontGL::HCENTER;
  740. }
  741. //else leave left
  742. return gl_hfont_align;
  743. }
  744. // static
  745. std::string LLFontGL::nameFromVAlign(LLFontGL::VAlign align)
  746. {
  747. if (align == TOP) return std::string("top");
  748. else if (align == VCENTER) return std::string("center");
  749. else if (align == BASELINE) return std::string("baseline");
  750. else if (align == BOTTOM) return std::string("bottom");
  751. else return std::string();
  752. }
  753. // static
  754. LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
  755. {
  756. LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
  757. if (name == "top")
  758. {
  759. gl_vfont_align = LLFontGL::TOP;
  760. }
  761. else if (name == "center")
  762. {
  763. gl_vfont_align = LLFontGL::VCENTER;
  764. }
  765. else if (name == "baseline")
  766. {
  767. gl_vfont_align = LLFontGL::BASELINE;
  768. }
  769. else if (name == "bottom")
  770. {
  771. gl_vfont_align = LLFontGL::BOTTOM;
  772. }
  773. //else leave baseline
  774. return gl_vfont_align;
  775. }
  776. //static
  777. LLFontGL* LLFontGL::getFontMonospace()
  778. {
  779. return getFont(LLFontDescriptor("Monospace","Monospace",0));
  780. }
  781. //static
  782. LLFontGL* LLFontGL::getFontSansSerifSmall()
  783. {
  784. return getFont(LLFontDescriptor("SansSerif","Small",0));
  785. }
  786. //static
  787. LLFontGL* LLFontGL::getFontSansSerif()
  788. {
  789. return getFont(LLFontDescriptor("SansSerif","Medium",0));
  790. }
  791. //static
  792. LLFontGL* LLFontGL::getFontSansSerifBig()
  793. {
  794. return getFont(LLFontDescriptor("SansSerif","Large",0));
  795. }
  796. //static 
  797. LLFontGL* LLFontGL::getFontSansSerifHuge()
  798. {
  799. return getFont(LLFontDescriptor("SansSerif","Huge",0));
  800. }
  801. //static 
  802. LLFontGL* LLFontGL::getFontSansSerifBold()
  803. {
  804. return getFont(LLFontDescriptor("SansSerif","Medium",BOLD));
  805. }
  806. //static
  807. LLFontGL* LLFontGL::getFontExtChar()
  808. {
  809. return getFontSansSerif();
  810. }
  811. //static 
  812. LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc)
  813. {
  814. return sFontRegistry->getFont(desc);
  815. }
  816. //static
  817. LLFontGL* LLFontGL::getFontByName(const std::string& name)
  818. {
  819. // check for most common fonts first
  820. if (name == "SANSSERIF")
  821. {
  822. return getFontSansSerif();
  823. }
  824. else if (name == "SANSSERIF_SMALL")
  825. {
  826. return getFontSansSerifSmall();
  827. }
  828. else if (name == "SANSSERIF_BIG")
  829. {
  830. return getFontSansSerifBig();
  831. }
  832. else if (name == "SMALL" || name == "OCRA")
  833. {
  834. // *BUG: Should this be "MONOSPACE"?  Do we use "OCRA" anymore?
  835. // Does "SMALL" mean "SERIF"?
  836. return getFontMonospace();
  837. }
  838. else
  839. {
  840. return NULL;
  841. }
  842. }
  843. //static
  844. LLFontGL* LLFontGL::getFontDefault()
  845. {
  846. return getFontSansSerif(); // Fallback to sans serif as default font
  847. }
  848. // static 
  849. std::string LLFontGL::getFontPathSystem()
  850. {
  851. std::string system_path;
  852. // Try to figure out where the system's font files are stored.
  853. char *system_root = NULL;
  854. #if LL_WINDOWS
  855. system_root = getenv("SystemRoot"); /* Flawfinder: ignore */
  856. if (!system_root)
  857. {
  858. llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl;
  859. }
  860. #endif
  861. if (system_root)
  862. {
  863. system_path = llformat("%s/fonts/", system_root);
  864. }
  865. else
  866. {
  867. #if LL_WINDOWS
  868. // HACK for windows 98/Me
  869. system_path = "/WINDOWS/FONTS/";
  870. #elif LL_DARWIN
  871. // HACK for Mac OS X
  872. system_path = "/System/Library/Fonts/";
  873. #endif
  874. }
  875. return system_path;
  876. }
  877. // static 
  878. std::string LLFontGL::getFontPathLocal()
  879. {
  880. std::string local_path;
  881. // Backup files if we can't load from system fonts directory.
  882. // We could store this in an end-user writable directory to allow
  883. // end users to switch fonts.
  884. if (LLFontGL::sAppDir.length())
  885. {
  886. // use specified application dir to look for fonts
  887. local_path = LLFontGL::sAppDir + "/fonts/";
  888. }
  889. else
  890. {
  891. // assume working directory is executable directory
  892. local_path = "./fonts/";
  893. }
  894. return local_path;
  895. }
  896. LLFontGL::LLFontGL(const LLFontGL &source)
  897. {
  898. llerrs << "Not implemented!" << llendl;
  899. }
  900. LLFontGL &LLFontGL::operator=(const LLFontGL &source)
  901. {
  902. llerrs << "Not implemented" << llendl;
  903. return *this;
  904. }
  905. void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const
  906. {
  907. gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
  908. gGL.vertex2f(llfont_round_x(screen_rect.mRight), 
  909. llfont_round_y(screen_rect.mTop));
  910. gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
  911. gGL.vertex2f(llfont_round_x(screen_rect.mLeft), 
  912. llfont_round_y(screen_rect.mTop));
  913. gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
  914. gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), 
  915. llfont_round_y(screen_rect.mBottom));
  916. gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
  917. gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt), 
  918. llfont_round_y(screen_rect.mBottom));
  919. }
  920. void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
  921. {
  922. F32 slant_offset;
  923. slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f);
  924. gGL.begin(LLRender::QUADS);
  925. {
  926. //FIXME: bold and drop shadow are mutually exclusive only for convenience
  927. //Allow both when we need them.
  928. if (style & BOLD)
  929. {
  930. gGL.color4fv(color.mV);
  931. for (S32 pass = 0; pass < 2; pass++)
  932. {
  933. LLRectf screen_rect_offset = screen_rect;
  934. screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
  935. renderQuad(screen_rect_offset, uv_rect, slant_offset);
  936. }
  937. }
  938. else if (shadow == DROP_SHADOW_SOFT)
  939. {
  940. LLColor4 shadow_color = LLFontGL::sShadowColor;
  941. shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH;
  942. gGL.color4fv(shadow_color.mV);
  943. for (S32 pass = 0; pass < 5; pass++)
  944. {
  945. LLRectf screen_rect_offset = screen_rect;
  946. switch(pass)
  947. {
  948. case 0:
  949. screen_rect_offset.translate(-1.f, -1.f);
  950. break;
  951. case 1:
  952. screen_rect_offset.translate(1.f, -1.f);
  953. break;
  954. case 2:
  955. screen_rect_offset.translate(1.f, 1.f);
  956. break;
  957. case 3:
  958. screen_rect_offset.translate(-1.f, 1.f);
  959. break;
  960. case 4:
  961. screen_rect_offset.translate(0, -2.f);
  962. break;
  963. }
  964. renderQuad(screen_rect_offset, uv_rect, slant_offset);
  965. }
  966. gGL.color4fv(color.mV);
  967. renderQuad(screen_rect, uv_rect, slant_offset);
  968. }
  969. else if (shadow == DROP_SHADOW)
  970. {
  971. LLColor4 shadow_color = LLFontGL::sShadowColor;
  972. shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
  973. gGL.color4fv(shadow_color.mV);
  974. LLRectf screen_rect_shadow = screen_rect;
  975. screen_rect_shadow.translate(1.f, -1.f);
  976. renderQuad(screen_rect_shadow, uv_rect, slant_offset);
  977. gGL.color4fv(color.mV);
  978. renderQuad(screen_rect, uv_rect, slant_offset);
  979. }
  980. else // normal rendering
  981. {
  982. gGL.color4fv(color.mV);
  983. renderQuad(screen_rect, uv_rect, slant_offset);
  984. }
  985. }
  986. gGL.end();
  987. }