diff options
author | vincentdarley <vincentdarley> | 2003-12-05 17:19:05 (GMT) |
---|---|---|
committer | vincentdarley <vincentdarley> | 2003-12-05 17:19:05 (GMT) |
commit | 95095f33c96ee93d276125f68a368155248c82f3 (patch) | |
tree | ac9a2a3935c2cc5f36e24d0fef108c0e5bb6addc /generic/tkTextDisp.c | |
parent | 2c4c5f606e4132d559e71e467cd803df38080b32 (diff) | |
download | tk-95095f33c96ee93d276125f68a368155248c82f3.zip tk-95095f33c96ee93d276125f68a368155248c82f3.tar.gz tk-95095f33c96ee93d276125f68a368155248c82f3.tar.bz2 |
performance of lines containing 10000+ characters
Diffstat (limited to 'generic/tkTextDisp.c')
-rw-r--r-- | generic/tkTextDisp.c | 138 |
1 files changed, 108 insertions, 30 deletions
diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index f015fd1..6968c82 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextDisp.c,v 1.36 2003/12/04 12:28:37 vincentdarley Exp $ + * RCS: @(#) $Id: tkTextDisp.c,v 1.37 2003/12/05 17:19:06 vincentdarley Exp $ */ #include "tkPort.h" @@ -292,6 +292,9 @@ typedef struct TextDInfo { * contained in the widget and update * their geometry calculations, if they * are out of date. */ + TkTextIndex metricIndex; + int metricPixelHeight; + int metricEpoch; int lastMetricUpdateLine; /* When the current update line reaches * this line, we are done and should * stop the asychronous callback @@ -512,7 +515,10 @@ TkTextCreateDInfo(textPtr) dInfoPtr->currentMetricUpdateLine = -1; dInfoPtr->lastMetricUpdateLine = -1; dInfoPtr->lineMetricUpdateEpoch = 1; - + dInfoPtr->metricEpoch = -1; + dInfoPtr->metricIndex.textPtr = NULL; + dInfoPtr->metricIndex.linePtr = NULL; + /* Add a refCount for each of the idle call-backs */ textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(0, @@ -2642,12 +2648,56 @@ TkTextUpdateLineMetrics(textPtr, lineNum, endLine, doThisMuch) /* Now update the line's metrics if necessary */ if (linePtr->pixelCalculationEpoch != textPtr->dInfoPtr->lineMetricUpdateEpoch) { - /* - * Update the line and update the counter, counting - * 10 for each line we actually re-layout. - */ - TkTextUpdateOneLine(textPtr, linePtr); - count += 10; + if (doThisMuch == -1) { + count += 8 * TkTextUpdateOneLine(textPtr, linePtr, + 0, NULL); + } else { + TkTextIndex index; + TkTextIndex *indexPtr; + int pixelHeight; + + /* + * If the metric epoch is the same as the widget's + * epoch, then we know that indexPtrs are still + * valid, and if the cached metricIndex (if any) is + * for the same line as we wish to examine, then + * we are looking at a long line wrapped many + * times, which we will examine in pieces. + */ + if (textPtr->dInfoPtr->metricEpoch == textPtr->stateEpoch + && textPtr->dInfoPtr->metricIndex.linePtr == linePtr) { + indexPtr = &textPtr->dInfoPtr->metricIndex; + pixelHeight = textPtr->dInfoPtr->metricPixelHeight; + } else { + index.tree = textPtr->tree; + index.linePtr = linePtr; + index.byteIndex = 0; + index.textPtr = NULL; + indexPtr = &index; + pixelHeight = 0; + } + /* + * Update the line and update the counter, counting + * 8 for each display line we actually re-layout. + */ + count += 8 * TkTextUpdateOneLine(textPtr, linePtr, + pixelHeight, indexPtr); + + if (indexPtr->linePtr == linePtr) { + /* + * We didn't complete the logical line, because it + * produced very many display lines -- it must be a + * long line wrapped many times. So we must + * cache as far as we got for next time around. + */ + if (pixelHeight == 0) { + textPtr->dInfoPtr->metricIndex = index; + textPtr->dInfoPtr->metricEpoch = textPtr->stateEpoch; + } + textPtr->dInfoPtr->metricPixelHeight = linePtr->pixelHeight; + break; + } + } } } else { /* @@ -3094,18 +3144,32 @@ TkTextIndexYPixels(textPtr, indexPtr) */ int -TkTextUpdateOneLine(textPtr, linePtr) +TkTextUpdateOneLine(textPtr, linePtr, pixelHeight, indexPtr) TkText *textPtr; /* Widget record for text widget. */ TkTextLine *linePtr; /* The line of which to calculate the * height. */ + int pixelHeight; /* If indexPtr is non-NULL, then this + * is the number of pixels in the logical + * line linePtr, up to the index which + * has been given. */ + TkTextIndex *indexPtr; /* Either NULL or an index at the start of + * a display line belonging to linePtr, + * up to which we have already calculated. */ { TkTextIndex index; - int pixelHeight, displayLines; + int displayLines, partialCalc; - index.tree = textPtr->tree; - index.linePtr = linePtr; - index.byteIndex = 0; - index.textPtr = NULL; + if (indexPtr == NULL) { + index.tree = textPtr->tree; + index.linePtr = linePtr; + index.byteIndex = 0; + index.textPtr = NULL; + indexPtr = &index; + pixelHeight = 0; + partialCalc = 0; + } else { + partialCalc = 1; + } /* * Iterate through all display-lines corresponding to the @@ -3114,7 +3178,6 @@ TkTextUpdateOneLine(textPtr, linePtr) * total is, therefore, the height of the logical line. */ - pixelHeight = 0; displayLines = 0; while (1) { @@ -3128,37 +3191,52 @@ TkTextUpdateOneLine(textPtr, linePtr) * specifically the 'linePtr->pixelHeight == pixelHeight' test * below this while loop. */ - height = CalculateDisplayLineHeight(textPtr, &index, &bytes); + height = CalculateDisplayLineHeight(textPtr, indexPtr, &bytes); if (height > 0) { pixelHeight += height; displayLines++; } - if (TkTextIndexForwBytes(&index, bytes, &index)) { + if (TkTextIndexForwBytes(indexPtr, bytes, indexPtr)) { break; } - if (index.linePtr != linePtr) { + if (indexPtr->linePtr != linePtr) { + /* + * If we reached the end of the logical line, then + * either way we don't have a partial calculation. + */ + partialCalc = 0; + break; + } + if (partialCalc && displayLines > 50) { + /* + * Only calculate 50 display lines at a time, to + * avoid huge delays. In any case it is very rare + * that a single line wraps 50 times! + */ break; } } - /* - * Mark the logical line as being up to date (caution: it isn't - * yet up to date, that will happen in TkBTreeAdjustPixelHeight - * just below). - */ - linePtr->pixelCalculationEpoch = textPtr->dInfoPtr->lineMetricUpdateEpoch; + if (!partialCalc) { + /* + * Mark the logical line as being up to date (caution: it isn't + * yet up to date, that will happen in TkBTreeAdjustPixelHeight + * just below). + */ + linePtr->pixelCalculationEpoch = textPtr->dInfoPtr->lineMetricUpdateEpoch; - if (linePtr->pixelHeight == pixelHeight) { - return displayLines; + if (linePtr->pixelHeight == pixelHeight) { + return displayLines; + } } - + /* - * We now use the resulting 'pixelHeight' to refer to the - * height of the entire widget, which may be used just below - * for reporting/debugging purposes + * We set the line's height, but the return value is now the height + * of the entire widget, which may be used just below for + * reporting/debugging purposes. */ pixelHeight = TkBTreeAdjustPixelHeight(linePtr, pixelHeight); |