From 5d2511e39e1c2cf9e1378c5dbbfdec37863d901d Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 19 Nov 2013 17:56:27 -0600 Subject: [PATCH 1/6] More font cleanup and updating. --- indra/llrender/llfontfreetype.cpp | 149 ++++++-------------- indra/llrender/llfontfreetype.h | 24 ++-- indra/llrender/llfontgl.cpp | 219 ++++++++++++++++-------------- indra/llrender/llfontregistry.cpp | 2 + indra/llui/lllineeditor.cpp | 31 +++-- 5 files changed, 193 insertions(+), 232 deletions(-) diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index a0322846a..98fc568fd 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -98,9 +98,7 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index) 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 - mBitmapNum(0), // Which bitmap in the bitmap cache contains this glyph - mIsRendered(FALSE), - mMetricsValid(FALSE) + mBitmapNum(0) // Which bitmap in the bitmap cache contains this glyph { } @@ -239,16 +237,12 @@ F32 LLFontFreetype::getXAdvance(const 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) + if (gi) { return gi->mXAdvance; } - //new else { char_glyph_info_map_t::iterator found_it = mCharGlyphInfoMap.find((llwchar)0); @@ -257,73 +251,29 @@ F32 LLFontFreetype::getXAdvance(const llwchar wch) const return found_it->second->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(); 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; - //gi->mIsRendered = 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(const llwchar char_left, const llwchar char_right) const +F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const { if (mFTFace == NULL) return 0.0; - llassert(!mIsFallback); - LLFontGlyphInfo* left_glyph_info = get_if_there(mCharGlyphInfoMap, char_left, (LLFontGlyphInfo*)NULL); + return glyph->mXAdvance; +} + +F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const +{ + if (mFTFace == NULL) + return 0.0; + + //llassert(!mIsFallback); + LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left);; 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); + LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right); U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; FT_Vector delta; @@ -333,22 +283,28 @@ F32 LLFontFreetype::getXKerning(const llwchar char_left, const llwchar char_righ return delta.x*(1.f/64.f); } -BOOL LLFontFreetype::hasGlyph(const llwchar wch) const +F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const +{ + if (mFTFace == NULL) + return 0.0; + + U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; + U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; + + 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); return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end()); - /*const LLFontGlyphInfo* gi = getGlyphInfo(wch); - if (gi && gi->mIsRendered) - { - return TRUE; - } - else - { - return FALSE; - }*/ } -BOOL LLFontFreetype::addGlyph(const llwchar wch) const +LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch) const { if (mFTFace == NULL) return FALSE; @@ -369,26 +325,25 @@ BOOL LLFontFreetype::addGlyph(const llwchar wch) const glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch); if (glyph_index) { - addGlyphFromFont(*iter, wch, glyph_index); - return TRUE; + return addGlyphFromFont(*iter, wch, glyph_index); } } } char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); - if (iter == mCharGlyphInfoMap.end() || !(iter->second->mIsRendered)) + if (iter == mCharGlyphInfoMap.end()) { return addGlyphFromFont(this, wch, glyph_index); } - return FALSE; + return NULL; } -BOOL LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, const llwchar wch, const U32 glyph_index) const +LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const { if (mFTFace == NULL) - return FALSE; + return NULL; - //llassert(!mIsFallback); + llassert(!mIsFallback); fontp->renderGlyph(glyph_index); S32 width = fontp->mFTFace->glyph->bitmap.width; S32 height = fontp->mFTFace->glyph->bitmap.rows; @@ -409,8 +364,6 @@ BOOL LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, const llwchar // 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); @@ -481,31 +434,25 @@ BOOL LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, const llwchar // omit it from the font-image. } - //new 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 gi; } -LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(const llwchar wch) const +LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch) const { char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); if (iter != mCharGlyphInfoMap.end()) { return iter->second; } - else if(addGlyph(wch))//new + else { // this glyph doesn't yet exist, so render it and return the result - char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); - if (iter != mCharGlyphInfoMap.end()) - { - return iter->second; - } + return addGlyph(wch); } - return NULL; } void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const @@ -536,7 +483,6 @@ void LLFontFreetype::renderGlyph(const U32 glyph_index) const void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi) { - //new resetBitmapCache(); loadFace(mName,mPointSize,vert_dpi,horz_dpi,mFontBitmapCachep->getNumComponents(),mIsFallback); if (!mIsFallback) @@ -557,21 +503,10 @@ void LLFontFreetype::reset(F32 vert_dpi, F32 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; - }*/ - //new for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); mCharGlyphInfoMap.clear(); @@ -605,7 +540,7 @@ void LLFontFreetype::setSubImageLuminanceAlpha(const U32 x, const U32 y, const U { LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); - //llassert(!mIsFallback); + llassert(!mIsFallback); llassert(image_raw && (image_raw->getComponents() == 2)); diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index 5e29e3fbb..948445835 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -27,7 +27,7 @@ #ifndef LL_LLFONTFREETYPE_H #define LL_LLFONTFREETYPE_H -#include +#include #include "llpointer.h" #include "llstl.h" @@ -67,10 +67,8 @@ struct LLFontGlyphInfo 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 @@ -129,9 +127,10 @@ public: LAST_CHAR_FULL = 255 }; - const LLFontGlyphInfo &getMetrics(const llwchar wc) const; - F32 getXAdvance(const llwchar wc) const; - F32 getXKerning(const llwchar char_left, const llwchar char_right) const; // Get the kerning between the two characters + F32 getXAdvance(llwchar wc) const; + F32 getXAdvance(const LLFontGlyphInfo* glyph) const; + F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters + F32 getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const; // Get the kerning between the two characters LLFontGlyphInfo* getGlyphInfo(const llwchar wch) const; void reset(F32 vert_dpi, F32 horz_dpi); @@ -147,13 +146,10 @@ public: private: void resetBitmapCache(); void setSubImageLuminanceAlpha(const U32 x, const U32 y, const U32 bitmap_num, const U32 width, const U32 height, const U8 *data, S32 stride = 0) const; -public: - BOOL hasGlyph(const llwchar wch) const; // Has a glyph for this character - BOOL addGlyph(const llwchar wch) const; // Add a new character to the font if necessary -private: - BOOL addGlyphFromFont(const LLFontFreetype *fontp, const llwchar wch, const U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found) - void renderGlyph(const U32 glyph_index) const; - + BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character + LLFontGlyphInfo* addGlyph(llwchar wch) const; // Add a new character to the font if necessary + LLFontGlyphInfo* 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) + void renderGlyph(U32 glyph_index) const; void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const; std::string mName; @@ -170,7 +166,7 @@ private: BOOL mValid; - typedef std::map char_glyph_info_map_t; + typedef boost::unordered_map char_glyph_info_map_t; mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap mutable LLPointer mFontBitmapCachep; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index d3cac8628..03f923761 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -266,6 +266,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } } + const LLFontGlyphInfo* next_glyph = NULL; // Remember last-used texture to avoid unnecesssary bind calls. LLImageGL *last_bound_texture = NULL; @@ -336,13 +337,12 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } else { - //new - /*if (!mFontFreetype->hasGlyph(wch)) + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) { - addChar(wch); - }*/ - - const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); + fgi = mFontFreetype->getGlyphInfo(wch); + } if (!fgi) { llerrs << "Missing Glyph Info" << llendl; @@ -384,13 +384,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons if (next_char && (next_char < LAST_CHARACTER)) { // Kern this puppy. - //new - /*if (!mFontFreetype->hasGlyph(next_char)) - { - addChar(next_char); - }*/ - mFontFreetype->getGlyphInfo(next_char); - cur_x += mFontFreetype->getXKerning(wch, next_char); + next_glyph = mFontFreetype->getGlyphInfo(next_char); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); } // Round after kerning. @@ -527,13 +522,13 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S F32 cur_x = 0; const S32 max_index = begin_offset + max_chars; - for (S32 i = begin_offset; i < max_index; i++) + + const LLFontGlyphInfo* next_glyph = NULL; + + F32 width_padding = 0.f; + for (S32 i = begin_offset; i < max_index && wchars[i] != 0; i++) { const llwchar wch = wchars[i]; - if (wch == 0) - { - break; // done - } const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; if (ext_data) { @@ -547,7 +542,23 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S } else { - cur_x += mFontFreetype->getXAdvance(wch); + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch); + } + + F32 advance = mFontFreetype->getXAdvance(fgi); + + // for the last character we want to measure the greater of its width and xadvance values + // so keep track of the difference between these values for the each character we measure + // so we can fix things up at the end + width_padding = llmax( 0.f, // always use positive padding amount + width_padding - advance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character + + cur_x += advance; llwchar next_char = wchars[i+1]; if (((i + 1) < begin_offset + max_chars) @@ -555,13 +566,17 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S && (next_char < LAST_CHARACTER)) { // Kern this puppy. - cur_x += mFontFreetype->getXKerning(wch, next_char); + next_glyph = mFontFreetype->getGlyphInfo(next_char); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); } + // Round after kerning. + cur_x = (F32)llround(cur_x); } - // Round after kerning. - cur_x = (F32)llround(cur_x); } + // add in extra pixels for last character's width past its xadvance + cur_x += width_padding; + return cur_x / sScaleX; } @@ -590,7 +605,11 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch S32 start_of_last_word = 0; BOOL in_word = FALSE; - F32 scaled_max_pixels = (F32)llceil(max_pixels * sScaleX); + // avoid S32 overflow when max_pixels == S32_MAX by staying in floating point + F32 scaled_max_pixels = max_pixels * sScaleX; + F32 width_padding = 0.f; + + LLFontGlyphInfo* next_glyph = NULL; S32 i; for (i=0; (i < max_chars); i++) @@ -651,9 +670,22 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch } } - cur_x += mFontFreetype->getXAdvance(wch); - - if (scaled_max_pixels < cur_x) + LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch); + } + + // account for glyphs that run beyond the starting point for the next glyphs + width_padding = llmax( 0.f, // always use positive padding amount + width_padding - fgi->mXAdvance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance); // difference between width of this character and advance to next character + + cur_x += fgi->mXAdvance; + + // clip if current character runs past scaled_max_pixels (using width_padding) + if (scaled_max_pixels < cur_x + width_padding) { clip = TRUE; break; @@ -662,7 +694,8 @@ 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 += mFontFreetype->getXKerning(wch, wchars[i+1]); + next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1]); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); } } // Round after kerning. @@ -717,34 +750,29 @@ 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 = 0; + F32 width = 0; if(ext_data) { - char_width = getEmbeddedCharAdvance(ext_data); + width = getEmbeddedCharAdvance(ext_data); } else { - //new const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); // last character uses character width, since the whole character needs to be visible // other characters just use advance - char_width = (i == start) + width = (i == start) ? (F32)(fgi->mWidth + fgi->mXBearing) // use actual width for last character - : fgi->mXAdvance; // use advance for all other characters - - //old - //const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); - //mFontFreetype->getXAdvance(wch); + : fgi->mXAdvance; // use advance for all other characters } - if( scaled_max_pixels < (total_width + char_width) ) + if( scaled_max_pixels < (total_width + width) ) { break; } - total_width += char_width; + total_width += width; drawable_chars++; if( max_chars >= 0 && drawable_chars >= max_chars ) @@ -759,10 +787,20 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ } // Round after kerning. - total_width = llround(total_width); + total_width = (F32)llround(total_width); } - return start_pos - drawable_chars; + if (drawable_chars == 0) + { + return start_pos; // just draw last character + } + else + { + // if only 1 character is drawable, we want to return start_pos as the first character to draw + // if 2 are drawable, return start_pos and character before start_pos, etc. + return start_pos + 1 - drawable_chars; + } + } @@ -781,6 +819,8 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars); F32 scaled_max_pixels = max_pixels * sScaleX; + + const LLFontGlyphInfo* next_glyph = NULL; S32 pos; for (pos = begin_offset; pos < max_index; pos++) @@ -790,83 +830,60 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, { break; // done } + const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) + const LLFontGlyphInfo* glyph = next_glyph; + next_glyph = NULL; + if(!glyph && !ext_data) { - F32 ext_advance = getEmbeddedCharAdvance(ext_data); + glyph = mFontFreetype->getGlyphInfo(wch); + } + + F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : mFontFreetype->getXAdvance(glyph); - if (round) - { - // Note: if the mouse is on the left half of the character, the pick is to the character's left - // If it's on the right half, the pick is to the right. - if (target_x < cur_x + ext_advance/2) - { - break; - } - } - else - { - if (target_x < cur_x + ext_advance) - { - break; - } - } - - if (scaled_max_pixels < cur_x + ext_advance) + if (round) + { + // Note: if the mouse is on the left half of the character, the pick is to the character's left + // If it's on the right half, the pick is to the right. + if (target_x < cur_x + char_width*0.5f) { break; } + } + else if (target_x < cur_x + char_width) + { + break; + } - pos++; - cur_x += ext_advance; + if (scaled_max_pixels < cur_x + char_width) + { + break; + } - if (((pos + 1) < max_index) - && (wchars[(pos + 1)])) + cur_x += char_width; + + if (((pos + 1) < max_index) + && (wchars[(pos + 1)])) + { + + if(ext_data) { cur_x += EXT_KERNING * sScaleX; } - // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); + else + { + next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1]); + cur_x += mFontFreetype->getXKerning(glyph, next_glyph); + } } - else - { - F32 char_width = mFontFreetype->getXAdvance(wch); - if (round) - { - // Note: if the mouse is on the left half of the character, the pick is to the character's left - // If it's on the right half, the pick is to the right. - if (target_x < cur_x + char_width*0.5f) - { - break; - } - } - else if (target_x < cur_x + char_width) - { - break; - } - if (scaled_max_pixels < cur_x + char_width) - { - break; - } - - pos++; - cur_x += char_width; - - if (((pos + 1) < max_index) - && (wchars[(pos + 1)])) - { - // Kern this puppy. - cur_x += mFontFreetype->getXKerning(wch, wchars[pos + 1]); - } - - // Round after kerning. - cur_x = (F32)llround(cur_x); - } + // Round after kerning. + cur_x = (F32)llround(cur_x); + } - return pos; + return llmin(max_chars, pos - begin_offset); } const LLFontDescriptor& LLFontGL::getFontDesc() const diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 6f56a463e..fa713cbb6 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -480,6 +480,8 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) result->mFontFreetype->setFallbackFonts(fontlist); } + norm_desc.setStyle(match_desc->getStyle()); + if (result) { result->mFontDescriptor = desc; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 79ccb6469..fb1673245 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -398,7 +398,10 @@ void LLLineEditor::setCursor( S32 pos ) { S32 width_chars_to_left = mGLFont->getWidth(mText.getWString().c_str(), 0, mScrollHPos); S32 last_visible_char = mGLFont->maxDrawableChars(mText.getWString().c_str(), llmax(0.f, (F32)(mMaxHPixels - mMinHPixels + width_chars_to_left))); - S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels - UI_LINEEDITOR_CURSOR_THICKNESS - UI_LINEEDITOR_H_PAD), mText.length(), getCursor()); + // character immediately to left of cursor should be last one visible (SCROLL_INCREMENT_ADD will scroll in more characters) + // or first character if cursor is at beginning + S32 new_last_visible_char = llmax(0, getCursor() - 1); + S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels - UI_LINEEDITOR_CURSOR_THICKNESS - UI_LINEEDITOR_H_PAD), mText.length(), new_last_visible_char); if (old_cursor_pos == last_visible_char) { mScrollHPos = llmin(mText.length(), llmax(min_scroll, mScrollHPos + SCROLL_INCREMENT_ADD)); @@ -1887,14 +1890,14 @@ void LLLineEditor::draw() { S32 select_left; S32 select_right; - if( mSelectionStart < getCursor() ) + if (mSelectionStart < mSelectionEnd) { select_left = mSelectionStart; - select_right = getCursor(); + select_right = mSelectionEnd; } else { - select_left = getCursor(); + select_left = mSelectionEnd; select_right = mSelectionStart; } @@ -1921,10 +1924,11 @@ void LLLineEditor::draw() width = llmin(width, mMaxHPixels - llround(rendered_pixels_right)); gl_rect_2d(llround(rendered_pixels_right), cursor_top, llround(rendered_pixels_right)+width, cursor_bottom, color); + LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ); rendered_text += mGLFont->render( mText, mScrollHPos + rendered_text, rendered_pixels_right, text_bottom, - LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ), + tmp_color, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, @@ -1936,7 +1940,7 @@ void LLLineEditor::draw() if( (rendered_pixels_right < (F32)mMaxHPixels) && (rendered_text < text_len) ) { // unselected, right side - mGLFont->render( + rendered_text += mGLFont->render( mText, mScrollHPos + rendered_text, rendered_pixels_right, text_bottom, text_color, @@ -1950,7 +1954,7 @@ void LLLineEditor::draw() } else { - mGLFont->render( + rendered_text = mGLFont->render( mText, mScrollHPos, rendered_pixels_right, text_bottom, text_color, @@ -1993,8 +1997,9 @@ void LLLineEditor::draw() cursor_right, cursor_bottom, text_color); if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) { + LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ); mGLFont->render(mText, getCursor(), (F32)(cursor_left + UI_LINEEDITOR_CURSOR_THICKNESS / 2), text_bottom, - LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ), + tmp_color, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, @@ -2787,13 +2792,19 @@ void LLLineEditor::updateAllowingLanguageInput() // fine on 1.15.0.2, since all prevalidate func reject any // non-ASCII characters. I'm not sure on future versions, // however... + LLWindow* window = getWindow(); + if (!window) + { + // test app, no window available + return; + } if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL) { - getWindow()->allowLanguageTextInput(this, TRUE); + window->allowLanguageTextInput(this, TRUE); } else { - getWindow()->allowLanguageTextInput(this, FALSE); + window->allowLanguageTextInput(this, FALSE); } } From 07736106b171b55dd7f958f57127ee068efa5e67 Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Wed, 20 Nov 2013 02:20:58 +0100 Subject: [PATCH 2/6] Suppress asserts in fallback font loading --- indra/llrender/llfontfreetype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index 98fc568fd..30b0ed429 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -343,7 +343,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l if (mFTFace == NULL) return NULL; - llassert(!mIsFallback); + //llassert(!mIsFallback); fontp->renderGlyph(glyph_index); S32 width = fontp->mFTFace->glyph->bitmap.width; S32 height = fontp->mFTFace->glyph->bitmap.rows; @@ -540,7 +540,7 @@ void LLFontFreetype::setSubImageLuminanceAlpha(const U32 x, const U32 y, const U { LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); - llassert(!mIsFallback); + //llassert(!mIsFallback); llassert(image_raw && (image_raw->getComponents() == 2)); From cde5b233530c3b43134039e8d8d5589b2daa28bf Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Wed, 20 Nov 2013 02:22:16 +0100 Subject: [PATCH 3/6] Limit avatar physics to 20-40 simulation steps per second to avoid wonky integration --- indra/newview/llphysicsmotion.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 6fc0ab438..d681dbd69 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -45,7 +45,8 @@ typedef std::map controller_map_t; typedef std::map default_controller_map_t; #define MIN_REQUIRED_PIXEL_AREA_AVATAR_PHYSICS_MOTION 0.f -#define TIME_ITERATION_STEP 0.1f +#define TIME_ITERATION_STEP 0.05f +#define MINIMUM_UPDATE_TIMESTEP 0.025f inline F64 llsgn(const F64 a) { @@ -592,7 +593,7 @@ BOOL LLPhysicsMotion::onUpdate(F32 time) const F32 time_delta = time - mLastTime; // Don't update too frequently, to avoid precision errors from small time slices. - if (time_delta <= .01) + if (time_delta <= MINIMUM_UPDATE_TIMESTEP) { return FALSE; } @@ -889,4 +890,4 @@ void LLPhysicsMotion::reset() mCharacter->setVisualParamWeight((*iter).mParam,(*iter).mParam->getDefaultWeight()); } } -} \ No newline at end of file +} From 3715b7439d10945a9a32a559edfbaae00aa289d4 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 19 Nov 2013 19:40:29 -0600 Subject: [PATCH 4/6] Doer fonts fast(er)! (better batching for font glyph rendering) --- indra/llrender/llfontgl.cpp | 235 +++++++++++++++++++++--------------- indra/llrender/llfontgl.h | 4 +- 2 files changed, 143 insertions(+), 96 deletions(-) diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 03f923761..6a353d06c 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -268,9 +268,15 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons const LLFontGlyphInfo* next_glyph = NULL; - // Remember last-used texture to avoid unnecesssary bind calls. - LLImageGL *last_bound_texture = NULL; + const S32 GLYPH_BATCH_SIZE = 30; + static LL_ALIGN_16(LLVector4a vertices[GLYPH_BATCH_SIZE * 4]); + static LLVector2 uvs[GLYPH_BATCH_SIZE * 4]; + static LLColor4U colors[GLYPH_BATCH_SIZE * 4]; + LLColor4U text_color(color); + + S32 bitmap_num = -1; + S32 glyph_count = 0; for (i = begin_offset; i < begin_offset + length; i++) { llwchar wch = wstr[i]; @@ -299,11 +305,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons break; } - if (last_bound_texture != ext_image) - { - gGL.getTexUnit(0)->bind(ext_image); - last_bound_texture = ext_image; - } + gGL.getTexUnit(0)->bind(ext_image); // snap origin to whole screen pixel const F32 ext_x = (F32)llround(cur_render_x + (EXT_X_BEARING * sScaleX)); @@ -311,7 +313,23 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons 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); + + if (glyph_count > 0) + { + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); + } + gGL.end(); + glyph_count = 0; + } + renderQuad(vertices, uvs, colors, screen_rect, uv_rect, LLColor4U::white, 0); + //No batching here. It will never happen. + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, 4); + } + gGL.end(); if (!label.empty()) { @@ -320,13 +338,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons /*llfloor*/(ext_x / sScaleX) + ext_image->getWidth() + EXT_X_BEARING - sCurOrigin.mX, /*llfloor*/(cur_render_y / sScaleY) - sCurOrigin.mY, color, - halign, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, + halign, BASELINE, UNDERLINE, NO_SHADOW, S32_MAX, S32_MAX, NULL, TRUE ); gGL.popMatrix(); } - gGL.color4fv(color.mV); - chars_drawn++; cur_x += ext_advance; if (((i + 1) < length) && wstr[i+1]) @@ -349,11 +365,24 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons break; } // Per-glyph bitmap texture. - LLImageGL *image_gl = font_bitmap_cache->getImageGL(fgi->mBitmapNum); - if (last_bound_texture != image_gl) + S32 next_bitmap_num = fgi->mBitmapNum; + if (next_bitmap_num != bitmap_num) { - gGL.getTexUnit(0)->bind(image_gl); - last_bound_texture = image_gl; + // Actually draw the queued glyphs before switching their texture; + // otherwise the queued glyphs will be taken from wrong textures. + if (glyph_count > 0) + { + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); + } + gGL.end(); + glyph_count = 0; + } + + bitmap_num = next_bitmap_num; + LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num); + gGL.getTexUnit(0)->bind(font_image); } if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) @@ -368,13 +397,24 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons (fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height, (fgi->mXBitmapOffset + fgi->mWidth) * inv_width, (fgi->mYBitmapOffset - PAD_UVY) * inv_height); - // snap glyph origin to whole screen pixel - LLRectf screen_rect((F32)llround(cur_render_x + (F32)fgi->mXBearing), + // snap glyph origin to whole screen pixel + LLRectf screen_rect((F32)llround(cur_render_x + (F32)fgi->mXBearing), (F32)llround(cur_render_y + (F32)fgi->mYBearing), (F32)llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth, (F32)llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight); - drawGlyph(screen_rect, uv_rect, color, style, shadow, drop_shadow_strength); + if (glyph_count >= GLYPH_BATCH_SIZE) + { + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); + } + gGL.end(); + + glyph_count = 0; + } + + drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style, shadow, drop_shadow_strength); chars_drawn++; cur_x += fgi->mXAdvance; @@ -400,6 +440,13 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } } + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); + } + gGL.end(); + + if (right_x) { *right_x = (cur_x - origin.mV[VX]) / sScaleX; @@ -1243,95 +1290,95 @@ LLFontGL &LLFontGL::operator=(const LLFontGL &source) return *this; } -void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const +void LLFontGL::renderQuad(LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const { - gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); - gGL.vertex2f(llfont_round_x(screen_rect.mRight), - llfont_round_y(screen_rect.mTop)); + S32 index = 0; - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); - gGL.vertex2f(llfont_round_x(screen_rect.mLeft), - llfont_round_y(screen_rect.mTop)); + vertex_out[index].set(screen_rect.mRight, screen_rect.mTop, 0.f); + uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); + colors_out[index] = color; + index++; - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); - gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), - llfont_round_y(screen_rect.mBottom)); + vertex_out[index].set(screen_rect.mLeft, screen_rect.mTop, 0.f); + uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop); + colors_out[index] = color; + index++; - gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); - gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt), - llfont_round_y(screen_rect.mBottom)); + vertex_out[index].set(screen_rect.mLeft, screen_rect.mBottom, 0.f); + uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom); + colors_out[index] = color; + index++; + + vertex_out[index].set(screen_rect.mRight, screen_rect.mBottom, 0.f); + uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom); + colors_out[index] = color; } -void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const +void LLFontGL::drawGlyph(S32& glyph_count, LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const { F32 slant_offset; slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f); - gGL.begin(LLRender::QUADS); + //FIXME: bold and drop shadow are mutually exclusive only for convenience + //Allow both when we need them. + if (style & BOLD) { - //FIXME: bold and drop shadow are mutually exclusive only for convenience - //Allow both when we need them. - if (style & BOLD) + for (S32 pass = 0; pass < 2; pass++) { - gGL.color4fv(color.mV); - for (S32 pass = 0; pass < 2; pass++) - { - LLRectf screen_rect_offset = screen_rect; + LLRectf screen_rect_offset = screen_rect; - screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); - renderQuad(screen_rect_offset, uv_rect, slant_offset); - } + screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, color, slant_offset); + glyph_count++; } - else if (shadow == DROP_SHADOW_SOFT) - { - LLColor4 shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH; - gGL.color4fv(shadow_color.mV); - for (S32 pass = 0; pass < 5; pass++) - { - LLRectf screen_rect_offset = screen_rect; - - switch(pass) - { - case 0: - screen_rect_offset.translate(-1.f, -1.f); - break; - case 1: - screen_rect_offset.translate(1.f, -1.f); - break; - case 2: - screen_rect_offset.translate(1.f, 1.f); - break; - case 3: - screen_rect_offset.translate(-1.f, 1.f); - break; - case 4: - screen_rect_offset.translate(0, -2.f); - break; - } - - renderQuad(screen_rect_offset, uv_rect, slant_offset); - } - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - else if (shadow == DROP_SHADOW) - { - LLColor4 shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength; - gGL.color4fv(shadow_color.mV); - LLRectf screen_rect_shadow = screen_rect; - screen_rect_shadow.translate(1.f, -1.f); - renderQuad(screen_rect_shadow, uv_rect, slant_offset); - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - else // normal rendering - { - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - } - gGL.end(); + else if (shadow == DROP_SHADOW_SOFT) + { + LLColor4U shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH); + for (S32 pass = 0; pass < 5; pass++) + { + LLRectf screen_rect_offset = screen_rect; + + switch(pass) + { + case 0: + screen_rect_offset.translate(-1.f, -1.f); + break; + case 1: + screen_rect_offset.translate(1.f, -1.f); + break; + case 2: + screen_rect_offset.translate(1.f, 1.f); + break; + case 3: + screen_rect_offset.translate(-1.f, 1.f); + break; + case 4: + screen_rect_offset.translate(0, -2.f); + break; + } + + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, shadow_color, slant_offset); + glyph_count++; + } + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } + else if (shadow == DROP_SHADOW) + { + LLColor4U shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength); + LLRectf screen_rect_shadow = screen_rect; + screen_rect_shadow.translate(1.f, -1.f); + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_shadow, uv_rect, shadow_color, slant_offset); + glyph_count++; + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } + else // normal rendering + { + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } } diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index d7c47995d..f83a72f73 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -232,8 +232,8 @@ protected: LLFontDescriptor mFontDescriptor; LLPointer mFontFreetype; - 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; + void renderQuad(LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const; + void drawGlyph(S32& glyph_count, LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const; // Registry holds all instantiated fonts. static LLFontRegistry* sFontRegistry; From f23dc157be8c39ab6fdbaee64fd3ad986fb560f2 Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Wed, 20 Nov 2013 05:49:43 +0100 Subject: [PATCH 5/6] Prevent accidental modification of vital stock grid --- indra/newview/app_settings/default_grids.xml | 3 +- indra/newview/hippogridmanager.cpp | 12 ++-- indra/newview/hippogridmanager.h | 4 +- indra/newview/hippopanelgrids.cpp | 60 +++++++++++++------- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/indra/newview/app_settings/default_grids.xml b/indra/newview/app_settings/default_grids.xml index b86d64ac3..258961627 100644 --- a/indra/newview/app_settings/default_grids.xml +++ b/indra/newview/app_settings/default_grids.xml @@ -2,7 +2,7 @@ - default_grids_version21 + default_grids_version22 @@ -20,6 +20,7 @@ render_compat1 inventory_links1 auto_update0 + locked1 diff --git a/indra/newview/hippogridmanager.cpp b/indra/newview/hippogridmanager.cpp index f4bda53ac..9057109d2 100644 --- a/indra/newview/hippogridmanager.cpp +++ b/indra/newview/hippogridmanager.cpp @@ -57,6 +57,7 @@ HippoGridInfo::HippoGridInfo(const std::string& gridName) : mRenderCompat(true), mInvLinks(false), mAutoUpdate(false), + mLocked(false), mMaxAgentGroups(-1), mCurrencySymbol("OS$"), mCurrencyText("OS Dollars"), @@ -174,10 +175,12 @@ void HippoGridInfo::setLoginUri(const std::string& loginUri) { mIsInProductionGrid = true; useHttps(); + setPlatform(PLATFORM_SECONDLIFE); } if (utf8str_tolower(LLURI(mLoginUri).hostName()) == "login.aditi.lindenlab.com") { useHttps(); + setPlatform(PLATFORM_SECONDLIFE); } if (utf8str_tolower(LLURI(mLoginUri).hostName()) == "login.avination.com" || utf8str_tolower(LLURI(mLoginUri).hostName()) == "login.avination.net") @@ -654,11 +657,6 @@ bool HippoGridInfo::getAutoUpdate() return mAutoUpdate; } -void HippoGridInfo::setAutoUpdate(bool b) -{ - mAutoUpdate = b; -} - bool HippoGridInfo::getUPCSupported() { if(isSecondLife()) @@ -1014,7 +1012,8 @@ void HippoGridManager::parseData(LLSD &gridInfo, bool mergeIfNewer) if (gridMap.has("search")) grid->setSearchUrl(gridMap["search"]); if (gridMap.has("render_compat")) grid->setRenderCompat(gridMap["render_compat"]); if (gridMap.has("inventory_links")) grid->setSupportsInvLinks(gridMap["inventory_links"]); - if (gridMap.has("auto_update")) grid->setAutoUpdate(gridMap["auto_update"]); + if (gridMap.has("auto_update")) grid->mAutoUpdate = gridMap["auto_update"]; + if (gridMap.has("locked")) grid->mLocked = gridMap["locked"]; if (newGrid) addGrid(grid); } } @@ -1051,6 +1050,7 @@ void HippoGridManager::saveFile() gridInfo[i]["render_compat"] = grid->isRenderCompat(); gridInfo[i]["inventory_links"] = grid->supportsInvLinks(); gridInfo[i]["auto_update"] = grid->getAutoUpdate(); + gridInfo[i]["locked"] = grid->getLocked(); } // write client grid info file diff --git a/indra/newview/hippogridmanager.h b/indra/newview/hippogridmanager.h index 089b381f9..4416e8598 100644 --- a/indra/newview/hippogridmanager.h +++ b/indra/newview/hippogridmanager.h @@ -22,6 +22,7 @@ class LLSD; class HippoGridInfo { + friend class HippoGridManager; public: enum Platform { PLATFORM_OTHER = 0, @@ -96,7 +97,7 @@ public: bool supportsInvLinks(); void setSupportsInvLinks(bool b); bool getAutoUpdate(); - void setAutoUpdate(bool b); + bool getLocked() { return mLocked; } void getGridInfo(); @@ -124,6 +125,7 @@ private: bool mRenderCompat; bool mInvLinks; bool mAutoUpdate; + bool mLocked; bool mUPCSupported; int mMaxAgentGroups; diff --git a/indra/newview/hippopanelgrids.cpp b/indra/newview/hippopanelgrids.cpp index d09d75fab..4057fb1a7 100644 --- a/indra/newview/hippopanelgrids.cpp +++ b/indra/newview/hippopanelgrids.cpp @@ -61,6 +61,7 @@ class HippoPanelGridsImpl : public HippoPanelGrids enum State { NORMAL, ADD_NEW, ADD_COPY }; State mState; std::string mCurGrid; + bool mIsEditable; void loadCurGrid(); bool saveCurGrid(); @@ -78,6 +79,8 @@ class HippoPanelGridsImpl : public HippoPanelGrids static void onClickGridInfo(void *data); static void onClickHelpRenderCompat(void *data); static void onClickAdvanced(void *data); + + void enableEditing(bool); }; @@ -103,7 +106,7 @@ HippoPanelGrids *HippoPanelGrids::create() HippoPanelGridsImpl::HippoPanelGridsImpl() : - mState(NORMAL) + mState(NORMAL), mIsEditable(true) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_grids.xml"); } @@ -194,27 +197,10 @@ void HippoPanelGridsImpl::refresh() childSetTextArg("default_grid", "[DEFAULT]", (defaultGrid != "")? defaultGrid: " "); - childSetEnabled("btn_delete", (selectIndex >= 0)); + childSetEnabled("btn_delete", (selectIndex >= 0) && mIsEditable ); childSetEnabled("btn_copy", (mState == NORMAL) && (selectIndex >= 0)); childSetEnabled("btn_default", (mState == NORMAL) && (selectIndex > 0)); - childSetEnabled("gridname", (mState == ADD_NEW) || (mState == ADD_COPY)); - - if (childGetValue("platform").asString() == "SecondLife") { - // disable platform selector, if logged into the grid edited and it is SL - // so object export restrictions cannot be circumvented by changing the platform - bool enablePlatform = (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) || - (mCurGrid != gHippoGridManager->getConnectedGrid()->getGridName()); - childSetEnabled("platform", enablePlatform); - childSetEnabled("search", false); - childSetText("search", LLStringExplicit("")); - childSetEnabled("render_compat", false); - childSetValue("render_compat", false); - } else { - childSetEnabled("platform", true); - childSetEnabled("search", true); - childSetText("search", gHippoGridManager->getConnectedGrid()->getSearchUrl()); - childSetEnabled("render_compat", true); - } + childSetEnabled("gridname", (mState == ADD_NEW) || (mState == ADD_COPY)); } @@ -256,9 +242,11 @@ void HippoPanelGridsImpl::loadCurGrid() childSetText("helperuri", gridInfo->getHelperUri()); childSetText("website", gridInfo->getWebSite()); childSetText("support", gridInfo->getSupportUrl()); + childSetText("search", gridInfo->getSearchUrl()); childSetText("register", gridInfo->getRegisterUrl()); childSetText("password", gridInfo->getPasswordUrl()); childSetValue("render_compat", gridInfo->isRenderCompat()); + enableEditing(!gridInfo->getLocked()); } else { std::string empty = ""; LLComboBox *platform = getChild("platform"); @@ -269,10 +257,11 @@ void HippoPanelGridsImpl::loadCurGrid() childSetText("helperuri", empty); childSetText("website", empty); childSetText("support", empty); + childSetText("search", empty); childSetText("register", empty); childSetText("password", empty); - childSetEnabled("render_compat", true); childSetValue("render_compat", true); + enableEditing(true); } if (mState == ADD_NEW) { @@ -281,6 +270,7 @@ void HippoPanelGridsImpl::loadCurGrid() childSetText("loginuri", required); } else if (mState == ADD_COPY) { childSetText("gridname", std::string("")); + enableEditing(true); } else if (mState != NORMAL) { llwarns << "Illegal state " << mState << '.' << llendl; } @@ -574,3 +564,31 @@ void HippoPanelGridsImpl::onClickHelpRenderCompat(void *data) { LLNotificationsUtil::add("HelpRenderCompat"); } + + +void HippoPanelGridsImpl::enableEditing(bool b) +{ + static const char * elements [] = { + "platform", + "gridname", + "loginuri", + "loginpage", + "helperuri", + "website", + "support", + "register", + "password", + "search", + "btn_delete", + "btn_gridinfo", + "render_compat", + "gridmessage", + 0 + }; + + for(int i = 0; elements[i]; ++i ) { + this->childSetEnabled(elements[i], b); + } + + mIsEditable = b; +} From 9c29488044140007d68275cfe5f59d242dce4272 Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Wed, 20 Nov 2013 10:33:15 +0100 Subject: [PATCH 6/6] If the text is too skinny to render, don't crash --- indra/llrender/llfontgl.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 6a353d06c..3626c88ea 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -150,7 +150,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons return wstr.length() ; } - if (wstr.empty()) + if (wstr.empty() || !max_pixels) { return 0; } @@ -440,11 +440,14 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } } - gGL.begin(LLRender::QUADS); + if(glyph_count) { - gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); + } + gGL.end(); } - gGL.end(); if (right_x)