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); } }