diff options
Diffstat (limited to 'indra/llrender/llfontfreetype.cpp')
| -rw-r--r-- | indra/llrender/llfontfreetype.cpp | 408 |
1 files changed, 272 insertions, 136 deletions
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index 6128e03fa7..91898e6de1 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -32,13 +32,14 @@ // Freetype stuff #include <ft2build.h> #ifdef LL_WINDOWS -#include <freetype2\freetype\ftsystem.h> +#include <freetype/ftsystem.h> #endif #include "llfontfreetypesvg.h" // For some reason, this won't work if it's not wrapped in the ifdef #ifdef FT_FREETYPE_H #include FT_FREETYPE_H +#include FT_MULTIPLE_MASTERS_H #endif #include "lldir.h" @@ -52,13 +53,15 @@ #include "llfontbitmapcache.h" #include "llgl.h" -#define ENABLE_OT_SVG_SUPPORT +#if !defined(LL_NO_OTSVG) + #define ENABLE_OT_SVG_SUPPORT +#endif FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL; -LLFontManager *gFontManagerp = NULL; +LLFontManager *gFontManagerp = nullptr; -FT_Library gFTLibrary = NULL; +FT_Library gFTLibrary = nullptr; //static void LLFontManager::initClass() @@ -73,7 +76,7 @@ void LLFontManager::initClass() void LLFontManager::cleanupClass() { delete gFontManagerp; - gFontManagerp = NULL; + gFontManagerp = nullptr; } LLFontManager::LLFontManager() @@ -87,7 +90,7 @@ LLFontManager::LLFontManager() FT_Done_FreeType(gFTLibrary); } -#ifdef ENABLE_OT_SVG_SUPPORT +#if defined(ENABLE_OT_SVG_SUPPORT) SVG_RendererHooks hooks = { LLFontFreeTypeSvgRenderer::OnInit, LLFontFreeTypeSvgRenderer::OnFree, @@ -101,6 +104,7 @@ LLFontManager::LLFontManager() LLFontManager::~LLFontManager() { FT_Done_FreeType(gFTLibrary); + unloadAllFonts(); } @@ -115,6 +119,8 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type) mYBitmapOffset(0), // Offset to the origin in the bitmap mXBearing(0), // Distance from baseline to left in pixels mYBearing(0), // Distance from baseline to top in pixels + mLsbDelta(0), + mRsbDelta(0), mBitmapEntry(std::make_pair(EFontGlyphType::Unspecified, -1)) // Which bitmap in the bitmap cache contains this glyph { } @@ -130,6 +136,8 @@ LLFontGlyphInfo::LLFontGlyphInfo(const LLFontGlyphInfo& fgi) , mYBitmapOffset(fgi.mYBitmapOffset) , mXBearing(fgi.mXBearing) , mYBearing(fgi.mYBearing) + , mLsbDelta(fgi.mLsbDelta) + , mRsbDelta(fgi.mRsbDelta) { mBitmapEntry = fgi.mBitmapEntry; } @@ -139,14 +147,10 @@ LLFontFreetype::LLFontFreetype() mAscender(0.f), mDescender(0.f), mLineHeight(0.f), -#ifdef LL_WINDOWS - pFileStream(NULL), - pFtStream(NULL), -#endif mIsFallback(false), - mFTFace(NULL), + mHinting(EFontHinting::FORCE_AUTOHINT), + mFTFace(nullptr), mRenderGlyphCount(0), - mAddGlyphCount(0), mStyle(0), mPointSize(0) { @@ -158,64 +162,54 @@ LLFontFreetype::~LLFontFreetype() // Clean up freetype libs. if (mFTFace) FT_Done_Face(mFTFace); - mFTFace = NULL; + mFTFace = nullptr; // Delete glyph info std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); mCharGlyphInfoMap.clear(); -#ifdef LL_WINDOWS - delete pFileStream; // closed by FT_Done_Face - delete pFtStream; -#endif delete mFontBitmapCachep; // mFallbackFonts cleaned up by LLPointer destructor } -#ifdef LL_WINDOWS -unsigned long ft_read_cb(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { - if (count <= 0) return count; - llifstream *file_stream = static_cast<llifstream *>(stream->descriptor.pointer); - file_stream->seekg(offset, std::ios::beg); - file_stream->read((char*)buffer, count); - return (unsigned long)file_stream->gcount(); -} - -void ft_close_cb(FT_Stream stream) { - llifstream *file_stream = static_cast<llifstream *>(stream->descriptor.pointer); - file_stream->close(); -} -#endif - -bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n) +bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 weight, bool is_fallback, S32 face_n, EFontHinting hinting, S32 flags) { // Don't leak face objects. This is also needed to deal with // changed font file names. if (mFTFace) { FT_Done_Face(mFTFace); - mFTFace = NULL; + mFTFace = nullptr; } - int error; -#ifdef LL_WINDOWS - error = ftOpenFace(filename, face_n); -#else - error = FT_New_Face( gFTLibrary, - filename.c_str(), - 0, - &mFTFace); -#endif + FT_Open_Args openArgs; + memset( &openArgs, 0, sizeof( openArgs ) ); + openArgs.memory_base = gFontManagerp->loadFont( filename, openArgs.memory_size ); + + if( !openArgs.memory_base ) + return false; + + openArgs.flags = FT_OPEN_MEMORY; + int error = FT_Open_Face( gFTLibrary, &openArgs, 0, &mFTFace ); if (error) - { -#ifdef LL_WINDOWS - clearFontStreams(); -#endif return false; - } mIsFallback = is_fallback; + mHinting = hinting; + mFontFlags = flags; + mWeight = weight; + + bool variable_font = false; + if (weight >= 0) + { + variable_font = setVariationAxis("wght", static_cast<F32>(weight)); + + // For Inter, also set optical size based on point size + // This makes text look better at different sizes + setVariationAxis("opsz", point_size); + } + F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi error = FT_Set_Char_Size(mFTFace, /* handle to face object */ @@ -228,10 +222,8 @@ bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v { // Clean up freetype libs. FT_Done_Face(mFTFace); -#ifdef LL_WINDOWS - clearFontStreams(); -#endif - mFTFace = NULL; + + mFTFace = nullptr; return false; } @@ -273,6 +265,18 @@ bool LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v { mStyle |= LLFontGL::BOLD; } + else if (flags & LLFontGL::BOLD) + { + // FontGL applies programmatic bolding to fonts that are a part of 'bold' descriptor but don't have the bold style set. + // Ex: Inter SemiBold doesn't have FT_STYLE_FLAG_BOLD and without this style it would be bolded programmatically. + mStyle |= LLFontGL::BOLD; + } + else if (weight >= 600 && variable_font) + { + // If the font is heavy enough, consider it bold and avoid programmatic bolding + // even if it doesn't have the bold style set. + mStyle |= LLFontGL::BOLD; + } if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC) { @@ -287,73 +291,30 @@ S32 LLFontFreetype::getNumFaces(const std::string& filename) if (mFTFace) { FT_Done_Face(mFTFace); - mFTFace = NULL; + mFTFace = nullptr; } S32 num_faces = 1; -#ifdef LL_WINDOWS - int error = ftOpenFace(filename, 0); + FT_Open_Args openArgs; + memset( &openArgs, 0, sizeof( openArgs ) ); + openArgs.memory_base = gFontManagerp->loadFont( filename, openArgs.memory_size ); + if( !openArgs.memory_base ) + return 0; + openArgs.flags = FT_OPEN_MEMORY; + int error = FT_Open_Face( gFTLibrary, &openArgs, 0, &mFTFace ); if (error) - { return 0; - } else - { num_faces = mFTFace->num_faces; - } FT_Done_Face(mFTFace); - clearFontStreams(); - mFTFace = NULL; -#endif + mFTFace = nullptr; return num_faces; } -#ifdef LL_WINDOWS -S32 LLFontFreetype::ftOpenFace(const std::string& filename, S32 face_n) -{ - S32 error = -1; - pFileStream = new llifstream(filename, std::ios::binary); - if (pFileStream->is_open()) - { - std::streampos beg = pFileStream->tellg(); - pFileStream->seekg(0, std::ios::end); - std::streampos end = pFileStream->tellg(); - std::size_t file_size = end - beg; - pFileStream->seekg(0, std::ios::beg); - - pFtStream = new LLFT_Stream(); - pFtStream->base = 0; - pFtStream->pos = 0; - pFtStream->size = static_cast<unsigned long>(file_size); - pFtStream->descriptor.pointer = pFileStream; - pFtStream->read = ft_read_cb; - pFtStream->close = ft_close_cb; - - FT_Open_Args args; - args.flags = FT_OPEN_STREAM; - args.stream = (FT_StreamRec*)pFtStream; - error = FT_Open_Face(gFTLibrary, &args, face_n, &mFTFace); - } - return error; -} - -void LLFontFreetype::clearFontStreams() -{ - if (pFileStream) - { - pFileStream->close(); - } - delete pFileStream; - delete pFtStream; - pFileStream = NULL; - pFtStream = NULL; -} -#endif - void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor) { @@ -377,7 +338,7 @@ F32 LLFontFreetype::getDescenderHeight() const F32 LLFontFreetype::getXAdvance(llwchar wch) const { - if (mFTFace == NULL) + if (mFTFace == nullptr) return 0.0; // Return existing info only if it is current @@ -401,7 +362,7 @@ F32 LLFontFreetype::getXAdvance(llwchar wch) const F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const { - if (mFTFace == NULL) + if (mFTFace == nullptr) return 0.0; return glyph->mXAdvance; @@ -409,26 +370,20 @@ F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const { - if (mFTFace == NULL) + if (mFTFace == nullptr) return 0.0; //llassert(!mIsFallback); LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left, EFontGlyphType::Unspecified);; - U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; // Kern this puppy. LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right, EFontGlyphType::Unspecified); - U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; - - FT_Vector delta; - llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); - - return delta.x*(1.f/64.f); + return getXKerning(left_glyph_info, right_glyph_info); } F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const { - if (mFTFace == NULL) + if (mFTFace == nullptr) return 0.0; U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; @@ -436,9 +391,28 @@ F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LL FT_Vector delta; - llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); + llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, FT_KERNING_UNFITTED, &delta)); + + // Apply the FreeType auto-hinter's subpixel side-bearing correction between + // adjacent glyphs. When the hinter has shifted the right side of the left + // glyph or the left side of the right glyph, (rsb_delta - lsb_delta) is the + // sub-pixel nudge that keeps spacing visually even. + F32 delta_correction = 0.0f; + if (left_glyph_info && right_glyph_info) + { + // According to FreeType docs, these delta values should only trigger + // discrete ±1 pixel adjustments when they cross certain thresholds. + // Substructing delta_diff from delta.x doesn't work as well as treating + // it as a thresholds + S32 delta_diff = left_glyph_info->mRsbDelta - right_glyph_info->mLsbDelta; + if (delta_diff > 32) + delta_correction = -1.0f; + else if (delta_diff < -31) + delta_correction = 1.0f; + } - return delta.x*(1.f/64.f); + // ft_kerning_unfitted mode always returns 26.6 fixed-point values + return (F32)(delta.x * (1.f / 64.f)) + delta_correction; } bool LLFontFreetype::hasGlyph(llwchar wch) const @@ -451,7 +425,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type { if (!mFTFace) { - return NULL; + return nullptr; } llassert(!mIsFallback); @@ -483,8 +457,8 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type continue; } glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); - if (glyph_index) - { + if (glyph_index) + { return addGlyphFromFont(pair.first, wch, glyph_index, glyph_type); } @@ -542,17 +516,17 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type { return addGlyphFromFont(this, wch, glyph_index, glyph_type); } - return NULL; + return nullptr; } LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType requested_glyph_type) const { LL_PROFILE_ZONE_SCOPED; - if (mFTFace == NULL) - return NULL; + if (mFTFace == nullptr) + return nullptr; llassert(!mIsFallback); - fontp->renderGlyph(requested_glyph_type, glyph_index); + fontp->renderGlyph(requested_glyph_type, glyph_index, wch); EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified; switch (fontp->mFTFace->glyph->bitmap.pixel_mode) @@ -574,7 +548,6 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l S32 pos_x, pos_y; U32 bitmap_num; mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_glyph_type, bitmap_num); - mAddGlyphCount++; LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index, requested_glyph_type); gi->mXBitmapOffset = pos_x; @@ -584,6 +557,11 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l gi->mHeight = height; gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; gi->mYBearing = fontp->mFTFace->glyph->bitmap_top; + // FreeType fills these when the glyph has been auto-hinted; they describe how + // much the hinter nudged the left/right side bearings (in 26.6 pixels). Keep + // them so inter-glyph spacing can be corrected in getXKerning(). + gi->mLsbDelta = (S32)fontp->mFTFace->glyph->lsb_delta; + gi->mRsbDelta = (S32)fontp->mFTFace->glyph->rsb_delta; // Convert these from 26.6 units to float pixels. gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; @@ -602,7 +580,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l { U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer; S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch; - U8 *tmp_graydata = NULL; + U8 *tmp_graydata = nullptr; if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) @@ -656,7 +634,14 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_glyph_type, bitmap_num); LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_glyph_type, bitmap_num); - image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); + if (image_gl && image_raw) + { + image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); + } + else + { + llassert(false); //images were just inserted by nextOpenPos, they shouldn't be missing + } return gi; } @@ -697,12 +682,12 @@ void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const } } -void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const +void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, llwchar wch) const { - if (mFTFace == NULL) + if (mFTFace == nullptr) return; - FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT; + FT_Int32 load_flags = (FT_Int32)mHinting; if (EFontGlyphType::Color == bitmap_type) { // We may not actually get a color render so our caller should always examine mFTFace->glyph->bitmap.pixel_mode @@ -712,11 +697,28 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) co FT_Error error = FT_Load_Glyph(mFTFace, glyph_index, load_flags); if (FT_Err_Ok != error) { + if (error == FT_Err_Out_Of_Memory) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS() << "Out of memory loading glyph for character " << llformat("U+%xu", U32(wch)) << LL_ENDL; + } + std::string message = llformat( - "Error %d (%s) loading glyph %u: bitmap_type=%u, load_flags=%d", - error, FT_Error_String(error), glyph_index, bitmap_type, load_flags); + "Error %d (%s) loading wchar %u glyph %u/%u: bitmap_type=%u, load_flags=%d", + error, FT_Error_String(error), wch, glyph_index, mFTFace->num_glyphs, bitmap_type, load_flags); LL_WARNS_ONCE() << message << LL_ENDL; error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR); + if (FT_Err_Invalid_Outline == error + || FT_Err_Invalid_Composite == error + || (FT_Err_Ok != error && LLStringOps::isEmoji(wch))) + { + // value~0 always corresponds to the 'missing glyph' + error = FT_Load_Glyph(mFTFace, 0, FT_LOAD_FORCE_AUTOHINT); + if (FT_Err_Ok != error) + { + LL_ERRS() << "Loading fallback for char '" << (U32)wch << "', glyph " << glyph_index << " failed with error : " << (S32)error << LL_ENDL; + } + } llassert_always_msg(FT_Err_Ok == error, message.c_str()); } @@ -728,7 +730,7 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) co void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi) { resetBitmapCache(); - loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0); + loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mWeight, mIsFallback, 0, mHinting, mFontFlags); if (!mIsFallback) { // This is the head of the list - need to rebuild ourself and all fallbacks. @@ -823,7 +825,12 @@ bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U1 { LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num); llassert(!mIsFallback); - llassert(image_raw && (image_raw->getComponents() == 4)); + if (!image_raw) + { + llassert(false); + return false; + } + llassert(image_raw->getComponents() == 4); // NOTE: inspired by LLImageRaw::setSubImage() U32* image_data = (U32*)image_raw->getData(); @@ -851,10 +858,17 @@ bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U1 void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const { LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, bitmap_num); - LLImageDataLock lock(image_raw); llassert(!mIsFallback); - llassert(image_raw && (image_raw->getComponents() == 2)); + if (!image_raw) + { + llassert(false); + return; + } + + LLImageDataLock lock(image_raw); + + llassert(image_raw->getComponents() == 2); U8 *target = image_raw->getData(); llassert(target); @@ -884,3 +898,125 @@ void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 } } +bool LLFontFreetype::setVariationAxis(const std::string& axis_tag, F32 value) +{ + if (!mFTFace) + return false; + + // Check if this is a variable font + FT_MM_Var* master = nullptr; + if (FT_Get_MM_Var(mFTFace, &master) != 0) + { + // Not a variable font - this is not an error, just silently skip + return false; + } + + // Find the axis by tag (e.g., "wght" for weight) + FT_UInt axis_index = 0; + bool found = false; + for (FT_UInt i = 0; i < master->num_axis; i++) + { + // Compare the 4-byte tag + if (master->axis[i].tag == FT_MAKE_TAG(axis_tag[0], axis_tag[1], axis_tag[2], axis_tag[3])) + { + axis_index = i; + found = true; + + // Clamp value to valid range for this axis + F32 min_val = master->axis[i].minimum / 65536.0f; + F32 max_val = master->axis[i].maximum / 65536.0f; + value = llclamp(value, min_val, max_val); + + break; + } + } + + if (!found) + { + FT_Done_MM_Var(gFTLibrary, master); + LL_WARNS_ONCE("Font") << "Axis '" << axis_tag << "' not found in font: " << mName << LL_ENDL; + return false; + } + + FT_UInt num_coords = master->num_axis; + FT_Fixed* coords = new FT_Fixed[num_coords]; + + // Get current coordinates + FT_Get_Var_Design_Coordinates(mFTFace, num_coords, coords); + + // Update the specific axis + coords[axis_index] = (FT_Fixed)(value * 65536.0f); + + // Set all coordinates + int error = FT_Set_Var_Design_Coordinates(mFTFace, num_coords, coords); + + delete[] coords; + FT_Done_MM_Var(gFTLibrary, master); + + if (error != 0) + { + LL_WARNS() << "Failed to set variation coordinates for " << axis_tag + << " = " << value << " in font: " << mName << LL_ENDL; + return false; + } + + LL_DEBUGS("Font") << "Set " << axis_tag << " = " << value + << " for font: " << mName << LL_ENDL; + return true; +} + + +namespace ll +{ + namespace fonts + { + class LoadedFont + { + public: + LoadedFont( std::string aName , std::string const &aAddress, std::size_t aSize ) + : mAddress( aAddress ) + { + mName = aName; + mSize = aSize; + mRefs = 1; + } + std::string mName; + std::string mAddress; + std::size_t mSize; + U32 mRefs; + }; + } +} + +U8 const* LLFontManager::loadFont( std::string const &aFilename, long &a_Size) +{ + a_Size = 0; + std::map< std::string, std::shared_ptr<ll::fonts::LoadedFont> >::iterator itr = m_LoadedFonts.find( aFilename ); + if( itr != m_LoadedFonts.end() ) + { + ++itr->second->mRefs; + // A possible overflow cannot happen here, as it is asserted that the size is less than std::numeric_limits<long>::max() a few lines below. + a_Size = static_cast<long>(itr->second->mSize); + return reinterpret_cast<U8 const*>(itr->second->mAddress.c_str()); + } + + auto strContent = LLFile::getContents(aFilename); + + if( strContent.empty() ) + return nullptr; + + // For fontconfig a type of long is required, std::string::size() returns size_t. I think it is safe to limit this to 2GiB and not support fonts that huge (can that even be a thing?) + llassert_always( strContent.size() < std::numeric_limits<long>::max() ); + + a_Size = static_cast<long>(strContent.size()); + + auto pCache = std::make_shared<ll::fonts::LoadedFont>( aFilename, strContent, a_Size ); + itr = m_LoadedFonts.insert( std::make_pair( aFilename, pCache ) ).first; + + return reinterpret_cast<U8 const*>(itr->second->mAddress.c_str()); +} + +void LLFontManager::unloadAllFonts() +{ + m_LoadedFonts.clear(); +} |
