diff options
Diffstat (limited to 'indra/llrender/llfontfreetype.cpp')
-rw-r--r-- | indra/llrender/llfontfreetype.cpp | 1174 |
1 files changed, 609 insertions, 565 deletions
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index d87fb5245c..92b373c835 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfontfreetype.cpp * @brief Freetype font library wrapper * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,7 +46,7 @@ #include "llimage.h" #include "llimagepng.h" //#include "llimagej2c.h" -#include "llmath.h" // Linden math +#include "llmath.h" // Linden math #include "llstring.h" //#include "imdebug.h" #include "llfontbitmapcache.h" @@ -63,779 +63,823 @@ FT_Library gFTLibrary = NULL; //static void LLFontManager::initClass() { - if (!gFontManagerp) - { - gFontManagerp = new LLFontManager; - } + if (!gFontManagerp) + { + gFontManagerp = new LLFontManager; + } } //static void LLFontManager::cleanupClass() { - delete gFontManagerp; - gFontManagerp = NULL; + delete gFontManagerp; + gFontManagerp = NULL; } LLFontManager::LLFontManager() { - int error; - error = FT_Init_FreeType(&gFTLibrary); - if (error) - { - // Clean up freetype libs. - LL_ERRS() << "Freetype initialization failure!" << LL_ENDL; - FT_Done_FreeType(gFTLibrary); - } + int error; + error = FT_Init_FreeType(&gFTLibrary); + if (error) + { + // Clean up freetype libs. + LL_ERRS() << "Freetype initialization failure!" << LL_ENDL; + FT_Done_FreeType(gFTLibrary); + } #ifdef ENABLE_OT_SVG_SUPPORT - SVG_RendererHooks hooks = { - LLFontFreeTypeSvgRenderer::OnInit, - LLFontFreeTypeSvgRenderer::OnFree, - LLFontFreeTypeSvgRenderer::OnRender, - LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot, - }; - FT_Property_Set(gFTLibrary, "ot-svg", "svg-hooks", &hooks); + SVG_RendererHooks hooks = { + LLFontFreeTypeSvgRenderer::OnInit, + LLFontFreeTypeSvgRenderer::OnFree, + LLFontFreeTypeSvgRenderer::OnRender, + LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot, + }; + FT_Property_Set(gFTLibrary, "ot-svg", "svg-hooks", &hooks); #endif } LLFontManager::~LLFontManager() { - FT_Done_FreeType(gFTLibrary); + FT_Done_FreeType(gFTLibrary); } LLFontGlyphInfo::LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type) -: mGlyphIndex(index), - mGlyphType(glyph_type), - mWidth(0), // In pixels - mHeight(0), // In pixels - mXAdvance(0.f), // In pixels - mYAdvance(0.f), // In pixels - mXBitmapOffset(0), // Offset to the origin in the bitmap - 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 - mBitmapEntry(std::make_pair(EFontGlyphType::Unspecified, -1)) // Which bitmap in the bitmap cache contains this glyph +: mGlyphIndex(index), + mGlyphType(glyph_type), + mWidth(0), // In pixels + mHeight(0), // In pixels + mXAdvance(0.f), // In pixels + mYAdvance(0.f), // In pixels + mXBitmapOffset(0), // Offset to the origin in the bitmap + 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 + mBitmapEntry(std::make_pair(EFontGlyphType::Unspecified, -1)) // Which bitmap in the bitmap cache contains this glyph { } LLFontGlyphInfo::LLFontGlyphInfo(const LLFontGlyphInfo& fgi) - : mGlyphIndex(fgi.mGlyphIndex) - , mGlyphType(fgi.mGlyphType) - , mWidth(fgi.mWidth) - , mHeight(fgi.mHeight) - , mXAdvance(fgi.mXAdvance) - , mYAdvance(fgi.mYAdvance) - , mXBitmapOffset(fgi.mXBitmapOffset) - , mYBitmapOffset(fgi.mYBitmapOffset) - , mXBearing(fgi.mXBearing) - , mYBearing(fgi.mYBearing) + : mGlyphIndex(fgi.mGlyphIndex) + , mGlyphType(fgi.mGlyphType) + , mWidth(fgi.mWidth) + , mHeight(fgi.mHeight) + , mXAdvance(fgi.mXAdvance) + , mYAdvance(fgi.mYAdvance) + , mXBitmapOffset(fgi.mXBitmapOffset) + , mYBitmapOffset(fgi.mYBitmapOffset) + , mXBearing(fgi.mXBearing) + , mYBearing(fgi.mYBearing) { - mBitmapEntry = fgi.mBitmapEntry; + mBitmapEntry = fgi.mBitmapEntry; } LLFontFreetype::LLFontFreetype() -: mFontBitmapCachep(new LLFontBitmapCache), - mAscender(0.f), - mDescender(0.f), - mLineHeight(0.f), +: mFontBitmapCachep(new LLFontBitmapCache), + mAscender(0.f), + mDescender(0.f), + mLineHeight(0.f), #ifdef LL_WINDOWS - pFileStream(NULL), - pFtStream(NULL), + pFileStream(NULL), + pFtStream(NULL), #endif - mIsFallback(FALSE), - mFTFace(NULL), - mRenderGlyphCount(0), - mAddGlyphCount(0), - mStyle(0), - mPointSize(0) + mIsFallback(FALSE), + mFTFace(NULL), + mRenderGlyphCount(0), + mAddGlyphCount(0), + mStyle(0), + mPointSize(0) { } LLFontFreetype::~LLFontFreetype() { - // Clean up freetype libs. - if (mFTFace) - FT_Done_Face(mFTFace); - mFTFace = NULL; + // Clean up freetype libs. + if (mFTFace) + FT_Done_Face(mFTFace); + mFTFace = NULL; - // Delete glyph info - std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); - mCharGlyphInfoMap.clear(); + // 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; + delete pFileStream; // closed by FT_Done_Face + delete pFtStream; #endif - delete mFontBitmapCachep; - // mFallbackFonts cleaned up by LLPointer destructor + 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 file_stream->gcount(); + 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 file_stream->gcount(); } void ft_close_cb(FT_Stream stream) { - llifstream *file_stream = static_cast<llifstream *>(stream->descriptor.pointer); - file_stream->close(); + 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) { - // Don't leak face objects. This is also needed to deal with - // changed font file names. - if (mFTFace) - { - FT_Done_Face(mFTFace); - mFTFace = NULL; - } - - int error; + // Don't leak face objects. This is also needed to deal with + // changed font file names. + if (mFTFace) + { + FT_Done_Face(mFTFace); + mFTFace = NULL; + } + + int error; #ifdef LL_WINDOWS - error = ftOpenFace(filename, face_n); + error = ftOpenFace(filename, face_n); #else - error = FT_New_Face( gFTLibrary, - filename.c_str(), - 0, - &mFTFace); + error = FT_New_Face( gFTLibrary, + filename.c_str(), + 0, + &mFTFace); #endif - if (error) - { + if (error) + { #ifdef LL_WINDOWS - clearFontStreams(); + clearFontStreams(); #endif - return FALSE; - } - - mIsFallback = is_fallback; - F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi - - error = FT_Set_Char_Size(mFTFace, /* handle to face object */ - 0, /* char_width in 1/64th of points */ - (S32)(point_size*64), /* char_height in 1/64th of points */ - (U32)horz_dpi, /* horizontal device resolution */ - (U32)vert_dpi); /* vertical device resolution */ - - if (error) - { - // Clean up freetype libs. - FT_Done_Face(mFTFace); + return FALSE; + } + + mIsFallback = is_fallback; + F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi + + error = FT_Set_Char_Size(mFTFace, /* handle to face object */ + 0, /* char_width in 1/64th of points */ + (S32)(point_size*64), /* char_height in 1/64th of points */ + (U32)horz_dpi, /* horizontal device resolution */ + (U32)vert_dpi); /* vertical device resolution */ + + if (error) + { + // Clean up freetype libs. + FT_Done_Face(mFTFace); #ifdef LL_WINDOWS - clearFontStreams(); + clearFontStreams(); #endif - mFTFace = NULL; - return FALSE; - } + mFTFace = NULL; + return FALSE; + } - F32 y_max, y_min, x_max, x_min; - F32 ems_per_unit = 1.f/ mFTFace->units_per_EM; - F32 pixels_per_unit = pixels_per_em * ems_per_unit; + F32 y_max, y_min, x_max, x_min; + F32 ems_per_unit = 1.f/ mFTFace->units_per_EM; + F32 pixels_per_unit = pixels_per_em * ems_per_unit; - // Get size of bbox in pixels - y_max = mFTFace->bbox.yMax * pixels_per_unit; - y_min = mFTFace->bbox.yMin * pixels_per_unit; - x_max = mFTFace->bbox.xMax * pixels_per_unit; - x_min = mFTFace->bbox.xMin * pixels_per_unit; - mAscender = mFTFace->ascender * pixels_per_unit; - mDescender = -mFTFace->descender * pixels_per_unit; - mLineHeight = mFTFace->height * pixels_per_unit; + // Get size of bbox in pixels + y_max = mFTFace->bbox.yMax * pixels_per_unit; + y_min = mFTFace->bbox.yMin * pixels_per_unit; + x_max = mFTFace->bbox.xMax * pixels_per_unit; + x_min = mFTFace->bbox.xMin * pixels_per_unit; + mAscender = mFTFace->ascender * pixels_per_unit; + mDescender = -mFTFace->descender * pixels_per_unit; + mLineHeight = mFTFace->height * pixels_per_unit; - S32 max_char_width = ll_round(0.5f + (x_max - x_min)); - S32 max_char_height = ll_round(0.5f + (y_max - y_min)); + S32 max_char_width = ll_round(0.5f + (x_max - x_min)); + S32 max_char_height = ll_round(0.5f + (y_max - y_min)); - mFontBitmapCachep->init(max_char_width, max_char_height); + mFontBitmapCachep->init(max_char_width, max_char_height); - if (!mFTFace->charmap) - { - //LL_INFOS() << " no unicode encoding, set whatever encoding there is..." << LL_ENDL; - FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]); - } + if (!mFTFace->charmap) + { + //LL_INFOS() << " no unicode encoding, set whatever encoding there is..." << LL_ENDL; + FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]); + } - if (!mIsFallback) - { - // Add the default glyph - addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale); - } + if (!mIsFallback) + { + // Add the default glyph + addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale); + } - mName = filename; - mPointSize = point_size; + mName = filename; + mPointSize = point_size; - mStyle = LLFontGL::NORMAL; - if(mFTFace->style_flags & FT_STYLE_FLAG_BOLD) - { - mStyle |= LLFontGL::BOLD; - } + mStyle = LLFontGL::NORMAL; + if(mFTFace->style_flags & FT_STYLE_FLAG_BOLD) + { + mStyle |= LLFontGL::BOLD; + } - if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC) - { - mStyle |= LLFontGL::ITALIC; - } + if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC) + { + mStyle |= LLFontGL::ITALIC; + } - return TRUE; + return TRUE; } S32 LLFontFreetype::getNumFaces(const std::string& filename) { - if (mFTFace) - { - FT_Done_Face(mFTFace); - mFTFace = NULL; - } + if (mFTFace) + { + FT_Done_Face(mFTFace); + mFTFace = NULL; + } - S32 num_faces = 1; + S32 num_faces = 1; #ifdef LL_WINDOWS - int error = ftOpenFace(filename, 0); - - if (error) - { - return 0; - } - else - { - num_faces = mFTFace->num_faces; - } - - FT_Done_Face(mFTFace); - clearFontStreams(); - mFTFace = NULL; + int error = ftOpenFace(filename, 0); + + if (error) + { + return 0; + } + else + { + num_faces = mFTFace->num_faces; + } + + FT_Done_Face(mFTFace); + clearFontStreams(); + mFTFace = NULL; #endif - return num_faces; + 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 = 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; + 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 = 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; + 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) +void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, + const char_functor_t& functor) { - // Insert functor fallbacks before generic fallbacks - mFallbackFonts.insert((functor) ? std::find_if(mFallbackFonts.begin(), mFallbackFonts.end(), [](const fallback_font_t& fe) { return !fe.second; }) : mFallbackFonts.end(), - std::make_pair(fallback_font, functor)); + mFallbackFonts.emplace_back(fallback_font, functor); } F32 LLFontFreetype::getLineHeight() const { - return mLineHeight; + return mLineHeight; } F32 LLFontFreetype::getAscenderHeight() const { - return mAscender; + return mAscender; } F32 LLFontFreetype::getDescenderHeight() const { - return mDescender; + return mDescender; } F32 LLFontFreetype::getXAdvance(llwchar wch) const { - if (mFTFace == NULL) - return 0.0; + if (mFTFace == NULL) + return 0.0; - // Return existing info only if it is current - LLFontGlyphInfo* gi = getGlyphInfo(wch, EFontGlyphType::Unspecified); - if (gi) - { - return gi->mXAdvance; - } - else - { - char_glyph_info_map_t::iterator found_it = mCharGlyphInfoMap.find((llwchar)0); - if (found_it != mCharGlyphInfoMap.end()) - { - return found_it->second->mXAdvance; - } - } + // Return existing info only if it is current + LLFontGlyphInfo* gi = getGlyphInfo(wch, EFontGlyphType::Unspecified); + if (gi) + { + return gi->mXAdvance; + } + else + { + char_glyph_info_map_t::iterator found_it = mCharGlyphInfoMap.find((llwchar)0); + if (found_it != mCharGlyphInfoMap.end()) + { + return found_it->second->mXAdvance; + } + } - // Last ditch fallback - no glyphs defined at all. - return (F32)mFontBitmapCachep->getMaxCharWidth(); + // Last ditch fallback - no glyphs defined at all. + return (F32)mFontBitmapCachep->getMaxCharWidth(); } F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const { - if (mFTFace == NULL) - return 0.0; + if (mFTFace == NULL) + return 0.0; - return glyph->mXAdvance; + return glyph->mXAdvance; } F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const { - if (mFTFace == NULL) - return 0.0; + if (mFTFace == NULL) + 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; + //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; + 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)); - return delta.x*(1.f/64.f); + return delta.x*(1.f/64.f); } F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const { - if (mFTFace == NULL) - return 0.0; + if (mFTFace == NULL) + return 0.0; - U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; - U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; + U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; + U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; - FT_Vector delta; + 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)); - return delta.x*(1.f/64.f); + return delta.x*(1.f/64.f); } BOOL LLFontFreetype::hasGlyph(llwchar wch) const { - llassert(!mIsFallback); - return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end()); + llassert(!mIsFallback); + return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end()); } LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type) const { - if (mFTFace == NULL) - return FALSE; - - llassert(!mIsFallback); - llassert(glyph_type < EFontGlyphType::Count); - //LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL; - - FT_UInt glyph_index; - - // Fallback fonts with a functor have precedence over everything else - fallback_font_vector_t::const_iterator it_fallback = mFallbackFonts.cbegin(); - /* This leads to a bug SL-19831 "Check marks in the menu are less visible." - ** Also, LLFontRegistry::createFont() says: "Fallback fonts don't render" - for (; it_fallback != mFallbackFonts.cend() && it_fallback->second; ++it_fallback) - { - if (it_fallback->second(wch)) - { - glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch); - if (glyph_index) - { - return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type); - } - } - } - */ - - // Initialize char to glyph map - glyph_index = FT_Get_Char_Index(mFTFace, wch); - if (glyph_index == 0) - { - //LL_INFOS() << "Trying to add glyph from fallback font!" << LL_ENDL; - for (; it_fallback != mFallbackFonts.cend(); ++it_fallback) - { - glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch); - if (glyph_index) - { - return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type); - } - } - } - - std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); - char_glyph_info_map_t::iterator iter = - std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }); - if (iter == range_it.second) - { - return addGlyphFromFont(this, wch, glyph_index, glyph_type); - } - return NULL; + if (!mFTFace) + { + return NULL; + } + + llassert(!mIsFallback); + llassert(glyph_type < EFontGlyphType::Count); + //LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL; + + // Initialize char to glyph map + FT_UInt glyph_index = FT_Get_Char_Index(mFTFace, wch); + if (glyph_index == 0) + { + // No corresponding glyph in this font: look for a glyph in fallback + // fonts. + size_t count = mFallbackFonts.size(); + if (LLStringOps::isEmoji(wch)) + { + // This is a "genuine" emoji (in the range 0x1f000-0x20000): print + // it using the emoji font(s) if possible. HB + for (size_t i = 0; i < count; ++i) + { + const fallback_font_t& pair = mFallbackFonts[i]; + if (!pair.second || !pair.second(wch)) + { + // If this font does not have a functor, or the character + // does not pass the functor, reject it. Note: we keep the + // functor test (despite the fact we already tested for + // LLStringOps::isEmoji(wch) above), in case we would use + // different, more restrictive or partionned functors in + // the future with several different emoji fonts. HB + continue; + } + glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(pair.first, wch, glyph_index, + glyph_type); + } + } + } + // Then try and find a monochrome fallback font that could print this + // glyph: such fonts do *not* have a functor. We give priority to + // monochrome fonts for non-genuine emojis so that UI elements which + // used to render with them before the emojis font introduction (e.g. + // check marks in menus, or LSL dialogs text and buttons) do render the + // same way as they always did. HB + std::vector<size_t> emoji_fonts_idx; + for (size_t i = 0; i < count; ++i) + { + const fallback_font_t& pair = mFallbackFonts[i]; + if (pair.second) + { + // If this font got a functor, remember the index for later and + // try the next fallback font. HB + emoji_fonts_idx.push_back(i); + continue; + } + glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(pair.first, wch, glyph_index, + glyph_type); + } + } + // Everything failed so far: this character is not a genuine emoji, + // neither a special character known from our monochrome fallback + // fonts: make a last try, using the emoji font(s), but ignoring the + // functor to render using whatever (colorful) glyph that might be + // available in such fonts for this character. HB + for (size_t j = 0, count2 = emoji_fonts_idx.size(); j < count2; ++j) + { + const fallback_font_t& pair = mFallbackFonts[emoji_fonts_idx[j]]; + glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(pair.first, wch, glyph_index, + glyph_type); + } + } + } + + auto range_it = mCharGlyphInfoMap.equal_range(wch); + char_glyph_info_map_t::iterator iter = + std::find_if(range_it.first, range_it.second, + [&glyph_type](const char_glyph_info_map_t::value_type& entry) + { + return entry.second->mGlyphType == glyph_type; + }); + if (iter == range_it.second) + { + return addGlyphFromFont(this, wch, glyph_index, glyph_type); + } + return NULL; } 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; - - llassert(!mIsFallback); - fontp->renderGlyph(requested_glyph_type, glyph_index); - - EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified; - switch (fontp->mFTFace->glyph->bitmap.pixel_mode) - { - case FT_PIXEL_MODE_MONO: - case FT_PIXEL_MODE_GRAY: - bitmap_glyph_type = EFontGlyphType::Grayscale; - break; - case FT_PIXEL_MODE_BGRA: - bitmap_glyph_type = EFontGlyphType::Color; - break; - default: - llassert_always(true); - break; - } - S32 width = fontp->mFTFace->glyph->bitmap.width; - S32 height = fontp->mFTFace->glyph->bitmap.rows; - - 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; - gi->mYBitmapOffset = pos_y; - gi->mBitmapEntry = std::make_pair(bitmap_glyph_type, bitmap_num); - gi->mWidth = width; - gi->mHeight = height; - gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; - gi->mYBearing = fontp->mFTFace->glyph->bitmap_top; - // 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; - - insertGlyphInfo(wch, gi); - - if (requested_glyph_type != bitmap_glyph_type) - { - LLFontGlyphInfo* gi_temp = new LLFontGlyphInfo(*gi); - gi_temp->mGlyphType = bitmap_glyph_type; - insertGlyphInfo(wch, gi_temp); - } - - if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO - || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) - { - U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer; - S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch; - U8 *tmp_graydata = NULL; - - if (fontp->mFTFace->glyph->bitmap.pixel_mode - == FT_PIXEL_MODE_MONO) - { - // need to expand 1-bit bitmap to 8-bit graymap. - tmp_graydata = new U8[width * height]; - S32 xpos, ypos; - for (ypos = 0; ypos < height; ++ypos) - { - S32 bm_row_offset = buffer_row_stride * ypos; - for (xpos = 0; xpos < width; ++xpos) - { - U32 bm_col_offsetbyte = xpos / 8; - U32 bm_col_offsetbit = 7 - (xpos % 8); - U32 bit = - !!(buffer_data[bm_row_offset - + bm_col_offsetbyte - ] & (1 << bm_col_offsetbit) ); - tmp_graydata[width*ypos + xpos] = - 255 * bit; - } - } - // use newly-built graymap. - buffer_data = tmp_graydata; - buffer_row_stride = width; - } - - setSubImageLuminanceAlpha(pos_x, - pos_y, - bitmap_num, - width, - height, - buffer_data, - buffer_row_stride); - - if (tmp_graydata) - delete[] tmp_graydata; - } - else if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) - { - setSubImageBGRA(pos_x, - pos_y, - bitmap_num, - fontp->mFTFace->glyph->bitmap.width, - fontp->mFTFace->glyph->bitmap.rows, - fontp->mFTFace->glyph->bitmap.buffer, - llabs(fontp->mFTFace->glyph->bitmap.pitch)); - } else { - llassert(false); - } - - 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()); - - return gi; + if (mFTFace == NULL) + return NULL; + + llassert(!mIsFallback); + fontp->renderGlyph(requested_glyph_type, glyph_index); + + EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified; + switch (fontp->mFTFace->glyph->bitmap.pixel_mode) + { + case FT_PIXEL_MODE_MONO: + case FT_PIXEL_MODE_GRAY: + bitmap_glyph_type = EFontGlyphType::Grayscale; + break; + case FT_PIXEL_MODE_BGRA: + bitmap_glyph_type = EFontGlyphType::Color; + break; + default: + llassert_always(true); + break; + } + S32 width = fontp->mFTFace->glyph->bitmap.width; + S32 height = fontp->mFTFace->glyph->bitmap.rows; + + 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; + gi->mYBitmapOffset = pos_y; + gi->mBitmapEntry = std::make_pair(bitmap_glyph_type, bitmap_num); + gi->mWidth = width; + gi->mHeight = height; + gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; + gi->mYBearing = fontp->mFTFace->glyph->bitmap_top; + // 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; + + insertGlyphInfo(wch, gi); + + if (requested_glyph_type != bitmap_glyph_type) + { + LLFontGlyphInfo* gi_temp = new LLFontGlyphInfo(*gi); + gi_temp->mGlyphType = bitmap_glyph_type; + insertGlyphInfo(wch, gi_temp); + } + + if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO + || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) + { + U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer; + S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch; + U8 *tmp_graydata = NULL; + + if (fontp->mFTFace->glyph->bitmap.pixel_mode + == FT_PIXEL_MODE_MONO) + { + // need to expand 1-bit bitmap to 8-bit graymap. + tmp_graydata = new U8[width * height]; + S32 xpos, ypos; + for (ypos = 0; ypos < height; ++ypos) + { + S32 bm_row_offset = buffer_row_stride * ypos; + for (xpos = 0; xpos < width; ++xpos) + { + U32 bm_col_offsetbyte = xpos / 8; + U32 bm_col_offsetbit = 7 - (xpos % 8); + U32 bit = + !!(buffer_data[bm_row_offset + + bm_col_offsetbyte + ] & (1 << bm_col_offsetbit) ); + tmp_graydata[width*ypos + xpos] = + 255 * bit; + } + } + // use newly-built graymap. + buffer_data = tmp_graydata; + buffer_row_stride = width; + } + + setSubImageLuminanceAlpha(pos_x, + pos_y, + bitmap_num, + width, + height, + buffer_data, + buffer_row_stride); + + if (tmp_graydata) + delete[] tmp_graydata; + } + else if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) + { + setSubImageBGRA(pos_x, + pos_y, + bitmap_num, + fontp->mFTFace->glyph->bitmap.width, + fontp->mFTFace->glyph->bitmap.rows, + fontp->mFTFace->glyph->bitmap.buffer, + llabs(fontp->mFTFace->glyph->bitmap.pitch)); + } else { + llassert(false); + } + + 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()); + + return gi; } LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const { - std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); + std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); - char_glyph_info_map_t::iterator iter = (EFontGlyphType::Unspecified != glyph_type) - ? std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }) - : range_it.first; - if (iter != range_it.second) - { - return iter->second; - } - else - { - // this glyph doesn't yet exist, so render it and return the result - return addGlyph(wch, (EFontGlyphType::Unspecified != glyph_type) ? glyph_type : EFontGlyphType::Grayscale); - } + char_glyph_info_map_t::iterator iter = (EFontGlyphType::Unspecified != glyph_type) + ? std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }) + : range_it.first; + if (iter != range_it.second) + { + return iter->second; + } + else + { + // this glyph doesn't yet exist, so render it and return the result + return addGlyph(wch, (EFontGlyphType::Unspecified != glyph_type) ? glyph_type : EFontGlyphType::Grayscale); + } } void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const { - llassert(gi->mGlyphType < EFontGlyphType::Count); - std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); + llassert(gi->mGlyphType < EFontGlyphType::Count); + std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); - char_glyph_info_map_t::iterator iter = - std::find_if(range_it.first, range_it.second, [&gi](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == gi->mGlyphType; }); - if (iter != range_it.second) - { - delete iter->second; - iter->second = gi; - } - else - { - mCharGlyphInfoMap.insert(std::make_pair(wch, gi)); - } + char_glyph_info_map_t::iterator iter = + std::find_if(range_it.first, range_it.second, [&gi](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == gi->mGlyphType; }); + if (iter != range_it.second) + { + delete iter->second; + iter->second = gi; + } + else + { + mCharGlyphInfoMap.insert(std::make_pair(wch, gi)); + } } void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const { - if (mFTFace == NULL) - return; + if (mFTFace == NULL) + return; - FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT; - if (EFontGlyphType::Color == bitmap_type) - { - // We may not actually get a color render so our caller should always examine mFTFace->glyph->bitmap.pixel_mode - load_flags |= FT_LOAD_COLOR; - } + FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT; + if (EFontGlyphType::Color == bitmap_type) + { + // We may not actually get a color render so our caller should always examine mFTFace->glyph->bitmap.pixel_mode + load_flags |= FT_LOAD_COLOR; + } - FT_Error error = FT_Load_Glyph(mFTFace, glyph_index, load_flags); - if (FT_Err_Ok != error) - { - 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); - LL_WARNS_ONCE() << message << LL_ENDL; - error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR); - llassert_always_msg(FT_Err_Ok == error, message.c_str()); - } + FT_Error error = FT_Load_Glyph(mFTFace, glyph_index, load_flags); + if (FT_Err_Ok != error) + { + 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); + LL_WARNS_ONCE() << message << LL_ENDL; + error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR); + llassert_always_msg(FT_Err_Ok == error, message.c_str()); + } - llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) ); + llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) ); - mRenderGlyphCount++; + mRenderGlyphCount++; } void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi) { - resetBitmapCache(); - loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0); - if (!mIsFallback) - { - // This is the head of the list - need to rebuild ourself and all fallbacks. - if (mFallbackFonts.empty()) - { - LL_WARNS() << "LLFontGL::reset(), no fallback fonts present" << LL_ENDL; - } - else - { - for (fallback_font_vector_t::iterator it = mFallbackFonts.begin(); it != mFallbackFonts.end(); ++it) - { - it->first->reset(vert_dpi, horz_dpi); - } - } - } + resetBitmapCache(); + loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0); + if (!mIsFallback) + { + // This is the head of the list - need to rebuild ourself and all fallbacks. + if (mFallbackFonts.empty()) + { + LL_WARNS() << "LLFontGL::reset(), no fallback fonts present" << LL_ENDL; + } + else + { + for (fallback_font_vector_t::iterator it = mFallbackFonts.begin(); it != mFallbackFonts.end(); ++it) + { + it->first->reset(vert_dpi, horz_dpi); + } + } + } } void LLFontFreetype::resetBitmapCache() { - for (char_glyph_info_map_t::iterator it = mCharGlyphInfoMap.begin(), end_it = mCharGlyphInfoMap.end(); - it != end_it; - ++it) - { - delete it->second; - } - mCharGlyphInfoMap.clear(); - mFontBitmapCachep->reset(); + for (char_glyph_info_map_t::iterator it = mCharGlyphInfoMap.begin(), end_it = mCharGlyphInfoMap.end(); + it != end_it; + ++it) + { + delete it->second; + } + mCharGlyphInfoMap.clear(); + mFontBitmapCachep->reset(); - // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). - // This if was added as fix for EXT-4971. - if(!mIsFallback) - { - // Add the empty glyph - addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale); - } + // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). + // This if was added as fix for EXT-4971. + if(!mIsFallback) + { + // Add the empty glyph + addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale); + } } void LLFontFreetype::destroyGL() { - mFontBitmapCachep->destroyGL(); + mFontBitmapCachep->destroyGL(); } const std::string &LLFontFreetype::getName() const { - return mName; + return mName; } static void dumpFontBitmap(const LLImageRaw* image_raw, const std::string& file_name) { - LLPointer<LLImagePNG> tmpImage = new LLImagePNG(); - if ( (tmpImage->encode(image_raw, 0.0f)) && (tmpImage->save(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name))) ) - { - LL_INFOS("Font") << "Successfully saved " << file_name << LL_ENDL; - } - else - { - LL_WARNS("Font") << "Failed to save " << file_name << LL_ENDL; - } + LLPointer<LLImagePNG> tmpImage = new LLImagePNG(); + if ( (tmpImage->encode(image_raw, 0.0f)) && (tmpImage->save(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name))) ) + { + LL_INFOS("Font") << "Successfully saved " << file_name << LL_ENDL; + } + else + { + LL_WARNS("Font") << "Failed to save " << file_name << LL_ENDL; + } } void LLFontFreetype::dumpFontBitmaps() const { - // Dump all the regular bitmaps (if any) - for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Grayscale); idx < cnt; idx++) - { - dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, idx), llformat("%s_%d_%d_%d.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); - } + // Dump all the regular bitmaps (if any) + for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Grayscale); idx < cnt; idx++) + { + dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, idx), llformat("%s_%d_%d_%d.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); + } - // Dump all the color bitmaps (if any) - for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Color); idx < cnt; idx++) - { - dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, idx), llformat("%s_%d_%d_%d_clr.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); - } + // Dump all the color bitmaps (if any) + for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Color); idx < cnt; idx++) + { + dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, idx), llformat("%s_%d_%d_%d_clr.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); + } } const LLFontBitmapCache* LLFontFreetype::getFontBitmapCache() const { - return mFontBitmapCachep; + return mFontBitmapCachep; } void LLFontFreetype::setStyle(U8 style) { - mStyle = style; + mStyle = style; } U8 LLFontFreetype::getStyle() const { - return mStyle; + return mStyle; } bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const { - LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num); - llassert(!mIsFallback); - llassert(image_raw && (image_raw->getComponents() == 4)); + LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num); + llassert(!mIsFallback); + llassert(image_raw && (image_raw->getComponents() == 4)); - // NOTE: inspired by LLImageRaw::setSubImage() - U32* image_data = (U32*)image_raw->getData(); - if (!image_data) - { - return false; - } + // NOTE: inspired by LLImageRaw::setSubImage() + U32* image_data = (U32*)image_raw->getData(); + if (!image_data) + { + return false; + } - for (U32 idxRow = 0; idxRow < height; idxRow++) - { - const U32 nSrcRow = height - 1 - idxRow; - const U32 nSrcOffset = nSrcRow * width * image_raw->getComponents(); - const U32 nDstOffset = (y + idxRow) * image_raw->getWidth() + x; + for (U32 idxRow = 0; idxRow < height; idxRow++) + { + const U32 nSrcRow = height - 1 - idxRow; + const U32 nSrcOffset = nSrcRow * width * image_raw->getComponents(); + const U32 nDstOffset = (y + idxRow) * image_raw->getWidth() + x; - for (U32 idxCol = 0; idxCol < width; idxCol++) - { - U32 nTemp = nSrcOffset + idxCol * 4; - image_data[nDstOffset + idxCol] = data[nTemp + 3] << 24 | data[nTemp] << 16 | data[nTemp + 1] << 8 | data[nTemp + 2]; - } - } + for (U32 idxCol = 0; idxCol < width; idxCol++) + { + U32 nTemp = nSrcOffset + idxCol * 4; + image_data[nDstOffset + idxCol] = data[nTemp + 3] << 24 | data[nTemp] << 16 | data[nTemp + 1] << 8 | data[nTemp + 2]; + } + } - return true; + return true; } 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); + LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, bitmap_num); + + llassert(!mIsFallback); + llassert(image_raw && (image_raw->getComponents() == 2)); - llassert(!mIsFallback); - llassert(image_raw && (image_raw->getComponents() == 2)); - - U8 *target = image_raw->getData(); + U8 *target = image_raw->getData(); llassert(target); - if (!data || !target) - { - return; - } - - if (0 == stride) - stride = width; - - U32 i, j; - U32 to_offset; - U32 from_offset; - U32 target_width = image_raw->getWidth(); - for (i = 0; i < height; i++) - { - to_offset = (y + i)*target_width + x; - from_offset = (height - 1 - i)*stride; - for (j = 0; j < width; j++) - { - *(target + to_offset*2 + 1) = *(data + from_offset); - to_offset++; - from_offset++; - } - } + if (!data || !target) + { + return; + } + + if (0 == stride) + stride = width; + + U32 i, j; + U32 to_offset; + U32 from_offset; + U32 target_width = image_raw->getWidth(); + for (i = 0; i < height; i++) + { + to_offset = (y + i)*target_width + x; + from_offset = (height - 1 - i)*stride; + for (j = 0; j < width; j++) + { + *(target + to_offset*2 + 1) = *(data + from_offset); + to_offset++; + from_offset++; + } + } } |