summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authorChristian Goetze <cg@lindenlab.com>2009-03-13 21:28:40 +0000
committerChristian Goetze <cg@lindenlab.com>2009-03-13 21:28:40 +0000
commit1aa0416aef379bb3ad1012441588b6d7fab81b40 (patch)
tree14a247470bd0d508aba923dc00e940b961d304da /indra/llrender
parent7573288ab3ede23f97bff2f5caefcb622e7e9842 (diff)
svn merge -r114093:114412 svn+ssh://svn.lindenlab.com/svn/linden/branches/featurettes/featurettes-batch5-merge
Melinda (coco): 5th and final batch of featurettes. My work here is done.
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/CMakeLists.txt8
-rw-r--r--indra/llrender/llfontbitmapcache.cpp168
-rw-r--r--indra/llrender/llfontbitmapcache.h78
-rw-r--r--indra/llrender/llfontgl.cpp552
-rw-r--r--indra/llrender/llfontgl.h69
-rw-r--r--indra/llrender/llfontregistry.cpp650
-rw-r--r--indra/llrender/llfontregistry.h113
-rw-r--r--indra/llrender/llimagegl.cpp3
8 files changed, 1201 insertions, 440 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 72aa3715c0..0bdb55f9d0 100644
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -9,6 +9,8 @@ include(LLImage)
include(LLMath)
include(LLRender)
include(LLWindow)
+include(LLXML)
+include(LLVFS)
include_directories(
${FREETYPE_INCLUDE_DIRS}
@@ -17,12 +19,16 @@ include_directories(
${LLMATH_INCLUDE_DIRS}
${LLRENDER_INCLUDE_DIRS}
${LLWINDOW_INCLUDE_DIRS}
+ ${LLXML_INCLUDE_DIRS}
+ ${LLVFS_INCLUDE_DIRS}
)
set(llrender_SOURCE_FILES
llcubemap.cpp
llfont.cpp
llfontgl.cpp
+ llfontbitmapcache.cpp
+ llfontregistry.cpp
llgldbg.cpp
llglslshader.cpp
llimagegl.cpp
@@ -38,6 +44,8 @@ set(llrender_HEADER_FILES
llcubemap.h
llfontgl.h
llfont.h
+ llfontbitmapcache.h
+ llfontregistry.h
llgl.h
llgldbg.h
llglheaders.h
diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp
new file mode 100644
index 0000000000..f6321b0534
--- /dev/null
+++ b/indra/llrender/llfontbitmapcache.cpp
@@ -0,0 +1,168 @@
+/**
+ * @file llfontbitmapcache.cpp
+ * @brief Storage for previously rendered glyphs.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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 "llgl.h"
+#include "llfontbitmapcache.h"
+
+LLFontBitmapCache::LLFontBitmapCache():
+ mNumComponents(0),
+ mMaxCharWidth(0),
+ mMaxCharHeight(0),
+ mBitmapWidth(0),
+ mBitmapHeight(0),
+ mCurrentOffsetX(1),
+ mCurrentOffsetY(1),
+ mCurrentBitmapNum(-1)
+{
+}
+
+LLFontBitmapCache::~LLFontBitmapCache()
+{
+}
+
+void LLFontBitmapCache::init(S32 num_components,
+ S32 max_char_width,
+ S32 max_char_height)
+{
+ reset();
+
+ mNumComponents = num_components;
+ mMaxCharWidth = max_char_width;
+ mMaxCharHeight = max_char_height;
+}
+
+LLImageRaw *LLFontBitmapCache::getImageRaw(U32 bitmap_num) const
+{
+ if ((bitmap_num < 0) || (bitmap_num >= mImageRawVec.size()))
+ return NULL;
+
+ return mImageRawVec[bitmap_num];
+}
+
+LLImageGL *LLFontBitmapCache::getImageGL(U32 bitmap_num) const
+{
+ if ((bitmap_num < 0) || (bitmap_num >= mImageGLVec.size()))
+ return NULL;
+
+ return mImageGLVec[bitmap_num];
+}
+
+
+BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32 &pos_x, S32 &pos_y, S32& bitmap_num)
+{
+ if ((mBitmapNum<0) || (mCurrentOffsetX + width + 1) > mBitmapWidth)
+ {
+ if ((mBitmapNum<0) || (mCurrentOffsetY + 2*mMaxCharHeight + 2) > mBitmapHeight)
+ {
+ // We're out of space in the current image, or no image
+ // has been allocated yet. Make a new one.
+ mImageRawVec.push_back(new LLImageRaw);
+ mBitmapNum = mImageRawVec.size()-1;
+ LLImageRaw *image_raw = getImageRaw(mBitmapNum);
+
+ // Make corresponding GL image.
+ mImageGLVec.push_back(new LLImageGL(FALSE));
+ LLImageGL *image_gl = getImageGL(mBitmapNum);
+
+ S32 image_width = mMaxCharWidth * 20;
+ S32 pow_iw = 2;
+ while (pow_iw < image_width)
+ {
+ pow_iw *= 2;
+ }
+ image_width = pow_iw;
+ image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever.
+ S32 image_height = image_width;
+
+ image_raw->resize(image_width, image_height, mNumComponents);
+
+ mBitmapWidth = image_width;
+ mBitmapHeight = image_height;
+
+ switch (mNumComponents)
+ {
+ case 1:
+ image_raw->clear();
+ break;
+ case 2:
+ image_raw->clear(255, 0);
+ break;
+ }
+
+ // Start at beginning of the new image.
+ mCurrentOffsetX = 1;
+ mCurrentOffsetY = 1;
+
+ // Attach corresponding GL texture.
+ image_gl->createGLTexture(0, image_raw);
+ gGL.getTexUnit(0)->bind(image_gl);
+ image_gl->setFilteringOption(LLTexUnit::TFO_POINT); // was setMipFilterNearest(TRUE, TRUE);
+ }
+ else
+ {
+ // Move to next row in current image.
+ mCurrentOffsetX = 1;
+ mCurrentOffsetY += mMaxCharHeight + 1;
+ }
+ }
+
+ pos_x = mCurrentOffsetX;
+ pos_y = mCurrentOffsetY;
+ bitmap_num = mBitmapNum;
+
+ mCurrentOffsetX += width + 1;
+
+ return TRUE;
+}
+
+void LLFontBitmapCache::destroyGL()
+{
+ for (std::vector<LLPointer<LLImageGL> >::iterator it = mImageGLVec.begin();
+ it != mImageGLVec.end(); ++it)
+ {
+ (*it)->destroyGLTexture();
+ }
+}
+
+void LLFontBitmapCache::reset()
+{
+ mImageRawVec.clear();
+ mImageGLVec.clear();
+
+ mBitmapWidth = 0,
+ mBitmapHeight = 0,
+ mCurrentOffsetX = 0,
+ mCurrentOffsetY = 0,
+ mCurrentBitmapNum = -1;
+}
+
diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h
new file mode 100644
index 0000000000..e5c09f8826
--- /dev/null
+++ b/indra/llrender/llfontbitmapcache.h
@@ -0,0 +1,78 @@
+/**
+ * @file llfontbitmapcache.h
+ * @brief Storage for previously rendered glyphs.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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_LLFONTBITMAPCACHE_H
+#define LL_LLFONTBITMAPCACHE_H
+
+#include <vector>
+
+// Maintain a collection of bitmaps containing rendered glyphs.
+// Generalizes the single-bitmap logic from LLFont and LLFontGL.
+class LLFontBitmapCache: public LLRefCount
+{
+public:
+ LLFontBitmapCache();
+ ~LLFontBitmapCache();
+
+ // Need to call this once, before caching any glyphs.
+ void init(S32 num_components,
+ S32 max_char_width,
+ S32 max_char_height);
+
+ void reset();
+
+ BOOL nextOpenPos(S32 width, S32 &posX, S32 &posY, S32 &bitmapNum);
+
+ void destroyGL();
+
+ LLImageRaw *getImageRaw(U32 bitmapNum = 0) const;
+ LLImageGL *getImageGL(U32 bitmapNum = 0) const;
+
+ S32 getMaxCharWidth() const { return mMaxCharWidth; }
+ S32 getNumComponents() const { return mNumComponents; }
+ S32 getBitmapWidth() const { return mBitmapWidth; }
+ S32 getBitmapHeight() const { return mBitmapHeight; }
+
+private:
+ S32 mNumComponents;
+ S32 mBitmapWidth;
+ S32 mBitmapHeight;
+ S32 mBitmapNum;
+ S32 mMaxCharWidth;
+ S32 mMaxCharHeight;
+ S32 mCurrentOffsetX;
+ S32 mCurrentOffsetY;
+ S32 mCurrentBitmapNum;
+ std::vector<LLPointer<LLImageRaw> > mImageRawVec;
+ std::vector<LLPointer<LLImageGL> > mImageGLVec;
+};
+
+#endif //LL_LLFONTBITMAPCACHE_H
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 3829306e25..e0c3ec3c24 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -36,6 +36,8 @@
#include "llfont.h"
#include "llfontgl.h"
+#include "llfontbitmapcache.h"
+#include "llfontregistry.h"
#include "llgl.h"
#include "llrender.h"
#include "v4color.h"
@@ -51,25 +53,12 @@ F32 LLFontGL::sScaleY = 1.f;
BOOL LLFontGL::sDisplayFont = TRUE ;
std::string LLFontGL::sAppDir;
-LLFontGL* LLFontGL::sMonospace = NULL;
-LLFontGL* LLFontGL::sSansSerifSmall = NULL;
-LLFontGL* LLFontGL::sSansSerif = NULL;
-LLFontGL* LLFontGL::sSansSerifBig = NULL;
-LLFontGL* LLFontGL::sSansSerifHuge = NULL;
-LLFontGL* LLFontGL::sSansSerifBold = NULL;
-LLFontList* LLFontGL::sMonospaceFallback = NULL;
-LLFontList* LLFontGL::sSSFallback = NULL;
-LLFontList* LLFontGL::sSSSmallFallback = NULL;
-LLFontList* LLFontGL::sSSBigFallback = NULL;
-LLFontList* LLFontGL::sSSHugeFallback = NULL;
-LLFontList* LLFontGL::sSSBoldFallback = NULL;
LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f);
+LLFontRegistry* LLFontGL::sFontRegistry = NULL;
LLCoordFont LLFontGL::sCurOrigin;
std::vector<LLCoordFont> LLFontGL::sOriginStack;
-LLFontGL*& gExtCharFont = LLFontGL::sSansSerif;
-
const F32 EXT_X_BEARING = 1.f;
const F32 EXT_Y_BEARING = 0.f;
const F32 EXT_KERNING = 1.f;
@@ -127,7 +116,6 @@ U8 LLFontGL::getStyleFromString(const std::string &style)
LLFontGL::LLFontGL()
: LLFont()
{
- init();
clearEmbeddedChars();
}
@@ -138,32 +126,30 @@ LLFontGL::LLFontGL(const LLFontGL &source)
LLFontGL::~LLFontGL()
{
- mImageGLp = NULL;
- mRawImageGLp = NULL;
clearEmbeddedChars();
}
-void LLFontGL::init()
+void LLFontGL::reset()
{
- if (mImageGLp.isNull())
- {
- mImageGLp = new LLImageGL(FALSE);
- //RN: use nearest mipmap filtering to obviate the need to do pixel-accurate positioning
- gGL.getTexUnit(0)->bind(mImageGLp);
- // we allow bilinear filtering to get sub-pixel positioning for drop shadows
- //mImageGLp->setMipFilterNearest(TRUE, TRUE);
- }
- if (mRawImageGLp.isNull())
+ resetBitmapCache();
+ if (!mIsFallback)
{
- mRawImageGLp = new LLImageRaw; // Note LLFontGL owns the image, not LLFont.
+ // 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();
+ }
+ }
}
- setRawImage( mRawImageGLp );
-}
-
-void LLFontGL::reset()
-{
- init();
- resetBitmap();
}
// static
@@ -220,243 +206,48 @@ std::string LLFontGL::getFontPathLocal()
return local_path;
}
-//static
-bool LLFontGL::loadFaceFallback(LLFontList *fontlistp, const std::string& fontname, const F32 point_size)
+bool findOrCreateFont(LLFontGL*& fontp, const LLFontDescriptor& desc)
{
- std::string local_path = getFontPathLocal();
- std::string sys_path = getFontPathSystem();
-
- // The fontname string may contain multiple font file names separated by semicolons.
- // Break it apart and try loading each one, in order.
- typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
- boost::char_separator<char> sep(";");
- tokenizer tokens(fontname, sep);
- tokenizer::iterator token_iter;
-
- for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
- {
- LLFont *fontp = new LLFont();
- std::string font_path = local_path + *token_iter;
- if (!fontp->loadFace(font_path, point_size, sVertDPI, sHorizDPI, 2, TRUE))
- {
- font_path = sys_path + *token_iter;
- if (!fontp->loadFace(font_path, point_size, sVertDPI, sHorizDPI, 2, TRUE))
- {
- LL_INFOS_ONCE("ViewerImages") << "Couldn't load font " << *token_iter << LL_ENDL;
- delete fontp;
- fontp = NULL;
- }
- }
-
- if(fontp)
- {
- fontlistp->addAtEnd(fontp);
- }
- }
-
- // We want to return true if at least one fallback font loaded correctly.
- return (fontlistp->size() > 0);
+ // 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
-bool LLFontGL::loadFace(LLFontGL *fontp, const std::string& fontname, const F32 point_size, LLFontList *fallback_fontp)
-{
- std::string local_path = getFontPathLocal();
- std::string font_path = local_path + fontname;
- if (!fontp->loadFace(font_path, point_size, sVertDPI, sHorizDPI, 2, FALSE))
- {
- std::string sys_path = getFontPathSystem();
- font_path = sys_path + fontname;
- if (!fontp->loadFace(font_path, point_size, sVertDPI, sHorizDPI, 2, FALSE))
- {
- LL_WARNS("ViewerImages") << "Couldn't load font " << fontname << LL_ENDL;
- return false;
- }
- }
-
- fontp->setFallbackFont(fallback_fontp);
- return true;
-}
-
-
// static
BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
- const std::string& monospace_file, F32 monospace_size,
- const std::string& sansserif_file,
- const std::string& sanserif_fallback_file, F32 ss_fallback_scale,
- F32 small_size, F32 medium_size, F32 big_size, F32 huge_size,
- const std::string& sansserif_bold_file, F32 bold_size,
- const std::string& app_dir)
+ const std::string& app_dir,
+ const std::vector<std::string>& xui_paths)
{
- BOOL failed = FALSE;
+ bool succ = true;
sVertDPI = (F32)llfloor(screen_dpi * y_scale);
sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
sScaleX = x_scale;
sScaleY = y_scale;
sAppDir = app_dir;
- //
- // Monospace font
- //
-
- if (!sMonospace)
- {
- sMonospace = new LLFontGL();
- }
- else
- {
- sMonospace->reset();
- }
-
- if (sMonospaceFallback)
+ // Font registry init
+ if (!sFontRegistry)
{
- delete sMonospaceFallback;
- }
- sMonospaceFallback = new LLFontList();
- if (!loadFaceFallback(
- sMonospaceFallback,
- sanserif_fallback_file,
- monospace_size * ss_fallback_scale))
- {
- delete sMonospaceFallback;
- sMonospaceFallback = NULL;
- }
-
- failed |= !loadFace(sMonospace, monospace_file, monospace_size, sMonospaceFallback);
-
- //
- // Sans-serif fonts
- //
- if(!sSansSerifHuge)
- {
- sSansSerifHuge = new LLFontGL();
+ sFontRegistry = new LLFontRegistry(xui_paths);
+ sFontRegistry->parseFontInfo("fonts.xml");
}
else
{
- sSansSerifHuge->reset();
+ sFontRegistry->reset();
}
- if (sSSHugeFallback)
- {
- delete sSSHugeFallback;
- }
- sSSHugeFallback = new LLFontList();
- if (!loadFaceFallback(
- sSSHugeFallback,
- sanserif_fallback_file,
- huge_size*ss_fallback_scale))
- {
- delete sSSHugeFallback;
- sSSHugeFallback = NULL;
- }
-
- failed |= !loadFace(sSansSerifHuge, sansserif_file, huge_size, sSSHugeFallback);
-
-
- if(!sSansSerifBig)
- {
- sSansSerifBig = new LLFontGL();
- }
- else
- {
- sSansSerifBig->reset();
- }
-
- if (sSSBigFallback)
- {
- delete sSSBigFallback;
- }
- sSSBigFallback = new LLFontList();
- if (!loadFaceFallback(
- sSSBigFallback,
- sanserif_fallback_file,
- big_size*ss_fallback_scale))
- {
- delete sSSBigFallback;
- sSSBigFallback = NULL;
- }
-
- failed |= !loadFace(sSansSerifBig, sansserif_file, big_size, sSSBigFallback);
-
-
- if(!sSansSerif)
- {
- sSansSerif = new LLFontGL();
- }
- else
- {
- sSansSerif->reset();
- }
-
- if (sSSFallback)
- {
- delete sSSFallback;
- }
- sSSFallback = new LLFontList();
- if (!loadFaceFallback(
- sSSFallback,
- sanserif_fallback_file,
- medium_size*ss_fallback_scale))
- {
- delete sSSFallback;
- sSSFallback = NULL;
- }
- failed |= !loadFace(sSansSerif, sansserif_file, medium_size, sSSFallback);
-
-
- if(!sSansSerifSmall)
- {
- sSansSerifSmall = new LLFontGL();
- }
- else
- {
- sSansSerifSmall->reset();
- }
-
- if(sSSSmallFallback)
- {
- delete sSSSmallFallback;
- }
- sSSSmallFallback = new LLFontList();
- if (!loadFaceFallback(
- sSSSmallFallback,
- sanserif_fallback_file,
- small_size*ss_fallback_scale))
- {
- delete sSSSmallFallback;
- sSSSmallFallback = NULL;
- }
- failed |= !loadFace(sSansSerifSmall, sansserif_file, small_size, sSSSmallFallback);
-
-
- //
- // Sans-serif bold
- //
- if(!sSansSerifBold)
- {
- sSansSerifBold = new LLFontGL();
- }
- else
- {
- sSansSerifBold->reset();
- }
-
- if (sSSBoldFallback)
- {
- delete sSSBoldFallback;
- }
- sSSBoldFallback = new LLFontList();
- if (!loadFaceFallback(
- sSSBoldFallback,
- sanserif_fallback_file,
- medium_size*ss_fallback_scale))
- {
- delete sSSBoldFallback;
- sSSBoldFallback = NULL;
- }
- failed |= !loadFace(sSansSerifBold, sansserif_bold_file, medium_size, sSSBoldFallback);
-
- return !failed;
+ // Force standard fonts to get generated up front.
+ // This is primarily for error detection purposes.
+ succ &= (NULL != getFontSansSerifSmall());
+ succ &= (NULL != getFontSansSerif());
+ succ &= (NULL != getFontSansSerifBig());
+ succ &= (NULL != getFontSansSerifHuge());
+ succ &= (NULL != getFontSansSerifBold());
+ succ &= (NULL != getFontMonospace());
+ succ &= (NULL != getFontExtChar());
+
+ return succ;
}
@@ -464,57 +255,23 @@ BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
// static
void LLFontGL::destroyDefaultFonts()
{
- delete sMonospace;
- sMonospace = NULL;
-
- delete sSansSerifHuge;
- sSansSerifHuge = NULL;
-
- delete sSansSerifBig;
- sSansSerifBig = NULL;
-
- delete sSansSerif;
- sSansSerif = NULL;
-
- delete sSansSerifSmall;
- sSansSerifSmall = NULL;
-
- delete sSansSerifBold;
- sSansSerifBold = NULL;
-
- delete sMonospaceFallback;
- sMonospaceFallback = NULL;
-
- delete sSSHugeFallback;
- sSSHugeFallback = NULL;
-
- delete sSSBigFallback;
- sSSBigFallback = NULL;
-
- delete sSSFallback;
- sSSFallback = NULL;
-
- delete sSSSmallFallback;
- sSSSmallFallback = NULL;
-
- delete sSSBoldFallback;
- sSSBoldFallback = NULL;
+ // Remove the actual fonts.
+ delete sFontRegistry;
+ sFontRegistry = NULL;
}
//static
-void LLFontGL::destroyGL()
+void LLFontGL::destroyAllGL()
{
- if (!sMonospace)
+ if (sFontRegistry)
{
- // Already all destroyed.
- return;
+ sFontRegistry->destroyGL();
}
- sMonospace->mImageGLp->destroyGLTexture();
- sSansSerifHuge->mImageGLp->destroyGLTexture();
- sSansSerifSmall->mImageGLp->destroyGLTexture();
- sSansSerif->mImageGLp->destroyGLTexture();
- sSansSerifBig->mImageGLp->destroyGLTexture();
- sSansSerifBold->mImageGLp->destroyGLTexture();
+}
+
+void LLFontGL::destroyGL()
+{
+ mFontBitmapCachep->destroyGL();
}
@@ -533,13 +290,58 @@ BOOL LLFontGL::loadFace(const std::string& filename,
{
return FALSE;
}
- mImageGLp->createGLTexture(0, mRawImageGLp);
- gGL.getTexUnit(0)->bind(mImageGLp);
- mImageGLp->setFilteringOption(LLTexUnit::TFO_POINT);
return TRUE;
}
-BOOL LLFontGL::addChar(const llwchar wch)
+//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);
+}
+
+BOOL LLFontGL::addChar(const llwchar wch) const
{
if (!LLFont::addChar(wch))
{
@@ -547,10 +349,12 @@ BOOL LLFontGL::addChar(const llwchar wch)
}
stop_glerror();
- mImageGLp->setSubImage(mRawImageGLp, 0, 0, mImageGLp->getWidth(), mImageGLp->getHeight());
- gGL.getTexUnit(0)->bind(mImageGLp);
- mImageGLp->setFilteringOption(LLTexUnit::TFO_POINT);
- 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;
}
@@ -584,30 +388,17 @@ S32 LLFontGL::render(const LLWString &wstr,
return wstr.length() ;
}
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-
if (wstr.empty())
{
return 0;
}
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+
S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);
- // HACK for better bolding
- if (style & BOLD)
- {
- if (this == LLFontGL::sSansSerif)
- {
- return LLFontGL::sSansSerifBold->render(
- wstr, begin_offset,
- x, y,
- color,
- halign, valign,
- (style & ~BOLD),
- max_chars, max_pixels,
- right_x, use_embedded);
- }
- }
+ // Strip off any style bits that are already accounted for by the font.
+ style = style & (~getFontDesc().getStyle());
F32 drop_shadow_strength = 0.f;
if (style & (DROP_SHADOW | DROP_SHADOW_SOFT))
@@ -649,10 +440,6 @@ S32 LLFontGL::render(const LLWString &wstr,
F32 cur_x, cur_y, cur_render_x, cur_render_y;
- // Bind the font texture
-
- gGL.getTexUnit(0)->bind(mImageGLp);
-
// Not guaranteed to be set correctly
gGL.setSceneBlendType(LLRender::BT_ALPHA);
@@ -697,8 +484,8 @@ S32 LLFontGL::render(const LLWString &wstr,
F32 start_x = cur_x;
- F32 inv_width = 1.f / mImageGLp->getWidth();
- F32 inv_height = 1.f / mImageGLp->getHeight();
+ F32 inv_width = 1.f / mFontBitmapCachep->getBitmapWidth();
+ F32 inv_height = 1.f / mFontBitmapCachep->getBitmapHeight();
const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;
@@ -717,6 +504,9 @@ S32 LLFontGL::render(const LLWString &wstr,
}
+ // Remember last-used texture to avoid unnecesssary bind calls.
+ LLImageGL *last_bound_texture = NULL;
+
for (i = begin_offset; i < begin_offset + length; i++)
{
llwchar wch = wstr[i];
@@ -736,7 +526,7 @@ S32 LLFontGL::render(const LLWString &wstr,
if (!label.empty())
{
- ext_advance += (EXT_X_BEARING + gExtCharFont->getWidthF32( label.c_str() )) * sScaleX;
+ ext_advance += (EXT_X_BEARING + getFontExtChar()->getWidthF32( label.c_str() )) * sScaleX;
}
if (start_x + scaled_max_pixels < cur_x + ext_advance)
@@ -745,7 +535,12 @@ S32 LLFontGL::render(const LLWString &wstr,
break;
}
- gGL.getTexUnit(0)->bind(ext_image);
+ if (last_bound_texture != ext_image)
+ {
+ gGL.getTexUnit(0)->bind(ext_image);
+ last_bound_texture = ext_image;
+ }
+
// 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));
@@ -760,7 +555,7 @@ S32 LLFontGL::render(const LLWString &wstr,
//glLoadIdentity();
//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
//glScalef(sScaleX, sScaleY, 1.f);
- gExtCharFont->render(label, 0,
+ getFontExtChar()->render(label, 0,
/*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX),
/*llfloor*/(cur_y / sScaleY),
color,
@@ -778,15 +573,12 @@ S32 LLFontGL::render(const LLWString &wstr,
cur_x += EXT_KERNING * sScaleX;
}
cur_render_x = cur_x;
-
- // Bind the font texture
- gGL.getTexUnit(0)->bind(mImageGLp);
}
else
{
if (!hasGlyph(wch))
{
- (const_cast<LLFontGL*>(this))->addChar(wch);
+ addChar(wch);
}
const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
@@ -795,6 +587,14 @@ S32 LLFontGL::render(const LLWString &wstr,
llerrs << "Missing Glyph Info" << llendl;
break;
}
+ // Per-glyph bitmap texture.
+ LLImageGL *image_gl = mFontBitmapCachep->getImageGL(fgi->mBitmapNum);
+ if (last_bound_texture != image_gl)
+ {
+ gGL.getTexUnit(0)->bind(image_gl);
+ last_bound_texture = image_gl;
+ }
+
if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
{
// Not enough room for this character.
@@ -825,7 +625,7 @@ S32 LLFontGL::render(const LLWString &wstr,
// Kern this puppy.
if (!hasGlyph(next_char))
{
- (const_cast<LLFontGL*>(this))->addChar(next_char);
+ addChar(next_char);
}
cur_x += getXKerning(wch, next_char);
}
@@ -879,14 +679,11 @@ S32 LLFontGL::render(const LLWString &wstr,
gGL.popMatrix();
+ gGL.getTexUnit(0)->disable();
+
return chars_drawn;
}
-
-LLImageGL *LLFontGL::getImageGL() const
-{
- return mImageGLp;
-}
S32 LLFontGL::getWidth(const std::string& utf8text) const
{
@@ -1258,7 +1055,7 @@ F32 LLFontGL::getEmbeddedCharAdvance(const embedded_data_t* ext_data) const
F32 ext_width = (F32)ext_image->getWidth();
if( !label.empty() )
{
- ext_width += (EXT_X_BEARING + gExtCharFont->getWidthF32(label.c_str())) * sScaleX;
+ ext_width += (EXT_X_BEARING + getFontExtChar()->getWidthF32(label.c_str())) * sScaleX;
}
return (EXT_X_BEARING * sScaleX) + ext_width;
@@ -1271,19 +1068,19 @@ void LLFontGL::clearEmbeddedChars()
mEmbeddedChars.clear();
}
-void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const std::string& label )
+void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const std::string& label ) const
{
LLWString wlabel = utf8str_to_wstring(label);
addEmbeddedChar(wc, image, wlabel);
}
-void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& wlabel )
+void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& wlabel ) const
{
embedded_data_t* ext_data = new embedded_data_t(image, wlabel);
mEmbeddedChars[wc] = ext_data;
}
-void LLFontGL::removeEmbeddedChar( llwchar wc )
+void LLFontGL::removeEmbeddedChar( llwchar wc ) const
{
embedded_map_t::iterator iter = mEmbeddedChars.find(wc);
if (iter != mEmbeddedChars.end())
@@ -1387,68 +1184,9 @@ void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, con
gGL.end();
}
-// static
std::string LLFontGL::nameFromFont(const LLFontGL* fontp)
{
- if (fontp == sSansSerifHuge)
- {
- return std::string("SansSerifHuge");
- }
- else if (fontp == sSansSerifSmall)
- {
- return std::string("SansSerifSmall");
- }
- else if (fontp == sSansSerif)
- {
- return std::string("SansSerif");
- }
- else if (fontp == sSansSerifBig)
- {
- return std::string("SansSerifBig");
- }
- else if (fontp == sSansSerifBold)
- {
- return std::string("SansSerifBold");
- }
- else if (fontp == sMonospace)
- {
- return std::string("Monospace");
- }
- else
- {
- return std::string();
- }
-}
-
-// static
-LLFontGL* LLFontGL::fontFromName(const std::string& font_name)
-{
- LLFontGL* gl_font = NULL;
- if (font_name == "SansSerifHuge")
- {
- gl_font = LLFontGL::sSansSerifHuge;
- }
- else if (font_name == "SansSerifSmall")
- {
- gl_font = LLFontGL::sSansSerifSmall;
- }
- else if (font_name == "SansSerif")
- {
- gl_font = LLFontGL::sSansSerif;
- }
- else if (font_name == "SansSerifBig")
- {
- gl_font = LLFontGL::sSansSerifBig;
- }
- else if (font_name == "SansSerifBold")
- {
- gl_font = LLFontGL::sSansSerifBold;
- }
- else if (font_name == "Monospace")
- {
- gl_font = LLFontGL::sMonospace;
- }
- return gl_font;
+ return fontp->getFontDesc().getName();
}
// static
diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h
index f8da460de2..6cb1727ff4 100644
--- a/indra/llrender/llfontgl.h
+++ b/indra/llrender/llfontgl.h
@@ -40,8 +40,16 @@
#include "llcoord.h"
#include "llrect.h"
+#include "llfontregistry.h"
+
class LLColor4;
+// Key used to request a font.
+class LLFontDescriptor;
+
+// Structure used to store previously requested fonts.
+class LLFontRegistry;
+
class LLFontGL : public LLFont
{
public:
@@ -86,18 +94,13 @@ public:
LLFontGL &operator=(const LLFontGL &source);
static BOOL initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
- const std::string& monospace_file, F32 monospace_size,
- const std::string& sansserif_file,
- const std::string& sansserif_fallback_file, F32 ss_fallback_scale,
- F32 small_size, F32 medium_size, F32 large_size, F32 huge_size,
- const std::string& sansserif_bold_file, F32 bold_size,
- const std::string& app_dir = LLStringUtil::null);
+ const std::string& app_dir,
+ const std::vector<std::string>& xui_paths);
static void destroyDefaultFonts();
- static void destroyGL();
+ static void destroyAllGL();
+ void destroyGL();
- static bool loadFaceFallback(LLFontList *fontp, const std::string& fontname, const F32 point_size);
- static bool loadFace(LLFontGL *fontp, const std::string& fontname, const F32 point_size, LLFontList *fallback_fontp);
/* 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);
@@ -192,12 +195,11 @@ public:
LLImageGL *getImageGL() const;
- void addEmbeddedChar( llwchar wc, LLImageGL* image, const std::string& label);
- void addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& label);
- void removeEmbeddedChar( llwchar wc );
+ void addEmbeddedChar( llwchar wc, LLImageGL* image, const std::string& label) const;
+ void addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& label) const;
+ void removeEmbeddedChar( llwchar wc ) const;
static std::string nameFromFont(const LLFontGL* fontp);
- static LLFontGL* fontFromName(const std::string& name);
static std::string nameFromHAlign(LLFontGL::HAlign align);
static LLFontGL::HAlign hAlignFromName(const std::string& name);
@@ -228,20 +230,14 @@ public:
static BOOL sDisplayFont ;
static std::string sAppDir; // For loading fonts
- static LLFontGL* sMonospace; // medium
- static LLFontList* sMonospaceFallback;
-
- static LLFontGL* sSansSerifSmall; // small
- static LLFontList* sSSSmallFallback;
- static LLFontGL* sSansSerif; // medium
- static LLFontList* sSSFallback;
- static LLFontGL* sSansSerifBig; // large
- static LLFontList* sSSBigFallback;
- static LLFontGL* sSansSerifHuge; // very large
- static LLFontList* sSSHugeFallback;
-
- static LLFontGL* sSansSerifBold; // medium, bolded
- static LLFontList* sSSBoldFallback;
+ static LLFontGL* getFontMonospace();
+ static LLFontGL* getFontSansSerifSmall();
+ static LLFontGL* getFontSansSerif();
+ static LLFontGL* getFontSansSerifBig();
+ static LLFontGL* getFontSansSerifHuge();
+ static LLFontGL* getFontSansSerifBold();
+ static LLFontGL* getFontExtChar();
+ static LLFontGL* getFont(const LLFontDescriptor& desc);
static LLColor4 sShadowColor;
@@ -249,19 +245,26 @@ public:
friend class LLHUDText;
protected:
- /*virtual*/ BOOL addChar(const llwchar wch);
- static std::string getFontPathLocal();
- static std::string getFontPathSystem();
+ /*virtual*/ BOOL addChar(const llwchar wch) const;
protected:
- LLPointer<LLImageRaw> mRawImageGLp;
- LLPointer<LLImageGL> mImageGLp;
typedef std::map<llwchar,embedded_data_t*> embedded_map_t;
- embedded_map_t mEmbeddedChars;
+ mutable embedded_map_t mEmbeddedChars;
+ LLFontDescriptor mFontDesc;
+
+ // Registry holds all instantiated fonts.
+ static LLFontRegistry* sFontRegistry;
+
public:
+ static std::string getFontPathLocal();
+ static std::string getFontPathSystem();
+
static LLCoordFont sCurOrigin;
static std::vector<LLCoordFont> sOriginStack;
+
+ const LLFontDescriptor &getFontDesc() const { return mFontDesc; }
+ void setFontDesc(const LLFontDescriptor& font_desc) { mFontDesc = font_desc; }
};
#endif
diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp
new file mode 100644
index 0000000000..9b5bc5d0af
--- /dev/null
+++ b/indra/llrender/llfontregistry.cpp
@@ -0,0 +1,650 @@
+/**
+ * @file llfontregistry.cpp
+ * @author Brad Payne
+ * @brief Storage for fonts.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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 "llgl.h"
+#include "llfontregistry.h"
+#include "llfontgl.h"
+#include <boost/tokenizer.hpp>
+#include "llcontrol.h"
+#include "lldir.h"
+#include "llwindow.h"
+
+extern LLControlGroup gSavedSettings;
+
+using std::string;
+using std::map;
+
+bool fontDescInitFromXML(LLXMLNodePtr node, LLFontDescriptor& desc);
+
+LLFontDescriptor::LLFontDescriptor():
+ mStyle(0)
+{
+}
+
+LLFontDescriptor::LLFontDescriptor(const std::string& name,
+ const std::string& size,
+ const U8 style,
+ const string_vec_t& file_names):
+ mName(name),
+ mSize(size),
+ mStyle(style),
+ mFileNames(file_names)
+{
+}
+
+LLFontDescriptor::LLFontDescriptor(const std::string& name,
+ const std::string& size,
+ const U8 style):
+ mName(name),
+ mSize(size),
+ mStyle(style)
+{
+}
+
+
+bool LLFontDescriptor::operator<(const LLFontDescriptor& b) const
+{
+ if (mName < b.mName)
+ return true;
+ else if (mName > b.mName)
+ return false;
+
+ if (mStyle < b.mStyle)
+ return true;
+ else if (mStyle > b.mStyle)
+ return false;
+
+ if (mSize < b.mSize)
+ return true;
+ else
+ return false;
+}
+
+static const std::string s_template_string("TEMPLATE");
+
+bool LLFontDescriptor::isTemplate() const
+{
+ return getSize() == s_template_string;
+}
+
+// Look for substring match and remove substring if matched.
+bool removeSubString(std::string& str, const std::string& substr)
+{
+ size_t pos = str.find(substr);
+ if (pos != string::npos)
+ {
+ str.replace(pos,substr.length(),(const char *)NULL, 0);
+ return true;
+ }
+ return false;
+}
+
+// Check for substring match without modifying the source string.
+bool findSubString(std::string& str, const std::string& substr)
+{
+ size_t pos = str.find(substr);
+ if (pos != string::npos)
+ {
+ return true;
+ }
+ return false;
+}
+
+
+// Normal form is
+// - raw name
+// - bold, italic style info reflected in both style and font name.
+// - other style info removed.
+// - size info moved to mSize, defaults to Medium
+// For example,
+// - "SansSerifHuge" would normalize to { "SansSerif", "Huge", 0 }
+// - "SansSerifBold" would normalize to { "SansSerifBold", "Medium", BOLD }
+LLFontDescriptor LLFontDescriptor::normalize() const
+{
+ std::string new_name(mName);
+ std::string new_size(mSize);
+ U8 new_style(mStyle);
+
+ // Only care about style to extent it can be picked up by font.
+ new_style &= (LLFontGL::BOLD | LLFontGL::ITALIC);
+
+ // All these transformations are to support old-style font specifications.
+ if (removeSubString(new_name,"Small"))
+ new_size = "Small";
+ if (removeSubString(new_name,"Big"))
+ new_size = "Large";
+ if (removeSubString(new_name,"Medium"))
+ new_size = "Medium";
+ if (removeSubString(new_name,"Large"))
+ new_size = "Large";
+ if (removeSubString(new_name,"Huge"))
+ new_size = "Huge";
+
+ // HACK - Monospace is the only one we don't remove, so
+ // name "Monospace" doesn't get taken down to ""
+ // For other fonts, there's no ambiguity between font name and size specifier.
+ if (new_size != s_template_string && new_size.empty() && findSubString(new_name,"Monospace"))
+ new_size = "Monospace";
+ if (new_size.empty())
+ new_size = "Medium";
+
+ if (removeSubString(new_name,"Bold"))
+ new_style |= LLFontGL::BOLD;
+
+ if (removeSubString(new_name,"Italic"))
+ new_style |= LLFontGL::ITALIC;
+
+ return LLFontDescriptor(new_name,new_size,new_style,getFileNames());
+}
+
+LLFontRegistry::LLFontRegistry(const string_vec_t& xui_paths)
+{
+ // Propagate this down from LLUICtrlFactory so LLRender doesn't
+ // need an upstream dependency on LLUI.
+ mXUIPaths = xui_paths;
+
+ // This is potentially a slow directory traversal, so we want to
+ // cache the result.
+ mUltimateFallbackList = LLWindow::getDynamicFallbackFontList();
+}
+
+LLFontRegistry::~LLFontRegistry()
+{
+ clear();
+}
+
+bool LLFontRegistry::parseFontInfo(const std::string& xml_filename)
+{
+ bool success = false; // Succeed if we find at least one XUI file
+ const string_vec_t& xml_paths = mXUIPaths;
+ for (string_vec_t::const_iterator path_it = xml_paths.begin();
+ path_it != xml_paths.end();
+ ++path_it)
+ {
+
+ LLXMLNodePtr root;
+ std::string full_filename = gDirUtilp->findSkinnedFilename(*path_it, xml_filename);
+ bool parsed_file = LLXMLNode::parseFile(full_filename, root, NULL);
+
+ if (!parsed_file)
+ continue;
+
+ if ( root.isNull() || ! root->hasName( "fonts" ) )
+ {
+ llwarns << "Bad font info file: "
+ << full_filename << llendl;
+ continue;
+ }
+
+ std::string root_name;
+ root->getAttributeString("name",root_name);
+ if (root->hasName("fonts"))
+ {
+ // Expect a collection of children consisting of "font" or "font_size" entries
+ bool init_succ = initFromXML(root);
+ success = success || init_succ;
+ }
+ }
+ if (success)
+ dump();
+
+ return success;
+}
+
+std::string currentOsName()
+{
+#if LL_WINDOWS
+ return "Windows";
+#elif LL_DARWIN
+ return "Mac";
+#elif LL_SDL
+ return "Linux";
+#else
+ return "";
+#endif
+}
+
+bool fontDescInitFromXML(LLXMLNodePtr node, LLFontDescriptor& desc)
+{
+ if (node->hasName("font"))
+ {
+ std::string attr_name;
+ if (node->getAttributeString("name",attr_name))
+ {
+ desc.setName(attr_name);
+ }
+
+ std::string attr_style;
+ if (node->getAttributeString("font_style",attr_style))
+ {
+ desc.setStyle(LLFontGL::getStyleFromString(attr_style));
+ }
+
+ desc.setSize(s_template_string);
+ }
+
+ LLXMLNodePtr child;
+ for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
+ {
+ std::string child_name;
+ child->getAttributeString("name",child_name);
+ if (child->hasName("file"))
+ {
+ std::string font_file_name = child->getTextContents();
+ desc.getFileNames().push_back(font_file_name);
+ }
+ else if (child->hasName("os"))
+ {
+ if (child_name == currentOsName())
+ {
+ fontDescInitFromXML(child, desc);
+ }
+ }
+ }
+ return true;
+}
+
+bool LLFontRegistry::initFromXML(LLXMLNodePtr node)
+{
+ LLXMLNodePtr child;
+
+ for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
+ {
+ std::string child_name;
+ child->getAttributeString("name",child_name);
+ if (child->hasName("font"))
+ {
+ LLFontDescriptor desc;
+ bool font_succ = fontDescInitFromXML(child, desc);
+ LLFontDescriptor norm_desc = desc.normalize();
+ if (font_succ)
+ {
+ // if this is the first time we've seen this font name,
+ // create a new template map entry for it.
+ const LLFontDescriptor *match_desc = getMatchingFontDesc(desc);
+ if (match_desc == NULL)
+ {
+ // Create a new entry (with no corresponding font).
+ mFontMap[norm_desc] = NULL;
+ }
+ // otherwise, find the existing entry and combine data.
+ else
+ {
+ // Prepend files from desc.
+ // A little roundabout because the map key is const,
+ // so we have to fetch it, make a new map key, and
+ // replace the old entry.
+ string_vec_t match_file_names = match_desc->getFileNames();
+ match_file_names.insert(match_file_names.begin(),
+ desc.getFileNames().begin(),
+ desc.getFileNames().end());
+ LLFontDescriptor new_desc = *match_desc;
+ new_desc.getFileNames() = match_file_names;
+ mFontMap.erase(*match_desc);
+ mFontMap[new_desc] = NULL;
+ }
+ }
+ }
+ else if (child->hasName("font_size"))
+ {
+ std::string size_name;
+ F32 size_value;
+ if (child->getAttributeString("name",size_name) &&
+ child->getAttributeF32("size",size_value))
+ {
+ mFontSizes[size_name] = size_value;
+ }
+
+ }
+ }
+ return true;
+}
+
+bool LLFontRegistry::nameToSize(const std::string& size_name, F32& size)
+{
+ font_size_map_t::iterator it = mFontSizes.find(size_name);
+ if (it != mFontSizes.end())
+ {
+ size = it->second;
+ return true;
+ }
+ return false;
+}
+
+
+LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
+{
+ // Name should hold a font name recognized as a setting; the value
+ // of the setting should be a list of font files.
+ // Size should be a recognized string value
+ // Style should be a set of flags including any implied by the font name.
+
+ // First decipher the requested size.
+ LLFontDescriptor norm_desc = desc.normalize();
+ F32 point_size;
+ bool found_size = nameToSize(norm_desc.getSize(),point_size);
+ if (!found_size)
+ {
+ llwarns << "createFont unrecognized size " << norm_desc.getSize() << llendl;
+ return NULL;
+ }
+ llinfos << "createFont " << norm_desc.getName() << " size " << norm_desc.getSize() << " style " << ((S32) norm_desc.getStyle()) << llendl;
+ F32 fallback_scale = 1.0;
+
+ // Find corresponding font template (based on same descriptor with no size specified)
+ LLFontDescriptor template_desc(norm_desc);
+ template_desc.setSize(s_template_string);
+ const LLFontDescriptor *match_desc = getClosestFontTemplate(template_desc);
+ if (!match_desc)
+ {
+ llwarns << "createFont failed, no template found for "
+ << norm_desc.getName() << " style [" << ((S32)norm_desc.getStyle()) << "]" << llendl;
+ return NULL;
+ }
+
+ // See whether this best-match font has already been instantiated in the requested size.
+ LLFontDescriptor nearest_exact_desc = *match_desc;
+ nearest_exact_desc.setSize(norm_desc.getSize());
+ font_reg_map_t::iterator it = mFontMap.find(nearest_exact_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;
+ }
+
+ // Build list of font names to look for.
+ // Files specified for this font come first, followed by those from the default descriptor.
+ string_vec_t file_names = match_desc->getFileNames();
+ string_vec_t default_file_names;
+ LLFontDescriptor default_desc("default",s_template_string,0);
+ const LLFontDescriptor *match_default_desc = getMatchingFontDesc(default_desc);
+ if (match_default_desc)
+ {
+ file_names.insert(file_names.end(),
+ match_default_desc->getFileNames().begin(),
+ match_default_desc->getFileNames().end());
+ }
+
+ // Add ultimate fallback list - generated dynamically on linux,
+ // null elsewhere.
+ file_names.insert(file_names.end(),
+ getUltimateFallbackList().begin(),
+ getUltimateFallbackList().end());
+
+ // Load fonts based on names.
+ if (file_names.empty())
+ {
+ llwarns << "createFont failed, no file names specified" << llendl;
+ return NULL;
+ }
+ LLFontList *fontlistp = new LLFontList;
+ LLFontGL *result = NULL;
+
+ // Snarf all fonts we can into fontlistp. 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;
+
+ std::string local_path = LLFontGL::getFontPathLocal();
+ std::string sys_path = LLFontGL::getFontPathSystem();
+
+ // The fontname string may contain multiple font file names separated by semicolons.
+ // Break it apart and try loading each one, in order.
+ for(string_vec_t::iterator file_name_it = file_names.begin();
+ file_name_it != file_names.end();
+ ++file_name_it)
+ {
+ LLFontGL *fontp = new LLFontGL;
+ std::string font_path = local_path + *file_name_it;
+ BOOL is_fallback = !is_first_found;
+ F32 extra_scale = (is_fallback)?fallback_scale:1.0;
+ if (!fontp->loadFace(font_path, extra_scale * point_size,
+ LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback))
+ {
+ font_path = sys_path + *file_name_it;
+
+ if (!fontp->loadFace(font_path, extra_scale * point_size,
+ LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback))
+ {
+ LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << *file_name_it << LL_ENDL;
+ delete fontp;
+ fontp = NULL;
+ }
+ }
+
+ if(fontp)
+ {
+ if (is_first_found)
+ {
+ result = fontp;
+ is_first_found = false;
+ }
+ else
+ fontlistp->addAtEnd(fontp);
+ }
+ }
+ if (result && !fontlistp->empty())
+ {
+ result->setFallbackFont(fontlistp);
+ }
+
+ norm_desc.setStyle(match_desc->getStyle());
+ if (result)
+ result->setFontDesc(norm_desc);
+
+ if (!result)
+ {
+ llwarns << "createFont failed in some way" << llendl;
+ }
+ mFontMap[norm_desc] = result;
+ return result;
+}
+
+void LLFontRegistry::reset()
+{
+ for (font_reg_map_t::iterator it = mFontMap.begin();
+ it != mFontMap.end();
+ ++it)
+ {
+ // Reset the corresponding font but preserve the entry.
+ if (it->second)
+ it->second->reset();
+ }
+}
+
+void LLFontRegistry::clear()
+{
+ for (font_reg_map_t::iterator it = mFontMap.begin();
+ it != mFontMap.end();
+ ++it)
+ {
+ LLFontGL *fontp = it->second;
+ delete fontp;
+ }
+ mFontMap.clear();
+}
+
+void LLFontRegistry::destroyGL()
+{
+ for (font_reg_map_t::iterator it = mFontMap.begin();
+ it != mFontMap.end();
+ ++it)
+ {
+ // Reset the corresponding font but preserve the entry.
+ if (it->second)
+ it->second->destroyGL();
+ }
+}
+
+LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& orig_desc)
+{
+ LLFontDescriptor norm_desc = orig_desc.normalize();
+
+ font_reg_map_t::iterator it = mFontMap.find(norm_desc);
+ if (it != mFontMap.end())
+ return it->second;
+ else
+ {
+ LLFontGL *fontp = createFont(orig_desc);
+ if (!fontp)
+ {
+ llwarns << "getFont failed, name " << orig_desc.getName()
+ <<" style=[" << ((S32) orig_desc.getStyle()) << "]"
+ << " size=[" << orig_desc.getSize() << "]" << llendl;
+ }
+ return fontp;
+ }
+}
+
+const LLFontDescriptor *LLFontRegistry::getMatchingFontDesc(const LLFontDescriptor& desc)
+{
+ LLFontDescriptor norm_desc = desc.normalize();
+
+ font_reg_map_t::iterator it = mFontMap.find(norm_desc);
+ if (it != mFontMap.end())
+ return &(it->first);
+ else
+ return NULL;
+}
+
+static U32 bitCount(U8 c)
+{
+ U32 count = 0;
+ if (c & 1)
+ count++;
+ if (c & 2)
+ count++;
+ if (c & 4)
+ count++;
+ if (c & 8)
+ count++;
+ if (c & 16)
+ count++;
+ if (c & 32)
+ count++;
+ if (c & 64)
+ count++;
+ if (c & 128)
+ count++;
+ return count;
+}
+
+// Find nearest match for the requested descriptor.
+const LLFontDescriptor *LLFontRegistry::getClosestFontTemplate(const LLFontDescriptor& desc)
+{
+ const LLFontDescriptor *exact_match_desc = getMatchingFontDesc(desc);
+ if (exact_match_desc)
+ {
+ return exact_match_desc;
+ }
+
+ LLFontDescriptor norm_desc = desc.normalize();
+
+ const LLFontDescriptor *best_match_desc = NULL;
+ for (font_reg_map_t::iterator it = mFontMap.begin();
+ it != mFontMap.end();
+ ++it)
+ {
+ const LLFontDescriptor* curr_desc = &(it->first);
+
+ // Ignore if not a template.
+ if (!curr_desc->isTemplate())
+ continue;
+
+ // Ignore if font name is wrong.
+ if (curr_desc->getName() != norm_desc.getName())
+ continue;
+
+ // Reject font if it matches any bits we don't want
+ if (curr_desc->getStyle() & ~norm_desc.getStyle())
+ {
+ continue;
+ }
+
+ // Take if it's the first plausible candidate we've found.
+ if (!best_match_desc)
+ {
+ best_match_desc = curr_desc;
+ continue;
+ }
+
+ // Take if it matches more bits than anything before.
+ U8 best_style_match_bits =
+ norm_desc.getStyle() & best_match_desc->getStyle();
+ U8 curr_style_match_bits =
+ norm_desc.getStyle() & curr_desc->getStyle();
+ if (bitCount(curr_style_match_bits) > bitCount(best_style_match_bits))
+ {
+ best_match_desc = curr_desc;
+ continue;
+ }
+
+ // Tie-breaker: take if it matches bold.
+ if (curr_style_match_bits & LLFontGL::BOLD) // Bold is requested and this descriptor matches it.
+ {
+ best_match_desc = curr_desc;
+ continue;
+ }
+ }
+
+ // Nothing matched.
+ return best_match_desc;
+}
+
+void LLFontRegistry::dump()
+{
+ llinfos << "LLFontRegistry dump: " << llendl;
+ for (font_size_map_t::iterator size_it = mFontSizes.begin();
+ size_it != mFontSizes.end();
+ ++size_it)
+ {
+ llinfos << "Size: " << size_it->first << " => " << size_it->second << llendl;
+ }
+ for (font_reg_map_t::iterator font_it = mFontMap.begin();
+ font_it != mFontMap.end();
+ ++font_it)
+ {
+ const LLFontDescriptor& desc = font_it->first;
+ llinfos << "Font: name=" << desc.getName()
+ << " style=[" << ((S32)desc.getStyle()) << "]"
+ << " size=[" << desc.getSize() << "]"
+ << " fileNames="
+ << llendl;
+ for (string_vec_t::const_iterator file_it=desc.getFileNames().begin();
+ file_it != desc.getFileNames().end();
+ ++file_it)
+ {
+ llinfos << " file: " << *file_it <<llendl;
+ }
+ }
+}
diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h
new file mode 100644
index 0000000000..ed775eeed0
--- /dev/null
+++ b/indra/llrender/llfontregistry.h
@@ -0,0 +1,113 @@
+/**
+ * @file llfontregistry.h
+ * @author Brad Payne
+ * @brief Storage for fonts.
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ *
+ * Copyright (c) 2008, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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_LLFONTREGISTRY_H
+#define LL_LLFONTREGISTRY_H
+
+#include "llxmlnode.h"
+
+class LLFontGL;
+
+typedef std::vector<std::string> string_vec_t;
+
+class LLFontDescriptor
+{
+public:
+ LLFontDescriptor();
+ LLFontDescriptor(const std::string& name, const std::string& size, const U8 style);
+ LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const string_vec_t& file_names);
+ LLFontDescriptor normalize() const;
+
+ bool operator<(const LLFontDescriptor& b) const;
+
+ bool isTemplate() const;
+
+ const std::string& getName() const { return mName; }
+ void setName(const std::string& name) { mName = name; }
+ const std::string& getSize() const { return mSize; }
+ void setSize(const std::string& size) { mSize = size; }
+ const std::vector<std::string>& getFileNames() const { return mFileNames; }
+ std::vector<std::string>& getFileNames() { return mFileNames; }
+ const U8 getStyle() const { return mStyle; }
+ void setStyle(U8 style) { mStyle = style; }
+
+private:
+ std::string mName;
+ std::string mSize;
+ string_vec_t mFileNames;
+ U8 mStyle;
+};
+
+class LLFontRegistry
+{
+public:
+ LLFontRegistry(const string_vec_t& xui_paths);
+ ~LLFontRegistry();
+
+ // Load standard font info from XML file(s).
+ bool parseFontInfo(const std::string& xml_filename);
+ bool initFromXML(LLXMLNodePtr node);
+
+ // Clear cached glyphs for all fonts.
+ void reset();
+
+ // Destroy all fonts.
+ void clear();
+
+ // GL cleanup
+ void destroyGL();
+
+ LLFontGL *getFont(const LLFontDescriptor& desc);
+ const LLFontDescriptor *getMatchingFontDesc(const LLFontDescriptor& desc);
+ const LLFontDescriptor *getClosestFontTemplate(const LLFontDescriptor& desc);
+
+ bool nameToSize(const std::string& size_name, F32& size);
+
+ void dump();
+
+ const string_vec_t& getUltimateFallbackList() const { return mUltimateFallbackList; }
+
+private:
+ LLFontGL *createFont(const LLFontDescriptor& desc);
+ typedef std::map<LLFontDescriptor,LLFontGL*> font_reg_map_t;
+ typedef std::map<std::string,F32> font_size_map_t;
+
+ // Given a descriptor, look up specific font instantiation.
+ font_reg_map_t mFontMap;
+ // Given a size name, look up the point size.
+ font_size_map_t mFontSizes;
+
+ string_vec_t mUltimateFallbackList;
+ string_vec_t mXUIPaths;
+};
+
+#endif // LL_LLFONTREGISTRY_H
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index c784019cd9..cdf626e16f 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1373,6 +1373,9 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
case GL_RGBA:
stride = 4;
break;
+ case GL_BGRA_EXT:
+ stride = 4;
+ break;
default:
llwarns << "Cannot analyze alpha of image with primary format " << std::hex << mFormatPrimary << std::dec << llendl;
return;