summaryrefslogtreecommitdiff
path: root/indra/llui/lltextbase.cpp
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-09-05 11:00:11 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-09-05 11:00:11 -0400
commit000a23ba0534fdf9bfc4a1b051b7cee0adceef3e (patch)
tree776fe10c7aaf76371a889f79c48c3c9405fd5a4e /indra/llui/lltextbase.cpp
parent7ac4c3b56e5246fceaa73e7c9c665d3c04827d6c (diff)
parentbacf9cfeab90bd1ffad827fa3c34ced985c768a2 (diff)
Merge branch 'develop' into release/luau-scripting
Diffstat (limited to 'indra/llui/lltextbase.cpp')
-rw-r--r--indra/llui/lltextbase.cpp251
1 files changed, 172 insertions, 79 deletions
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index d236b59937..3aad8f5fe6 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -401,8 +401,8 @@ std::vector<LLRect> LLTextBase::getSelectionRects()
// Use F32 otherwise a string of multiple segments
// will accumulate a large error
- F32 left_precise = line_iter->mRect.mLeft;
- F32 right_precise = line_iter->mRect.mLeft;
+ F32 left_precise = (F32)line_iter->mRect.mLeft;
+ F32 right_precise = (F32)line_iter->mRect.mLeft;
for (; segment_iter != mSegments.end(); ++segment_iter, segment_offset = 0)
{
@@ -448,8 +448,8 @@ std::vector<LLRect> LLTextBase::getSelectionRects()
}
LLRect selection_rect;
- selection_rect.mLeft = left_precise;
- selection_rect.mRight = right_precise;
+ selection_rect.mLeft = (S32)left_precise;
+ selection_rect.mRight = (S32)right_precise;
selection_rect.mBottom = line_iter->mRect.mBottom;
selection_rect.mTop = line_iter->mRect.mTop;
@@ -584,9 +584,8 @@ void LLTextBase::drawCursor()
if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection() && text[mCursorPos] != '\n')
{
- LLColor4 text_color;
const LLFontGL* fontp;
- text_color = segmentp->getColor();
+ const LLColor4& text_color = segmentp->getColor();
fontp = segmentp->getStyle()->getFont();
fontp->render(text, mCursorPos, cursor_rect,
LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha),
@@ -598,7 +597,7 @@ void LLTextBase::drawCursor()
// Make sure the IME is in the right place
LLRect screen_pos = calcScreenRect();
- LLCoordGL ime_pos( screen_pos.mLeft + llfloor(cursor_rect.mLeft), screen_pos.mBottom + llfloor(cursor_rect.mTop) );
+ LLCoordGL ime_pos( screen_pos.mLeft + cursor_rect.mLeft, screen_pos.mBottom + cursor_rect.mTop );
ime_pos.mX = (S32) (ime_pos.mX * LLUI::getScaleFactor().mV[VX]);
ime_pos.mY = (S32) (ime_pos.mY * LLUI::getScaleFactor().mV[VY]);
@@ -755,9 +754,9 @@ void LLTextBase::drawText()
line_end = next_start;
}
- LLRectf text_rect(line.mRect.mLeft, line.mRect.mTop, line.mRect.mRight, line.mRect.mBottom);
- text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents
- text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position
+ LLRectf text_rect((F32)line.mRect.mLeft, (F32)line.mRect.mTop, (F32)line.mRect.mRight, (F32)line.mRect.mBottom);
+ text_rect.mRight = (F32)mDocumentView->getRect().getWidth(); // clamp right edge to document extents
+ text_rect.translate((F32)mDocumentView->getRect().mLeft, (F32)mDocumentView->getRect().mBottom); // adjust by scroll position
// draw a single line of text
S32 seg_start = line_start;
@@ -802,13 +801,13 @@ void LLTextBase::drawText()
S32 squiggle_start = 0, squiggle_end = 0, pony = 0;
cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_start - seg_start, squiggle_start, pony);
cur_segment->getDimensions(misspell_start - cur_segment->getStart(), misspell_end - misspell_start, squiggle_end, pony);
- squiggle_start += text_rect.mLeft;
+ squiggle_start += (S32)text_rect.mLeft;
pony = (squiggle_end + 3) / 6;
squiggle_start += squiggle_end / 2 - pony * 3;
squiggle_end = squiggle_start + pony * 6;
- S32 squiggle_bottom = text_rect.mBottom + (S32)cur_segment->getStyle()->getFont()->getDescenderHeight();
+ S32 squiggle_bottom = (S32)text_rect.mBottom + (S32)cur_segment->getStyle()->getFont()->getDescenderHeight();
gGL.color4ub(255, 0, 0, 200);
while (squiggle_start + 1 < squiggle_end)
@@ -949,7 +948,6 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
{
-
beforeValueChange();
segment_set_t::iterator seg_iter = getSegIterContaining(pos);
while(seg_iter != mSegments.end())
@@ -1326,6 +1324,7 @@ void LLTextBase::reshape(S32 width, S32 height, bool called_from_parent)
//virtual
void LLTextBase::draw()
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
// reflow if needed, on demand
reflow();
@@ -1368,7 +1367,7 @@ void LLTextBase::draw()
{
bg_rect.intersectWith(text_rect);
}
- LLColor4 bg_color = mReadOnly
+ const LLColor4& bg_color = mReadOnly
? mReadOnlyBgColor.get()
: hasFocus()
? mFocusBgColor.get()
@@ -1379,7 +1378,7 @@ void LLTextBase::draw()
// Draw highlighted if needed
if( ll::ui::SearchableControl::getHighlighted() )
{
- LLColor4 bg_color = ll::ui::SearchableControl::getHighlightColor();
+ const LLColor4& bg_color = ll::ui::SearchableControl::getHighlightColor();
LLRect bg_rect = mVisibleTextRect;
if( mScroller )
bg_rect.intersectWith( text_rect );
@@ -1412,14 +1411,14 @@ void LLTextBase::draw()
//virtual
-void LLTextBase::setColor( const LLColor4& c )
+void LLTextBase::setColor( const LLUIColor& c )
{
mFgColor = c;
mStyleDirty = true;
}
//virtual
-void LLTextBase::setReadOnlyColor(const LLColor4 &c)
+void LLTextBase::setReadOnlyColor(const LLUIColor &c)
{
mReadOnlyFgColor = c;
mStyleDirty = true;
@@ -1674,7 +1673,7 @@ void LLTextBase::reflow()
segment_set_t::iterator seg_iter = mSegments.begin();
S32 seg_offset = 0;
S32 line_start_index = 0;
- const F32 text_available_width = mVisibleTextRect.getWidth() - mHPad; // reserve room for margin
+ const F32 text_available_width = (F32)(mVisibleTextRect.getWidth() - mHPad); // reserve room for margin
F32 remaining_pixels = text_available_width;
S32 line_count = 0;
@@ -1881,7 +1880,7 @@ S32 LLTextBase::getLineNumFromDocIndex( S32 doc_index, bool include_wordwrap) co
line_list_t::const_iterator iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), doc_index, line_end_compare());
if (include_wordwrap)
{
- return iter - mLineInfoList.begin();
+ return (S32)(iter - mLineInfoList.begin());
}
else
{
@@ -1918,7 +1917,7 @@ S32 LLTextBase::getFirstVisibleLine() const
// binary search for line that starts before top of visible buffer
line_list_t::const_iterator iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
- return iter - mLineInfoList.begin();
+ return (S32)(iter - mLineInfoList.begin());
}
std::pair<S32, S32> LLTextBase::getVisibleLines(bool require_fully_visible)
@@ -1940,7 +1939,7 @@ std::pair<S32, S32> LLTextBase::getVisibleLines(bool require_fully_visible)
first_iter = std::upper_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mTop, compare_bottom());
last_iter = std::lower_bound(mLineInfoList.begin(), mLineInfoList.end(), visible_region.mBottom, compare_top());
}
- return std::pair<S32, S32>(first_iter - mLineInfoList.begin(), last_iter - mLineInfoList.begin());
+ return std::pair<S32, S32>((S32)(first_iter - mLineInfoList.begin()), (S32)(last_iter - mLineInfoList.begin()));
}
@@ -2203,8 +2202,8 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
- LLStyle::Params style_params(input_params);
- style_params.fillFrom(getStyleParams());
+ LLStyle::Params style_params(getStyleParams());
+ style_params.overwriteFrom(input_params);
S32 part = (S32)LLTextParser::WHOLE;
if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
@@ -2418,16 +2417,14 @@ void LLTextBase::appendAndHighlightTextImpl(const std::string &new_text, S32 hig
{
LLStyle::Params highlight_params(style_params);
- LLSD pieces = LLTextParser::instance().parsePartialLineHighlights(new_text, highlight_params.color(), (LLTextParser::EHighlightPosition)highlight_part);
+ auto pieces = LLTextParser::instance().parsePartialLineHighlights(new_text, highlight_params.color, (LLTextParser::EHighlightPosition)highlight_part);
for (S32 i = 0; i < pieces.size(); i++)
{
- LLSD color_llsd = pieces[i]["color"];
- LLColor4 lcolor;
- lcolor.setValue(color_llsd);
- highlight_params.color = lcolor;
+ const auto& piece_pair = pieces[i];
+ highlight_params.color = piece_pair.second;
LLWString wide_text;
- wide_text = utf8str_to_wstring(pieces[i]["text"].asString());
+ wide_text = utf8str_to_wstring(piece_pair.first);
S32 cur_length = getLength();
LLStyleConstSP sp(new LLStyle(highlight_params));
@@ -2589,6 +2586,11 @@ const LLWString& LLTextBase::getWText() const
return getViewModel()->getDisplay();
}
+S32 LLTextBase::getTextGeneration() const
+{
+ return getViewModel()->getDisplayGeneration();
+}
+
// If round is true, if the position is on the right half of a character, the cursor
// will be put to its right. If round is false, the cursor will always be put to the
// character's left.
@@ -2608,7 +2610,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, bool round,
}
S32 pos = getLength();
- F32 start_x = line_iter->mRect.mLeft + doc_rect.mLeft;
+ F32 start_x = (F32)(line_iter->mRect.mLeft + doc_rect.mLeft);
segment_set_t::iterator line_seg_iter;
S32 line_seg_offset;
@@ -2626,7 +2628,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, bool round,
if(newline)
{
- pos = segment_line_start + segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round);
+ pos = segment_line_start + segmentp->getOffset(local_x - (S32)start_x, line_seg_offset, segment_line_length, round);
break;
}
@@ -2656,7 +2658,7 @@ S32 LLTextBase::getDocIndexFromLocalCoord( S32 local_x, S32 local_y, bool round,
}
else
{
- offset = segmentp->getOffset(local_x - start_x, line_seg_offset, segment_line_length, round);
+ offset = segmentp->getOffset(local_x - (S32)start_x, line_seg_offset, segment_line_length, round);
}
pos = segment_line_start + offset;
break;
@@ -2703,7 +2705,7 @@ LLRect LLTextBase::getDocRectFromDocIndex(S32 pos) const
getSegmentAndOffset(line_iter->mDocIndexStart, &line_seg_iter, &line_seg_offset);
getSegmentAndOffset(pos, &cursor_seg_iter, &cursor_seg_offset);
- F32 doc_left_precise = line_iter->mRect.mLeft;
+ F32 doc_left_precise = (F32)line_iter->mRect.mLeft;
while(line_seg_iter != mSegments.end())
{
@@ -2734,7 +2736,7 @@ LLRect LLTextBase::getDocRectFromDocIndex(S32 pos) const
}
LLRect doc_rect;
- doc_rect.mLeft = doc_left_precise;
+ doc_rect.mLeft = (S32)doc_left_precise;
doc_rect.mBottom = line_iter->mRect.mBottom;
doc_rect.mTop = line_iter->mRect.mTop;
@@ -3247,8 +3249,8 @@ F32 LLTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_e
bool LLTextSegment::canEdit() const { return false; }
void LLTextSegment::unlinkFromDocument(LLTextBase*) {}
void LLTextSegment::linkToDocument(LLTextBase*) {}
-const LLColor4& LLTextSegment::getColor() const { return LLColor4::white; }
-//void LLTextSegment::setColor(const LLColor4 &color) {}
+const LLUIColor& LLTextSegment::getColor() const { static const LLUIColor white = LLUIColorTable::instance().getColor("White", LLColor4::white); return white; }
+//void LLTextSegment::setColor(const LLUIColor &color) {}
LLStyleConstSP LLTextSegment::getStyle() const {static LLStyleConstSP sp(new LLStyle()); return sp; }
void LLTextSegment::setStyle(LLStyleConstSP style) {}
void LLTextSegment::setToken( LLKeywordToken* token ) {}
@@ -3283,7 +3285,8 @@ LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 e
: LLTextSegment(start, end),
mStyle( style ),
mToken(NULL),
- mEditor(editor)
+ mEditor(editor),
+ mLastGeneration(-1)
{
mFontHeight = mStyle->getFont()->getLineHeight();
@@ -3294,10 +3297,11 @@ LLNormalTextSegment::LLNormalTextSegment( LLStyleConstSP style, S32 start, S32 e
}
}
-LLNormalTextSegment::LLNormalTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, bool is_visible)
+LLNormalTextSegment::LLNormalTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible)
: LLTextSegment(start, end),
mToken(NULL),
- mEditor(editor)
+ mEditor(editor),
+ mLastGeneration(-1)
{
mStyle = new LLStyle(LLStyle::Params().visible(is_visible).color(color));
@@ -3316,25 +3320,42 @@ F32 LLNormalTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 selec
{
return drawClippedSegment( getStart() + start, getStart() + end, selection_start, selection_end, draw_rect);
}
+ else
+ {
+ mFontBufferPreSelection.reset();
+ mFontBufferSelection.reset();
+ mFontBufferPostSelection.reset();
+ }
return draw_rect.mLeft;
}
// Draws a single text segment, reversing the color for selection if needed.
F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 selection_start, S32 selection_end, LLRectf rect)
{
- F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha;
-
- const LLWString &text = getWText();
-
F32 right_x = rect.mLeft;
if (!mStyle->isVisible())
{
return right_x;
}
+ F32 alpha = LLViewDrawContext::getCurrentContext().mAlpha;
+
+ const LLWString& text = getWText();
+ S32 text_gen = mEditor.getTextGeneration();
+ bool is_text_read_only = mEditor.getReadOnly();
+
+ if (text_gen != mLastGeneration)
+ {
+ mLastGeneration = text_gen;
+
+ mFontBufferPreSelection.reset();
+ mFontBufferSelection.reset();
+ mFontBufferPostSelection.reset();
+ }
+
const LLFontGL* font = mStyle->getFont();
- LLColor4 color = (mEditor.getReadOnly() ? mStyle->getReadOnlyColor() : mStyle->getColor()) % alpha;
+ LLColor4 color = (is_text_read_only ? mStyle->getReadOnlyColor() : mStyle->getColor()) % (alpha * mStyle->getAlpha());
if( selection_start > seg_start )
{
@@ -3342,16 +3363,40 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
S32 start = seg_start;
S32 end = llmin( selection_start, seg_end );
S32 length = end - start;
- font->render(text, start,
- rect,
- color,
- LLFontGL::LEFT, mEditor.mTextVAlign,
- LLFontGL::NORMAL,
- mStyle->getShadowType(),
- length,
- &right_x,
- mEditor.getUseEllipses(),
- mEditor.getUseColor());
+ if (is_text_read_only)
+ {
+ mFontBufferPreSelection.render(
+ font,
+ text, start,
+ rect,
+ color,
+ LLFontGL::LEFT, mEditor.mTextVAlign,
+ LLFontGL::NORMAL,
+ mStyle->getShadowType(),
+ length,
+ &right_x,
+ mEditor.getUseEllipses(),
+ mEditor.getUseColor());
+ }
+ else
+ {
+ // Font buffer doesn't do well with changes and huge notecard with a bunch
+ // of segments will see a lot of buffer updates, so instead use derect
+ // rendering to cache.
+ // Todo: instead of mLastGeneration make buffer invalidation more fine grained
+ // like string hash of a given segment.
+ font->render(
+ text, start,
+ rect,
+ color,
+ LLFontGL::LEFT, mEditor.mTextVAlign,
+ LLFontGL::NORMAL,
+ mStyle->getShadowType(),
+ length,
+ &right_x,
+ mEditor.getUseEllipses(),
+ mEditor.getUseColor());
+ }
}
rect.mLeft = right_x;
@@ -3362,16 +3407,35 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
S32 end = llmin( selection_end, seg_end );
S32 length = end - start;
- font->render(text, start,
- rect,
- mStyle->getSelectedColor().get(),
- LLFontGL::LEFT, mEditor.mTextVAlign,
- LLFontGL::NORMAL,
- LLFontGL::NO_SHADOW,
- length,
- &right_x,
- mEditor.getUseEllipses(),
- mEditor.getUseColor());
+ if (is_text_read_only)
+ {
+ mFontBufferSelection.render(
+ font,
+ text, start,
+ rect,
+ mStyle->getSelectedColor().get(),
+ LLFontGL::LEFT, mEditor.mTextVAlign,
+ LLFontGL::NORMAL,
+ LLFontGL::NO_SHADOW,
+ length,
+ &right_x,
+ mEditor.getUseEllipses(),
+ mEditor.getUseColor());
+ }
+ else
+ {
+ font->render(
+ text, start,
+ rect,
+ mStyle->getSelectedColor().get(),
+ LLFontGL::LEFT, mEditor.mTextVAlign,
+ LLFontGL::NORMAL,
+ LLFontGL::NO_SHADOW,
+ length,
+ &right_x,
+ mEditor.getUseEllipses(),
+ mEditor.getUseColor());
+ }
}
rect.mLeft = right_x;
if( selection_end < seg_end )
@@ -3380,16 +3444,36 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
S32 start = llmax( selection_end, seg_start );
S32 end = seg_end;
S32 length = end - start;
- font->render(text, start,
- rect,
- color,
- LLFontGL::LEFT, mEditor.mTextVAlign,
- LLFontGL::NORMAL,
- mStyle->getShadowType(),
- length,
- &right_x,
- mEditor.getUseEllipses(),
- mEditor.getUseColor());
+ if (is_text_read_only)
+ {
+ mFontBufferPostSelection.render(
+ font,
+ text, start,
+ rect,
+ color,
+ LLFontGL::LEFT, mEditor.mTextVAlign,
+ LLFontGL::NORMAL,
+ mStyle->getShadowType(),
+ length,
+ &right_x,
+ mEditor.getUseEllipses(),
+ mEditor.getUseColor());
+ }
+ else
+ {
+ font->render(
+ text, start,
+ rect,
+ color,
+ LLFontGL::LEFT, mEditor.mTextVAlign,
+ LLFontGL::NORMAL,
+ mStyle->getShadowType(),
+ length,
+ &right_x,
+ mEditor.getUseEllipses(),
+ mEditor.getUseColor());
+
+ }
}
return right_x;
}
@@ -3576,6 +3660,15 @@ S32 LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin
return num_chars;
}
+void LLNormalTextSegment::updateLayout(const class LLTextBase& editor)
+{
+ LLTextSegment::updateLayout(editor);
+
+ mFontBufferPreSelection.reset();
+ mFontBufferSelection.reset();
+ mFontBufferPostSelection.reset();
+}
+
void LLNormalTextSegment::dump() const
{
LL_INFOS() << "Segment [" <<
@@ -3604,7 +3697,7 @@ LLLabelTextSegment::LLLabelTextSegment( LLStyleConstSP style, S32 start, S32 end
{
}
-LLLabelTextSegment::LLLabelTextSegment( const LLColor4& color, S32 start, S32 end, LLTextBase& editor, bool is_visible)
+LLLabelTextSegment::LLLabelTextSegment( const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible)
: LLNormalTextSegment(color, start, end, editor, is_visible)
{
}
@@ -3628,7 +3721,7 @@ LLEmojiTextSegment::LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end,
{
}
-LLEmojiTextSegment::LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, bool is_visible)
+LLEmojiTextSegment::LLEmojiTextSegment(const LLUIColor& color, S32 start, S32 end, LLTextBase& editor, bool is_visible)
: LLNormalTextSegment(color, start, end, editor, is_visible)
{
}
@@ -3720,7 +3813,7 @@ bool LLInlineViewSegment::getDimensionsF32(S32 first_char, S32 num_chars, F32& w
}
else
{
- width = mLeftPad + mRightPad + mView->getRect().getWidth();
+ width = (F32)(mLeftPad + mRightPad + mView->getRect().getWidth());
height = mBottomPad + mTopPad + mView->getRect().getHeight();
}
@@ -3871,10 +3964,10 @@ F32 LLImageTextSegment::draw(S32 start, S32 end, S32 selection_start, S32 select
S32 style_image_width = image->getWidth();
// Text is drawn from the top of the draw_rect downward
- S32 text_center = draw_rect.mTop - (draw_rect.getHeight() / 2);
+ S32 text_center = (S32)(draw_rect.mTop - (draw_rect.getHeight() / 2.f));
// Align image to center of draw rect
S32 image_bottom = text_center - (style_image_height / 2);
- image->draw(draw_rect.mLeft, image_bottom,
+ image->draw((S32)draw_rect.mLeft, image_bottom,
style_image_width, style_image_height, color);
const S32 IMAGE_HPAD = 3;