diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llrender/llfont.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llrender/llfont.cpp | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/linden/indra/llrender/llfont.cpp b/linden/indra/llrender/llfont.cpp new file mode 100644 index 0000000..c64744e --- /dev/null +++ b/linden/indra/llrender/llfont.cpp | |||
@@ -0,0 +1,627 @@ | |||
1 | /** | ||
2 | * @file llfont.cpp | ||
3 | * @brief Font library wrapper | ||
4 | * | ||
5 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include "llfont.h" | ||
31 | |||
32 | // Freetype stuff | ||
33 | #if LL_LINUX // I had to do some work to avoid the system-installed FreeType headers... --ryan. | ||
34 | #include "llfreetype2/freetype/ft2build.h" | ||
35 | #else | ||
36 | #include <ft2build.h> | ||
37 | #endif | ||
38 | |||
39 | // For some reason, this won't work if it's not wrapped in the ifdef | ||
40 | #ifdef FT_FREETYPE_H | ||
41 | #include FT_FREETYPE_H | ||
42 | #endif | ||
43 | |||
44 | #include "llerror.h" | ||
45 | #include "llimage.h" | ||
46 | //#include "llimagej2c.h" | ||
47 | #include "llmath.h" // Linden math | ||
48 | #include "llstring.h" | ||
49 | //#include "imdebug.h" | ||
50 | |||
51 | FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL; | ||
52 | |||
53 | LLFontManager *gFontManagerp = NULL; | ||
54 | |||
55 | FT_Library gFTLibrary = NULL; | ||
56 | |||
57 | //static | ||
58 | void LLFontManager::initClass() | ||
59 | { | ||
60 | gFontManagerp = new LLFontManager; | ||
61 | } | ||
62 | |||
63 | //static | ||
64 | void LLFontManager::cleanupClass() | ||
65 | { | ||
66 | delete gFontManagerp; | ||
67 | gFontManagerp = NULL; | ||
68 | } | ||
69 | |||
70 | LLFontManager::LLFontManager() | ||
71 | { | ||
72 | int error; | ||
73 | error = FT_Init_FreeType(&gFTLibrary); | ||
74 | if (error) | ||
75 | { | ||
76 | // Clean up freetype libs. | ||
77 | llerrs << "Freetype initialization failure!" << llendl; | ||
78 | FT_Done_FreeType(gFTLibrary); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | |||
83 | LLFontManager::~LLFontManager() | ||
84 | { | ||
85 | FT_Done_FreeType(gFTLibrary); | ||
86 | } | ||
87 | |||
88 | |||
89 | LLFontGlyphInfo::LLFontGlyphInfo(U32 index) | ||
90 | { | ||
91 | mGlyphIndex = index; | ||
92 | mXBitmapOffset = 0; // Offset to the origin in the bitmap | ||
93 | mYBitmapOffset = 0; // Offset to the origin in the bitmap | ||
94 | mXBearing = 0; // Distance from baseline to left in pixels | ||
95 | mYBearing = 0; // Distance from baseline to top in pixels | ||
96 | mWidth = 0; // In pixels | ||
97 | mHeight = 0; // In pixels | ||
98 | mXAdvance = 0.f; // In pixels | ||
99 | mYAdvance = 0.f; // In pixels | ||
100 | mIsRendered = FALSE; | ||
101 | } | ||
102 | |||
103 | LLFontList::LLFontList() | ||
104 | { | ||
105 | } | ||
106 | |||
107 | LLFontList::~LLFontList() | ||
108 | { | ||
109 | LLFontList::iterator iter; | ||
110 | for(iter = this->begin(); iter != this->end(); iter++) | ||
111 | { | ||
112 | delete *iter; | ||
113 | // The (now dangling) pointers in the vector will be cleaned up when the vector is deleted by the superclass destructor. | ||
114 | } | ||
115 | } | ||
116 | void LLFontList::addAtEnd(LLFont *font) | ||
117 | { | ||
118 | // Purely a convenience function | ||
119 | this->push_back(font); | ||
120 | } | ||
121 | |||
122 | LLFont::LLFont(LLImageRaw *imagep) | ||
123 | : mRawImagep(imagep) | ||
124 | { | ||
125 | mValid = FALSE; | ||
126 | mAscender = 0.f; | ||
127 | mDescender = 0.f; | ||
128 | mLineHeight = 0.f; | ||
129 | mBitmapWidth = 0; | ||
130 | mBitmapHeight = 0; | ||
131 | mCurrentOffsetX = 1; | ||
132 | mCurrentOffsetY = 1; | ||
133 | mMaxCharWidth = 0; | ||
134 | mMaxCharHeight = 0; | ||
135 | mNumComponents = 0; | ||
136 | mFallbackFontp = NULL; | ||
137 | mIsFallback = FALSE; | ||
138 | } | ||
139 | |||
140 | |||
141 | LLFont::~LLFont() | ||
142 | { | ||
143 | mRawImagep = NULL; // dereferences or deletes image | ||
144 | |||
145 | // Clean up freetype libs. | ||
146 | FT_Done_Face(mFTFace); | ||
147 | mFTFace = NULL; | ||
148 | |||
149 | // Delete glyph info | ||
150 | std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); | ||
151 | } | ||
152 | |||
153 | void LLFont::setRawImage(LLImageRaw *imagep) | ||
154 | { | ||
155 | mRawImagep = imagep; // will delete old raw image if we have one and created it | ||
156 | } | ||
157 | |||
158 | // virtual | ||
159 | F32 LLFont::getLineHeight() const | ||
160 | { | ||
161 | return mLineHeight; | ||
162 | } | ||
163 | |||
164 | // virtual | ||
165 | F32 LLFont::getAscenderHeight() const | ||
166 | { | ||
167 | return mAscender; | ||
168 | } | ||
169 | |||
170 | // virtual | ||
171 | F32 LLFont::getDescenderHeight() const | ||
172 | { | ||
173 | return mDescender; | ||
174 | } | ||
175 | |||
176 | BOOL LLFont::loadFace(const std::string& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback) | ||
177 | { | ||
178 | int error; | ||
179 | error = FT_New_Face( gFTLibrary, | ||
180 | filename.c_str(), | ||
181 | 0, | ||
182 | &mFTFace ); | ||
183 | |||
184 | if (error) | ||
185 | { | ||
186 | return FALSE; | ||
187 | } | ||
188 | |||
189 | mIsFallback = is_fallback; | ||
190 | mNumComponents = components; | ||
191 | F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi | ||
192 | |||
193 | error = FT_Set_Char_Size(mFTFace, /* handle to face object */ | ||
194 | 0, /* char_width in 1/64th of points */ | ||
195 | (S32)(point_size*64), /* char_height in 1/64th of points */ | ||
196 | (U32)horz_dpi, /* horizontal device resolution */ | ||
197 | (U32)vert_dpi); /* vertical device resolution */ | ||
198 | |||
199 | if (error) | ||
200 | { | ||
201 | // Clean up freetype libs. | ||
202 | FT_Done_Face(mFTFace); | ||
203 | return FALSE; | ||
204 | } | ||
205 | |||
206 | F32 y_max, y_min, x_max, x_min; | ||
207 | F32 ems_per_unit = 1.f/ mFTFace->units_per_EM; | ||
208 | F32 pixels_per_unit = pixels_per_em * ems_per_unit; | ||
209 | |||
210 | // Get size of bbox in pixels | ||
211 | y_max = mFTFace->bbox.yMax * pixels_per_unit; | ||
212 | y_min = mFTFace->bbox.yMin * pixels_per_unit; | ||
213 | x_max = mFTFace->bbox.xMax * pixels_per_unit; | ||
214 | x_min = mFTFace->bbox.xMin * pixels_per_unit; | ||
215 | mAscender = mFTFace->ascender * pixels_per_unit; | ||
216 | mDescender = -mFTFace->descender * pixels_per_unit; | ||
217 | mLineHeight = mFTFace->height * pixels_per_unit; | ||
218 | |||
219 | mMaxCharWidth = llround(0.5f + (x_max - x_min)); | ||
220 | mMaxCharHeight = llround(0.5f + (y_max - y_min)); | ||
221 | |||
222 | if (!mFTFace->charmap) | ||
223 | { | ||
224 | //llinfos << " no unicode encoding, set whatever encoding there is..." << llendl; | ||
225 | FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]); | ||
226 | } | ||
227 | |||
228 | if (mRawImagep.isNull() && !mIsFallback) | ||
229 | { | ||
230 | mRawImagep = new LLImageRaw(); | ||
231 | } | ||
232 | |||
233 | if (!mIsFallback) | ||
234 | { | ||
235 | // Place text into bitmap, and generate all necessary positions/ | ||
236 | // offsets for the individual characters. | ||
237 | |||
238 | // calc width and height for mRawImagep (holds all characters) | ||
239 | // Guess for approximately 20*20 characters | ||
240 | S32 image_width = mMaxCharWidth * 20; | ||
241 | S32 pow_iw = 2; | ||
242 | while (pow_iw < image_width) | ||
243 | { | ||
244 | pow_iw *= 2; | ||
245 | } | ||
246 | image_width = pow_iw; | ||
247 | image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever. | ||
248 | S32 image_height = image_width; | ||
249 | |||
250 | //llinfos << "Guessing texture size of " << image_width << " pixels square" << llendl; | ||
251 | |||
252 | mRawImagep->resize(image_width, image_height, components); | ||
253 | |||
254 | mBitmapWidth = image_width; | ||
255 | mBitmapHeight = image_height; | ||
256 | |||
257 | switch (components) | ||
258 | { | ||
259 | case 1: | ||
260 | mRawImagep->clear(); | ||
261 | break; | ||
262 | case 2: | ||
263 | mRawImagep->clear(255, 0); | ||
264 | break; | ||
265 | } | ||
266 | |||
267 | mCurrentOffsetX = 1; | ||
268 | mCurrentOffsetY = 1; | ||
269 | |||
270 | // Add the default glyph | ||
271 | addGlyph(0, 0); | ||
272 | } | ||
273 | |||
274 | mName = filename; | ||
275 | |||
276 | return TRUE; | ||
277 | } | ||
278 | |||
279 | |||
280 | void LLFont::resetBitmap() | ||
281 | { | ||
282 | llinfos << "Rebuilding bitmap for glyph" << llendl; | ||
283 | |||
284 | // Iterate through glyphs and clear the mIsRendered flag | ||
285 | for (char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.begin(); | ||
286 | iter != mCharGlyphInfoMap.end(); ++iter) | ||
287 | { | ||
288 | iter->second->mIsRendered = FALSE; | ||
289 | } | ||
290 | |||
291 | mCurrentOffsetX = 1; | ||
292 | mCurrentOffsetY = 1; | ||
293 | |||
294 | // Add the empty glyph | ||
295 | addGlyph(0, 0); | ||
296 | } | ||
297 | |||
298 | LLFontGlyphInfo* LLFont::getGlyphInfo(const llwchar wch) const | ||
299 | { | ||
300 | char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); | ||
301 | if (iter != mCharGlyphInfoMap.end()) | ||
302 | { | ||
303 | return iter->second; | ||
304 | } | ||
305 | return NULL; | ||
306 | } | ||
307 | |||
308 | |||
309 | BOOL LLFont::hasGlyph(const llwchar wch) const | ||
310 | { | ||
311 | llassert(!mIsFallback); | ||
312 | const LLFontGlyphInfo* gi = getGlyphInfo(wch); | ||
313 | if (gi && gi->mIsRendered) | ||
314 | { | ||
315 | return TRUE; | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | return FALSE; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | BOOL LLFont::addChar(const llwchar wch) | ||
324 | { | ||
325 | llassert(!mIsFallback); | ||
326 | //lldebugs << "Adding new glyph for " << wch << " to font" << llendl; | ||
327 | |||
328 | FT_UInt glyph_index; | ||
329 | |||
330 | // Initialize char to glyph map | ||
331 | glyph_index = FT_Get_Char_Index(mFTFace, wch); | ||
332 | if (glyph_index == 0) | ||
333 | { | ||
334 | // Try looking it up in the backup Unicode font | ||
335 | if (mFallbackFontp) | ||
336 | { | ||
337 | //llinfos << "Trying to add glyph from fallback font!" << llendl | ||
338 | LLFontList::iterator iter; | ||
339 | for(iter = mFallbackFontp->begin(); iter != mFallbackFontp->end(); iter++) | ||
340 | { | ||
341 | glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch); | ||
342 | if (glyph_index) | ||
343 | { | ||
344 | addGlyphFromFont(*iter, wch, glyph_index); | ||
345 | return TRUE; | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); | ||
352 | if (iter == mCharGlyphInfoMap.end() || !(iter->second->mIsRendered)) | ||
353 | { | ||
354 | BOOL result = addGlyph(wch, glyph_index); | ||
355 | //imdebug("luma b=8 w=%d h=%d t=%s %p", mRawImagep->getWidth(), mRawImagep->getHeight(), mName.c_str(), mRawImagep->getData()); | ||
356 | return result; | ||
357 | } | ||
358 | return FALSE; | ||
359 | } | ||
360 | |||
361 | void LLFont::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const | ||
362 | { | ||
363 | char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); | ||
364 | if (iter != mCharGlyphInfoMap.end()) | ||
365 | { | ||
366 | delete iter->second; | ||
367 | iter->second = gi; | ||
368 | } | ||
369 | else | ||
370 | { | ||
371 | mCharGlyphInfoMap[wch] = gi; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | BOOL LLFont::addGlyphFromFont(LLFont *fontp, const llwchar wch, const U32 glyph_index) | ||
376 | { | ||
377 | llassert(!mIsFallback); | ||
378 | fontp->renderGlyph(glyph_index); | ||
379 | S32 width = fontp->mFTFace->glyph->bitmap.width; | ||
380 | S32 height = fontp->mFTFace->glyph->bitmap.rows; | ||
381 | |||
382 | if ((mCurrentOffsetX + width + 1) > mRawImagep->getWidth()) | ||
383 | { | ||
384 | if ((mCurrentOffsetY + 2*mMaxCharHeight + 2) > mBitmapHeight) | ||
385 | { | ||
386 | // We're out of space in this texture - clear it an all of the glyphs | ||
387 | // and start over again. Easier than LRU and should work just as well | ||
388 | // (just slightly slower on the rebuild). As long as the texture has | ||
389 | // enough room to hold all glyphs needed for a particular frame this | ||
390 | // shouldn't be too slow. | ||
391 | |||
392 | resetBitmap(); | ||
393 | |||
394 | // Need to rerender the glyph, as it's been overwritten by the default glyph. | ||
395 | fontp->renderGlyph(glyph_index); | ||
396 | width = fontp->mFTFace->glyph->bitmap.width; | ||
397 | height = fontp->mFTFace->glyph->bitmap.rows; | ||
398 | |||
399 | // We should have a reasonable offset for x and y, no need to check that it's in range | ||
400 | } | ||
401 | else | ||
402 | { | ||
403 | mCurrentOffsetX = 1; | ||
404 | mCurrentOffsetY += mMaxCharHeight + 1; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index); | ||
409 | gi->mXBitmapOffset = mCurrentOffsetX; | ||
410 | gi->mYBitmapOffset = mCurrentOffsetY; | ||
411 | gi->mWidth = width; | ||
412 | gi->mHeight = height; | ||
413 | gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; | ||
414 | gi->mYBearing = fontp->mFTFace->glyph->bitmap_top; | ||
415 | // Convert these from 26.6 units to float pixels. | ||
416 | gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; | ||
417 | gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; | ||
418 | gi->mIsRendered = TRUE; | ||
419 | |||
420 | insertGlyphInfo(wch, gi); | ||
421 | |||
422 | llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO | ||
423 | || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); | ||
424 | |||
425 | if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO | ||
426 | || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) | ||
427 | { | ||
428 | U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer; | ||
429 | S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch; | ||
430 | U8 *tmp_graydata = NULL; | ||
431 | |||
432 | if (fontp->mFTFace->glyph->bitmap.pixel_mode | ||
433 | == FT_PIXEL_MODE_MONO) | ||
434 | { | ||
435 | // need to expand 1-bit bitmap to 8-bit graymap. | ||
436 | tmp_graydata = new U8[width * height]; | ||
437 | S32 xpos, ypos; | ||
438 | for (ypos = 0; ypos < height; ++ypos) | ||
439 | { | ||
440 | S32 bm_row_offset = buffer_row_stride * ypos; | ||
441 | for (xpos = 0; xpos < width; ++xpos) | ||
442 | { | ||
443 | U32 bm_col_offsetbyte = xpos / 8; | ||
444 | U32 bm_col_offsetbit = 7 - (xpos % 8); | ||
445 | U32 bit = | ||
446 | !!(buffer_data[bm_row_offset | ||
447 | + bm_col_offsetbyte | ||
448 | ] & (1 << bm_col_offsetbit) ); | ||
449 | tmp_graydata[width*ypos + xpos] = | ||
450 | 255 * bit; | ||
451 | } | ||
452 | } | ||
453 | // use newly-built graymap. | ||
454 | buffer_data = tmp_graydata; | ||
455 | buffer_row_stride = width; | ||
456 | } | ||
457 | |||
458 | switch (mNumComponents) | ||
459 | { | ||
460 | case 1: | ||
461 | mRawImagep->setSubImage(mCurrentOffsetX, | ||
462 | mCurrentOffsetY, | ||
463 | width, | ||
464 | height, | ||
465 | buffer_data, | ||
466 | buffer_row_stride, | ||
467 | TRUE); | ||
468 | break; | ||
469 | case 2: | ||
470 | setSubImageLuminanceAlpha(mCurrentOffsetX, | ||
471 | mCurrentOffsetY, | ||
472 | width, | ||
473 | height, | ||
474 | buffer_data, | ||
475 | buffer_row_stride); | ||
476 | break; | ||
477 | default: | ||
478 | break; | ||
479 | } | ||
480 | |||
481 | if (tmp_graydata) | ||
482 | delete[] tmp_graydata; | ||
483 | } else { | ||
484 | // we don't know how to handle this pixel format from FreeType; | ||
485 | // omit it from the font-image. | ||
486 | } | ||
487 | |||
488 | mCurrentOffsetX += width + 1; | ||
489 | return TRUE; | ||
490 | } | ||
491 | |||
492 | BOOL LLFont::addGlyph(const llwchar wch, const U32 glyph_index) | ||
493 | { | ||
494 | return addGlyphFromFont(this, wch, glyph_index); | ||
495 | } | ||
496 | |||
497 | |||
498 | F32 LLFont::getXAdvance(const llwchar wch) const | ||
499 | { | ||
500 | llassert(!mIsFallback); | ||
501 | U32 glyph_index; | ||
502 | |||
503 | // Return existing info only if it is current | ||
504 | LLFontGlyphInfo* gi = getGlyphInfo(wch); | ||
505 | if (gi && gi->mIsRendered) | ||
506 | { | ||
507 | return gi->mXAdvance; | ||
508 | } | ||
509 | |||
510 | const LLFont* fontp = this; | ||
511 | |||
512 | // Initialize char to glyph map | ||
513 | glyph_index = FT_Get_Char_Index(mFTFace, wch); | ||
514 | if (glyph_index == 0 && mFallbackFontp) | ||
515 | { | ||
516 | LLFontList::iterator iter; | ||
517 | for(iter = mFallbackFontp->begin(); (iter != mFallbackFontp->end()) && (glyph_index == 0); iter++) | ||
518 | { | ||
519 | glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch); | ||
520 | if(glyph_index) | ||
521 | { | ||
522 | fontp = *iter; | ||
523 | } | ||
524 | } | ||
525 | } | ||
526 | |||
527 | if (glyph_index) | ||
528 | { | ||
529 | // This font has this glyph | ||
530 | (const_cast<LLFont *>(fontp))->renderGlyph(glyph_index); | ||
531 | |||
532 | // Create the entry if it's not there | ||
533 | char_glyph_info_map_t::iterator iter2 = mCharGlyphInfoMap.find(wch); | ||
534 | if (iter2 == mCharGlyphInfoMap.end()) | ||
535 | { | ||
536 | gi = new LLFontGlyphInfo(glyph_index); | ||
537 | insertGlyphInfo(wch, gi); | ||
538 | } | ||
539 | else | ||
540 | { | ||
541 | gi = iter2->second; | ||
542 | } | ||
543 | |||
544 | gi->mWidth = fontp->mFTFace->glyph->bitmap.width; | ||
545 | gi->mHeight = fontp->mFTFace->glyph->bitmap.rows; | ||
546 | |||
547 | // Convert these from 26.6 units to float pixels. | ||
548 | gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; | ||
549 | gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; | ||
550 | return gi->mXAdvance; | ||
551 | } | ||
552 | else | ||
553 | { | ||
554 | gi = get_if_there(mCharGlyphInfoMap, (llwchar)0, (LLFontGlyphInfo*)NULL); | ||
555 | if (gi) | ||
556 | { | ||
557 | return gi->mXAdvance; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | // Last ditch fallback - no glyphs defined at all. | ||
562 | return (F32)mMaxCharWidth; | ||
563 | } | ||
564 | |||
565 | |||
566 | void LLFont::renderGlyph(const U32 glyph_index) | ||
567 | { | ||
568 | int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_DEFAULT ); | ||
569 | llassert(!error); | ||
570 | |||
571 | error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode); | ||
572 | llassert(!error); | ||
573 | } | ||
574 | |||
575 | |||
576 | F32 LLFont::getXKerning(const llwchar char_left, const llwchar char_right) const | ||
577 | { | ||
578 | llassert(!mIsFallback); | ||
579 | LLFontGlyphInfo* left_glyph_info = get_if_there(mCharGlyphInfoMap, char_left, (LLFontGlyphInfo*)NULL); | ||
580 | U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; | ||
581 | // Kern this puppy. | ||
582 | LLFontGlyphInfo* right_glyph_info = get_if_there(mCharGlyphInfoMap, char_right, (LLFontGlyphInfo*)NULL); | ||
583 | U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; | ||
584 | |||
585 | FT_Vector delta; | ||
586 | |||
587 | llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); | ||
588 | |||
589 | return delta.x*(1.f/64.f); | ||
590 | } | ||
591 | |||
592 | void LLFont::setSubImageLuminanceAlpha(const U32 x, | ||
593 | const U32 y, | ||
594 | const U32 width, | ||
595 | const U32 height, | ||
596 | const U8 *data, | ||
597 | S32 stride) | ||
598 | { | ||
599 | llassert(!mIsFallback); | ||
600 | llassert(mRawImagep->getComponents() == 2); | ||
601 | |||
602 | U8 *target = mRawImagep->getData(); | ||
603 | |||
604 | if (!data) | ||
605 | { | ||
606 | return; | ||
607 | } | ||
608 | |||
609 | if (0 == stride) | ||
610 | stride = width; | ||
611 | |||
612 | U32 i, j; | ||
613 | U32 to_offset; | ||
614 | U32 from_offset; | ||
615 | U32 target_width = mRawImagep->getWidth(); | ||
616 | for (i = 0; i < height; i++) | ||
617 | { | ||
618 | to_offset = (y + i)*target_width + x; | ||
619 | from_offset = (height - 1 - i)*stride; | ||
620 | for (j = 0; j < width; j++) | ||
621 | { | ||
622 | *(target + to_offset*2 + 1) = *(data + from_offset); | ||
623 | to_offset++; | ||
624 | from_offset++; | ||
625 | } | ||
626 | } | ||
627 | } | ||