summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/CMakeLists.txt4
-rw-r--r--indra/llrender/llfontbitmapcache.h2
-rw-r--r--indra/llrender/llfontfreetype.cpp630
-rw-r--r--indra/llrender/llfontfreetype.h380
-rw-r--r--indra/llrender/llfontgl.cpp864
-rw-r--r--indra/llrender/llfontgl.h217
-rw-r--r--indra/llrender/llfontregistry.cpp57
-rw-r--r--indra/llrender/llfontregistry.h2
8 files changed, 1551 insertions, 605 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 0e0fc6ce6c..aac650bec9 100644
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -26,7 +26,7 @@ include_directories(
set(llrender_SOURCE_FILES
llcubemap.cpp
- llfont.cpp
+ llfontfreetype.cpp
llfontgl.cpp
llfontbitmapcache.cpp
llfontregistry.cpp
@@ -45,7 +45,7 @@ set(llrender_HEADER_FILES
llcubemap.h
llfontgl.h
- llfont.h
+ llfontfreetype.h
llfontbitmapcache.h
llfontregistry.h
llgl.h
diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h
index 4beea0d026..4a57052b91 100644
--- a/indra/llrender/llfontbitmapcache.h
+++ b/indra/llrender/llfontbitmapcache.h
@@ -36,7 +36,7 @@
#include <vector>
// Maintain a collection of bitmaps containing rendered glyphs.
-// Generalizes the single-bitmap logic from LLFont and LLFontGL.
+// Generalizes the single-bitmap logic from LLFontFreetype and LLFontGL.
class LLFontBitmapCache: public LLRefCount
{
public:
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
new file mode 100644
index 0000000000..91a95cdd25
--- /dev/null
+++ b/indra/llrender/llfontfreetype.cpp
@@ -0,0 +1,630 @@
+/**
+ * @file llfontfreetype.cpp
+ * @brief Freetype font library wrapper
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llfontfreetype.h"
+
+// Freetype stuff
+#include <ft2build.h>
+
+// For some reason, this won't work if it's not wrapped in the ifdef
+#ifdef FT_FREETYPE_H
+#include FT_FREETYPE_H
+#endif
+
+#include "llerror.h"
+#include "llimage.h"
+//#include "llimagej2c.h"
+#include "llmath.h" // Linden math
+#include "llstring.h"
+//#include "imdebug.h"
+#include "llfontbitmapcache.h"
+#include "llgl.h"
+
+FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;
+
+LLFontManager *gFontManagerp = NULL;
+
+FT_Library gFTLibrary = NULL;
+
+//static
+void LLFontManager::initClass()
+{
+ gFontManagerp = new LLFontManager;
+}
+
+//static
+void LLFontManager::cleanupClass()
+{
+ delete gFontManagerp;
+ gFontManagerp = NULL;
+}
+
+LLFontManager::LLFontManager()
+{
+ int error;
+ error = FT_Init_FreeType(&gFTLibrary);
+ if (error)
+ {
+ // Clean up freetype libs.
+ llerrs << "Freetype initialization failure!" << llendl;
+ FT_Done_FreeType(gFTLibrary);
+ }
+}
+
+LLFontManager::~LLFontManager()
+{
+ FT_Done_FreeType(gFTLibrary);
+}
+
+
+LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
+: mGlyphIndex(index),
+ 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
+ mWidth(0), // In pixels
+ mHeight(0), // In pixels
+ mXAdvance(0.f), // In pixels
+ mYAdvance(0.f), // In pixels
+ mIsRendered(FALSE),
+ mMetricsValid(FALSE)
+{
+}
+
+LLFontFreetype::LLFontFreetype()
+: mFontBitmapCachep(new LLFontBitmapCache),
+ mValid(FALSE),
+ mAscender(0.f),
+ mDescender(0.f),
+ mLineHeight(0.f),
+ mIsFallback(FALSE),
+ mFTFace(NULL),
+ mRenderGlyphCount(0),
+ mAddGlyphCount(0),
+ mPointSize(0)
+{
+}
+
+
+LLFontFreetype::~LLFontFreetype()
+{
+ // Clean up freetype libs.
+ if (mFTFace)
+ FT_Done_Face(mFTFace);
+ mFTFace = NULL;
+
+ // Delete glyph info
+ std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer());
+
+ // mFontBitmapCachep will be cleaned up by LLPointer destructor.
+ // mFallbackFonts cleaned up by LLPointer destructor
+}
+
+BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback)
+{
+ // 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;
+
+ error = FT_New_Face( gFTLibrary,
+ filename.c_str(),
+ 0,
+ &mFTFace );
+
+ if (error)
+ {
+ 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);
+ 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;
+
+ // 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 = llround(0.5f + (x_max - x_min));
+ S32 max_char_height = llround(0.5f + (y_max - y_min));
+
+ mFontBitmapCachep->init(components, max_char_width, max_char_height);
+
+ if (!mFTFace->charmap)
+ {
+ //llinfos << " no unicode encoding, set whatever encoding there is..." << llendl;
+ FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]);
+ }
+
+ if (!mIsFallback)
+ {
+ // Add the default glyph
+ addGlyph(0, 0);
+ }
+
+ mName = filename;
+ mPointSize = point_size;
+
+ return TRUE;
+}
+
+void LLFontFreetype::setFallbackFonts(const font_vector_t &font)
+{
+ mFallbackFonts = font;
+}
+
+const LLFontFreetype::font_vector_t &LLFontFreetype::getFallbackFonts() const
+{
+ return mFallbackFonts;
+}
+
+F32 LLFontFreetype::getLineHeight() const
+{
+ return mLineHeight;
+}
+
+F32 LLFontFreetype::getAscenderHeight() const
+{
+ return mAscender;
+}
+
+F32 LLFontFreetype::getDescenderHeight() const
+{
+ return mDescender;
+}
+
+F32 LLFontFreetype::getXAdvance(llwchar wch) const
+{
+ if (mFTFace == NULL)
+ return 0.0;
+
+ llassert(!mIsFallback);
+ U32 glyph_index;
+
+ // Return existing info only if it is current
+ LLFontGlyphInfo* gi = getGlyphInfo(wch);
+ if (gi && gi->mMetricsValid)
+ {
+ return gi->mXAdvance;
+ }
+
+ const LLFontFreetype* fontp = this;
+
+ // Initialize char to glyph map
+ glyph_index = FT_Get_Char_Index(mFTFace, wch);
+ if (glyph_index == 0)
+ {
+ font_vector_t::const_iterator iter;
+ for(iter = mFallbackFonts.begin(); (iter != mFallbackFonts.end()) && (glyph_index == 0); iter++)
+ {
+ glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
+ if(glyph_index)
+ {
+ fontp = *iter;
+ }
+ }
+ }
+
+ if (glyph_index)
+ {
+ // This font has this glyph
+ fontp->renderGlyph(glyph_index);
+
+ // Create the entry if it's not there
+ char_glyph_info_map_t::iterator iter2 = mCharGlyphInfoMap.find(wch);
+ if (iter2 == mCharGlyphInfoMap.end())
+ {
+ gi = new LLFontGlyphInfo(glyph_index);
+ insertGlyphInfo(wch, gi);
+ }
+ else
+ {
+ gi = iter2->second;
+ }
+
+ gi->mWidth = fontp->mFTFace->glyph->bitmap.width;
+ gi->mHeight = fontp->mFTFace->glyph->bitmap.rows;
+
+ // 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;
+ gi->mMetricsValid = TRUE;
+ return gi->mXAdvance;
+ }
+ else
+ {
+ gi = get_if_there(mCharGlyphInfoMap, (llwchar)0, (LLFontGlyphInfo*)NULL);
+ if (gi)
+ {
+ return gi->mXAdvance;
+ }
+ }
+
+ // Last ditch fallback - no glyphs defined at all.
+ return (F32)mFontBitmapCachep->getMaxCharWidth();
+}
+
+F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const
+{
+ if (mFTFace == NULL)
+ return 0.0;
+
+ llassert(!mIsFallback);
+ LLFontGlyphInfo* left_glyph_info = get_if_there(mCharGlyphInfoMap, char_left, (LLFontGlyphInfo*)NULL);
+ U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;
+ // Kern this puppy.
+ LLFontGlyphInfo* right_glyph_info = get_if_there(mCharGlyphInfoMap, char_right, (LLFontGlyphInfo*)NULL);
+ 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);
+}
+
+BOOL LLFontFreetype::hasGlyph(llwchar wch) const
+{
+ llassert(!mIsFallback);
+ const LLFontGlyphInfo* gi = getGlyphInfo(wch);
+ if (gi && gi->mIsRendered)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+BOOL LLFontFreetype::addChar(llwchar wch) const
+{
+ if (mFTFace == NULL)
+ return FALSE;
+
+ llassert(!mIsFallback);
+ //lldebugs << "Adding new glyph for " << wch << " to font" << llendl;
+
+ FT_UInt glyph_index;
+
+ // Initialize char to glyph map
+ glyph_index = FT_Get_Char_Index(mFTFace, wch);
+ if (glyph_index == 0)
+ {
+ //llinfos << "Trying to add glyph from fallback font!" << llendl
+ font_vector_t::const_iterator iter;
+ for(iter = mFallbackFonts.begin(); iter != mFallbackFonts.end(); iter++)
+ {
+ glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
+ if (glyph_index)
+ {
+ addGlyphFromFont(*iter, wch, glyph_index);
+ return TRUE;
+ }
+ }
+ }
+
+ char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
+ if (iter == mCharGlyphInfoMap.end() || !(iter->second->mIsRendered))
+ {
+ BOOL result = addGlyph(wch, glyph_index);
+ return result;
+ }
+ return FALSE;
+}
+
+BOOL LLFontFreetype::addGlyph(llwchar wch, U32 glyph_index) const
+{
+ return addGlyphFromFont(this, wch, glyph_index);
+}
+
+BOOL LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const
+{
+ if (mFTFace == NULL)
+ return FALSE;
+
+ llassert(!mIsFallback);
+ fontp->renderGlyph(glyph_index);
+ S32 width = fontp->mFTFace->glyph->bitmap.width;
+ S32 height = fontp->mFTFace->glyph->bitmap.rows;
+
+ S32 pos_x, pos_y;
+ S32 bitmap_num;
+ mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_num);
+ mAddGlyphCount++;
+
+ LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index);
+ gi->mXBitmapOffset = pos_x;
+ gi->mYBitmapOffset = pos_y;
+ gi->mBitmapNum = 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;
+ gi->mIsRendered = TRUE;
+ gi->mMetricsValid = TRUE;
+
+ insertGlyphInfo(wch, gi);
+
+ llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
+ || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
+
+ 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;
+ }
+
+ switch (mFontBitmapCachep->getNumComponents())
+ {
+ case 1:
+ mFontBitmapCachep->getImageRaw(bitmap_num)->setSubImage(pos_x,
+ pos_y,
+ width,
+ height,
+ buffer_data,
+ buffer_row_stride,
+ TRUE);
+ break;
+ case 2:
+ setSubImageLuminanceAlpha(pos_x,
+ pos_y,
+ bitmap_num,
+ width,
+ height,
+ buffer_data,
+ buffer_row_stride);
+ break;
+ default:
+ break;
+ }
+
+ if (tmp_graydata)
+ delete[] tmp_graydata;
+ } else {
+ // we don't know how to handle this pixel format from FreeType;
+ // omit it from the font-image.
+ }
+
+ return TRUE;
+}
+
+LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch) const
+{
+ char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
+ if (iter != mCharGlyphInfoMap.end())
+ {
+ return iter->second;
+ }
+ return NULL;
+}
+
+void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
+{
+ char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
+ if (iter != mCharGlyphInfoMap.end())
+ {
+ delete iter->second;
+ iter->second = gi;
+ }
+ else
+ {
+ mCharGlyphInfoMap[wch] = gi;
+ }
+}
+
+void LLFontFreetype::renderGlyph(U32 glyph_index) const
+{
+ if (mFTFace == NULL)
+ return;
+
+ int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_DEFAULT );
+ llassert(!error);
+
+ error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode);
+
+ mRenderGlyphCount++;
+
+ llassert(!error);
+}
+
+void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
+{
+ if (!mIsFallback)
+ {
+ // This is the head of the list - need to rebuild ourself and all fallbacks.
+ loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mFontBitmapCachep->getNumComponents(), mIsFallback);
+
+ if (mFallbackFonts.empty())
+ {
+ llwarns << "LLFontGL::reset(), no fallback fonts present" << llendl;
+ }
+ else
+ {
+ for(font_vector_t::iterator it = mFallbackFonts.begin();
+ it != mFallbackFonts.end();
+ ++it)
+ {
+ (*it)->reset(vert_dpi, horz_dpi);
+ }
+ }
+ }
+ resetBitmapCache();
+}
+
+void LLFontFreetype::resetBitmapCache()
+{
+ // Iterate through glyphs and clear the mIsRendered flag
+ for (char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.begin();
+ iter != mCharGlyphInfoMap.end(); ++iter)
+ {
+ iter->second->mIsRendered = FALSE;
+ //FIXME: this is only strictly necessary when resetting the entire font,
+ //not just flushing the bitmap
+ iter->second->mMetricsValid = FALSE;
+ }
+ mFontBitmapCachep->reset();
+
+ // Add the empty glyph`5
+ addGlyph(0, 0);
+}
+
+void LLFontFreetype::destroyGL()
+{
+ mFontBitmapCachep->destroyGL();
+}
+
+BOOL LLFontFreetype::getIsFallback() const
+{
+ return mIsFallback;
+}
+
+const std::string &LLFontFreetype::getName() const
+{
+ return mName;
+}
+
+F32 LLFontFreetype::getPointSize() const
+{
+ return mPointSize;
+}
+
+const LLPointer<LLFontBitmapCache> LLFontFreetype::getFontBitmapCache() const
+{
+ return mFontBitmapCachep;
+}
+
+void LLFontFreetype::setStyle(U8 style)
+{
+ mStyle = style;
+}
+
+U8 LLFontFreetype::getStyle() const
+{
+ return mStyle;
+}
+
+void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const
+{
+ LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num);
+
+ llassert(!mIsFallback);
+ llassert(image_raw && (image_raw->getComponents() == 2));
+
+
+ U8 *target = image_raw->getData();
+
+ if (!data)
+ {
+ 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++;
+ }
+ }
+}
+
diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h
new file mode 100644
index 0000000000..0520ef2cd6
--- /dev/null
+++ b/indra/llrender/llfontfreetype.h
@@ -0,0 +1,380 @@
+/**
+ * @file llfontfreetype.h
+ * @brief Font library wrapper
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFONTFREETYPE_H
+#define LL_LLFONTFREETYPE_H
+
+#include <map>
+#include "llpointer.h"
+#include "llstl.h"
+
+#include "llimagegl.h"
+#include "llfontbitmapcache.h"
+
+// Hack. FT_Face is just a typedef for a pointer to a struct,
+// but there's no simple forward declarations file for FreeType,
+// and the main include file is 200K.
+// We'll forward declare the struct here. JC
+struct FT_FaceRec_;
+typedef struct FT_FaceRec_* LLFT_Face;
+
+class LLFontManager
+{
+public:
+ static void initClass();
+ static void cleanupClass();
+
+private:
+ LLFontManager();
+ ~LLFontManager();
+};
+
+class LLFontGlyphInfo
+{
+public:
+ LLFontGlyphInfo(U32 index);
+
+ U32 mGlyphIndex;
+
+ // Metrics
+ S32 mWidth; // In pixels
+ S32 mHeight; // In pixels
+ F32 mXAdvance; // In pixels
+ F32 mYAdvance; // In pixels
+ BOOL mMetricsValid; // We have up-to-date metrics for this glyph
+
+ // Information for actually rendering
+ BOOL mIsRendered; // We actually have rendered this glyph
+ S32 mXBitmapOffset; // Offset to the origin in the bitmap
+ S32 mYBitmapOffset; // Offset to the origin in the bitmap
+ S32 mXBearing; // Distance from baseline to left in pixels
+ S32 mYBearing; // Distance from baseline to top in pixels
+ S32 mBitmapNum; // Which bitmap in the bitmap cache contains this glyph
+};
+
+extern LLFontManager *gFontManagerp;
+
+class LLFontFreetype : public LLRefCount
+{
+public:
+ LLFontFreetype();
+ ~LLFontFreetype();
+
+ // is_fallback should be true for fallback fonts that aren't used
+ // to render directly (Unicode backup, primarily)
+ BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback);
+
+ typedef std::vector<LLPointer<LLFontFreetype> > font_vector_t;
+
+ void setFallbackFonts(const font_vector_t &font);
+ const font_vector_t &getFallbackFonts() const;
+
+ // Global font metrics - in units of pixels
+ F32 getLineHeight() const;
+ F32 getAscenderHeight() const;
+ F32 getDescenderHeight() const;
+
+
+// For a lowercase "g":
+//
+// ------------------------------
+// ^ ^
+// | |
+// xxx x |Ascender
+// x x v |
+// --------- xxxx-------------- Baseline
+// ^ x |
+// | Descender x |
+// v xxxx |LineHeight
+// ----------------------- |
+// v
+// ------------------------------
+
+ enum
+ {
+ FIRST_CHAR = 32,
+ NUM_CHARS = 127 - 32,
+ LAST_CHAR_BASIC = 127,
+
+ // Need full 8-bit ascii range for spanish
+ NUM_CHARS_FULL = 255 - 32,
+ LAST_CHAR_FULL = 255
+ };
+
+ F32 getXAdvance(llwchar wc) const;
+ F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters
+
+ BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character
+ BOOL addChar(llwchar wch) const; // Add a new character to the font if necessary
+ BOOL addGlyph(llwchar wch, U32 glyph_index) const; // Add a new glyph to the existing font
+ BOOL addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
+
+ LLFontGlyphInfo* getGlyphInfo(llwchar wch) const;
+
+ void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const;
+ void renderGlyph(U32 glyph_index) const;
+
+ void reset(F32 vert_dpi, F32 horz_dpi);
+ void resetBitmapCache();
+
+ void destroyGL();
+
+ BOOL getIsFallback() const;
+
+ const std::string& getName() const;
+
+ F32 getPointSize() const;
+
+ const LLPointer<LLFontBitmapCache> getFontBitmapCache() const;
+
+ void setStyle(U8 style);
+ U8 getStyle() const;
+
+private:
+ void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const;
+
+ std::string mName;
+
+ U8 mStyle;
+
+ F32 mPointSize;
+ F32 mAscender;
+ F32 mDescender;
+ F32 mLineHeight;
+
+ LLFT_Face mFTFace;
+
+ BOOL mIsFallback;
+ font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
+
+ BOOL mValid;
+
+ typedef std::map<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
+ mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap
+
+ mutable LLPointer<LLFontBitmapCache> mFontBitmapCachep;
+
+ mutable S32 mRenderGlyphCount;
+ mutable S32 mAddGlyphCount;
+};
+
+#endif // LL_FONTFREETYPE_H
+/**
+ * @file llfontfreetype.h
+ * @brief Font library wrapper
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ *
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLFONTFREETYPE_H
+#define LL_LLFONTFREETYPE_H
+
+#include <map>
+#include "llpointer.h"
+#include "llstl.h"
+
+#include "llimagegl.h"
+#include "llfontbitmapcache.h"
+
+// Hack. FT_Face is just a typedef for a pointer to a struct,
+// but there's no simple forward declarations file for FreeType,
+// and the main include file is 200K.
+// We'll forward declare the struct here. JC
+struct FT_FaceRec_;
+typedef struct FT_FaceRec_* LLFT_Face;
+
+class LLFontManager
+{
+public:
+ static void initClass();
+ static void cleanupClass();
+
+private:
+ LLFontManager();
+ ~LLFontManager();
+};
+
+class LLFontGlyphInfo
+{
+public:
+ LLFontGlyphInfo(U32 index);
+
+ U32 mGlyphIndex;
+
+ // Metrics
+ S32 mWidth; // In pixels
+ S32 mHeight; // In pixels
+ F32 mXAdvance; // In pixels
+ F32 mYAdvance; // In pixels
+ BOOL mMetricsValid; // We have up-to-date metrics for this glyph
+
+ // Information for actually rendering
+ BOOL mIsRendered; // We actually have rendered this glyph
+ S32 mXBitmapOffset; // Offset to the origin in the bitmap
+ S32 mYBitmapOffset; // Offset to the origin in the bitmap
+ S32 mXBearing; // Distance from baseline to left in pixels
+ S32 mYBearing; // Distance from baseline to top in pixels
+ S32 mBitmapNum; // Which bitmap in the bitmap cache contains this glyph
+};
+
+extern LLFontManager *gFontManagerp;
+
+class LLFontFreetype : public LLRefCount
+{
+public:
+ LLFontFreetype();
+ ~LLFontFreetype();
+
+ // is_fallback should be true for fallback fonts that aren't used
+ // to render directly (Unicode backup, primarily)
+ BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback);
+
+ typedef std::vector<LLPointer<LLFontFreetype> > font_vector_t;
+
+ void setFallbackFonts(const font_vector_t &font);
+ const font_vector_t &getFallbackFonts() const;
+
+ // Global font metrics - in units of pixels
+ F32 getLineHeight() const;
+ F32 getAscenderHeight() const;
+ F32 getDescenderHeight() const;
+
+
+// For a lowercase "g":
+//
+// ------------------------------
+// ^ ^
+// | |
+// xxx x |Ascender
+// x x v |
+// --------- xxxx-------------- Baseline
+// ^ x |
+// | Descender x |
+// v xxxx |LineHeight
+// ----------------------- |
+// v
+// ------------------------------
+
+ enum
+ {
+ FIRST_CHAR = 32,
+ NUM_CHARS = 127 - 32,
+ LAST_CHAR_BASIC = 127,
+
+ // Need full 8-bit ascii range for spanish
+ NUM_CHARS_FULL = 255 - 32,
+ LAST_CHAR_FULL = 255
+ };
+
+ F32 getXAdvance(llwchar wc) const;
+ F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters
+
+ BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character
+ BOOL addChar(llwchar wch) const; // Add a new character to the font if necessary
+ BOOL addGlyph(llwchar wch, U32 glyph_index) const; // Add a new glyph to the existing font
+ BOOL addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
+
+ LLFontGlyphInfo* getGlyphInfo(llwchar wch) const;
+
+ void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const;
+ void renderGlyph(U32 glyph_index) const;
+
+ void reset(F32 vert_dpi, F32 horz_dpi);
+ void resetBitmapCache();
+
+ void destroyGL();
+
+ BOOL getIsFallback() const;
+
+ const std::string& getName() const;
+
+ F32 getPointSize() const;
+
+ const LLPointer<LLFontBitmapCache> getFontBitmapCache() const;
+
+ void setStyle(U8 style);
+ U8 getStyle() const;
+
+private:
+ void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const;
+
+ std::string mName;
+
+ U8 mStyle;
+
+ F32 mPointSize;
+ F32 mAscender;
+ F32 mDescender;
+ F32 mLineHeight;
+
+ LLFT_Face mFTFace;
+
+ BOOL mIsFallback;
+ font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
+
+ BOOL mValid;
+
+ typedef std::map<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
+ mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap
+
+ mutable LLPointer<LLFontBitmapCache> mFontBitmapCachep;
+
+ mutable S32 mRenderGlyphCount;
+ mutable S32 mAddGlyphCount;
+};
+
+#endif // LL_FONTFREETYPE_H
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 0b57d86c78..32a008047c 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -35,7 +35,7 @@
#include "llfontgl.h"
// Linden library includes
-#include "llfont.h"
+#include "llfontfreetype.h"
#include "llfontbitmapcache.h"
#include "llfontregistry.h"
#include "llgl.h"
@@ -73,54 +73,25 @@ const F32 PIXEL_CORRECTION_DISTANCE = 0.01f;
const F32 PAD_UVY = 0.5f; // half of vertical padding between glyphs in the glyph texture
const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f;
-F32 llfont_round_x(F32 x)
+static F32 llfont_round_x(F32 x)
{
//return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX;
//return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY;
return x;
}
-F32 llfont_round_y(F32 y)
+static F32 llfont_round_y(F32 y)
{
//return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY;
//return llfloor(y+0.5f);
return y;
}
-// static
-U8 LLFontGL::getStyleFromString(const std::string &style)
-{
- S32 ret = 0;
- if (style.find("NORMAL") != style.npos)
- {
- ret |= NORMAL;
- }
- if (style.find("BOLD") != style.npos)
- {
- ret |= BOLD;
- }
- if (style.find("ITALIC") != style.npos)
- {
- ret |= ITALIC;
- }
- if (style.find("UNDERLINE") != style.npos)
- {
- ret |= UNDERLINE;
- }
- return ret;
-}
-
LLFontGL::LLFontGL()
- : LLFont()
{
clearEmbeddedChars();
}
-LLFontGL::LLFontGL(const LLFontGL &source)
-{
- llerrs << "Not implemented!" << llendl;
-}
-
LLFontGL::~LLFontGL()
{
clearEmbeddedChars();
@@ -128,293 +99,26 @@ LLFontGL::~LLFontGL()
void LLFontGL::reset()
{
- if (!mIsFallback)
- {
- // This is the head of the list - need to rebuild ourself and all fallbacks.
- loadFace(mName,mPointSize,sVertDPI,sHorizDPI,mFontBitmapCachep->getNumComponents(),mIsFallback);
- if (mFallbackFontp==NULL)
- {
- llwarns << "LLFontGL::reset(), no fallback fonts present" << llendl;
- }
- else
- {
- for (LLFontList::iterator it = mFallbackFontp->begin();
- it != mFallbackFontp->end();
- ++it)
- {
- (*it)->reset();
- }
- }
- }
- resetBitmapCache();
-}
-
-// static
-std::string LLFontGL::getFontPathSystem()
-{
- std::string system_path;
-
- // Try to figure out where the system's font files are stored.
- char *system_root = NULL;
-#if LL_WINDOWS
- system_root = getenv("SystemRoot"); /* Flawfinder: ignore */
- if (!system_root)
- {
- llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl;
- }
-#endif
-
- if (system_root)
- {
- system_path = llformat("%s/fonts/", system_root);
- }
- else
- {
-#if LL_WINDOWS
- // HACK for windows 98/Me
- system_path = "/WINDOWS/FONTS/";
-#elif LL_DARWIN
- // HACK for Mac OS X
- system_path = "/System/Library/Fonts/";
-#endif
- }
- return system_path;
-}
-
-
-// static
-std::string LLFontGL::getFontPathLocal()
-{
- std::string local_path;
-
- // Backup files if we can't load from system fonts directory.
- // We could store this in an end-user writable directory to allow
- // end users to switch fonts.
- if (LLFontGL::sAppDir.length())
- {
- // use specified application dir to look for fonts
- local_path = LLFontGL::sAppDir + "/fonts/";
- }
- else
- {
- // assume working directory is executable directory
- local_path = "./fonts/";
- }
- return local_path;
-}
-
-bool findOrCreateFont(LLFontGL*& fontp, const LLFontDescriptor& desc)
-{
- // Don't delete existing fonts, if any, here, because they've
- // already been deleted by LLFontRegistry::clear()
- fontp = LLFontGL::getFont(desc);
- return (fontp != NULL);
-}
-
-// static
-void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale,
- const std::string& app_dir,
- const std::vector<std::string>& xui_paths,
- bool create_gl_textures)
-{
- sVertDPI = (F32)llfloor(screen_dpi * y_scale);
- sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
- sScaleX = x_scale;
- sScaleY = y_scale;
- sAppDir = app_dir;
-
- // Font registry init
- if (!sFontRegistry)
- {
- sFontRegistry = new LLFontRegistry(xui_paths, create_gl_textures);
- sFontRegistry->parseFontInfo("fonts.xml");
- }
- else
- {
- sFontRegistry->reset();
- }
-}
-
-// Force standard fonts to get generated up front.
-// This is primarily for error detection purposes.
-// Don't do this during initClass because it can be slow and we want to get
-// the viewer window on screen first. JC
-// static
-bool LLFontGL::loadDefaultFonts()
-{
- bool succ = true;
- succ &= (NULL != getFontSansSerifSmall());
- succ &= (NULL != getFontSansSerif());
- succ &= (NULL != getFontSansSerifBig());
- succ &= (NULL != getFontSansSerifHuge());
- succ &= (NULL != getFontSansSerifBold());
- succ &= (NULL != getFontMonospace());
- succ &= (NULL != getFontExtChar());
- return succ;
-}
-
-
-
-// static
-void LLFontGL::destroyDefaultFonts()
-{
- // Remove the actual fonts.
- delete sFontRegistry;
- sFontRegistry = NULL;
-}
-
-//static
-void LLFontGL::destroyAllGL()
-{
- if (sFontRegistry)
- {
- sFontRegistry->destroyGL();
- }
+ mFontFreetype->reset(sVertDPI, sHorizDPI);
}
void LLFontGL::destroyGL()
{
- mFontBitmapCachep->destroyGL();
-}
-
-
-
-LLFontGL &LLFontGL::operator=(const LLFontGL &source)
-{
- llerrs << "Not implemented" << llendl;
- return *this;
-}
-
-BOOL LLFontGL::loadFace(const std::string& filename,
- const F32 point_size, const F32 vert_dpi, const F32 horz_dpi,
- const S32 components, BOOL is_fallback)
-{
- if (!LLFont::loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback))
- {
- return FALSE;
- }
- return TRUE;
-}
-
-//static
-LLFontGL* LLFontGL::getFontMonospace()
-{
- return getFont(LLFontDescriptor("Monospace","Monospace",0));
-}
-
-//static
-LLFontGL* LLFontGL::getFontSansSerifSmall()
-{
- return getFont(LLFontDescriptor("SansSerif","Small",0));
-}
-
-//static
-LLFontGL* LLFontGL::getFontSansSerif()
-{
- return getFont(LLFontDescriptor("SansSerif","Medium",0));
-}
-
-//static
-LLFontGL* LLFontGL::getFontSansSerifBig()
-{
- return getFont(LLFontDescriptor("SansSerif","Large",0));
-}
-
-//static
-LLFontGL* LLFontGL::getFontSansSerifHuge()
-{
- return getFont(LLFontDescriptor("SansSerif","Huge",0));
-}
-
-//static
-LLFontGL* LLFontGL::getFontSansSerifBold()
-{
- return getFont(LLFontDescriptor("SansSerif","Medium",BOLD));
-}
-
-//static
-LLFontGL* LLFontGL::getFontExtChar()
-{
- return getFontSansSerif();
-}
-
-//static
-LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc)
-{
- return sFontRegistry->getFont(desc);
-}
-
-//static
-LLFontGL* LLFontGL::getFontByName(const std::string& name)
-{
- // check for most common fonts first
- if (name == "SANSSERIF")
- {
- return getFontSansSerif();
- }
- else if (name == "SANSSERIF_SMALL")
- {
- return getFontSansSerifSmall();
- }
- else if (name == "SANSSERIF_BIG")
- {
- return getFontSansSerifBig();
- }
- else if (name == "SMALL" || name == "OCRA")
- {
- // *BUG: Should this be "MONOSPACE"? Do we use "OCRA" anymore?
- // Does "SMALL" mean "SERIF"?
- return getFontMonospace();
- }
- else
- {
- return NULL;
- }
+ mFontFreetype->destroyGL();
}
-BOOL LLFontGL::addChar(const llwchar wch) const
+BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback)
{
- if (!LLFont::addChar(wch))
+ if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
{
- return FALSE;
+ mFontFreetype = new LLFontFreetype;
}
- stop_glerror();
-
- LLFontGlyphInfo *glyph_info = getGlyphInfo(wch);
- U32 bitmap_num = glyph_info->mBitmapNum;
- LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num);
- LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num);
- image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());
- return TRUE;
+ return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback);
}
-
-S32 LLFontGL::renderUTF8(const std::string &text, const S32 offset,
- const F32 x, const F32 y,
- const LLColor4 &color,
- const HAlign halign, const VAlign valign,
- U8 style,
- ShadowType shadow,
- const S32 max_chars, const S32 max_pixels,
- F32* right_x,
- BOOL use_ellipses) const
-{
- LLWString wstr = utf8str_to_wstring(text);
- return render(wstr, offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, FALSE, use_ellipses);
-}
-
-S32 LLFontGL::render(const LLWString &wstr,
- const S32 begin_offset,
- const F32 x, const F32 y,
- const LLColor4 &color,
- const HAlign halign, const VAlign valign,
- U8 style,
- ShadowType shadow,
- const S32 max_chars, S32 max_pixels,
- F32* right_x,
- BOOL use_embedded,
- BOOL use_ellipses) const
+S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
+ ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_embedded, BOOL use_ellipses) const
{
if(!sDisplayFont) //do not display texts
{
@@ -430,8 +134,9 @@ S32 LLFontGL::render(const LLWString &wstr,
S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);
- // Strip off any style bits that are already accounted for by the font.
- style = style & (~getFontDesc().getStyle());
+ // determine which style flags need to be added programmatically by striping off the
+ // style bits that are drawn by the underlying Freetype font
+ U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle();
F32 drop_shadow_strength = 0.f;
if (shadow != NO_SHADOW)
@@ -483,13 +188,13 @@ S32 LLFontGL::render(const LLWString &wstr,
switch (valign)
{
case TOP:
- cur_y -= mAscender;
+ cur_y -= mFontFreetype->getAscenderHeight();
break;
case BOTTOM:
- cur_y += mDescender;
+ cur_y += mFontFreetype->getDescenderHeight();
break;
case VCENTER:
- cur_y -= ((mAscender - mDescender)/2.f);
+ cur_y -= ((mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight())/2.f);
break;
case BASELINE:
// Baseline, do nothing.
@@ -517,10 +222,12 @@ S32 LLFontGL::render(const LLWString &wstr,
F32 start_x = cur_x;
- F32 inv_width = 1.f / mFontBitmapCachep->getBitmapWidth();
- F32 inv_height = 1.f / mFontBitmapCachep->getBitmapHeight();
+ const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();
+
+ F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
+ F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();
- const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;
+ const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
BOOL draw_ellipses = FALSE;
@@ -576,11 +283,11 @@ S32 LLFontGL::render(const LLWString &wstr,
// snap origin to whole screen pixel
const F32 ext_x = (F32)llround(cur_render_x + (EXT_X_BEARING * sScaleX));
- const F32 ext_y = (F32)llround(cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight));
+ const F32 ext_y = (F32)llround(cur_render_y + (EXT_Y_BEARING * sScaleY + mFontFreetype->getAscenderHeight() - mFontFreetype->getLineHeight()));
LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);
- drawGlyph(screen_rect, uv_rect, LLColor4::white, style, shadow, drop_shadow_strength);
+ drawGlyph(screen_rect, uv_rect, LLColor4::white, style_to_add, shadow, drop_shadow_strength);
if (!label.empty())
{
@@ -609,19 +316,19 @@ S32 LLFontGL::render(const LLWString &wstr,
}
else
{
- if (!hasGlyph(wch))
+ if (!mFontFreetype->hasGlyph(wch))
{
addChar(wch);
}
- const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
+ const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch);
if (!fgi)
{
llerrs << "Missing Glyph Info" << llendl;
break;
}
// Per-glyph bitmap texture.
- LLImageGL *image_gl = mFontBitmapCachep->getImageGL(fgi->mBitmapNum);
+ LLImageGL *image_gl = mFontFreetype->getFontBitmapCache()->getImageGL(fgi->mBitmapNum);
if (last_bound_texture != image_gl)
{
gGL.getTexUnit(0)->bind(image_gl);
@@ -646,7 +353,7 @@ S32 LLFontGL::render(const LLWString &wstr,
llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
- drawGlyph(screen_rect, uv_rect, color, style, shadow, drop_shadow_strength);
+ drawGlyph(screen_rect, uv_rect, color, style_to_add, shadow, drop_shadow_strength);
chars_drawn++;
cur_x += fgi->mXAdvance;
@@ -656,11 +363,11 @@ S32 LLFontGL::render(const LLWString &wstr,
if (next_char && (next_char < LAST_CHARACTER))
{
// Kern this puppy.
- if (!hasGlyph(next_char))
+ if (!mFontFreetype->hasGlyph(next_char))
{
addChar(next_char);
}
- cur_x += getXKerning(wch, next_char);
+ cur_x += mFontFreetype->getXKerning(wch, next_char);
}
// Round after kerning.
@@ -680,12 +387,14 @@ S32 LLFontGL::render(const LLWString &wstr,
*right_x = cur_x / sScaleX;
}
- if (style & UNDERLINE)
+ if (style_to_add & UNDERLINE)
{
+ F32 descender = mFontFreetype->getDescenderHeight();
+
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gGL.begin(LLRender::LINES);
- gGL.vertex2f(start_x, cur_y - (mDescender));
- gGL.vertex2f(cur_x, cur_y - (mDescender));
+ gGL.vertex2f(start_x, cur_y - (descender));
+ gGL.vertex2f(cur_x, cur_y - (descender));
gGL.end();
}
@@ -703,7 +412,7 @@ S32 LLFontGL::render(const LLWString &wstr,
cur_x / sScaleX, (F32)y,
color,
LEFT, valign,
- style,
+ style_to_add,
shadow,
S32_MAX, max_pixels,
right_x,
@@ -716,6 +425,41 @@ S32 LLFontGL::render(const LLWString &wstr,
return chars_drawn;
}
+S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const
+{
+ return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE, FALSE);
+}
+
+S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
+{
+ return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, FALSE, use_ellipses);
+}
+
+S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const
+{
+ return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
+}
+
+S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const
+{
+ return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE);
+}
+
+// font metrics - override for LLFontFreetype that returns units of virtual pixels
+F32 LLFontGL::getLineHeight() const
+{
+ return (F32)llround(mFontFreetype->getLineHeight() / sScaleY);
+}
+
+F32 LLFontGL::getAscenderHeight() const
+{
+ return (F32)llround(mFontFreetype->getAscenderHeight() / sScaleY);
+}
+
+F32 LLFontGL::getDescenderHeight() const
+{
+ return (F32)llround(mFontFreetype->getDescenderHeight() / sScaleY);
+}
S32 LLFontGL::getWidth(const std::string& utf8text) const
{
@@ -728,13 +472,13 @@ S32 LLFontGL::getWidth(const llwchar* wchars) const
return getWidth(wchars, 0, S32_MAX);
}
-S32 LLFontGL::getWidth(const std::string& utf8text, const S32 begin_offset, const S32 max_chars) const
+S32 LLFontGL::getWidth(const std::string& utf8text, S32 begin_offset, S32 max_chars) const
{
LLWString wtext = utf8str_to_wstring(utf8text);
return getWidth(wtext.c_str(), begin_offset, max_chars);
}
-S32 LLFontGL::getWidth(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const
+S32 LLFontGL::getWidth(const llwchar* wchars, S32 begin_offset, S32 max_chars, BOOL use_embedded) const
{
F32 width = getWidthF32(wchars, begin_offset, max_chars, use_embedded);
return llround(width);
@@ -751,15 +495,15 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars) const
return getWidthF32(wchars, 0, S32_MAX);
}
-F32 LLFontGL::getWidthF32(const std::string& utf8text, const S32 begin_offset, const S32 max_chars ) const
+F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max_chars ) const
{
LLWString wtext = utf8str_to_wstring(utf8text);
return getWidthF32(wtext.c_str(), begin_offset, max_chars);
}
-F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const
+F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, BOOL use_embedded) const
{
- const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;
+ const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;
F32 cur_x = 0;
const S32 max_index = begin_offset + max_chars;
@@ -783,7 +527,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S
}
else
{
- cur_x += getXAdvance(wch);
+ cur_x += mFontFreetype->getXAdvance(wch);
llwchar next_char = wchars[i+1];
if (((i + 1) < max_chars)
@@ -791,7 +535,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S
&& (next_char < LAST_CHARACTER))
{
// Kern this puppy.
- cur_x += getXKerning(wch, next_char);
+ cur_x += mFontFreetype->getXKerning(wch, next_char);
}
}
// Round after kerning.
@@ -801,12 +545,8 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S
return cur_x / sScaleX;
}
-
-
// Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
-S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars,
- BOOL end_on_word_boundary, const BOOL use_embedded,
- F32* drawn_pixels) const
+S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, BOOL end_on_word_boundary, BOOL use_embedded, F32* drawn_pixels) const
{
if (!wchars || !wchars[0] || max_chars == 0)
{
@@ -899,7 +639,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
}
}
- cur_x += getXAdvance(wch);
+ cur_x += mFontFreetype->getXAdvance(wch);
if (scaled_max_pixels < cur_x)
{
@@ -910,7 +650,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
if (((i+1) < max_chars) && wchars[i+1])
{
// Kern this puppy.
- cur_x += getXKerning(wch, wchars[i+1]);
+ cur_x += mFontFreetype->getXKerning(wch, wchars[i+1]);
}
}
// Round after kerning.
@@ -929,7 +669,6 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
return i;
}
-
S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const
{
if (!wchars || !wchars[0] || max_chars == 0)
@@ -948,7 +687,7 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_
llwchar wch = wchars[i];
const embedded_data_t* ext_data = getEmbeddedCharData(wch);
- F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : getXAdvance(wch);
+ F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : mFontFreetype->getXAdvance(wch);
if( scaled_max_pixels < (total_width + char_width) )
{
@@ -966,7 +705,7 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_
if ( i > 0 )
{
// kerning
- total_width += ext_data ? (EXT_KERNING * sScaleX) : getXKerning(wchars[i-1], wch);
+ total_width += ext_data ? (EXT_KERNING * sScaleX) : mFontFreetype->getXKerning(wchars[i-1], wch);
}
// Round after kerning.
@@ -976,8 +715,7 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_
return start_pos - drawable_chars;
}
-
-S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const
+S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const
{
if (!wchars || !wchars[0] || max_chars == 0)
{
@@ -1041,7 +779,7 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset,
}
else
{
- F32 char_width = getXAdvance(wch);
+ F32 char_width = mFontFreetype->getXAdvance(wch);
if (round)
{
@@ -1070,7 +808,7 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset,
{
llwchar next_char = wchars[i + 1];
// Kern this puppy.
- cur_x += getXKerning(wch, next_char);
+ cur_x += mFontFreetype->getXKerning(wch, next_char);
}
// Round after kerning.
@@ -1081,60 +819,370 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset,
return pos;
}
+void LLFontGL::addEmbeddedChar( llwchar wc, LLTexture* image, const std::string& label ) const
+{
+ LLWString wlabel = utf8str_to_wstring(label);
+ addEmbeddedChar(wc, image, wlabel);
+}
-const LLFontGL::embedded_data_t* LLFontGL::getEmbeddedCharData(const llwchar wch) const
+void LLFontGL::addEmbeddedChar( llwchar wc, LLTexture* image, const LLWString& wlabel ) const
{
- // Handle crappy embedded hack
- embedded_map_t::const_iterator iter = mEmbeddedChars.find(wch);
+ embedded_data_t* ext_data = new embedded_data_t(image->getGLTexture(), wlabel);
+ mEmbeddedChars[wc] = ext_data;
+}
+
+void LLFontGL::removeEmbeddedChar(llwchar wc) const
+{
+ embedded_map_t::iterator iter = mEmbeddedChars.find(wc);
if (iter != mEmbeddedChars.end())
{
- return iter->second;
+ delete iter->second;
+ mEmbeddedChars.erase(wc);
}
- return NULL;
}
+BOOL LLFontGL::addChar(llwchar wch) const
+{
+ if (!mFontFreetype->addChar(wch))
+ {
+ return FALSE;
+ }
+
+ stop_glerror();
-F32 LLFontGL::getEmbeddedCharAdvance(const embedded_data_t* ext_data) const
+ LLFontGlyphInfo *glyph_info = mFontFreetype->getGlyphInfo(wch);
+ U32 bitmap_num = glyph_info->mBitmapNum;
+
+ const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();
+ LLImageGL *image_gl = font_bitmap_cache->getImageGL(bitmap_num);
+ LLImageRaw *image_raw = font_bitmap_cache->getImageRaw(bitmap_num);
+ image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());
+ return TRUE;
+}
+
+const LLFontDescriptor& LLFontGL::getFontDesc() const
{
- const LLWString& label = ext_data->mLabel;
- LLImageGL* ext_image = ext_data->mImage;
+ return mFontDescriptor;
+}
- F32 ext_width = (F32)ext_image->getWidth();
- if( !label.empty() )
+// static
+void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector<std::string>& xui_paths, bool create_gl_textures)
+{
+ sVertDPI = (F32)llfloor(screen_dpi * y_scale);
+ sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
+ sScaleX = x_scale;
+ sScaleY = y_scale;
+ sAppDir = app_dir;
+
+ // Font registry init
+ if (!sFontRegistry)
{
- ext_width += (EXT_X_BEARING + getFontExtChar()->getWidthF32(label.c_str())) * sScaleX;
+ sFontRegistry = new LLFontRegistry(xui_paths, create_gl_textures);
+ sFontRegistry->parseFontInfo("fonts.xml");
+ }
+ else
+ {
+ sFontRegistry->reset();
}
+}
- return (EXT_X_BEARING * sScaleX) + ext_width;
+// Force standard fonts to get generated up front.
+// This is primarily for error detection purposes.
+// Don't do this during initClass because it can be slow and we want to get
+// the viewer window on screen first. JC
+// static
+bool LLFontGL::loadDefaultFonts()
+{
+ bool succ = true;
+ succ &= (NULL != getFontSansSerifSmall());
+ succ &= (NULL != getFontSansSerif());
+ succ &= (NULL != getFontSansSerifBig());
+ succ &= (NULL != getFontSansSerifHuge());
+ succ &= (NULL != getFontSansSerifBold());
+ succ &= (NULL != getFontMonospace());
+ succ &= (NULL != getFontExtChar());
+ return succ;
}
+// static
+void LLFontGL::destroyDefaultFonts()
+{
+ // Remove the actual fonts.
+ delete sFontRegistry;
+ sFontRegistry = NULL;
+}
-void LLFontGL::clearEmbeddedChars()
+//static
+void LLFontGL::destroyAllGL()
{
- for_each(mEmbeddedChars.begin(), mEmbeddedChars.end(), DeletePairedPointer());
- mEmbeddedChars.clear();
+ if (sFontRegistry)
+ {
+ sFontRegistry->destroyGL();
+ }
}
-void LLFontGL::addEmbeddedChar( llwchar wc, LLTexture* image, const std::string& label ) const
+// static
+U8 LLFontGL::getStyleFromString(const std::string &style)
{
- LLWString wlabel = utf8str_to_wstring(label);
- addEmbeddedChar(wc, image, wlabel);
+ S32 ret = 0;
+ if (style.find("NORMAL") != style.npos)
+ {
+ ret |= NORMAL;
+ }
+ if (style.find("BOLD") != style.npos)
+ {
+ ret |= BOLD;
+ }
+ if (style.find("ITALIC") != style.npos)
+ {
+ ret |= ITALIC;
+ }
+ if (style.find("UNDERLINE") != style.npos)
+ {
+ ret |= UNDERLINE;
+ }
+ return ret;
}
-void LLFontGL::addEmbeddedChar( llwchar wc, LLTexture* image, const LLWString& wlabel ) const
+// static
+std::string LLFontGL::nameFromFont(const LLFontGL* fontp)
{
- embedded_data_t* ext_data = new embedded_data_t(image->getGLTexture(), wlabel);
- mEmbeddedChars[wc] = ext_data;
+ return fontp->mFontDescriptor.getName();
}
-void LLFontGL::removeEmbeddedChar( llwchar wc ) const
+// static
+std::string LLFontGL::nameFromHAlign(LLFontGL::HAlign align)
{
- embedded_map_t::iterator iter = mEmbeddedChars.find(wc);
+ if (align == LEFT) return std::string("left");
+ else if (align == RIGHT) return std::string("right");
+ else if (align == HCENTER) return std::string("center");
+ else return std::string();
+}
+
+// static
+LLFontGL::HAlign LLFontGL::hAlignFromName(const std::string& name)
+{
+ LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
+ if (name == "left")
+ {
+ gl_hfont_align = LLFontGL::LEFT;
+ }
+ else if (name == "right")
+ {
+ gl_hfont_align = LLFontGL::RIGHT;
+ }
+ else if (name == "center")
+ {
+ gl_hfont_align = LLFontGL::HCENTER;
+ }
+ //else leave left
+ return gl_hfont_align;
+}
+
+// static
+std::string LLFontGL::nameFromVAlign(LLFontGL::VAlign align)
+{
+ if (align == TOP) return std::string("top");
+ else if (align == VCENTER) return std::string("center");
+ else if (align == BASELINE) return std::string("baseline");
+ else if (align == BOTTOM) return std::string("bottom");
+ else return std::string();
+}
+
+// static
+LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
+{
+ LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
+ if (name == "top")
+ {
+ gl_vfont_align = LLFontGL::TOP;
+ }
+ else if (name == "center")
+ {
+ gl_vfont_align = LLFontGL::VCENTER;
+ }
+ else if (name == "baseline")
+ {
+ gl_vfont_align = LLFontGL::BASELINE;
+ }
+ else if (name == "bottom")
+ {
+ gl_vfont_align = LLFontGL::BOTTOM;
+ }
+ //else leave baseline
+ return gl_vfont_align;
+}
+
+//static
+LLFontGL* LLFontGL::getFontMonospace()
+{
+ return getFont(LLFontDescriptor("Monospace","Monospace",0));
+}
+
+//static
+LLFontGL* LLFontGL::getFontSansSerifSmall()
+{
+ return getFont(LLFontDescriptor("SansSerif","Small",0));
+}
+
+//static
+LLFontGL* LLFontGL::getFontSansSerif()
+{
+ return getFont(LLFontDescriptor("SansSerif","Medium",0));
+}
+
+//static
+LLFontGL* LLFontGL::getFontSansSerifBig()
+{
+ return getFont(LLFontDescriptor("SansSerif","Large",0));
+}
+
+//static
+LLFontGL* LLFontGL::getFontSansSerifHuge()
+{
+ return getFont(LLFontDescriptor("SansSerif","Huge",0));
+}
+
+//static
+LLFontGL* LLFontGL::getFontSansSerifBold()
+{
+ return getFont(LLFontDescriptor("SansSerif","Medium",BOLD));
+}
+
+//static
+LLFontGL* LLFontGL::getFontExtChar()
+{
+ return getFontSansSerif();
+}
+
+//static
+LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc)
+{
+ return sFontRegistry->getFont(desc);
+}
+
+//static
+LLFontGL* LLFontGL::getFontByName(const std::string& name)
+{
+ // check for most common fonts first
+ if (name == "SANSSERIF")
+ {
+ return getFontSansSerif();
+ }
+ else if (name == "SANSSERIF_SMALL")
+ {
+ return getFontSansSerifSmall();
+ }
+ else if (name == "SANSSERIF_BIG")
+ {
+ return getFontSansSerifBig();
+ }
+ else if (name == "SMALL" || name == "OCRA")
+ {
+ // *BUG: Should this be "MONOSPACE"? Do we use "OCRA" anymore?
+ // Does "SMALL" mean "SERIF"?
+ return getFontMonospace();
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+// static
+std::string LLFontGL::getFontPathSystem()
+{
+ std::string system_path;
+
+ // Try to figure out where the system's font files are stored.
+ char *system_root = NULL;
+#if LL_WINDOWS
+ system_root = getenv("SystemRoot"); /* Flawfinder: ignore */
+ if (!system_root)
+ {
+ llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl;
+ }
+#endif
+
+ if (system_root)
+ {
+ system_path = llformat("%s/fonts/", system_root);
+ }
+ else
+ {
+#if LL_WINDOWS
+ // HACK for windows 98/Me
+ system_path = "/WINDOWS/FONTS/";
+#elif LL_DARWIN
+ // HACK for Mac OS X
+ system_path = "/System/Library/Fonts/";
+#endif
+ }
+ return system_path;
+}
+
+
+// static
+std::string LLFontGL::getFontPathLocal()
+{
+ std::string local_path;
+
+ // Backup files if we can't load from system fonts directory.
+ // We could store this in an end-user writable directory to allow
+ // end users to switch fonts.
+ if (LLFontGL::sAppDir.length())
+ {
+ // use specified application dir to look for fonts
+ local_path = LLFontGL::sAppDir + "/fonts/";
+ }
+ else
+ {
+ // assume working directory is executable directory
+ local_path = "./fonts/";
+ }
+ return local_path;
+}
+
+LLFontGL::LLFontGL(const LLFontGL &source)
+{
+ llerrs << "Not implemented!" << llendl;
+}
+
+LLFontGL &LLFontGL::operator=(const LLFontGL &source)
+{
+ llerrs << "Not implemented" << llendl;
+ return *this;
+}
+
+const LLFontGL::embedded_data_t* LLFontGL::getEmbeddedCharData(llwchar wch) const
+{
+ // Handle crappy embedded hack
+ embedded_map_t::const_iterator iter = mEmbeddedChars.find(wch);
if (iter != mEmbeddedChars.end())
{
- delete iter->second;
- mEmbeddedChars.erase(wc);
+ return iter->second;
+ }
+ return NULL;
+}
+
+F32 LLFontGL::getEmbeddedCharAdvance(const embedded_data_t* ext_data) const
+{
+ const LLWString& label = ext_data->mLabel;
+ LLImageGL* ext_image = ext_data->mImage;
+
+ F32 ext_width = (F32)ext_image->getWidth();
+ if( !label.empty() )
+ {
+ ext_width += (EXT_X_BEARING + getFontExtChar()->getWidthF32(label.c_str())) * sScaleX;
}
+
+ return (EXT_X_BEARING * sScaleX) + ext_width;
+}
+
+void LLFontGL::clearEmbeddedChars()
+{
+ for_each(mEmbeddedChars.begin(), mEmbeddedChars.end(), DeletePairedPointer());
+ mEmbeddedChars.clear();
}
@@ -1160,7 +1208,7 @@ void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F3
void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
{
F32 slant_offset;
- slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f);
+ slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f);
gGL.begin(LLRender::QUADS);
{
@@ -1230,71 +1278,3 @@ void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, con
}
gGL.end();
}
-
-std::string LLFontGL::nameFromFont(const LLFontGL* fontp)
-{
- return fontp->getFontDesc().getName();
-}
-
-// static
-std::string LLFontGL::nameFromHAlign(LLFontGL::HAlign align)
-{
- if (align == LEFT) return std::string("left");
- else if (align == RIGHT) return std::string("right");
- else if (align == HCENTER) return std::string("center");
- else return std::string();
-}
-
-// static
-LLFontGL::HAlign LLFontGL::hAlignFromName(const std::string& name)
-{
- LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
- if (name == "left")
- {
- gl_hfont_align = LLFontGL::LEFT;
- }
- else if (name == "right")
- {
- gl_hfont_align = LLFontGL::RIGHT;
- }
- else if (name == "center")
- {
- gl_hfont_align = LLFontGL::HCENTER;
- }
- //else leave left
- return gl_hfont_align;
-}
-
-// static
-std::string LLFontGL::nameFromVAlign(LLFontGL::VAlign align)
-{
- if (align == TOP) return std::string("top");
- else if (align == VCENTER) return std::string("center");
- else if (align == BASELINE) return std::string("baseline");
- else if (align == BOTTOM) return std::string("bottom");
- else return std::string();
-}
-
-// static
-LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
-{
- LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
- if (name == "top")
- {
- gl_vfont_align = LLFontGL::TOP;
- }
- else if (name == "center")
- {
- gl_vfont_align = LLFontGL::VCENTER;
- }
- else if (name == "baseline")
- {
- gl_vfont_align = LLFontGL::BASELINE;
- }
- else if (name == "bottom")
- {
- gl_vfont_align = LLFontGL::BOTTOM;
- }
- //else leave baseline
- return gl_vfont_align;
-}
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index 2298db0ef3..42ed7a381f 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -35,21 +35,21 @@
#define LL_LLFONTGL_H
#include "llcoord.h"
-#include "llfont.h"
#include "llfontregistry.h"
+#include "llimagegl.h"
#include "llpointer.h"
#include "llrect.h"
#include "v2math.h"
class LLColor4;
-class LLImageGL;
// Key used to request a font.
class LLFontDescriptor;
+class LLFontFreetype;
// Structure used to store previously requested fonts.
class LLFontRegistry;
-class LLFontGL : public LLFont
+class LLFontGL
{
public:
enum HAlign
@@ -85,130 +85,72 @@ public:
DROP_SHADOW,
DROP_SHADOW_SOFT
};
-
- // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC"
- static U8 getStyleFromString(const std::string &style);
LLFontGL();
- LLFontGL(const LLFontGL &source);
~LLFontGL();
- void init(); // Internal init, or reinitialization
- void reset(); // Reset a font after GL cleanup. ONLY works on an already loaded font.
- LLFontGL &operator=(const LLFontGL &source);
-
- static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale,
- const std::string& app_dir,
- const std::vector<std::string>& xui_paths,
- bool create_gl_textures = true);
+ void reset(); // Reset a font after GL cleanup. ONLY works on an already loaded font.
- // Load sans-serif, sans-serif-small, etc.
- // Slow, requires multiple seconds to load fonts.
- static bool loadDefaultFonts();
- static void destroyDefaultFonts();
- static void destroyAllGL();
void destroyGL();
- /* virtual*/ BOOL loadFace(const std::string& filename,
- const F32 point_size, const F32 vert_dpi, const F32 horz_dpi,
- const S32 components, BOOL is_fallback);
+ BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback);
+ S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign = LEFT, VAlign valign = BASELINE, U8 style = NORMAL,
+ ShadowType shadow = NO_SHADOW, S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, F32* right_x=NULL, BOOL use_embedded = FALSE, BOOL use_ellipses = FALSE) const;
+ S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const;
- S32 renderUTF8(const std::string &text, const S32 begin_offset,
- S32 x, S32 y,
- const LLColor4 &color) const
- {
- return renderUTF8(text, begin_offset, (F32)x, (F32)y, color,
- LEFT, BASELINE, NORMAL, NO_SHADOW,
- S32_MAX, S32_MAX, NULL, FALSE);
- }
-
- S32 renderUTF8(const std::string &text, const S32 begin_offset,
- S32 x, S32 y,
- const LLColor4 &color,
- HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const
- {
- return renderUTF8(text, begin_offset, (F32)x, (F32)y, color,
- halign, valign, style, shadow,
- S32_MAX, S32_MAX, NULL, FALSE);
- }
-
// renderUTF8 does a conversion, so is slower!
- S32 renderUTF8(const std::string &text,
- S32 begin_offset,
- F32 x, F32 y,
- const LLColor4 &color,
- HAlign halign,
- VAlign valign,
- U8 style,
- ShadowType shadow,
- S32 max_chars,
- S32 max_pixels,
- F32* right_x,
- BOOL use_ellipses) const;
-
- S32 render(const LLWString &text, const S32 begin_offset,
- F32 x, F32 y,
- const LLColor4 &color) const
- {
- return render(text, begin_offset, x, y, color,
- LEFT, BASELINE, NORMAL, NO_SHADOW,
- S32_MAX, S32_MAX, NULL, FALSE, FALSE);
- }
-
+ S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const;
+ S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const;
+ S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const;
- S32 render(const LLWString &text,
- S32 begin_offset,
- F32 x, F32 y,
- const LLColor4 &color,
- HAlign halign = LEFT,
- VAlign valign = BASELINE,
- U8 style = NORMAL,
- ShadowType shadow = NO_SHADOW,
- S32 max_chars = S32_MAX,
- S32 max_pixels = S32_MAX,
- F32* right_x=NULL,
- BOOL use_embedded = FALSE,
- BOOL use_ellipses = FALSE) const;
-
- // font metrics - override for LLFont that returns units of virtual pixels
- /*virtual*/ F32 getLineHeight() const { return (F32)llround(mLineHeight / sScaleY); }
- /*virtual*/ F32 getAscenderHeight() const { return (F32)llround(mAscender / sScaleY); }
- /*virtual*/ F32 getDescenderHeight() const { return (F32)llround(mDescender / sScaleY); }
-
- virtual S32 getWidth(const std::string& utf8text) const;
- virtual S32 getWidth(const llwchar* wchars) const;
- virtual S32 getWidth(const std::string& utf8text, const S32 offset, const S32 max_chars ) const;
- virtual S32 getWidth(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE) const;
+ // font metrics - override for LLFontFreetype that returns units of virtual pixels
+ F32 getLineHeight() const;
+ F32 getAscenderHeight() const;
+ F32 getDescenderHeight() const;
- virtual F32 getWidthF32(const std::string& utf8text) const;
- virtual F32 getWidthF32(const llwchar* wchars) const;
- virtual F32 getWidthF32(const std::string& text, const S32 offset, const S32 max_chars ) const;
- virtual F32 getWidthF32(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE ) const;
+ S32 getWidth(const std::string& utf8text) const;
+ S32 getWidth(const llwchar* wchars) const;
+ S32 getWidth(const std::string& utf8text, S32 offset, S32 max_chars ) const;
+ S32 getWidth(const llwchar* wchars, S32 offset, S32 max_chars, BOOL use_embedded = FALSE) const;
+
+ F32 getWidthF32(const std::string& utf8text) const;
+ F32 getWidthF32(const llwchar* wchars) const;
+ F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars ) const;
+ F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars, BOOL use_embedded = FALSE ) const;
// The following are called often, frequently with large buffers, so do not use a string interface
// Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
- virtual S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX,
- BOOL end_on_word_boundary = FALSE, const BOOL use_embedded = FALSE,
- F32* drawn_pixels = NULL) const;
+ S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, BOOL end_on_word_boundary = FALSE, BOOL use_embedded = FALSE, F32* drawn_pixels = NULL) const;
// Returns the index of the first complete characters from text that can be drawn in max_pixels
// given that the character at start_pos should be the last character (or as close to last as possible).
- virtual S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const;
+ S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const;
// Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars)
- virtual S32 charFromPixelOffset(const llwchar* wchars, const S32 char_offset,
- F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX,
- BOOL round = TRUE, BOOL use_embedded = FALSE) const;
+ S32 charFromPixelOffset(const llwchar* wchars, S32 char_offset, F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX, BOOL round = TRUE, BOOL use_embedded = FALSE) const;
+
+ void addEmbeddedChar( llwchar wc, LLTexture* image, const std::string& label) const;
+ void addEmbeddedChar( llwchar wc, LLTexture* image, const LLWString& label) const;
+ void removeEmbeddedChar( llwchar wc ) const;
+ BOOL addChar(const llwchar wch) const;
- LLImageGL *getImageGL() const;
+ const LLFontDescriptor& getFontDesc() const;
- void addEmbeddedChar( llwchar wc, LLTexture* image, const std::string& label) const;
- void addEmbeddedChar( llwchar wc, LLTexture* image, const LLWString& label) const;
- void removeEmbeddedChar( llwchar wc ) const;
+
+ static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector<std::string>& xui_paths, bool create_gl_textures = true);
+
+ // Load sans-serif, sans-serif-small, etc.
+ // Slow, requires multiple seconds to load fonts.
+ static bool loadDefaultFonts();
+ static void destroyDefaultFonts();
+ static void destroyAllGL();
+
+ // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC"
+ static U8 getStyleFromString(const std::string &style);
static std::string nameFromFont(const LLFontGL* fontp);
@@ -218,28 +160,7 @@ public:
static std::string nameFromVAlign(LLFontGL::VAlign align);
static LLFontGL::VAlign vAlignFromName(const std::string& name);
- static void setFontDisplay(BOOL flag) { sDisplayFont = flag ; }
-
-protected:
- struct embedded_data_t
- {
- embedded_data_t(LLImageGL* image, const LLWString& label) : mImage(image), mLabel(label) {}
- LLPointer<LLImageGL> mImage;
- LLWString mLabel;
- };
- const embedded_data_t* getEmbeddedCharData(const llwchar wch) const;
- F32 getEmbeddedCharAdvance(const embedded_data_t* ext_data) const;
- void clearEmbeddedChars();
- void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const;
- void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const;
-
-public:
- static F32 sVertDPI;
- static F32 sHorizDPI;
- static F32 sScaleX;
- static F32 sScaleY;
- static BOOL sDisplayFont ;
- static std::string sAppDir; // For loading fonts
+ static void setFontDisplay(BOOL flag) { sDisplayFont = flag; }
static LLFontGL* getFontMonospace();
static LLFontGL* getFontSansSerifSmall();
@@ -252,32 +173,50 @@ public:
// Use with legacy names like "SANSSERIF_SMALL" or "OCRA"
static LLFontGL* getFontByName(const std::string& name);
+ static std::string getFontPathLocal();
+ static std::string getFontPathSystem();
+
+ static LLCoordFont sCurOrigin;
+ static std::vector<LLCoordFont> sOriginStack;
+
static LLColor4 sShadowColor;
+ static F32 sVertDPI;
+ static F32 sHorizDPI;
+ static F32 sScaleX;
+ static F32 sScaleY;
+ static BOOL sDisplayFont ;
+ static std::string sAppDir; // For loading fonts
+
+private:
+ friend class LLFontRegistry;
friend class LLTextBillboard;
friend class LLHUDText;
-protected:
- /*virtual*/ BOOL addChar(const llwchar wch) const;
+ LLFontGL(const LLFontGL &source);
+ LLFontGL &operator=(const LLFontGL &source);
-protected:
- typedef std::map<llwchar,embedded_data_t*> embedded_map_t;
- mutable embedded_map_t mEmbeddedChars;
-
LLFontDescriptor mFontDescriptor;
+ LLPointer<LLFontFreetype> mFontFreetype;
- // Registry holds all instantiated fonts.
- static LLFontRegistry* sFontRegistry;
+ struct embedded_data_t
+ {
+ embedded_data_t(LLImageGL* image, const LLWString& label) : mImage(image), mLabel(label) {}
+ LLPointer<LLImageGL> mImage;
+ LLWString mLabel;
+ };
-public:
- static std::string getFontPathLocal();
- static std::string getFontPathSystem();
+ typedef std::map<llwchar,embedded_data_t*> embedded_map_t;
+ mutable embedded_map_t mEmbeddedChars;
- static LLCoordFont sCurOrigin;
- static std::vector<LLCoordFont> sOriginStack;
+ const embedded_data_t* getEmbeddedCharData(llwchar wch) const;
+ F32 getEmbeddedCharAdvance(const embedded_data_t* ext_data) const;
+ void clearEmbeddedChars();
+ void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const;
+ void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const;
- const LLFontDescriptor &getFontDesc() const { return mFontDescriptor; }
- void setFontDesc(const LLFontDescriptor& font_desc) { mFontDescriptor = font_desc; }
+ // Registry holds all instantiated fonts.
+ static LLFontRegistry* sFontRegistry;
};
#endif
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
index 3b5c62a5ea..553e7b8f9d 100644
--- a/indra/llrender/llfontregistry.cpp
+++ b/indra/llrender/llfontregistry.cpp
@@ -33,8 +33,9 @@
#include "linden_common.h"
#include "llgl.h"
-#include "llfontregistry.h"
+#include "llfontfreetype.h"
#include "llfontgl.h"
+#include "llfontregistry.h"
#include <boost/tokenizer.hpp>
#include "llcontrol.h"
#include "lldir.h"
@@ -382,7 +383,14 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
if (it != mFontMap.end())
{
llinfos << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << llendl;
- return it->second;
+
+ // copying underlying Freetype font, and storing in LLFontGL with requested font descriptor
+ LLFontGL *font = new LLFontGL;
+ font->mFontDescriptor = desc;
+ font->mFontFreetype = it->second->mFontFreetype;
+ mFontMap[desc] = font;
+
+ return font;
}
// Build list of font names to look for.
@@ -410,10 +418,11 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
llwarns << "createFont failed, no file names specified" << llendl;
return NULL;
}
- LLFontList *fontlistp = new LLFontList;
+
+ LLFontFreetype::font_vector_t fontlist;
LLFontGL *result = NULL;
- // Snarf all fonts we can into fontlistp. First will get pulled
+ // Snarf all fonts we can into fontlist. First will get pulled
// off the list and become the "head" font, set to non-fallback.
// Rest will consitute the fallback list.
BOOL is_first_found = TRUE;
@@ -455,23 +464,28 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
is_first_found = false;
}
else
- fontlistp->addAtEnd(fontp);
+ {
+ fontlist.push_back(fontp->mFontFreetype);
+ }
}
}
- if (result && !fontlistp->empty())
+
+ if (result && !fontlist.empty())
{
- result->setFallbackFont(fontlistp);
+ result->mFontFreetype->setFallbackFonts(fontlist);
}
- norm_desc.setStyle(match_desc->getStyle());
if (result)
- result->setFontDesc(norm_desc);
-
- if (!result)
+ {
+ result->mFontFreetype->setStyle(match_desc->getStyle());
+ result->mFontDescriptor = desc;
+ }
+ else
{
llwarns << "createFont failed in some way" << llendl;
}
- mFontMap[norm_desc] = result;
+
+ mFontMap[desc] = result;
return result;
}
@@ -511,21 +525,19 @@ void LLFontRegistry::destroyGL()
}
}
-LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& orig_desc)
+LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& desc)
{
- LLFontDescriptor norm_desc = orig_desc.normalize();
-
- font_reg_map_t::iterator it = mFontMap.find(norm_desc);
+ font_reg_map_t::iterator it = mFontMap.find(desc);
if (it != mFontMap.end())
return it->second;
else
{
- LLFontGL *fontp = createFont(orig_desc);
+ LLFontGL *fontp = createFont(desc);
if (!fontp)
{
- llwarns << "getFont failed, name " << orig_desc.getName()
- <<" style=[" << ((S32) orig_desc.getStyle()) << "]"
- << " size=[" << orig_desc.getSize() << "]" << llendl;
+ llwarns << "getFont failed, name " << desc.getName()
+ <<" style=[" << ((S32) desc.getStyle()) << "]"
+ << " size=[" << desc.getSize() << "]" << llendl;
}
return fontp;
}
@@ -653,3 +665,8 @@ void LLFontRegistry::dump()
}
}
}
+
+const string_vec_t& LLFontRegistry::getUltimateFallbackList() const
+{
+ return mUltimateFallbackList;
+}
diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h
index 198ca0b920..4da4ca48bb 100644
--- a/indra/llrender/llfontregistry.h
+++ b/indra/llrender/llfontregistry.h
@@ -98,7 +98,7 @@ public:
void dump();
- const string_vec_t& getUltimateFallbackList() const { return mUltimateFallbackList; }
+ const string_vec_t& getUltimateFallbackList() const;
private:
LLFontGL *createFont(const LLFontDescriptor& desc);