diff options
| author | Matthias Melcher <github@matthiasm.com> | 2024-08-04 00:32:05 +0200 |
|---|---|---|
| committer | Matthias Melcher <github@matthiasm.com> | 2024-08-04 00:32:11 +0200 |
| commit | 9bb9cb3f962bea7365e21bb1a836bf140deb6570 (patch) | |
| tree | 97e66074c84b140cdce7f883925f395617e49d99 /src/Fl_Text_Display.cxx | |
| parent | bc7358036683fd7bd4e6a0fe29256fc70f573978 (diff) | |
Optimize Fl_Text_Display scrolling speed (#596).
Diffstat (limited to 'src/Fl_Text_Display.cxx')
| -rw-r--r-- | src/Fl_Text_Display.cxx | 66 |
1 files changed, 58 insertions, 8 deletions
diff --git a/src/Fl_Text_Display.cxx b/src/Fl_Text_Display.cxx index c91c98a79..84571af47 100644 --- a/src/Fl_Text_Display.cxx +++ b/src/Fl_Text_Display.cxx @@ -560,9 +560,9 @@ void Fl_Text_Display::recalc_display() { if (mContinuousWrap && !mWrapMarginPix && text_area.w != oldTAWidth) { int oldFirstChar = mFirstChar; - mNBufferLines = count_lines(0, buffer()->length(), true); mFirstChar = line_start(mFirstChar); mTopLineNum = count_lines(0, mFirstChar, true)+1; + mNBufferLines = mTopLineNum-1 + count_lines(mFirstChar, buffer()->length(), true); absolute_top_line_number(oldFirstChar); #ifdef DEBUG2 printf(" mNBufferLines=%d\n", mNBufferLines); @@ -1436,16 +1436,66 @@ int Fl_Text_Display::count_lines(int startPos, int endPos, if (!mContinuousWrap) return buffer()->count_lines(startPos, endPos); - wrapped_line_counter(buffer(), startPos, endPos, INT_MAX, - startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, - &retLineEnd); + /* + Correctly counting wrapped lines is very slow. We have to query the length + of every segment of text for every line change and style change and find + potential soft line breaks. + + Most of the resulting information is needed for calculating the vertical + scroll bar size. After a certain text length, the scroll bar size is no + longer very precise anyway, so we optimize line count for all lines but + the visible ones (plus minus a few lines for rounding). + + The optimized code is several magnitudes faster and makes scrolling and + window resizing of long texts quite responsive. There is a slight but IMHO + tollerable drawback: when walking huge files using arrow up and down, the + text display sometimes jumps 2 or 3 lines instead of 1, but the overall + buffer stays intact as well as the scroll position. + */ + if (buffer()->length() > 16384) { + // Optimized line counting + int nLines = 0; + int firstVisibleChar = buffer()->rewind_lines(mFirstChar, 3); + int lastVisibleChar = buffer()->skip_lines(mLastChar, 3); + // Calculate the averga number of characters up to a soft line break + if (mColumnScale==0.0) x_to_col(1.0); + int avgCharsPerLine = mWrapMarginPix; + if (!avgCharsPerLine) avgCharsPerLine = text_area.w; + avgCharsPerLine = (int)(avgCharsPerLine / mColumnScale) + 1; + + // first segment, lines up to display, count fast + if (startPos < firstVisibleChar) { + int tmpEnd = endPos<firstVisibleChar ? endPos : firstVisibleChar; + nLines += buffer()->estimate_lines(startPos, tmpEnd, avgCharsPerLine); + startPos = tmpEnd; + } + // second segement, count displayed liens + if (startPos < endPos && startPos < mLastChar) { + // Precisse line counting only for visible text: + int tmpEnd = endPos<lastVisibleChar ? endPos : lastVisibleChar; + wrapped_line_counter(buffer(), startPos, tmpEnd, INT_MAX, + startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, + &retLineEnd); + nLines += retLines; + startPos = tmpEnd; + } + // third segement is everything after displayed lines + if (startPos < endPos && startPos >= lastVisibleChar) { + nLines += buffer()->estimate_lines(startPos, endPos, avgCharsPerLine); + } + return nLines; + } else { + // Precise line counting only for small text buffer sizes: + wrapped_line_counter(buffer(), startPos, endPos, INT_MAX, + startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, + &retLineEnd); #ifdef DEBUG - printf(" # after WLC: retPos=%d, retLines=%d, retLineStart=%d, retLineEnd=%d\n", - retPos, retLines, retLineStart, retLineEnd); + printf(" # after WLC: retPos=%d, retLines=%d, retLineStart=%d, retLineEnd=%d\n", + retPos, retLines, retLineStart, retLineEnd); #endif // DEBUG - - return retLines; + return retLines; + } } |
