00001
00032 #include "linden_common.h"
00033
00034 #include "llfont.h"
00035
00036
00037 #if !defined(LL_LINUX) || defined(LL_STANDALONE)
00038 # include <ft2build.h>
00039 #else
00040
00041 # include "llfreetype2/freetype/ft2build.h"
00042 #endif
00043
00044
00045 #ifdef FT_FREETYPE_H
00046 #include FT_FREETYPE_H
00047 #endif
00048
00049 #include "llerror.h"
00050 #include "llimage.h"
00051
00052 #include "llmath.h"
00053 #include "llstring.h"
00054
00055
00056 FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;
00057
00058 LLFontManager *gFontManagerp = NULL;
00059
00060 FT_Library gFTLibrary = NULL;
00061
00062
00063 void LLFontManager::initClass()
00064 {
00065 gFontManagerp = new LLFontManager;
00066 }
00067
00068
00069 void LLFontManager::cleanupClass()
00070 {
00071 delete gFontManagerp;
00072 gFontManagerp = NULL;
00073 }
00074
00075 LLFontManager::LLFontManager()
00076 {
00077 int error;
00078 error = FT_Init_FreeType(&gFTLibrary);
00079 if (error)
00080 {
00081
00082 llerrs << "Freetype initialization failure!" << llendl;
00083 FT_Done_FreeType(gFTLibrary);
00084 }
00085 }
00086
00087
00088 LLFontManager::~LLFontManager()
00089 {
00090 FT_Done_FreeType(gFTLibrary);
00091 }
00092
00093
00094 LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
00095 {
00096 mGlyphIndex = index;
00097 mXBitmapOffset = 0;
00098 mYBitmapOffset = 0;
00099 mXBearing = 0;
00100 mYBearing = 0;
00101 mWidth = 0;
00102 mHeight = 0;
00103 mXAdvance = 0.f;
00104 mYAdvance = 0.f;
00105 mIsRendered = FALSE;
00106 }
00107
00108 LLFontList::LLFontList()
00109 {
00110 }
00111
00112 LLFontList::~LLFontList()
00113 {
00114 LLFontList::iterator iter;
00115 for(iter = this->begin(); iter != this->end(); iter++)
00116 {
00117 delete *iter;
00118
00119 }
00120 }
00121 void LLFontList::addAtEnd(LLFont *font)
00122 {
00123
00124 this->push_back(font);
00125 }
00126
00127 LLFont::LLFont(LLImageRaw *imagep)
00128 : mRawImagep(imagep)
00129 {
00130 mValid = FALSE;
00131 mAscender = 0.f;
00132 mDescender = 0.f;
00133 mLineHeight = 0.f;
00134 mBitmapWidth = 0;
00135 mBitmapHeight = 0;
00136 mCurrentOffsetX = 1;
00137 mCurrentOffsetY = 1;
00138 mMaxCharWidth = 0;
00139 mMaxCharHeight = 0;
00140 mNumComponents = 0;
00141 mFallbackFontp = NULL;
00142 mIsFallback = FALSE;
00143 mFTFace = NULL;
00144 }
00145
00146
00147 LLFont::~LLFont()
00148 {
00149 mRawImagep = NULL;
00150
00151
00152 if (mFTFace)
00153 FT_Done_Face(mFTFace);
00154 mFTFace = NULL;
00155
00156
00157 std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer());
00158 }
00159
00160 void LLFont::setRawImage(LLImageRaw *imagep)
00161 {
00162 mRawImagep = imagep;
00163 }
00164
00165
00166 F32 LLFont::getLineHeight() const
00167 {
00168 return mLineHeight;
00169 }
00170
00171
00172 F32 LLFont::getAscenderHeight() const
00173 {
00174 return mAscender;
00175 }
00176
00177
00178 F32 LLFont::getDescenderHeight() const
00179 {
00180 return mDescender;
00181 }
00182
00183 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)
00184 {
00185
00186
00187 if (mFTFace)
00188 {
00189 FT_Done_Face(mFTFace);
00190 mFTFace = NULL;
00191 }
00192
00193 int error;
00194
00195 error = FT_New_Face( gFTLibrary,
00196 filename.c_str(),
00197 0,
00198 &mFTFace );
00199
00200 if (error)
00201 {
00202 return FALSE;
00203 }
00204
00205 mIsFallback = is_fallback;
00206 mNumComponents = components;
00207 F32 pixels_per_em = (point_size / 72.f)*vert_dpi;
00208
00209 error = FT_Set_Char_Size(mFTFace,
00210 0,
00211 (S32)(point_size*64),
00212 (U32)horz_dpi,
00213 (U32)vert_dpi);
00214
00215 if (error)
00216 {
00217
00218 FT_Done_Face(mFTFace);
00219 mFTFace = NULL;
00220 return FALSE;
00221 }
00222
00223 F32 y_max, y_min, x_max, x_min;
00224 F32 ems_per_unit = 1.f/ mFTFace->units_per_EM;
00225 F32 pixels_per_unit = pixels_per_em * ems_per_unit;
00226
00227
00228 y_max = mFTFace->bbox.yMax * pixels_per_unit;
00229 y_min = mFTFace->bbox.yMin * pixels_per_unit;
00230 x_max = mFTFace->bbox.xMax * pixels_per_unit;
00231 x_min = mFTFace->bbox.xMin * pixels_per_unit;
00232 mAscender = mFTFace->ascender * pixels_per_unit;
00233 mDescender = -mFTFace->descender * pixels_per_unit;
00234 mLineHeight = mFTFace->height * pixels_per_unit;
00235
00236 mMaxCharWidth = llround(0.5f + (x_max - x_min));
00237 mMaxCharHeight = llround(0.5f + (y_max - y_min));
00238
00239 if (!mFTFace->charmap)
00240 {
00241
00242 FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]);
00243 }
00244
00245 if (mRawImagep.isNull() && !mIsFallback)
00246 {
00247 mRawImagep = new LLImageRaw();
00248 }
00249
00250 if (!mIsFallback)
00251 {
00252
00253
00254
00255
00256
00257 S32 image_width = mMaxCharWidth * 20;
00258 S32 pow_iw = 2;
00259 while (pow_iw < image_width)
00260 {
00261 pow_iw *= 2;
00262 }
00263 image_width = pow_iw;
00264 image_width = llmin(512, image_width);
00265 S32 image_height = image_width;
00266
00267
00268
00269 mRawImagep->resize(image_width, image_height, components);
00270
00271 mBitmapWidth = image_width;
00272 mBitmapHeight = image_height;
00273
00274 switch (components)
00275 {
00276 case 1:
00277 mRawImagep->clear();
00278 break;
00279 case 2:
00280 mRawImagep->clear(255, 0);
00281 break;
00282 }
00283
00284 mCurrentOffsetX = 1;
00285 mCurrentOffsetY = 1;
00286
00287
00288 addGlyph(0, 0);
00289 }
00290
00291 mName = filename;
00292
00293 return TRUE;
00294 }
00295
00296
00297 void LLFont::resetBitmap()
00298 {
00299 llinfos << "Rebuilding bitmap for glyph" << llendl;
00300
00301
00302 for (char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.begin();
00303 iter != mCharGlyphInfoMap.end(); ++iter)
00304 {
00305 iter->second->mIsRendered = FALSE;
00306 }
00307
00308 mCurrentOffsetX = 1;
00309 mCurrentOffsetY = 1;
00310
00311
00312 addGlyph(0, 0);
00313 }
00314
00315 LLFontGlyphInfo* LLFont::getGlyphInfo(const llwchar wch) const
00316 {
00317 char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
00318 if (iter != mCharGlyphInfoMap.end())
00319 {
00320 return iter->second;
00321 }
00322 return NULL;
00323 }
00324
00325
00326 BOOL LLFont::hasGlyph(const llwchar wch) const
00327 {
00328 llassert(!mIsFallback);
00329 const LLFontGlyphInfo* gi = getGlyphInfo(wch);
00330 if (gi && gi->mIsRendered)
00331 {
00332 return TRUE;
00333 }
00334 else
00335 {
00336 return FALSE;
00337 }
00338 }
00339
00340 BOOL LLFont::addChar(const llwchar wch)
00341 {
00342 if (mFTFace == NULL)
00343 return FALSE;
00344
00345 llassert(!mIsFallback);
00346
00347
00348 FT_UInt glyph_index;
00349
00350
00351 glyph_index = FT_Get_Char_Index(mFTFace, wch);
00352 if (glyph_index == 0)
00353 {
00354
00355 if (mFallbackFontp)
00356 {
00357
00358 LLFontList::iterator iter;
00359 for(iter = mFallbackFontp->begin(); iter != mFallbackFontp->end(); iter++)
00360 {
00361 glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
00362 if (glyph_index)
00363 {
00364 addGlyphFromFont(*iter, wch, glyph_index);
00365 return TRUE;
00366 }
00367 }
00368 }
00369 }
00370
00371 char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
00372 if (iter == mCharGlyphInfoMap.end() || !(iter->second->mIsRendered))
00373 {
00374 BOOL result = addGlyph(wch, glyph_index);
00375
00376 return result;
00377 }
00378 return FALSE;
00379 }
00380
00381 void LLFont::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
00382 {
00383 char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
00384 if (iter != mCharGlyphInfoMap.end())
00385 {
00386 delete iter->second;
00387 iter->second = gi;
00388 }
00389 else
00390 {
00391 mCharGlyphInfoMap[wch] = gi;
00392 }
00393 }
00394
00395 BOOL LLFont::addGlyphFromFont(LLFont *fontp, const llwchar wch, const U32 glyph_index)
00396 {
00397 if (mFTFace == NULL)
00398 return FALSE;
00399
00400 llassert(!mIsFallback);
00401 fontp->renderGlyph(glyph_index);
00402 S32 width = fontp->mFTFace->glyph->bitmap.width;
00403 S32 height = fontp->mFTFace->glyph->bitmap.rows;
00404
00405 if ((mCurrentOffsetX + width + 1) > mRawImagep->getWidth())
00406 {
00407 if ((mCurrentOffsetY + 2*mMaxCharHeight + 2) > mBitmapHeight)
00408 {
00409
00410
00411
00412
00413
00414
00415 resetBitmap();
00416
00417
00418 fontp->renderGlyph(glyph_index);
00419 width = fontp->mFTFace->glyph->bitmap.width;
00420 height = fontp->mFTFace->glyph->bitmap.rows;
00421
00422
00423 }
00424 else
00425 {
00426 mCurrentOffsetX = 1;
00427 mCurrentOffsetY += mMaxCharHeight + 1;
00428 }
00429 }
00430
00431 LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index);
00432 gi->mXBitmapOffset = mCurrentOffsetX;
00433 gi->mYBitmapOffset = mCurrentOffsetY;
00434 gi->mWidth = width;
00435 gi->mHeight = height;
00436 gi->mXBearing = fontp->mFTFace->glyph->bitmap_left;
00437 gi->mYBearing = fontp->mFTFace->glyph->bitmap_top;
00438
00439 gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f;
00440 gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f;
00441 gi->mIsRendered = TRUE;
00442
00443 insertGlyphInfo(wch, gi);
00444
00445 llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
00446 || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
00447
00448 if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
00449 || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
00450 {
00451 U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer;
00452 S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch;
00453 U8 *tmp_graydata = NULL;
00454
00455 if (fontp->mFTFace->glyph->bitmap.pixel_mode
00456 == FT_PIXEL_MODE_MONO)
00457 {
00458
00459 tmp_graydata = new U8[width * height];
00460 S32 xpos, ypos;
00461 for (ypos = 0; ypos < height; ++ypos)
00462 {
00463 S32 bm_row_offset = buffer_row_stride * ypos;
00464 for (xpos = 0; xpos < width; ++xpos)
00465 {
00466 U32 bm_col_offsetbyte = xpos / 8;
00467 U32 bm_col_offsetbit = 7 - (xpos % 8);
00468 U32 bit =
00469 !!(buffer_data[bm_row_offset
00470 + bm_col_offsetbyte
00471 ] & (1 << bm_col_offsetbit) );
00472 tmp_graydata[width*ypos + xpos] =
00473 255 * bit;
00474 }
00475 }
00476
00477 buffer_data = tmp_graydata;
00478 buffer_row_stride = width;
00479 }
00480
00481 switch (mNumComponents)
00482 {
00483 case 1:
00484 mRawImagep->setSubImage(mCurrentOffsetX,
00485 mCurrentOffsetY,
00486 width,
00487 height,
00488 buffer_data,
00489 buffer_row_stride,
00490 TRUE);
00491 break;
00492 case 2:
00493 setSubImageLuminanceAlpha(mCurrentOffsetX,
00494 mCurrentOffsetY,
00495 width,
00496 height,
00497 buffer_data,
00498 buffer_row_stride);
00499 break;
00500 default:
00501 break;
00502 }
00503
00504 if (tmp_graydata)
00505 delete[] tmp_graydata;
00506 } else {
00507
00508
00509 }
00510
00511 mCurrentOffsetX += width + 1;
00512 return TRUE;
00513 }
00514
00515 BOOL LLFont::addGlyph(const llwchar wch, const U32 glyph_index)
00516 {
00517 return addGlyphFromFont(this, wch, glyph_index);
00518 }
00519
00520
00521 F32 LLFont::getXAdvance(const llwchar wch) const
00522 {
00523 if (mFTFace == NULL)
00524 return 0.0;
00525
00526 llassert(!mIsFallback);
00527 U32 glyph_index;
00528
00529
00530 LLFontGlyphInfo* gi = getGlyphInfo(wch);
00531 if (gi && gi->mIsRendered)
00532 {
00533 return gi->mXAdvance;
00534 }
00535
00536 const LLFont* fontp = this;
00537
00538
00539 glyph_index = FT_Get_Char_Index(mFTFace, wch);
00540 if (glyph_index == 0 && mFallbackFontp)
00541 {
00542 LLFontList::iterator iter;
00543 for(iter = mFallbackFontp->begin(); (iter != mFallbackFontp->end()) && (glyph_index == 0); iter++)
00544 {
00545 glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
00546 if(glyph_index)
00547 {
00548 fontp = *iter;
00549 }
00550 }
00551 }
00552
00553 if (glyph_index)
00554 {
00555
00556 (const_cast<LLFont *>(fontp))->renderGlyph(glyph_index);
00557
00558
00559 char_glyph_info_map_t::iterator iter2 = mCharGlyphInfoMap.find(wch);
00560 if (iter2 == mCharGlyphInfoMap.end())
00561 {
00562 gi = new LLFontGlyphInfo(glyph_index);
00563 insertGlyphInfo(wch, gi);
00564 }
00565 else
00566 {
00567 gi = iter2->second;
00568 }
00569
00570 gi->mWidth = fontp->mFTFace->glyph->bitmap.width;
00571 gi->mHeight = fontp->mFTFace->glyph->bitmap.rows;
00572
00573
00574 gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f;
00575 gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f;
00576 return gi->mXAdvance;
00577 }
00578 else
00579 {
00580 gi = get_if_there(mCharGlyphInfoMap, (llwchar)0, (LLFontGlyphInfo*)NULL);
00581 if (gi)
00582 {
00583 return gi->mXAdvance;
00584 }
00585 }
00586
00587
00588 return (F32)mMaxCharWidth;
00589 }
00590
00591
00592 void LLFont::renderGlyph(const U32 glyph_index)
00593 {
00594 if (mFTFace == NULL)
00595 return;
00596
00597 int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_DEFAULT );
00598 llassert(!error);
00599
00600 error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode);
00601 llassert(!error);
00602 }
00603
00604
00605 F32 LLFont::getXKerning(const llwchar char_left, const llwchar char_right) const
00606 {
00607 if (mFTFace == NULL)
00608 return 0.0;
00609
00610 llassert(!mIsFallback);
00611 LLFontGlyphInfo* left_glyph_info = get_if_there(mCharGlyphInfoMap, char_left, (LLFontGlyphInfo*)NULL);
00612 U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;
00613
00614 LLFontGlyphInfo* right_glyph_info = get_if_there(mCharGlyphInfoMap, char_right, (LLFontGlyphInfo*)NULL);
00615 U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0;
00616
00617 FT_Vector delta;
00618
00619 llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta));
00620
00621 return delta.x*(1.f/64.f);
00622 }
00623
00624 void LLFont::setSubImageLuminanceAlpha(const U32 x,
00625 const U32 y,
00626 const U32 width,
00627 const U32 height,
00628 const U8 *data,
00629 S32 stride)
00630 {
00631 llassert(!mIsFallback);
00632 llassert(mRawImagep->getComponents() == 2);
00633
00634 U8 *target = mRawImagep->getData();
00635
00636 if (!data)
00637 {
00638 return;
00639 }
00640
00641 if (0 == stride)
00642 stride = width;
00643
00644 U32 i, j;
00645 U32 to_offset;
00646 U32 from_offset;
00647 U32 target_width = mRawImagep->getWidth();
00648 for (i = 0; i < height; i++)
00649 {
00650 to_offset = (y + i)*target_width + x;
00651 from_offset = (height - 1 - i)*stride;
00652 for (j = 0; j < width; j++)
00653 {
00654 *(target + to_offset*2 + 1) = *(data + from_offset);
00655 to_offset++;
00656 from_offset++;
00657 }
00658 }
00659 }